summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEarlopain <14981592+Earlopain@users.noreply.github.com>2026-02-04 14:31:32 +0100
committergit <svn-admin@ruby-lang.org>2026-02-04 14:58:08 +0000
commit673c37d76ac2767b13a1ab7ba74b0ea8cda17c81 (patch)
tree7447e58dbe4772161e957b1646f38d0366fb47be
parent1258992bdff8818d3ce868e98ccc3496069d996d (diff)
[ruby/prism] Rewrite "version: nearest" to require no maintenance
Currently I see myself not updating this when a new version is added. Instead, rewrite it to just work with new versions: * Try to set the version * If that doesn't succeed, check if it is lower * If it isn't lower, it must be higher We can then use `PM_OPTIONS_VERSION_LATEST` which doesn't need to change. Also added a very basic test. https://github.com/ruby/prism/commit/443e9b9959
-rw-r--r--lib/prism/ffi.rb43
-rw-r--r--prism/extension.c20
-rw-r--r--test/prism/api/parse_test.rb4
3 files changed, 31 insertions, 36 deletions
diff --git a/lib/prism/ffi.rb b/lib/prism/ffi.rb
index 57d878a33f..618324ded6 100644
--- a/lib/prism/ffi.rb
+++ b/lib/prism/ffi.rb
@@ -423,27 +423,28 @@ module Prism
# Return the value that should be dumped for the version option.
def dump_options_version(version)
- checking =
- case version
- when "current"
- RUBY_VERSION
- when "latest"
- nil
- when "nearest"
- if RUBY_VERSION <= "3.3"
- "3.3"
- elsif RUBY_VERSION >= "4.1"
- "4.1"
- else
- RUBY_VERSION
- end
+ case version
+ when "current"
+ version_string_to_number(RUBY_VERSION) || raise(CurrentVersionError, RUBY_VERSION)
+ when "latest", nil
+ 0 # Handled in pm_parser_init
+ when "nearest"
+ dump = version_string_to_number(RUBY_VERSION)
+ return dump if dump
+ if RUBY_VERSION < "3.3"
+ version_string_to_number("3.3")
else
- version
+ 0 # Handled in pm_parser_init
end
+ else
+ version_string_to_number(version) || raise(ArgumentError, "invalid version: #{version}")
+ end
+ end
- case checking
- when nil
- 0 # Handled in pm_parser_init
+ # Converts a version string like "4.0.0" or "4.0" into a number.
+ # Returns nil if the version is unknown.
+ def version_string_to_number(version)
+ case version
when /\A3\.3(\.\d+)?\z/
1
when /\A3\.4(\.\d+)?\z/
@@ -452,12 +453,6 @@ module Prism
3
when /\A4\.1(\.\d+)?\z/
4
- else
- if version == "current"
- raise CurrentVersionError, RUBY_VERSION
- else
- raise ArgumentError, "invalid version: #{version}"
- end
end
end
diff --git a/prism/extension.c b/prism/extension.c
index 363144970c..fe3cd6a8f3 100644
--- a/prism/extension.c
+++ b/prism/extension.c
@@ -205,18 +205,14 @@ build_options_i(VALUE key, VALUE value, VALUE argument) {
rb_exc_raise(rb_exc_new_cstr(rb_cPrismCurrentVersionError, ruby_version));
}
} else if (RSTRING_LEN(value) == 7 && strncmp(version, "nearest", 7) == 0) {
- const char *nearest_version;
-
- if (ruby_version[0] < '3' || (ruby_version[0] == '3' && ruby_version[2] < '3')) {
- nearest_version = "3.3";
- } else if (ruby_version[0] > '4' || (ruby_version[0] == '4' && ruby_version[2] > '1')) {
- nearest_version = "4.1";
- } else {
- nearest_version = ruby_version;
- }
-
- if (!pm_options_version_set(options, nearest_version, 3)) {
- rb_raise(rb_eArgError, "invalid nearest version: %s", nearest_version);
+ if (!pm_options_version_set(options, ruby_version, 3)) {
+ // Prism doesn't know this specific version. Is it lower?
+ if (ruby_version[0] < '3' || (ruby_version[0] == '3' && ruby_version[2] < '3')) {
+ options->version == PM_OPTIONS_VERSION_CRUBY_3_3;
+ } else {
+ // Must be higher.
+ options->version == PM_OPTIONS_VERSION_LATEST;
+ }
}
} else if (!pm_options_version_set(options, version, RSTRING_LEN(value))) {
rb_raise(rb_eArgError, "invalid version: %" PRIsVALUE, value);
diff --git a/test/prism/api/parse_test.rb b/test/prism/api/parse_test.rb
index bbf28201ff..c9a47c1a61 100644
--- a/test/prism/api/parse_test.rb
+++ b/test/prism/api/parse_test.rb
@@ -154,6 +154,10 @@ module Prism
end
end
+ def test_nearest
+ assert Prism.parse_success?("1 + 1", version: "nearest")
+ end
+
def test_scopes
assert_kind_of Prism::CallNode, Prism.parse_statement("foo")
assert_kind_of Prism::LocalVariableReadNode, Prism.parse_statement("foo", scopes: [[:foo]])