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