MatchData#named_captures: add optional symbolize_names keyword (#6952)
This commit is contained in:
parent
2dff1d4fda
commit
b09f5c7bf7
Notes:
git
2023-04-18 23:20:02 +00:00
Merged-By: ioquatix <samuel@codeotaku.com>
4
NEWS.md
4
NEWS.md
@ -30,6 +30,10 @@ Note: We're only listing outstanding class updates.
|
|||||||
* `Dir#chdir` added for changing the directory to the directory specified
|
* `Dir#chdir` added for changing the directory to the directory specified
|
||||||
by the provided `Dir` object. [[Feature #19347]]
|
by the provided `Dir` object. [[Feature #19347]]
|
||||||
|
|
||||||
|
* MatchData
|
||||||
|
|
||||||
|
* MatchData#named_captures now accepts optional `symbolize_names` keyword. [[Feature #19591]]
|
||||||
|
|
||||||
* String
|
* String
|
||||||
|
|
||||||
* `String#unpack` now raises ArgumentError for unknown directives. [[Bug #19150]]
|
* `String#unpack` now raises ArgumentError for unknown directives. [[Bug #19150]]
|
||||||
|
34
re.c
34
re.c
@ -2316,7 +2316,7 @@ match_named_captures_iter(const OnigUChar *name, const OnigUChar *name_end,
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* call-seq:
|
* call-seq:
|
||||||
* named_captures -> hash
|
* named_captures(symbolize_names: false) -> hash
|
||||||
*
|
*
|
||||||
* Returns a hash of the named captures;
|
* Returns a hash of the named captures;
|
||||||
* each key is a capture name; each value is its captured string or +nil+:
|
* each key is a capture name; each value is its captured string or +nil+:
|
||||||
@ -2337,10 +2337,17 @@ match_named_captures_iter(const OnigUChar *name, const OnigUChar *name_end,
|
|||||||
* # => #<MatchData "01" a:"0" a:"1">
|
* # => #<MatchData "01" a:"0" a:"1">
|
||||||
* m.named_captures #=> {"a" => "1"}
|
* m.named_captures #=> {"a" => "1"}
|
||||||
*
|
*
|
||||||
|
* If keyword argument +symbolize_names+ is given
|
||||||
|
* a true value, the keys in the resulting hash are Symbols:
|
||||||
|
*
|
||||||
|
* m = /(?<a>.)(?<a>.)/.match("01")
|
||||||
|
* # => #<MatchData "01" a:"0" a:"1">
|
||||||
|
* m.named_captures(symbolize_names: true) #=> {:a => "1"}
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static VALUE
|
static VALUE
|
||||||
match_named_captures(VALUE match)
|
match_named_captures(int argc, VALUE *argv, VALUE match)
|
||||||
{
|
{
|
||||||
VALUE hash;
|
VALUE hash;
|
||||||
struct MEMO *memo;
|
struct MEMO *memo;
|
||||||
@ -2349,8 +2356,27 @@ match_named_captures(VALUE match)
|
|||||||
if (NIL_P(RMATCH(match)->regexp))
|
if (NIL_P(RMATCH(match)->regexp))
|
||||||
return rb_hash_new();
|
return rb_hash_new();
|
||||||
|
|
||||||
|
VALUE opt;
|
||||||
|
VALUE symbolize_names = 0;
|
||||||
|
|
||||||
|
rb_scan_args(argc, argv, "0:", &opt);
|
||||||
|
|
||||||
|
if (!NIL_P(opt)) {
|
||||||
|
static ID keyword_ids[1];
|
||||||
|
|
||||||
|
VALUE symbolize_names_val;
|
||||||
|
|
||||||
|
if (!keyword_ids[0]) {
|
||||||
|
keyword_ids[0] = rb_intern_const("symbolize_names");
|
||||||
|
}
|
||||||
|
rb_get_kwargs(opt, keyword_ids, 0, 1, &symbolize_names_val);
|
||||||
|
if (!UNDEF_P(symbolize_names_val) && RTEST(symbolize_names_val)) {
|
||||||
|
symbolize_names = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
hash = rb_hash_new();
|
hash = rb_hash_new();
|
||||||
memo = MEMO_NEW(hash, match, 0);
|
memo = MEMO_NEW(hash, match, symbolize_names);
|
||||||
|
|
||||||
onig_foreach_name(RREGEXP(RMATCH(match)->regexp)->ptr, match_named_captures_iter, (void*)memo);
|
onig_foreach_name(RREGEXP(RMATCH(match)->regexp)->ptr, match_named_captures_iter, (void*)memo);
|
||||||
|
|
||||||
@ -4754,7 +4780,7 @@ Init_Regexp(void)
|
|||||||
rb_define_method(rb_cMatch, "[]", match_aref, -1);
|
rb_define_method(rb_cMatch, "[]", match_aref, -1);
|
||||||
rb_define_method(rb_cMatch, "captures", match_captures, 0);
|
rb_define_method(rb_cMatch, "captures", match_captures, 0);
|
||||||
rb_define_alias(rb_cMatch, "deconstruct", "captures");
|
rb_define_alias(rb_cMatch, "deconstruct", "captures");
|
||||||
rb_define_method(rb_cMatch, "named_captures", match_named_captures, 0);
|
rb_define_method(rb_cMatch, "named_captures", match_named_captures, -1);
|
||||||
rb_define_method(rb_cMatch, "deconstruct_keys", match_deconstruct_keys, 1);
|
rb_define_method(rb_cMatch, "deconstruct_keys", match_deconstruct_keys, 1);
|
||||||
rb_define_method(rb_cMatch, "values_at", match_values_at, -1);
|
rb_define_method(rb_cMatch, "values_at", match_values_at, -1);
|
||||||
rb_define_method(rb_cMatch, "pre_match", rb_reg_match_pre, 0);
|
rb_define_method(rb_cMatch, "pre_match", rb_reg_match_pre, 0);
|
||||||
|
@ -12,4 +12,16 @@ describe 'MatchData#named_captures' do
|
|||||||
it 'returns the latest matched capture, even if a later one that does not match exists' do
|
it 'returns the latest matched capture, even if a later one that does not match exists' do
|
||||||
/\A(?<a>.)(?<b>.)(?<b>.)(?<a>.)?\z/.match('012').named_captures.should == { 'a' => '0', 'b' => '2' }
|
/\A(?<a>.)(?<b>.)(?<b>.)(?<a>.)?\z/.match('012').named_captures.should == { 'a' => '0', 'b' => '2' }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
ruby_version_is "3.3" do
|
||||||
|
it 'returns a Hash with Symbol keys when symbolize_names is provided a true value' do
|
||||||
|
/(?<a>.)(?<b>.)?/.match('0').named_captures(symbolize_names: true).should == { a: '0', b: nil }
|
||||||
|
/(?<a>.)(?<b>.)?/.match('0').named_captures(symbolize_names: "truly").should == { a: '0', b: nil }
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns a Hash with String keys when symbolize_names is provided a false value' do
|
||||||
|
/(?<a>.)(?<b>.)?/.match('02').named_captures(symbolize_names: false).should == { 'a' => '0', 'b' => '2' }
|
||||||
|
/(?<a>.)(?<b>.)?/.match('02').named_captures(symbolize_names: nil).should == { 'a' => '0', 'b' => '2' }
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
@ -304,6 +304,9 @@ class TestRegexp < Test::Unit::TestCase
|
|||||||
assert_equal({'a' => '1', 'b' => '2', 'c' => '3'}, /^(?<a>.)(?<b>.)(?<c>.)?/.match('123').named_captures)
|
assert_equal({'a' => '1', 'b' => '2', 'c' => '3'}, /^(?<a>.)(?<b>.)(?<c>.)?/.match('123').named_captures)
|
||||||
assert_equal({'a' => '1', 'b' => '2', 'c' => ''}, /^(?<a>.)(?<b>.)(?<c>.?)/.match('12').named_captures)
|
assert_equal({'a' => '1', 'b' => '2', 'c' => ''}, /^(?<a>.)(?<b>.)(?<c>.?)/.match('12').named_captures)
|
||||||
|
|
||||||
|
assert_equal({a: '1', b: '2', c: ''}, /^(?<a>.)(?<b>.)(?<c>.?)/.match('12').named_captures(symbolize_names: true))
|
||||||
|
assert_equal({'a' => '1', 'b' => '2', 'c' => ''}, /^(?<a>.)(?<b>.)(?<c>.?)/.match('12').named_captures(symbolize_names: false))
|
||||||
|
|
||||||
assert_equal({'a' => 'x'}, /(?<a>x)|(?<a>y)/.match('x').named_captures)
|
assert_equal({'a' => 'x'}, /(?<a>x)|(?<a>y)/.match('x').named_captures)
|
||||||
assert_equal({'a' => 'y'}, /(?<a>x)|(?<a>y)/.match('y').named_captures)
|
assert_equal({'a' => 'y'}, /(?<a>x)|(?<a>y)/.match('y').named_captures)
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user