我有一个父类:
1
和一些子课程 - 目前有五个,还会有更多:
class Base
def my_method
block_method do
# EXECUTE WHATEVER'S IN THE CHILD VERSION OF my_method
# HOW TO DO?
end
end
def block_method
original_foo = 'foo'
foo = 'CUSTOM FOO'
yield
foo = original_foo
end
end
我想在每个class ChildA < Base
def my_method
puts 'apple'
puts 'aardvark'
end
end
class ChildE < Base
def my_method
puts 'eel'
puts 'elephant'
end
end
Child
的持续时间内更改变量引用的内容。
我的想法是通过将每个#my_method
的{{1}}的功能包装在一个块中来实现。但我宁愿在父类中执行此操作,也不必将每个子类的Child
包装在完全相同的块中。
关于我如何做到这一点的任何见解?
如果与#my_method
存在某种相反的情况,我想这将是实现我想要做的事情的一种方式。
答案 0 :(得分:3)
你可以使用模块和prepend
来表达你所谓的“与超级相反”的想法:
module MethodThing
# added to remove binding from class since
# #my_method relies on the existence of #foo and #foo=
def self.prepended(base)
base.attr_reader(:foo) unless base.method_defined?(:foo)
base.attr_writer(:foo) unless base.method_defined?(:foo=)
end
def my_method
puts "Before: #{foo}"
original_foo = foo
self.foo= 'CUSTOM FOO'
begin
super
rescue NoMethodError
warn "(skipped) #{self.class}##{__method__} not defined"
end
self.foo = original_foo
puts "After: #{foo}"
end
end
在继承上添加模块
class Base
def self.inherited(child)
child.prepend(MethodThing)
end
attr_accessor :foo
def initialize
@foo = 12
end
end
class ChildA < Base
def my_method
puts 'apple'
puts "During: #{foo}"
puts 'aardvark'
end
end
class ChildE < Base
end
输出:
ChildA.new.my_method
# Before: 12
# apple
# During: CUSTOM FOO
# aardvark
# After: 12
ChildE.new.my_method
# Before: 12
# (skipped) ChildE#my_method not defined
# After: 12
还有其他奇怪的方法可以通过继承实现这一点,例如
class Base
class << self
attr_accessor :delegate_my_method
def method_added(method_name)
if method_name.to_s == "my_method" && self.name != "Base"
warn "#{self.name}#my_method has been overwritten use delegate_my_method instead"
end
end
end
attr_accessor :foo
def my_method
puts "Before: #{foo}"
original_foo = foo
self.foo= 'CUSTOM FOO'
begin
method(self.class.delegate_my_method.to_s).()
rescue NameError, TypeError
warn "(skipped) #{self.class} method delegation not defined
end
self.foo = original_foo
puts "After: #{foo}"
end
end
class ChildA < Base
self.delegate_my_method = :delegation_method
def delegation_method
puts 'apple'
puts "During: #{foo}"
puts 'aardvark'
end
end
我可能继续用陌生人和陌生人的方式来解决这个问题,但我认为这些会让你到达你需要去的地方。
答案 1 :(得分:2)
一种选择是定义父类可以调用的私有或nodoc方法,并在每个子节点中定义。
class Parent
def my_method
block_method do
my_method_behavior
end
end
def block_method
original_foo = @foo
@foo = 'CUSTOM FOO'
yield
@foo = original_foo
end
end
class Child1 < Parent
def my_method_behavior
puts @foo
end
end
class Child2 < Parent
def my_method_behavior
puts @foo
end
end