Oli*_*lay 5 ruby metaprogramming
我希望将以下模块包含在我的课程中:
module InheritanceEnumerator
def self.included(klass)
klass.instance_eval do
instance_variable_set('@subclasses',[])
def self.subclasses
@subclasses
end
original_method = self.respond_to?(:inherited) ? self.public_method(:inherited) : nil
instance_variable_set('@original_inherited_method', original_method)
def self.inherited(subclass)
@original_inherited_method.call(subclass) if @original_inherited_method
@subclasses<<subclass
end
end
end
end
Run Code Online (Sandbox Code Playgroud)
我要实现的目标是希望我的父类具有对直接子代的引用。我还需要其他东西在班级上设置的任何其他以前的“继承”方法,以保持不变。我究竟做错了什么?
您的代码在这种情况下有效(对我来说):
class C; include InheritanceEnumerator; end
C.subclasses #=> []
class C1 < C; end
class C2 < C; end
C.subclasses #=> [C1, C2]
Run Code Online (Sandbox Code Playgroud)
但在以下情况下会失败:
class C11 < C1; end
C1.subclasses => NoMethodError: undefined method `<<' for nil:NilClass
Run Code Online (Sandbox Code Playgroud)
这是因为您仅@subclasses在包含模块时才进行初始化;但您忘记了 的子类C也可以访问模块方法,但没有显式include访问。
您可以通过执行以下操作来修复此问题:
def self.subclasses
@subclasses ||= []
@subclasses
end
def self.inherited(subclass)
@original_inherited_method.call(subclass) if @original_inherited_method
@subclasses ||= []
@subclasses << subclass
end
Run Code Online (Sandbox Code Playgroud)
编辑:
好的,以后请更全面地说明你的问题是什么,并提供你正在使用的测试代码;因为这是一种挫败感的练习。
以下内容适用于您的代码:
class C
def self.inherited(s)
puts "inherited by #{s}!"
end
include InheritanceEnumerator
end
class D < C; end #=> "inherited by D!"
C.subclasses #=> [D]
Run Code Online (Sandbox Code Playgroud)
也许它对你不起作用的原因是你在定义方法InheritanceEnumerator 之前inherited就包含了它?
| 归档时间: |
|
| 查看次数: |
298 次 |
| 最近记录: |