зеркало из https://github.com/github/ruby.git
Make a cyclic prepend not modify ancestors for the receiver
Check for cyclic prepend before making any changes. This requires scanning the module ancestor chain twice, but in general modules do not have large numbers of ancestors.
This commit is contained in:
Родитель
b83ad02997
Коммит
2d877327e1
14
class.c
14
class.c
|
@ -1024,6 +1024,18 @@ include_modules_at(const VALUE klass, VALUE c, VALUE module, int search_super)
|
||||||
struct rb_id_table *const klass_m_tbl = RCLASS_M_TBL(klass_origin);
|
struct rb_id_table *const klass_m_tbl = RCLASS_M_TBL(klass_origin);
|
||||||
VALUE original_klass = klass;
|
VALUE original_klass = klass;
|
||||||
|
|
||||||
|
if (klass_m_tbl) {
|
||||||
|
VALUE original_module = module;
|
||||||
|
|
||||||
|
while (module) {
|
||||||
|
if (klass_m_tbl == RCLASS_M_TBL(module))
|
||||||
|
return -1;
|
||||||
|
module = RCLASS_SUPER(module);
|
||||||
|
}
|
||||||
|
|
||||||
|
module = original_module;
|
||||||
|
}
|
||||||
|
|
||||||
while (module) {
|
while (module) {
|
||||||
int c_seen = FALSE;
|
int c_seen = FALSE;
|
||||||
int superclass_seen = FALSE;
|
int superclass_seen = FALSE;
|
||||||
|
@ -1032,8 +1044,6 @@ include_modules_at(const VALUE klass, VALUE c, VALUE module, int search_super)
|
||||||
if (klass == c) {
|
if (klass == c) {
|
||||||
c_seen = TRUE;
|
c_seen = TRUE;
|
||||||
}
|
}
|
||||||
if (klass_m_tbl && klass_m_tbl == RCLASS_M_TBL(module))
|
|
||||||
return -1;
|
|
||||||
if (klass_origin != c || search_super) {
|
if (klass_origin != c || search_super) {
|
||||||
/* ignore if the module included already in superclasses for include,
|
/* ignore if the module included already in superclasses for include,
|
||||||
* ignore if the module included before origin class for prepend
|
* ignore if the module included before origin class for prepend
|
||||||
|
|
|
@ -478,6 +478,13 @@ class TestModule < Test::Unit::TestCase
|
||||||
assert_raise(ArgumentError) { Module.new { include } }
|
assert_raise(ArgumentError) { Module.new { include } }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_prepend_self
|
||||||
|
m = Module.new
|
||||||
|
assert_equal([m], m.ancestors)
|
||||||
|
m.prepend(m) rescue nil
|
||||||
|
assert_equal([m], m.ancestors)
|
||||||
|
end
|
||||||
|
|
||||||
def test_prepend_works_with_duped_classes
|
def test_prepend_works_with_duped_classes
|
||||||
m = Module.new
|
m = Module.new
|
||||||
a = Class.new do
|
a = Class.new do
|
||||||
|
|
Загрузка…
Ссылка в новой задаче