Skip to content

Release v6.0.0 - #218

Merged
emancu merged 16 commits into
masterfrom
6.0/release
Sep 28, 2026
Merged

emancu merged 16 commits into
masterfrom
6.0/release

Conversation

@emancu

@emancu emancu commented Sep 28, 2026

Copy link
Copy Markdown
Owner

toml-rb 6.0.0 replaces Citrus with a pure Ruby parser, and the gem has no runtime dependencies. The parser work was reviewed and merged into tmp/no-citrus in #211, #212, #213, #214, #216 and #217. Only the last commit is new: VERSION, the CHANGELOG date and two README lines.

On 9,257 real-world TOML files, the new parser gives the same data as 5.0.0 on MRI 2.5 to 4.0, JRuby and TruffleRuby. It is 60 to 90 times faster (benchmark/README.md). The breaking changes are in CHANGELOG.md.

This branch collects the Citrus replacement PRs before they go to
master, so its pushes and pull requests need the same checks.
The date, time and offset checks and the Time construction lived in the
Citrus mixins, so they read Citrus captures. Move them to
TomlRB::DatetimeParser functions that take the field strings. The
mixins now only read their captures and call these functions, so a
parser without Citrus can use the same checks.
The Citrus PEG grammars built a match tree for every document and
backtracked between rule alternatives. Most of the parse time went to
that work, not to toml-rb.

A recursive-descent parser on StringScanner now reads the document and
feeds the same visitor, so tables, keys, escapes and datetimes keep their
semantics. The grammars and their mixins are removed. Nested arrays and
inline tables stop at 100 levels with TomlRB::ParseError, because deeper
recursion exhausts the stack differently on each Ruby engine. Syntax
errors give a line and a column.
The parser no longer uses Citrus, so the gem does not need it. The gem
now has no runtime dependencies. The gemspec also stops packing the
.citrus grammar files, and the README and the gem description no longer
mention Citrus.
Parse with StringScanner instead of Citrus
Time.local moves a clock time that does not occur in the system time
zone. In Europe/Warsaw, 2026-03-29T02:30:00 became 03:30, and
TomlRB.dump wrote 03:30:00. Time.utc keeps the date and clock time
from the TOML text in every time zone, like TomlRB::LocalTime already
does.
Build local datetimes and dates as UTC Time
Keep the short v5.0.0 CHANGELOG section from master, and shorten the
Unreleased section in the same way.
Merge v5.0.0 into tmp/no-citrus
benchmark/run.rb parses the same documents with this checkout, toml-rb
5.0.0 and 4.2.2, tomlrb, perfect_toml and tomlib, each in its own
process, and prints the CPU time for each parse. benchmark/README.md
shows how to run it and the results.
Plain, YJIT and ZJIT runs on the same machine as the Ruby 3.4.1 results.
Add a benchmark against other TOML libraries
Set VERSION to 6.0.0, date the CHANGELOG heading, and describe the
gem as pure Ruby in the README. CI runs for master only again.
@emancu emancu self-assigned this Sep 28, 2026
String#+= copied all the output for each line, so dump time grew with
the square of the output size. A 3.3 MB lock file took 3.4 s to dump,
and now takes 0.08 s. The output does not change.
Comment thread lib/toml-rb/dumper.rb

def initialize(hash)
@toml_str = ""
@toml_str = +""

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What a weird syntax for String.new

@emancu
emancu merged commit 1cceb66 into master Sep 28, 2026
18 checks passed
@emancu
emancu deleted the 6.0/release branch September 28, 2026 15:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant