有人可以幫我修改爲intercepting instance method calls提供的答案,以便它可以與類方法調用或類和實例方法調用一起使用?從我對Ruby元編程知識的有限知識來看,我會想象它會在使用class << self
打開某個地方的單例類時做些什麼,但我已經嘗試過在不同的地方使用此代碼來做這件事,而且我似乎無法想辦法。然而,不是直接的答案,你能否向我提供正確的方向?除非我完全沒有深度,否則我很樂意爲自己做些事情。謝謝!如何攔截類方法調用,而不僅僅是實例方法調用
回答
這是我的解決方案從您提供的鏈接中的答案修改而來。我將鉤子邏輯從超類移動到一個單獨的模塊,以便當有類需要鉤子時,它只包含或擴展該模塊並調用鉤子方法。
before_each_method type, &block
-type
可以:class
或:instance
,以及該塊是每種方法之前要執行的代碼。該塊將在某些環境下進行評估,也就是說,方法self
中的塊是該實例;對於類方法,塊中的self
是類。before_class_method &block
- 別名before_each_method :class, &block
before_instance_method &block
- 別名before_each_method :instance, &block
module MethodHooker
def self.included(base)
base.extend(ClassMethods)
end
def self.extended(base)
base.extend(ClassMethods)
end
module ClassMethods
def before_each_method type, &block
singleton = class << self; self; end
case type
when :instance
this = self
singleton.instance_eval do
define_method :method_added do |name|
last = instance_variable_get(:@__last_methods_added)
return if last and last.include?(name)
with = :"#{name}_with_before_each_method"
without = :"#{name}_without_before_each_method"
instance_variable_set(:@__last_methods_added, [name, with, without])
this.class_eval do
define_method with do |*args, &blk|
instance_exec(name, args, blk, &block)
send without, *args, &blk
end
alias_method without, name
alias_method name, with
end
instance_variable_set(:@__last_methods_added, nil)
end
end
when :class
this = self
singleton.instance_eval do
define_method :singleton_method_added do |name|
return if name == :singleton_method_added
last = instance_variable_get(:@__last_singleton_methods_added)
return if last and last.include?(name)
with = :"#{name}_with_before_each_method"
without = :"#{name}_without_before_each_method"
instance_variable_set(:@__last_singleton_methods_added, [name, with, without])
singleton.class_eval do
define_method with do |*args, &blk|
instance_exec(name, args, blk, &block)
send without, *args, &blk
end
alias_method without, name
alias_method name, with
end
instance_variable_set(:@__last_singleton_methods_added, nil)
end
end
end
end
def before_class_method &block
before_each_method :class, &block
end
def before_instance_method &block
before_each_method :instance, &block
end
end
end
class Test
extend MethodHooker
before_each_method :instance do |method, args, block|
p [method, args, block]
puts "before instance method(#{method}) #{@var}"
end
before_class_method do |method, args, block|
puts "before class method(#{method}) #{@class_instance_var}"
end
@class_instance_var = 'stackoverflow'
def initialize
@var = 1
end
def test(a, b, c)
puts "instance method test"
end
def self.test1
puts "class method test"
end
end
Test.new.test(1, "arg2", [3]) {|t| t}
Test.test1
的輸出將是這樣的:
[:initialize, [], nil]
before instance method(initialize)
[:test, [1, "arg2", [3]], #<Proc:[email protected]/Users/test/before_method.rb:88>]
before instance method(test) 1
instance method test
before class method(test1) stackoverflow
class method test
這很酷!我試圖在使用它之前消化所有這些,雖然哈哈。你可以向我解釋一下這個代碼片段在做什麼(在'when:instance'塊內): 'define_method with do | * args,&blk | instance_exec(name,args,blk,&block) 發送時沒有,* args,&blk end' – DesAdams
具體使用'instance_exec()'。我不確定那是幹什麼的。 – DesAdams
我想我明白了!這段代碼就是發生'rerouting'的地方:對'instance_exec()'的調用將原來的參數(給予原始方法調用)傳遞給給'before_each_method'的塊,然後執行該塊;之後它將發送執行原始方法調用與正確的參數。這是對的嗎? – DesAdams
- 1. 如何攔截實例方法調用?
- 2. .NET方法調用攔截
- 3. Python攔截方法調用
- 4. Java CDI。攔截器僅在類中的第一個方法調用中調用
- 5. 如何「攔截」測試方法調用?
- 6. 如何攔截dll方法調用?
- 7. Castle Dynamic Proxy在類內調用時不攔截方法調用
- 8. 不使用攔截器綁定調用攔截器方法
- 9. Objective-C類方法不調用委託方法而實例方法確實
- 10. Ruby:如何攔截方法,擺弄args然後調用方法
- 11. 如何調用基類方法而不是擴展類方法
- 12. 如何攔截使用PostSharp的基類的方法調用?
- 13. 調用實例方法的實例方法調用實例方法
- 14. 僅從類中調用一次方法
- 15. 攔截器方法未被調用
- 16. 攔截方法調用Objective-C
- 17. 攔截調用定義的PHP方法
- 18. Python中的攔截方法調用
- 19. 跟蹤/攔截方法調用
- 20. 攔截PHP中的方法調用
- 21. 統一攔截調用基本方法
- 22. C#4攔截方法調用
- 23. 攔截每個http調用ES6方法
- 24. 分類實例方法不調用
- 25. 如何攔截Java或Android中的庫類的方法調用?
- 26. 如何攔截一個類的方法調用
- 27. .NET Web方法不僅僅是從javascript調用頁面
- 28. JUnit:攔截方法調用,然後調用不同的參數
- 29. 調用實例方法而不是類方法通常更快嗎?
- 30. ruby方法如何不能repond_方法,而是調用方法?
您是在正確的策略。嘗試將你的'class << self'代碼放入類定義本身。 – Linuxios