Entity类是一个基类,它由几个子类继承,这些子类包含通过REST API接收的实体。实体类是不可变的,并且只要尝试进行更改,就应该返回自己的新实例。
Entity类有一个.update()
方法,它接受值的哈希值进行更新,如果更改没有真正更改则返回自身,如果有真正的更改,则返回自身的新实例实例化之前发生的变化。
为了方便用户实体还允许直接分配属性(这样,如果Entity的子类具有name属性,您可以执行instance.name = 'New Name'
),它也会返回该类的新实例。这是使用在实例化类时创建的动态方法更新实现的。
他们就是问题所在。
Entity类中的代码部分看起来像这样(对于完整的代码列表和测试,请查看Github repo:https://github.com/my-codeworks/fortnox-api.git):
require "virtus"
require "ice_nine"
class Entity
extend Forwardable
include Virtus.model
def initialize( hash = {} )
super
create_attribute_setter_methods
IceNine.deep_freeze( self )
end
def update( hash )
attributes = self.to_hash.merge( hash )
return self if attributes == self.to_hash
self.class.new( attributes )
end
private
def create_attribute_setter_methods
attribute_set.each do |attribute|
name = attribute.options[ :name ]
create_attribute_setter_method( name )
end
end
def create_attribute_setter_method( name )
self.define_singleton_method "#{name}=" do | value |
self.update( name => value )
end
end
end
这样做:
instance.update( name: 'New Name' )
和此:
instance.name = 'New Name'
应该是相同的,因为一个是用另一个实现的。
虽然.update()
完美无缺,.attr=()
方法会返回您指定的值。
因此,在上面的示例中,.update()
返回Entity子类的新实例,但.attr=()
返回'New Name'
...
我尝试捕获.attr=()
方法中的输出并在返回之前记录它,以便我有这个:
self.define_singleton_method "#{name}=" do | value |
p "Called as :#{name}=, redirecting to update( #{name}: #{value} )"
r = self.update( name => value )
p "Got #{r} back from update"
return r
end
日志行说:
"Called as :name=, redirecting to update( name: 'New Name' )"
"Got #<TestEntity:0x007ffedbd0ad18> back from update"
但我得到的只是字符串'New Name'
...
我的前额是血腥的,我找不到任何贴近这个的帖子。我打赌我做错了什么但我找不到。
Github repo在rspec中测试你可以运行,失败的那些现在正在集中,一些额外的日志记录在Entity类中捕获不同的内部步骤。
欢迎评论,链接和/或拉取请求。