Ruby 2.3.1 的 OpenStruct 问题
OpenStruct issue with Ruby 2.3.1
在Ruby 2.1.5 和2.2.4 中,创建新的Collector returns 结果正确。
require 'ostruct'
module ResourceResponses
class Collector < OpenStruct
def initialize
super
@table = Hash.new {|h,k| h[k] = Response.new }
end
end
class Response
attr_reader :publish_formats, :publish_block, :blocks, :block_order
def initialize
@publish_formats = []
@blocks = {}
@block_order = []
end
end
end
> Collector.new
=> #<ResourceResponses::Collector>
Collector.new.responses
=> #<ResourceResponses::Response:0x007fb3f409ae98 @block_order=[], @blocks= {}, @publish_formats=[]>
当我升级到 Ruby 2.3.1 时,它开始返回 nil。
> Collector.new
=> #<ResourceResponses::Collector>
> Collector.new.responses
=> nil
我已经阅读了大量有关 OpenStruct 现在如何在 2.3 中快 10 倍的文章,但我没有看到会破坏 Collector 和 Response 之间关系的更改。非常感谢任何帮助。 Rails 版本为 4.2.7.1。
让我们看看method_missing
在当前implementation中的实现:
def method_missing(mid, *args) # :nodoc:
len = args.length
if mname = mid[/.*(?==\z)/m]
if len != 1
raise ArgumentError, "wrong number of arguments (#{len} for 1)", caller(1)
end
modifiable?[new_ostruct_member!(mname)] = args[0]
elsif len == 0
if @table.key?(mid)
new_ostruct_member!(mid) unless frozen?
@table[mid]
end
else
err = NoMethodError.new "undefined method `#{mid}' for #{self}", mid, args
err.set_backtrace caller(1)
raise err
end
end
有趣的部分是中间的块,它在方法名称未以 =
结尾且没有附加参数时运行:
if @table.key?(mid)
new_ostruct_member!(mid) unless frozen?
@table[mid]
end
如您所见,在实际读取值之前,实现首先检查键是否存在。
当未设置 key/value 时,这会破坏您使用 returns 新 Response.new
的散列的实现。因为只是调用 key?
不会触发默认值的设置:
hash = Hash.new { |h,k| h[k] = :bar }
hash.has_key?(:foo)
#=> false
hash
#=> {}
hash[:foo]
#=> :bar
hash
#=> { :foo => :bar }
Ruby 2.2 没有这个优化。它只是返回 @table[mid]
而没有先检查 @table.key?
。
在Ruby 2.1.5 和2.2.4 中,创建新的Collector returns 结果正确。
require 'ostruct'
module ResourceResponses
class Collector < OpenStruct
def initialize
super
@table = Hash.new {|h,k| h[k] = Response.new }
end
end
class Response
attr_reader :publish_formats, :publish_block, :blocks, :block_order
def initialize
@publish_formats = []
@blocks = {}
@block_order = []
end
end
end
> Collector.new
=> #<ResourceResponses::Collector>
Collector.new.responses
=> #<ResourceResponses::Response:0x007fb3f409ae98 @block_order=[], @blocks= {}, @publish_formats=[]>
当我升级到 Ruby 2.3.1 时,它开始返回 nil。
> Collector.new
=> #<ResourceResponses::Collector>
> Collector.new.responses
=> nil
我已经阅读了大量有关 OpenStruct 现在如何在 2.3 中快 10 倍的文章,但我没有看到会破坏 Collector 和 Response 之间关系的更改。非常感谢任何帮助。 Rails 版本为 4.2.7.1。
让我们看看method_missing
在当前implementation中的实现:
def method_missing(mid, *args) # :nodoc:
len = args.length
if mname = mid[/.*(?==\z)/m]
if len != 1
raise ArgumentError, "wrong number of arguments (#{len} for 1)", caller(1)
end
modifiable?[new_ostruct_member!(mname)] = args[0]
elsif len == 0
if @table.key?(mid)
new_ostruct_member!(mid) unless frozen?
@table[mid]
end
else
err = NoMethodError.new "undefined method `#{mid}' for #{self}", mid, args
err.set_backtrace caller(1)
raise err
end
end
有趣的部分是中间的块,它在方法名称未以 =
结尾且没有附加参数时运行:
if @table.key?(mid)
new_ostruct_member!(mid) unless frozen?
@table[mid]
end
如您所见,在实际读取值之前,实现首先检查键是否存在。
当未设置 key/value 时,这会破坏您使用 returns 新 Response.new
的散列的实现。因为只是调用 key?
不会触发默认值的设置:
hash = Hash.new { |h,k| h[k] = :bar }
hash.has_key?(:foo)
#=> false
hash
#=> {}
hash[:foo]
#=> :bar
hash
#=> { :foo => :bar }
Ruby 2.2 没有这个优化。它只是返回 @table[mid]
而没有先检查 @table.key?
。