ruby钩子

2015-05-29  本文已影响197人  SecondRocker

ruby有很多有用的钩子,如included,inhered,以及method_missing。对方法调用添加钩子可以用alias环绕别名实现,但终归有些麻烦,alias_method_chain需要定义with_feature方法也较麻烦,因此实现了下列module,include后调用method_callback :before_method,:after_method即可为before_method添加after_method钩子,目前方法不可传参,目前没有解决思路

module MethodCallback
  def self.included(base)
    base.extend ClassMethods
  end
  module ClassMethods
    def method_callback(before_m,after_m)
      target_with = "#{before_m}_with_#{after_m}}"
      target_without = "#{before_m}_without_#{after_m}"
      alias_method target_without, before_m
      define_method before_m do
        eval(target_without)
        eval(after_m.to_s)
      end
      alias_method target_with, before_m
    end
  end
end

class Student
  include MethodCallback
  def enter_class
    puts "enter class"
  end
  def after_enter_class
    puts "after enter class"
  end
  method_callback :enter_class ,:after_enter_class
end
Student.new.enter_class

今天又重新思考了下,参数问题得以解决,代码如下

module AfterCall
  def self.included(base)
    base.extend(ClassMethods)
  end
  module ClassMethods
    def after_call when_call,then_call,*args_then,&block_then
      alias_method "old_#{when_call}",when_call
      define_method when_call do |*args_when,&block_when|
        send "old_#{when_call}",*args_when,&block_when
        send then_call,*args_then,&block_then
      end
    end
  end
end
class Student
  include AfterCall
  def enter_class sb
    puts "enter class #{sb}"
    yield('before') if block_given?
  end
  private
  def after_enter_class pop
    puts "after enter class #{pop}"
    yield('after') if block_given?
  end
  protected
  def third_after
    puts "from third enter"
  end
  
  after_call :after_enter_class ,:third_after
  after_call :enter_class ,:after_enter_class,"doubi", &lambda {|x|puts "from lambda #{x}"}
end
Student.new.enter_class "1" do |x|
  puts "from lambda #{x}"
end
#运行结果如下
#enter class 1
#from lambda before
#after enter class doubi
#from lambda after
#from third enter
上一篇下一篇

猜你喜欢

热点阅读