我有很多的乐趣加载ActiveModel用的序列化,具体的as_json
和serializable_hash
的错综复杂的定义方法。只允许模块如果包括类/模块不
我的应用程序收集了大量的由包括模块共享行为模型,我们把它叫做SharedBehavior
。
我的团队已经决定,我们有我们要被强制转换成JSON(在一个Rails应用程序渲染),当所有这些类遵循默认格式,但其中一些应该表现稍有不同。由于ActiveModel库中这两种方法的行为异常,在模块中添加白名单或黑名单的属性会被本模块中的方法定义覆盖,然后传递给ActiveModel中的超级声明。
由于这个原因,我希望这个模块只将这些方法的定义应用到模型中(如果它们没有在这些模型中被显式覆盖)(实质上,从少数方法调用的祖先链中取出模块),但我仍然需要这个模块的共享行为。
我试图通过有条件地解决这个,动态应用的模块纳入方法IRB:
class A
def foo
puts 'in A'
end
end
module D
def self.included(base)
unless base.instance_methods(false).include?(:foo)
define_method(:foo) do
puts 'in D'
super()
end
end
end
end
class B < A
include D
end
class C < A
include D
def foo
puts 'in C'
super
end
end
有了这个声明,我预计C.new.foo
输出为
in C
in A
,但它是而不是
in C
in D
in A
我唯一的想法是移动这个逻辑出现在另一个模块中,并在每个类中包含该模块(其中大约有54个)并没有明确地覆盖该方法,但是有一些缺点:
- 它引入了一些隐式耦合在项目的新模式包括该模块当且仅当它不希望重写此方法实现
- 当前实现的模块中,这些序列化方法与行为,并通过该模块建立的属性做的,所以我觉得像如果有第二个模块知道并取决于
SharedBehavior
的实现细节,虽然第二个模块与第一个模块几乎没有任何关系,但这将是不直观的。
其他人能否想到另一种解决方案,或者可能在上面的代码示例中发现我的疏忽,这将允许我在included
挂钩中拨打电话? (我也尝试切换C
类定义foo
方法的顺序,并包含D
模块,但看到完全相同的行为)。
这是伟大的。实际上,我在3分钟前得到了与此类似的东西,除了在我的解决方案中,我在'base'上调用了私有方法'define_method'。我试图避开'* _eval'方法,可能是由于我缺乏知识。我听说他们非常不安全,可能导致安全风险。你的例子在这方面有什么不同吗? – 2014-11-14 22:16:19
如果你传递一个可能包含任意代码的字符串,''eval'方法只是不安全的。在这种情况下,它非常好,我只是用它将隐式接收器从'D'改为'base'。 – Max 2014-11-14 22:17:37
甜。刚刚在IRB中验证过。这是一个非常有启发性的练习。谢谢! – 2014-11-14 22:20:49