ruby-changes:58634
From: Kazuki <ko1@a...>
Date: Fri, 8 Nov 2019 11:38:58 +0900 (JST)
Subject: [ruby-changes:58634] d4da74ea78 (master): Define Struct#deconstruct_keys
https://git.ruby-lang.org/ruby.git/commit/?id=d4da74ea78 From d4da74ea786da7906fdb85e593593a9c6c11fe96 Mon Sep 17 00:00:00 2001 From: Kazuki Tsujimoto <kazuki@c...> Date: Fri, 8 Nov 2019 11:37:07 +0900 Subject: Define Struct#deconstruct_keys diff --git a/struct.c b/struct.c index 273c719..f4ae094 100644 --- a/struct.c +++ b/struct.c @@ -944,6 +944,33 @@ rb_struct_to_h(VALUE s) https://github.com/ruby/ruby/blob/trunk/struct.c#L944 return h; } +static VALUE +rb_struct_deconstruct_keys(VALUE s, VALUE keys) +{ + VALUE h; + long i; + + if (NIL_P(keys)) { + return rb_struct_to_h(s); + } + if (UNLIKELY(!RB_TYPE_P(keys, T_ARRAY))) { + rb_raise(rb_eTypeError, + "wrong argument type %"PRIsVALUE" (expected Array or nil)", + rb_obj_class(keys)); + + } + h = rb_hash_new_with_size(RARRAY_LEN(keys)); + for (i=0; i<RARRAY_LEN(keys); i++) { + VALUE key = RARRAY_AREF(keys, i); + int i = rb_struct_pos(s, &key); + if (i < 0) { + return rb_hash_new_with_size(0); + } + rb_hash_aset(h, key, RSTRUCT_GET(s, i)); + } + return h; +} + /* :nodoc: */ VALUE rb_struct_init_copy(VALUE copy, VALUE s) @@ -1357,6 +1384,7 @@ InitVM_Struct(void) https://github.com/ruby/ruby/blob/trunk/struct.c#L1384 rb_define_method(rb_cStruct, "dig", rb_struct_dig, -1); rb_define_method(rb_cStruct, "deconstruct", rb_struct_to_a, 0); + rb_define_method(rb_cStruct, "deconstruct_keys", rb_struct_deconstruct_keys, 1); } #undef rb_intern diff --git a/test/ruby/test_pattern_matching.rb b/test/ruby/test_pattern_matching.rb index 0338f90..9af091a 100644 --- a/test/ruby/test_pattern_matching.rb +++ b/test/ruby/test_pattern_matching.rb @@ -1230,6 +1230,30 @@ END https://github.com/ruby/ruby/blob/trunk/test/ruby/test_pattern_matching.rb#L1230 true end end + + s = Struct.new(:a, :b, keyword_init: true) + assert_block do + case s[a: 0, b: 1] + in **r + r == {a: 0, b: 1} + end + end + assert_block do + s = Struct.new(:a, :b, keyword_init: true) + case s[a: 0, b: 1] + in a:, b: + a == 0 && b == 1 + end + end + assert_block do + s = Struct.new(:a, :b, keyword_init: true) + case s[a: 0, b: 1] + in a:, c: + flunk + in b: + b == 1 + end + end end ################################################################ diff --git a/test/ruby/test_struct.rb b/test/ruby/test_struct.rb index 22a6ce8..06a8a1b 100644 --- a/test/ruby/test_struct.rb +++ b/test/ruby/test_struct.rb @@ -431,6 +431,18 @@ module TestStruct https://github.com/ruby/ruby/blob/trunk/test/ruby/test_struct.rb#L431 } end + def test_deconstruct_keys + klass = @Struct.new(:a, :b) + o = klass.new(1, 2) + assert_equal({a: 1, b: 2}, o.deconstruct_keys(nil)) + assert_equal({a: 1, b: 2}, o.deconstruct_keys([:b, :a])) + assert_equal({a: 1}, o.deconstruct_keys([:a])) + assert_equal({}, o.deconstruct_keys([:a, :c])) + assert_raise(TypeError) { + o.deconstruct_keys(0) + } + end + class TopStruct < Test::Unit::TestCase include TestStruct -- cgit v0.10.2 -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/