[ruby/ostruct] Refactor handling of frozen OpenStruct. Simplify new_ostruct_member!

This commit is contained in:
Marc-Andre Lafortune 2020-09-08 16:13:15 -04:00
parent 5e7ec05319
commit ebb8de7302

View File

@ -93,9 +93,7 @@ class OpenStruct
@table = {}
if hash
hash.each_pair do |k, v|
k = k.to_sym
@table[k] = v
new_ostruct_member!(k)
self[k] = v
end
end
end
@ -165,42 +163,31 @@ class OpenStruct
@table.each_key{|key| new_ostruct_member!(key)}
end
#
# Used internally to check if the OpenStruct is able to be
# modified before granting access to the internal Hash table to be modified.
#
def modifiable? # :nodoc:
begin
@modifiable = true
rescue
raise FrozenError, "can't modify frozen #{self.class}", caller(3)
end
@table
end
private :modifiable?
#
# Used internally to defined properties on the
# OpenStruct. It does this by using the metaprogramming function
# define_singleton_method for both the getter method and the setter method.
#
def new_ostruct_member!(name) # :nodoc:
name = name.to_sym
unless respond_to?(name)
define_singleton_method(name) { @table[name] }
define_singleton_method("#{name}=") {|x| modifiable?[name] = x}
define_singleton_method("#{name}=") {|x| @table[name] = x}
end
name
end
private :new_ostruct_member!
def freeze
@table.freeze
super
end
def method_missing(mid, *args) # :nodoc:
len = args.length
if mname = mid[/.*(?==\z)/m]
if len != 1
raise ArgumentError, "wrong number of arguments (given #{len}, expected 1)", caller(1)
end
modifiable?[new_ostruct_member!(mname)] = args[0]
self[mname]= args[0]
elsif len == 0
elsif @table.key?(mid)
raise ArgumentError, "wrong number of arguments (given #{len}, expected 0)"
@ -240,7 +227,9 @@ class OpenStruct
# person.age # => 42
#
def []=(name, value)
modifiable?[new_ostruct_member!(name)] = value
name = name.to_sym
new_ostruct_member!(name)
@table[name] = value
end
# :call-seq: