Skip to content

Commit 9ced6d5

Browse files
authored
ClassModule#superclass= accepts a ClassModule as an argument (#1222)
It is necessary for ClassModule's instance variable @superclass to always be a String (or nil) so that the class can be saved with `#marshal_dump` and loaded with `#marshal_load`. However, there's no type checking being done, which allows a bug like the one reported in #1221 (which was introduced in #1217) that sets superclass to a ClassModule. That bug requires: - setting a superclass to a NormalClass - marshal_save - marshal_load (which raises an exception) With this change, passing a ClassModule to ClassModule#superclass= is explicitly allowed by saving the full name of the ClassModule in the @superclass instance variable.
1 parent a4f13d2 commit 9ced6d5

File tree

2 files changed

+34
-1
lines changed

2 files changed

+34
-1
lines changed

lib/rdoc/code_object/class_module.rb

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -705,10 +705,23 @@ def superclass
705705

706706
##
707707
# Set the superclass of this class to +superclass+
708+
#
709+
# where +superclass+ is one of:
710+
#
711+
# - +nil+
712+
# - a String containing the full name of the superclass
713+
# - the RDoc::ClassModule representing the superclass
708714

709715
def superclass=(superclass)
710716
raise NoMethodError, "#{full_name} is a module" if module?
711-
@superclass = superclass
717+
case superclass
718+
when RDoc::ClassModule
719+
@superclass = superclass.full_name
720+
when nil, String
721+
@superclass = superclass
722+
else
723+
raise TypeError, "superclass must be a String or RDoc::ClassModule, not #{superclass.class}"
724+
end
712725
end
713726

714727
##

test/rdoc/test_rdoc_class_module.rb

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1279,6 +1279,26 @@ def test_superclass
12791279
assert_equal @c3_h1, @c3_h2.superclass
12801280
end
12811281

1282+
def test_setting_superclass
1283+
@c1.superclass = nil
1284+
assert_nil(@c1.superclass)
1285+
assert_nil(@c1.instance_variable_get("@superclass")) # proxy to test marshalling
1286+
1287+
@c1.superclass = @c4_c4.full_name
1288+
assert_equal(@c1.superclass, @c4_c4)
1289+
assert_equal(@c4_c4.full_name, @c1.instance_variable_get("@superclass"))
1290+
1291+
@c1.superclass = @c4_c4
1292+
assert_equal(@c1.superclass, @c4_c4)
1293+
assert_equal(@c4_c4.full_name, @c1.instance_variable_get("@superclass"))
1294+
1295+
# we could support this if we find we need to in the future.
1296+
assert_raise(TypeError) { @c1.superclass = Object }
1297+
1298+
# but this doesn't make sense.
1299+
assert_raise(TypeError) { @c1.superclass = Object.new }
1300+
end
1301+
12821302
def test_super_classes
12831303
rdoc_c3_h1 = @xref_data.find_module_named('C3::H1')
12841304
rdoc_object = @xref_data.find_module_named('Object')

0 commit comments

Comments
 (0)