[ruby/ostruct] Avoid self calling our public methods.

Found because `json` has a bad example in its test suite.
This implementation still offers better encapsulation.
This commit is contained in:
Marc-Andre Lafortune 2020-09-14 13:48:29 -04:00 committed by Marc-André Lafortune
parent 67e5f7a9e5
commit 606c009ce2
Notes: git 2020-09-15 05:11:07 +09:00
2 changed files with 22 additions and 2 deletions

View File

@ -124,7 +124,7 @@ class OpenStruct
@table = {}
if hash
hash.each_pair do |k, v|
self[k] = v
set_ostruct_member_value!(k, v)
end
end
end
@ -218,7 +218,7 @@ class OpenStruct
if len != 1
raise ArgumentError, "wrong number of arguments (given #{len}, expected 1)", caller(1)
end
self[mname]= args[0]
set_ostruct_member_value!(mname, args[0])
elsif len == 0
elsif @table.key?(mid)
raise ArgumentError, "wrong number of arguments (given #{len}, expected 0)"
@ -262,6 +262,8 @@ class OpenStruct
new_ostruct_member!(name)
@table[name] = value
end
alias_method :set_ostruct_member_value!, :[]=
private :set_ostruct_member_value!
# :call-seq:
# ostruct.dig(name, *identifiers) -> object

View File

@ -246,4 +246,22 @@ class TC_OpenStruct < Test::Unit::TestCase
os = OpenStruct.new(method: :foo)
assert_equal(os.object_id, os.method!(:object_id).call)
end
def test_mistaken_subclass
sub = Class.new(OpenStruct) do
def [](k)
__send__(k)
super
end
def []=(k, v)
@item_set = true
__send__("#{k}=", v)
super
end
end
o = sub.new
o.foo = 42
assert_equal 42, o.foo
end
end