зеркало из https://github.com/github/ruby.git
Add MatchData#deconstruct/deconstruct_keys
This commit is contained in:
Родитель
546566d34b
Коммит
4954c9fc0f
2
NEWS.md
2
NEWS.md
|
@ -141,6 +141,8 @@ Note: We're only listing outstanding class updates.
|
||||||
|
|
||||||
* MatchData
|
* MatchData
|
||||||
* MatchData#byteoffset has been added. [[Feature #13110]]
|
* MatchData#byteoffset has been added. [[Feature #13110]]
|
||||||
|
* MatchData#deconstruct has been added. [[Feature #18821]]
|
||||||
|
* MatchData#deconstruct_keys has been added. [[Feature #18821]]
|
||||||
|
|
||||||
* Module
|
* Module
|
||||||
* Module.used_refinements has been added. [[Feature #14332]]
|
* Module.used_refinements has been added. [[Feature #14332]]
|
||||||
|
|
85
re.c
85
re.c
|
@ -2283,8 +2283,14 @@ match_named_captures_iter(const OnigUChar *name, const OnigUChar *name_end,
|
||||||
struct MEMO *memo = MEMO_CAST(arg);
|
struct MEMO *memo = MEMO_CAST(arg);
|
||||||
VALUE hash = memo->v1;
|
VALUE hash = memo->v1;
|
||||||
VALUE match = memo->v2;
|
VALUE match = memo->v2;
|
||||||
|
long symbolize = memo->u3.state;
|
||||||
|
|
||||||
VALUE key = rb_enc_str_new((const char *)name, name_end-name, regex->enc);
|
VALUE key = rb_enc_str_new((const char *)name, name_end-name, regex->enc);
|
||||||
|
|
||||||
|
if (symbolize > 0) {
|
||||||
|
key = rb_str_intern(key);
|
||||||
|
}
|
||||||
|
|
||||||
VALUE value;
|
VALUE value;
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
|
@ -2348,6 +2354,83 @@ match_named_captures(VALUE match)
|
||||||
return hash;
|
return hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* call-seq:
|
||||||
|
* deconstruct_keys(array_of_names) -> hash
|
||||||
|
*
|
||||||
|
* Returns a hash of the named captures for the given names.
|
||||||
|
*
|
||||||
|
* m = /(?<hours>\d{2}):(?<minutes>\d{2}):(?<seconds>\d{2})/.match("18:37:22")
|
||||||
|
* m.deconstruct_keys([:hours, :minutes]) # => {:hours => "18", :minutes => "37"}
|
||||||
|
* m.deconstruct_keys(nil) # => {:hours => "18", :minutes => "37", :seconds => "22"}
|
||||||
|
*
|
||||||
|
* Returns an empty hash of no named captures were defined:
|
||||||
|
*
|
||||||
|
* m = /(\d{2}):(\d{2}):(\d{2})/.match("18:37:22")
|
||||||
|
* m.deconstruct_keys(nil) # => {}
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static VALUE
|
||||||
|
match_deconstruct_keys(VALUE match, VALUE keys)
|
||||||
|
{
|
||||||
|
VALUE h;
|
||||||
|
long i;
|
||||||
|
|
||||||
|
match_check(match);
|
||||||
|
|
||||||
|
if (NIL_P(RMATCH(match)->regexp)) {
|
||||||
|
return rb_hash_new_with_size(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (NIL_P(keys)) {
|
||||||
|
h = rb_hash_new_with_size(onig_number_of_names(RREGEXP_PTR(RMATCH(match)->regexp)));
|
||||||
|
|
||||||
|
struct MEMO *memo;
|
||||||
|
memo = MEMO_NEW(h, match, 1);
|
||||||
|
|
||||||
|
onig_foreach_name(RREGEXP_PTR(RMATCH(match)->regexp), match_named_captures_iter, (void*)memo);
|
||||||
|
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (UNLIKELY(!RB_TYPE_P(keys, T_ARRAY))) {
|
||||||
|
rb_raise(rb_eTypeError,
|
||||||
|
"wrong argument type %"PRIsVALUE" (expected Array or nil)",
|
||||||
|
rb_obj_class(keys));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (onig_number_of_names(RREGEXP_PTR(RMATCH(match)->regexp)) < RARRAY_LEN(keys)) {
|
||||||
|
return rb_hash_new_with_size(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
h = rb_hash_new_with_size(RARRAY_LEN(keys));
|
||||||
|
|
||||||
|
for (i=0; i<RARRAY_LEN(keys); i++) {
|
||||||
|
VALUE key = RARRAY_AREF(keys, i);
|
||||||
|
VALUE name;
|
||||||
|
|
||||||
|
if (UNLIKELY(!SYMBOL_P(key))) {
|
||||||
|
rb_raise(rb_eTypeError,
|
||||||
|
"wrong argument type %"PRIsVALUE" (expected Symbol)",
|
||||||
|
rb_obj_class(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
name = rb_sym2str(key);
|
||||||
|
|
||||||
|
int num = NAME_TO_NUMBER(RMATCH_REGS(match), RMATCH(match)->regexp, RMATCH(match)->regexp,
|
||||||
|
RSTRING_PTR(name), RSTRING_END(name));
|
||||||
|
|
||||||
|
if (num >= 0) {
|
||||||
|
rb_hash_aset(h, key, rb_reg_nth_match(num, match));
|
||||||
|
} else {
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* call-seq:
|
* call-seq:
|
||||||
* string -> string
|
* string -> string
|
||||||
|
@ -4542,7 +4625,9 @@ Init_Regexp(void)
|
||||||
rb_define_method(rb_cMatch, "to_a", match_to_a, 0);
|
rb_define_method(rb_cMatch, "to_a", match_to_a, 0);
|
||||||
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_method(rb_cMatch, "named_captures", match_named_captures, 0);
|
rb_define_method(rb_cMatch, "named_captures", match_named_captures, 0);
|
||||||
|
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);
|
||||||
rb_define_method(rb_cMatch, "post_match", rb_reg_match_post, 0);
|
rb_define_method(rb_cMatch, "post_match", rb_reg_match_post, 0);
|
||||||
|
|
|
@ -608,6 +608,38 @@ class TestRegexp < Test::Unit::TestCase
|
||||||
assert_equal('#<MatchData "foobarbaz" 1:"foo" 2:"bar" 3:"baz" 4:nil>', m.inspect)
|
assert_equal('#<MatchData "foobarbaz" 1:"foo" 2:"bar" 3:"baz" 4:nil>', m.inspect)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_match_data_deconstruct
|
||||||
|
m = /foo.+/.match("foobarbaz")
|
||||||
|
assert_equal([], m.deconstruct)
|
||||||
|
|
||||||
|
m = /(foo).+(baz)/.match("foobarbaz")
|
||||||
|
assert_equal(["foo", "baz"], m.deconstruct)
|
||||||
|
|
||||||
|
m = /(...)(...)(...)(...)?/.match("foobarbaz")
|
||||||
|
assert_equal(["foo", "bar", "baz", nil], m.deconstruct)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_match_data_deconstruct_keys
|
||||||
|
m = /foo.+/.match("foobarbaz")
|
||||||
|
assert_equal({}, m.deconstruct_keys([:a]))
|
||||||
|
|
||||||
|
m = /(?<a>foo).+(?<b>baz)/.match("foobarbaz")
|
||||||
|
assert_equal({a: "foo", b: "baz"}, m.deconstruct_keys(nil))
|
||||||
|
assert_equal({a: "foo", b: "baz"}, m.deconstruct_keys([:a, :b]))
|
||||||
|
assert_equal({b: "baz"}, m.deconstruct_keys([:b]))
|
||||||
|
assert_equal({}, m.deconstruct_keys([:c, :a]))
|
||||||
|
assert_equal({a: "foo"}, m.deconstruct_keys([:a, :c]))
|
||||||
|
assert_equal({}, m.deconstruct_keys([:a, :b, :c]))
|
||||||
|
|
||||||
|
assert_raise(TypeError) {
|
||||||
|
m.deconstruct_keys(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_raise(TypeError) {
|
||||||
|
m.deconstruct_keys(["a", "b"])
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
def test_initialize
|
def test_initialize
|
||||||
assert_raise(ArgumentError) { Regexp.new }
|
assert_raise(ArgumentError) { Regexp.new }
|
||||||
assert_equal(/foo/, assert_warning(/ignored/) {Regexp.new(/foo/, Regexp::IGNORECASE)})
|
assert_equal(/foo/, assert_warning(/ignored/) {Regexp.new(/foo/, Regexp::IGNORECASE)})
|
||||||
|
|
Загрузка…
Ссылка в новой задаче