mirror of
https://github.com/ruby/ruby.git
synced 2026-10-29 00:46:26 +08:00
Freeze all instances of Regexp, except subclass instances
* Instances of a subclass of Regexp are not frozen for compatibility. * [Feature #8948] * Use a less confusing example in test_regexp2, the ivar was named @encoding but had no effect on Regexp#encoding.
This commit is contained in:
1 parent
be659a0ef2
commit
cb03bf43eb
16 files changed
+175
-57
Notes:
git
2026-03-25 09:00:32 +00:00
No files matched your search
@@ -42,6 +42,12 @@ Note: We're only listing outstanding class updates.
|
||||
* `Array#pack` accepts a new format `R` and `r` for unpacking unsigned
|
||||
and signed LEB128 encoded integers. [[Feature #21785]]
|
||||
|
||||
* Regexp
|
||||
|
||||
* All instances of `Regexp` are now frozen, not just literals.
|
||||
Subclasses of `Regexp` are not frozen for compatibility.
|
||||
[[Feature #8948]]
|
||||
|
||||
* Set
|
||||
|
||||
* A deprecated behavior, `Set#to_set`, `Range#to_set`, and
|
||||
@@ -140,6 +146,7 @@ A lot of work has gone into making Ractors more stable, performant, and usable.
|
||||
## JIT
|
||||
|
||||
[Feature #6012]: https://bugs.ruby-lang.org/issues/6012
|
||||
[Feature #8948]: https://bugs.ruby-lang.org/issues/8948
|
||||
[Feature #15330]: https://bugs.ruby-lang.org/issues/15330
|
||||
[Feature #21390]: https://bugs.ruby-lang.org/issues/21390
|
||||
[Feature #21785]: https://bugs.ruby-lang.org/issues/21785
|
||||
|
||||
@@ -8862,6 +8862,7 @@ marshal.$(OBJEXT): $(top_srcdir)/internal/hash.h
|
||||
marshal.$(OBJEXT): $(top_srcdir)/internal/imemo.h
|
||||
marshal.$(OBJEXT): $(top_srcdir)/internal/numeric.h
|
||||
marshal.$(OBJEXT): $(top_srcdir)/internal/object.h
|
||||
marshal.$(OBJEXT): $(top_srcdir)/internal/re.h
|
||||
marshal.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
|
||||
marshal.$(OBJEXT): $(top_srcdir)/internal/serial.h
|
||||
marshal.$(OBJEXT): $(top_srcdir)/internal/set_table.h
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include "ruby/ruby.h" /* for VALUE */
|
||||
|
||||
/* re.c */
|
||||
VALUE rb_reg_s_alloc(VALUE klass);
|
||||
VALUE rb_reg_compile(VALUE str, int options, const char *sourcefile, int sourceline);
|
||||
VALUE rb_reg_check_preprocess(VALUE);
|
||||
long rb_reg_search0(VALUE, VALUE, long, int, int, VALUE *);
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include "internal/hash.h"
|
||||
#include "internal/numeric.h"
|
||||
#include "internal/object.h"
|
||||
#include "internal/re.h"
|
||||
#include "internal/struct.h"
|
||||
#include "internal/symbol.h"
|
||||
#include "internal/util.h"
|
||||
@@ -1731,7 +1732,10 @@ r_ivar_encoding(VALUE obj, struct load_arg *arg, VALUE sym, VALUE val)
|
||||
int idx = sym2encidx(sym, val);
|
||||
if (idx >= 0) {
|
||||
if (rb_enc_capable(obj)) {
|
||||
rb_enc_associate_index(obj, idx);
|
||||
// Check if needed to avoid rb_check_frozen() check for Regexps
|
||||
if (rb_enc_get_index(obj) != idx) {
|
||||
rb_enc_associate_index(obj, idx);
|
||||
}
|
||||
}
|
||||
else {
|
||||
rb_raise(rb_eArgError, "%"PRIsVALUE" is not enc_capable", obj);
|
||||
@@ -1854,17 +1858,17 @@ append_extmod(VALUE obj, VALUE extmod)
|
||||
override_ivar_error(type, str); \
|
||||
} while (0)
|
||||
|
||||
static VALUE r_object_for(struct load_arg *arg, bool partial, int *ivp, VALUE extmod, int type);
|
||||
static VALUE r_object_for(struct load_arg *arg, bool partial, int *ivp, VALUE klass, VALUE extmod, int type);
|
||||
|
||||
static VALUE
|
||||
r_object0(struct load_arg *arg, bool partial, int *ivp, VALUE extmod)
|
||||
{
|
||||
int type = r_byte(arg);
|
||||
return r_object_for(arg, partial, ivp, extmod, type);
|
||||
return r_object_for(arg, partial, ivp, 0, extmod, type);
|
||||
}
|
||||
|
||||
static VALUE
|
||||
r_object_for(struct load_arg *arg, bool partial, int *ivp, VALUE extmod, int type)
|
||||
r_object_for(struct load_arg *arg, bool partial, int *ivp, VALUE klass, VALUE extmod, int type)
|
||||
{
|
||||
VALUE (*hash_new_with_size)(st_index_t) = rb_hash_new_with_size;
|
||||
VALUE v = Qnil;
|
||||
@@ -1940,12 +1944,12 @@ r_object_for(struct load_arg *arg, bool partial, int *ivp, VALUE extmod, int typ
|
||||
}
|
||||
type = r_byte(arg);
|
||||
if ((c == rb_cHash) &&
|
||||
/* Hack for compare_by_identify */
|
||||
/* Hack for compare_by_identity */
|
||||
(type == TYPE_HASH || type == TYPE_HASH_DEF)) {
|
||||
hash_new_with_size = rb_ident_hash_new_with_size;
|
||||
goto type_hash;
|
||||
}
|
||||
v = r_object_for(arg, partial, 0, extmod, type);
|
||||
v = r_object_for(arg, partial, 0, c, extmod, type);
|
||||
if (RB_SPECIAL_CONST_P(v) || RB_TYPE_P(v, T_OBJECT) || RB_TYPE_P(v, T_CLASS)) {
|
||||
goto format_error;
|
||||
}
|
||||
@@ -2082,7 +2086,10 @@ r_object_for(struct load_arg *arg, bool partial, int *ivp, VALUE extmod, int typ
|
||||
}
|
||||
rb_str_set_len(str, dst - ptr);
|
||||
}
|
||||
VALUE regexp = rb_reg_new_str(str, options);
|
||||
if (!klass) {
|
||||
klass = rb_cRegexp;
|
||||
}
|
||||
VALUE regexp = rb_reg_init_str(rb_reg_s_alloc(klass), str, options);
|
||||
r_copy_ivar(regexp, str);
|
||||
|
||||
v = r_entry0(regexp, idx, arg);
|
||||
|
||||
@@ -3368,6 +3368,9 @@ rb_reg_initialize(VALUE obj, const char *s, long len, rb_encoding *enc,
|
||||
options & ARG_REG_OPTION_MASK, err,
|
||||
sourcefile, sourceline);
|
||||
if (!re->ptr) return -1;
|
||||
if (RBASIC_CLASS(obj) == rb_cRegexp) {
|
||||
OBJ_FREEZE(obj);
|
||||
}
|
||||
RB_GC_GUARD(unescaped);
|
||||
return 0;
|
||||
}
|
||||
@@ -3407,7 +3410,7 @@ rb_reg_initialize_str(VALUE obj, VALUE str, int options, onig_errmsg_buffer err,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
VALUE
|
||||
rb_reg_s_alloc(VALUE klass)
|
||||
{
|
||||
NEWOBJ_OF(re, struct RRegexp, klass, T_REGEXP | (RGENGC_WB_PROTECTED_REGEXP ? FL_WB_PROTECTED : 0), sizeof(struct RRegexp), 0);
|
||||
@@ -3460,9 +3463,7 @@ rb_reg_init_str_enc(VALUE re, VALUE s, rb_encoding *enc, int options)
|
||||
VALUE
|
||||
rb_reg_new_ary(VALUE ary, int opt)
|
||||
{
|
||||
VALUE re = rb_reg_new_str(rb_reg_preprocess_dregexp(ary, opt), opt);
|
||||
rb_obj_freeze(re);
|
||||
return re;
|
||||
return rb_reg_new_str(rb_reg_preprocess_dregexp(ary, opt), opt);
|
||||
}
|
||||
|
||||
VALUE
|
||||
@@ -3496,7 +3497,6 @@ rb_reg_compile(VALUE str, int options, const char *sourcefile, int sourceline)
|
||||
rb_set_errinfo(rb_reg_error_desc(str, options, err));
|
||||
return Qnil;
|
||||
}
|
||||
rb_obj_freeze(re);
|
||||
return re;
|
||||
}
|
||||
|
||||
@@ -4033,6 +4033,9 @@ reg_copy(VALUE copy, VALUE orig)
|
||||
RREGEXP_PTR(copy)->timelimit = RREGEXP_PTR(orig)->timelimit;
|
||||
rb_enc_copy(copy, orig);
|
||||
FL_SET_RAW(copy, FL_TEST_RAW(orig, KCODE_FIXED|REG_ENCODING_NONE));
|
||||
if (RBASIC_CLASS(copy) == rb_cRegexp) {
|
||||
OBJ_FREEZE(copy);
|
||||
}
|
||||
|
||||
return copy;
|
||||
}
|
||||
@@ -4115,6 +4118,9 @@ rb_reg_initialize_m(int argc, VALUE *argv, VALUE self)
|
||||
}
|
||||
|
||||
set_timeout(&RREGEXP_PTR(self)->timelimit, args.timeout);
|
||||
if (RBASIC_CLASS(self) == rb_cRegexp) {
|
||||
OBJ_FREEZE(self);
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -473,14 +473,26 @@ describe "Marshal.dump" do
|
||||
Marshal.dump(//im).should == "\x04\bI/\x00\x05\x06:\x06EF"
|
||||
end
|
||||
|
||||
it "dumps a Regexp with instance variables" do
|
||||
o = Regexp.new("")
|
||||
it "dumps a Regexp subclass with instance variables" do
|
||||
o = UserRegexp.new("")
|
||||
o.instance_variable_set(:@ivar, :ivar)
|
||||
Marshal.dump(o).should == "\x04\bI/\x00\x00\a:\x06EF:\n@ivar:\tivar"
|
||||
Marshal.dump(o).should == "\x04\bIC:\x0FUserRegexp/\x00\x00\a:\x06EF:\n@ivar:\tivar"
|
||||
end
|
||||
|
||||
it "dumps an extended Regexp" do
|
||||
Marshal.dump(Regexp.new("").extend(Meths)).should == "\x04\bIe:\nMeths/\x00\x00\x06:\x06EF"
|
||||
it "dumps an extended Regexp subclass" do
|
||||
Marshal.dump(UserRegexp.new("").extend(Meths)).should == "\x04\bIe:\nMethsC:\x0FUserRegexp/\x00\x00\x06:\x06EF"
|
||||
end
|
||||
|
||||
ruby_version_is ""..."4.1" do
|
||||
it "dumps a Regexp with instance variables" do
|
||||
o = Regexp.new("")
|
||||
o.instance_variable_set(:@ivar, :ivar)
|
||||
Marshal.dump(o).should == "\x04\bI/\x00\x00\a:\x06EF:\n@ivar:\tivar"
|
||||
end
|
||||
|
||||
it "dumps an extended Regexp" do
|
||||
Marshal.dump(Regexp.new("").extend(Meths)).should == "\x04\bIe:\nMeths/\x00\x00\x06:\x06EF"
|
||||
end
|
||||
end
|
||||
|
||||
it "dumps a Regexp subclass" do
|
||||
|
||||
@@ -901,14 +901,52 @@ describe :marshal_load, shared: true do
|
||||
end
|
||||
|
||||
describe "for a Regexp" do
|
||||
it "loads an extended Regexp" do
|
||||
obj = /[a-z]/.dup.extend(Meths, MethsMore)
|
||||
new_obj = Marshal.send(@method, "\004\be:\nMethse:\016MethsMore/\n[a-z]\000")
|
||||
ruby_version_is "4.1" do
|
||||
it "raises FrozenError for an extended Regexp" do
|
||||
-> {
|
||||
Marshal.send(@method, "\004\be:\nMethse:\016MethsMore/\n[a-z]\000")
|
||||
}.should raise_error(FrozenError)
|
||||
end
|
||||
|
||||
it "raises FrozenError when regexp has instance variables" do
|
||||
-> {
|
||||
Marshal.send(@method, "\x04\bI/\nhello\x00\a:\x06EF:\x11@regexp_ivar[\x06i/")
|
||||
}.should raise_error(FrozenError)
|
||||
end
|
||||
end
|
||||
|
||||
ruby_version_is ""..."4.1" do
|
||||
it "loads an extended Regexp" do
|
||||
obj = /[a-z]/.dup.extend(Meths, MethsMore)
|
||||
new_obj = Marshal.send(@method, "\004\be:\nMethse:\016MethsMore/\n[a-z]\000")
|
||||
|
||||
new_obj.should == obj
|
||||
new_obj_metaclass_ancestors = class << new_obj; ancestors; end
|
||||
new_obj_metaclass_ancestors[@num_self_class, 3].should ==
|
||||
[Meths, MethsMore, Regexp]
|
||||
end
|
||||
|
||||
it "restore the regexp instance variables" do
|
||||
obj = Regexp.new("hello")
|
||||
obj.instance_variable_set(:@regexp_ivar, [42])
|
||||
|
||||
new_obj = Marshal.send(@method, "\x04\bI/\nhello\x00\a:\x06EF:\x11@regexp_ivar[\x06i/")
|
||||
new_obj.instance_variables.should == [:@regexp_ivar]
|
||||
new_obj.instance_variable_get(:@regexp_ivar).should == [42]
|
||||
end
|
||||
end
|
||||
|
||||
it "loads a Regexp subclass instance variables" do
|
||||
obj = UserRegexp.new('abc')
|
||||
obj.instance_variable_set(:@noise, 'much')
|
||||
|
||||
new_obj = Marshal.send(@method, Marshal.dump(obj))
|
||||
|
||||
new_obj.should == obj
|
||||
new_obj.instance_variable_get(:@noise).should == 'much'
|
||||
new_obj_metaclass_ancestors = class << new_obj; ancestors; end
|
||||
new_obj_metaclass_ancestors[@num_self_class, 3].should ==
|
||||
[Meths, MethsMore, Regexp]
|
||||
new_obj_metaclass_ancestors[@num_self_class, 2].should ==
|
||||
[UserRegexp, Regexp]
|
||||
end
|
||||
|
||||
it "loads a Regexp subclass instance variables when it is extended with a module" do
|
||||
@@ -924,15 +962,6 @@ describe :marshal_load, shared: true do
|
||||
[Meths, UserRegexp, Regexp]
|
||||
end
|
||||
|
||||
it "restore the regexp instance variables" do
|
||||
obj = Regexp.new("hello")
|
||||
obj.instance_variable_set(:@regexp_ivar, [42])
|
||||
|
||||
new_obj = Marshal.send(@method, "\x04\bI/\nhello\x00\a:\x06EF:\x11@regexp_ivar[\x06i/")
|
||||
new_obj.instance_variables.should == [:@regexp_ivar]
|
||||
new_obj.instance_variable_get(:@regexp_ivar).should == [42]
|
||||
end
|
||||
|
||||
it "preserves Regexp encoding" do
|
||||
source_object = Regexp.new("a".encode("utf-32le"))
|
||||
regexp = Marshal.send(@method, Marshal.dump(source_object))
|
||||
|
||||
@@ -9,7 +9,21 @@ describe "Regexp#initialize" do
|
||||
-> { //.send(:initialize, "") }.should raise_error(FrozenError)
|
||||
end
|
||||
|
||||
it "raises a TypeError on an initialized non-literal Regexp" do
|
||||
-> { Regexp.new("").send(:initialize, "") }.should raise_error(TypeError)
|
||||
ruby_version_is "4.1" do
|
||||
it "raises a FrozenError on an initialized non-literal Regexp" do
|
||||
regexp = Regexp.new("")
|
||||
-> { regexp.send(:initialize, "") }.should raise_error(FrozenError)
|
||||
end
|
||||
end
|
||||
|
||||
ruby_version_is ""..."4.1" do
|
||||
it "raises a TypeError on an initialized non-literal Regexp" do
|
||||
-> { Regexp.new("").send(:initialize, "") }.should raise_error(TypeError)
|
||||
end
|
||||
end
|
||||
|
||||
it "raises a TypeError on an initialized non-literal Regexp subclass" do
|
||||
r = Class.new(Regexp).new("")
|
||||
-> { r.send(:initialize, "") }.should raise_error(TypeError)
|
||||
end
|
||||
end
|
||||
@@ -5,6 +5,12 @@ describe :regexp_new, shared: true do
|
||||
Regexp.send(@method, '').is_a?(Regexp).should == true
|
||||
end
|
||||
|
||||
ruby_version_is "4.1" do
|
||||
it "is frozen" do
|
||||
Regexp.send(@method, '').should.frozen?
|
||||
end
|
||||
end
|
||||
|
||||
it "works by default for subclasses with overridden #initialize" do
|
||||
class RegexpSpecsSubclass < Regexp
|
||||
def initialize(*args)
|
||||
|
||||
@@ -137,9 +137,17 @@ describe "String#match" do
|
||||
end
|
||||
|
||||
it "calls match on the regular expression" do
|
||||
regexp = /./.dup
|
||||
regexp.should_receive(:match).and_return(:foo)
|
||||
'hello'.match(regexp).should == :foo
|
||||
# Can't use regexp.should_receive(:match).and_return(:foo) since regexps are frozen
|
||||
ScratchPad.clear
|
||||
regexp = Class.new(Regexp) {
|
||||
def match(*args)
|
||||
ScratchPad.record [:match, *args]
|
||||
super(*args)
|
||||
end
|
||||
}.new('.')
|
||||
|
||||
'hello'.match(regexp)
|
||||
ScratchPad.recorded.should == [:match, 'hello']
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -489,12 +489,20 @@ describe "C-API Encoding function" do
|
||||
@s.rb_enc_copy("string", @obj).encoding.should == Encoding::US_ASCII
|
||||
end
|
||||
|
||||
it "raises a RuntimeError if the second argument is a Symbol" do
|
||||
it "raises a RuntimeError if the first argument is a Symbol" do
|
||||
-> { @s.rb_enc_copy(:symbol, @obj) }.should raise_error(RuntimeError)
|
||||
end
|
||||
|
||||
it "sets the encoding of a Regexp to that of the second argument" do
|
||||
@s.rb_enc_copy(/regexp/.dup, @obj).encoding.should == Encoding::US_ASCII
|
||||
ruby_version_is "4.1" do
|
||||
it "raises a FrozenError if the first argument is a Regexp" do
|
||||
-> { @s.rb_enc_copy(/regexp/.dup, @obj) }.should raise_error(FrozenError)
|
||||
end
|
||||
end
|
||||
|
||||
ruby_version_is ""..."4.1" do
|
||||
it "sets the encoding of a Regexp to that of the second argument" do
|
||||
@s.rb_enc_copy(/regexp/.dup, @obj).encoding.should == Encoding::US_ASCII
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -544,8 +552,16 @@ describe "C-API Encoding function" do
|
||||
-> { @s.rb_enc_associate(:symbol, "US-ASCII") }.should raise_error(RuntimeError)
|
||||
end
|
||||
|
||||
it "sets the encoding of a Regexp to the encoding" do
|
||||
@s.rb_enc_associate(/regexp/.dup, "BINARY").encoding.should == Encoding::BINARY
|
||||
ruby_version_is "4.1" do
|
||||
it "raises a FrozenError if the argument is a Regexp" do
|
||||
-> { @s.rb_enc_associate(/regexp/.dup, "BINARY") }.should raise_error(FrozenError)
|
||||
end
|
||||
end
|
||||
|
||||
ruby_version_is ""..."4.1" do
|
||||
it "sets the encoding of a Regexp to the encoding" do
|
||||
@s.rb_enc_associate(/regexp/.dup, "BINARY").encoding.should == Encoding::BINARY
|
||||
end
|
||||
end
|
||||
|
||||
it "sets the encoding of a String to a default when the encoding is NULL" do
|
||||
@@ -560,10 +576,19 @@ describe "C-API Encoding function" do
|
||||
enc.should == Encoding::BINARY
|
||||
end
|
||||
|
||||
it "sets the encoding of a Regexp to the encoding" do
|
||||
index = @s.rb_enc_find_index("UTF-8")
|
||||
enc = @s.rb_enc_associate_index(/regexp/.dup, index).encoding
|
||||
enc.should == Encoding::UTF_8
|
||||
ruby_version_is "4.1" do
|
||||
it "raises a FrozenError if the argument is a Regexp" do
|
||||
index = @s.rb_enc_find_index("UTF-8")
|
||||
-> { @s.rb_enc_associate_index(/regexp/.dup, index) }.should raise_error(FrozenError)
|
||||
end
|
||||
end
|
||||
|
||||
ruby_version_is ""..."4.1" do
|
||||
it "sets the encoding of a Regexp to the encoding" do
|
||||
index = @s.rb_enc_find_index("UTF-8")
|
||||
enc = @s.rb_enc_associate_index(/regexp/.dup, index).encoding
|
||||
enc.should == Encoding::UTF_8
|
||||
end
|
||||
end
|
||||
|
||||
it "sets the encoding of a Symbol to the encoding" do
|
||||
|
||||
@@ -69,11 +69,11 @@ class TestEnumerable < Test::Unit::TestCase
|
||||
assert_equal(['z', 42, nil], [:a, 'b', 'z', :c, 42, nil].grep_v(/[a-d]/), bug17030)
|
||||
assert_equal('match', $1, bug17030)
|
||||
|
||||
regexp = Regexp.new('x')
|
||||
assert_equal([], @obj.grep(regexp), bug17030) # sanity check
|
||||
def regexp.===(other)
|
||||
true
|
||||
end
|
||||
regexp = Class.new(Regexp) {
|
||||
def ===(other)
|
||||
true
|
||||
end
|
||||
}.new('x')
|
||||
assert_equal([1, 2, 3, 1, 2], @obj.grep(regexp), bug17030)
|
||||
|
||||
o = Object.new
|
||||
|
||||
@@ -314,7 +314,7 @@ class TestMarshal < Test::Unit::TestCase
|
||||
def test_regexp2
|
||||
assert_equal(/\\u/, Marshal.load("\004\b/\b\\\\u\000"))
|
||||
assert_equal(/u/, Marshal.load("\004\b/\a\\u\000"))
|
||||
assert_equal(/u/, Marshal.load("\004\bI/\a\\u\000\006:\016@encoding\"\vEUC-JP"))
|
||||
assert_raise(FrozenError) { Marshal.load("\x04\bI/\x06u\x00\a:\x06EF:\t@fooi/") }
|
||||
|
||||
bug2109 = '[ruby-core:25625]'
|
||||
a = "\x82\xa0".force_encoding(Encoding::Windows_31J)
|
||||
@@ -988,7 +988,7 @@ class TestMarshal < Test::Unit::TestCase
|
||||
end
|
||||
|
||||
def test_proc_returned_object_are_not_frozen
|
||||
source = ["foo", {}, /foo/, 1..2]
|
||||
source = ["foo", {}, 1..2]
|
||||
objects = Marshal.load(encode(source), ->(o) { o.dup }, freeze: true)
|
||||
assert_equal source, objects
|
||||
refute_predicate objects, :frozen?
|
||||
|
||||
@@ -975,7 +975,7 @@ class TestRegexp < Test::Unit::TestCase
|
||||
|
||||
def test_dup
|
||||
assert_equal(//, //.dup)
|
||||
assert_raise(TypeError) { //.dup.instance_eval { initialize_copy(nil) } }
|
||||
assert_raise(FrozenError) { //.dup.instance_eval { initialize_copy(/a/) } }
|
||||
end
|
||||
|
||||
def test_regsub
|
||||
|
||||
@@ -2757,8 +2757,9 @@ CODE
|
||||
def test_match_method
|
||||
assert_equal("bar", S("foobarbaz").match(/bar/).to_s)
|
||||
|
||||
o = Regexp.new('foo')
|
||||
def o.match(x, y, z); x + y + z; end
|
||||
o = Class.new(Regexp) {
|
||||
def match(x, y, z) = x + y + z
|
||||
}.new('foo')
|
||||
assert_equal("foobarbaz", S("foo").match(o, "bar", "baz"))
|
||||
x = nil
|
||||
S("foo").match(o, "bar", "baz") {|y| x = y }
|
||||
|
||||
@@ -417,8 +417,9 @@ class TestSymbol < Test::Unit::TestCase
|
||||
def test_match_method
|
||||
assert_equal("bar", :"foobarbaz".match(/bar/).to_s)
|
||||
|
||||
o = Regexp.new('foo')
|
||||
def o.match(x, y, z); x + y + z; end
|
||||
o = Class.new(Regexp) {
|
||||
def match(x, y, z) = x + y + z
|
||||
}.new('foo')
|
||||
assert_equal("foobarbaz", :"foo".match(o, "bar", "baz"))
|
||||
x = nil
|
||||
:"foo".match(o, "bar", "baz") {|y| x = y }
|
||||
|
||||
Reference in new issue
Block a user