Ruby 反射组合:从重新定义的方法调用原始方法
Ruby reflection composition: call original method from redefined method
先了解一下上下文
我有一个 class Phone
定义了一个方法 advertise
像这样:
class Phone
def advertise(phone_call)
'ringtone'
end
end
我想对这种方法进行一些改编。
例如,当用户处于安静的环境中时,phone 应该振动而不是响铃。
为此,我定义了像
这样的模块
module DiscreetPhone
def advertise_quietly (phone_call)
'vibrator'
end
end
那么我的程序可以做到
# add the module to the class so that we can redefine the method
Phone.include(DiscreetPhone)
# redefine the method with its adaptation
Phone.send(:define_method, :advertise, DiscreetPhone.instance_method(:advertise_quietly ))
当然,对于这个例子,我硬编码了 class 和模块的名称,但它们应该是函数的参数。
因此,一个执行示例将给出:
phone = Phone.new
phone.advertise(a_call) # -> 'ringtone'
# do some adaptation stuff to redefine the method
...
phone.advertise(a_call) # -> 'vibrator'
终于回答我的问题了
我想要一个调用原始函数并在其结果中附加一些内容的改编。我想这样写
module ScreeningPhone
def advertise_with_screening (phone_call)
proceed + ' with screening'
end
end
但我不知道 proceed
调用应该做什么,甚至不知道我应该在哪里定义它。
- 我在 Windows 上使用 Ruby 2.3.0。
proceed
可以用其他东西代替,但我想在定义改编的模块中尽可能保持干净。
在我看来,这种方法太复杂了,而且 Module
s 的使用不当。
我建议考虑一种更简单的方法来实现它。
一个简单的方法是只包含 Phone class.
中的所有方法
或者,您可以使用散列作为环形策略的查找 table:
class Phone
attr_accessor :ring_strategy
RING_STRATEGIES = {
ringtone: -> { ring_with_tone },
discreet: -> { ring_quietly },
screening: -> { ring_with_tone; ring_screening_too }
# ...
}
def initialize(ring_strategy = :ringtone)
@ring_strategy = ring_strategy
end
def ring
RING_STRATEGIES[:ring_strategy].()
end
end
您可以通过 prepending 您的模块而不是包含它来完成此操作。
与其将 define_method
用作一种替代品 alias_method
,不如在您的模块中也调用方法 advertise
。
在您的 advertise
方法中,您可以调用 super
调用继承层次结构。
先了解一下上下文
我有一个 class Phone
定义了一个方法 advertise
像这样:
class Phone
def advertise(phone_call)
'ringtone'
end
end
我想对这种方法进行一些改编。 例如,当用户处于安静的环境中时,phone 应该振动而不是响铃。 为此,我定义了像
这样的模块module DiscreetPhone
def advertise_quietly (phone_call)
'vibrator'
end
end
那么我的程序可以做到
# add the module to the class so that we can redefine the method
Phone.include(DiscreetPhone)
# redefine the method with its adaptation
Phone.send(:define_method, :advertise, DiscreetPhone.instance_method(:advertise_quietly ))
当然,对于这个例子,我硬编码了 class 和模块的名称,但它们应该是函数的参数。
因此,一个执行示例将给出:
phone = Phone.new
phone.advertise(a_call) # -> 'ringtone'
# do some adaptation stuff to redefine the method
...
phone.advertise(a_call) # -> 'vibrator'
终于回答我的问题了
我想要一个调用原始函数并在其结果中附加一些内容的改编。我想这样写
module ScreeningPhone
def advertise_with_screening (phone_call)
proceed + ' with screening'
end
end
但我不知道 proceed
调用应该做什么,甚至不知道我应该在哪里定义它。
- 我在 Windows 上使用 Ruby 2.3.0。
proceed
可以用其他东西代替,但我想在定义改编的模块中尽可能保持干净。
在我看来,这种方法太复杂了,而且 Module
s 的使用不当。
我建议考虑一种更简单的方法来实现它。
一个简单的方法是只包含 Phone class.
中的所有方法或者,您可以使用散列作为环形策略的查找 table:
class Phone
attr_accessor :ring_strategy
RING_STRATEGIES = {
ringtone: -> { ring_with_tone },
discreet: -> { ring_quietly },
screening: -> { ring_with_tone; ring_screening_too }
# ...
}
def initialize(ring_strategy = :ringtone)
@ring_strategy = ring_strategy
end
def ring
RING_STRATEGIES[:ring_strategy].()
end
end
您可以通过 prepending 您的模块而不是包含它来完成此操作。
与其将 define_method
用作一种替代品 alias_method
,不如在您的模块中也调用方法 advertise
。
在您的 advertise
方法中,您可以调用 super
调用继承层次结构。