Skip to content

Commit 3ae76eb

Browse files
authored
Merge pull request #765 from nevans/replace-c-ext-init_data-with-Data-initialize-bind_call
Replace C extension `ToRuby#init_data` with `Data#initialize` bind_call
2 parents 5af4cec + fa487aa commit 3ae76eb

File tree

4 files changed

+32
-13
lines changed

4 files changed

+32
-13
lines changed

.github/workflows/test.yml

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,11 @@ jobs:
2626
ruby: ${{ fromJson(needs.ruby-versions.outputs.versions) }}
2727
os: [ ubuntu-latest, macos-latest, windows-latest ]
2828
include:
29-
# jruby is broken with "undefined method 'init_data'"
30-
# https://github.com/ruby/psych/actions/runs/15434465445/job/43438083198?pr=734
29+
# jruby-10.0.2.0 does not support Data instances with ivars
3130
- { os: windows-latest, ruby: jruby-head }
3231
- { os: macos-latest, ruby: jruby-head }
3332
- { os: ubuntu-latest, ruby: jruby-head }
34-
# Needs truffleruby-head for rb_struct_initialize() (which truffleruby 25.0 does not have)
33+
# Needs truffleruby-head for (base) Data#initialize (which truffleruby 25.0 does not have)
3534
- { os: ubuntu-latest, ruby: truffleruby-head }
3635
- { os: macos-latest, ruby: truffleruby-head }
3736
- { os: windows-latest, ruby: ucrt }
@@ -59,7 +58,6 @@ jobs:
5958
- name: Run test
6059
id: test
6160
run: rake
62-
continue-on-error: ${{ matrix.ruby == 'jruby-head' }}
6361
- name: Install gem
6462
run: rake install
6563
if: ${{ steps.test.outcome == 'success' }}

ext/psych/psych_to_ruby.c

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,6 @@ static VALUE path2class(VALUE self, VALUE path)
2828
return rb_path_to_class(path);
2929
}
3030

31-
static VALUE init_data(VALUE self, VALUE data, VALUE values)
32-
{
33-
rb_struct_initialize(data, values);
34-
return data;
35-
}
36-
3731
void Init_psych_to_ruby(void)
3832
{
3933
VALUE psych = rb_define_module("Psych");
@@ -43,7 +37,6 @@ void Init_psych_to_ruby(void)
4337
VALUE visitor = rb_define_class_under(visitors, "Visitor", rb_cObject);
4438
cPsychVisitorsToRuby = rb_define_class_under(visitors, "ToRuby", visitor);
4539

46-
rb_define_private_method(cPsychVisitorsToRuby, "init_data", init_data, 2);
4740
rb_define_private_method(cPsychVisitorsToRuby, "build_exception", build_exception, 2);
4841
rb_define_private_method(class_loader, "path2class", path2class, 1);
4942
}

lib/psych/visitors/to_ruby.rb

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@ module Visitors
1212
###
1313
# This class walks a YAML AST, converting each node to Ruby
1414
class ToRuby < Psych::Visitors::Visitor
15+
unless RUBY_VERSION < "3.2"
16+
DATA_INITIALIZE = Data.instance_method(:initialize)
17+
end
18+
1519
def self.create(symbolize_names: false, freeze: false, strict_integer: false, parse_symbols: true)
1620
class_loader = ClassLoader.new
1721
scanner = ScalarScanner.new class_loader, strict_integer: strict_integer, parse_symbols: parse_symbols
@@ -219,8 +223,7 @@ def visit_Psych_Nodes_Mapping o
219223
revive_data_members(members, o)
220224
end
221225
data ||= allocate_anon_data(o, members)
222-
values = data.members.map { |m| members[m] }
223-
init_data(data, values)
226+
DATA_INITIALIZE.bind_call(data, **members)
224227
data.freeze
225228
data
226229

test/psych/test_data.rb

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,31 @@ def test_load
6464
assert_equal "hello", obj.bar
6565
assert_equal "bar", obj.foo
6666
end
67+
68+
def test_members_must_be_identical
69+
TestData.const_set :D, Data.define(:a, :b)
70+
d = Psych.dump(TestData::D.new(1, 2))
71+
72+
# more members
73+
TestData.send :remove_const, :D
74+
TestData.const_set :D, Data.define(:a, :b, :c)
75+
e = assert_raise(ArgumentError) { Psych.unsafe_load d }
76+
assert_equal 'missing keyword: :c', e.message
77+
78+
# less members
79+
TestData.send :remove_const, :D
80+
TestData.const_set :D, Data.define(:a)
81+
e = assert_raise(ArgumentError) { Psych.unsafe_load d }
82+
assert_equal 'unknown keyword: :b', e.message
83+
84+
# completely different members
85+
TestData.send :remove_const, :D
86+
TestData.const_set :D, Data.define(:foo, :bar)
87+
e = assert_raise(ArgumentError) { Psych.unsafe_load d }
88+
assert_equal 'unknown keywords: :a, :b', e.message
89+
ensure
90+
TestData.send :remove_const, :D
91+
end
6792
end
6893
end
6994

0 commit comments

Comments
 (0)