【问题标题】:Executing code before all method calls [duplicate]在所有方法调用之前执行代码[重复]
【发布时间】:2012-09-06 11:37:12
【问题描述】:

我在很多方面对 Ruby 还是很陌生,所以在尝试这样做时有点卡住(通过模块?还是基类?)。

我想为类上执行的每个方法调用做一个“放置”。类似于黄瓜格式化程序的一个非常简单的形式,即:

class MyClass
    def method_a
        puts 'doing some stuff'
    end 
end

所以输出看起来像:

MyClass.new.method_a => 'methods_a', 'doing some stuff'

更重要的是,我希望它适用于任何类的任何方法(动态地,不会乱扔我的代码)。我想应用一些格式,即'method_a' => 'Method A'。最好的方法是什么? AOP 框架?

【问题讨论】:

标签: ruby


【解决方案1】:
class MyClass
  def method_a
    puts "Doing A..."
  end

  def method_b
    puts "Doing B..."
  end

  def self.call_before_all_methods
    all_instance_methods = instance_methods - Class.instance_methods
    all_instance_methods.each do |x|
      class_eval <<-END
        alias old_#{x} #{x}
        def #{x}
          print "\'#{x.to_s.split('_').each{|x| x.capitalize!}.join(' ')}\', "
          old_#{x}
        end
        # remove_method old_#{x}.to_sym
      END
    end
  end

  private_class_method :call_before_all_methods
  call_before_all_methods
end

a = MyClass.new
a.method_a
a.method_b

所以这里的诀窍是先为每个方法创建一个别名,然后通过“打印格式化方法名称”+“原始方法即别名”重新定义方法。它也被 Here document (

但是由于每个方法的重新定义都会调用它原来的方法,最终不可能remove_method或undef别名。我认为将所有这些别名(old_method_a,ol​​d_method_b)留在那里没什么大不了的。

【讨论】:

  • @Bealer,对不起,我的误解,你在这里。
【解决方案2】:

你在这里(除了 before_filter),尽管我不知道你为什么要这样做:

class MyClass
  def puts_all(&blk)
    # get all instance_methods, also including default ones, so remove them by - Class.instance_methods
    all_other_methods = self.class.instance_methods - Class.instance_methods
    # remove the method name itself dynamically by saying __callee__
    all_other_methods.delete(__callee__)
    # formatting as per your need
    all_other_methods.each do |x|
      print "#{x.to_s.split('_').each{|x| x.capitalize!}.join(' ')}, "
      send(x)
    end
  end

  def method_a
    puts "Doing A..."
  end

  def method_b
    puts "Doing B..."
  end

  def another_fancy_method
    puts "Doing fancy..."
  end
end

MyClass.new.puts_all
#=> Method A, Doing A...
#=> Method B, Doing B...
#=> Another Fancy Method, Doing fancy...

因此,要动态地实现这一点,您可以简单地使用 instance_methods 和 _callee_。

【讨论】:

  • @Bealerless,我认为这种动态方法几乎可以满足您的需求。你能告诉它是否适合你吗?谢谢。
  • 不完全。我不想动态执行方法。我只想在方法执行时调用一段代码。在我的例子中,输出正在执行的方法的名称。
猜你喜欢
  • 1970-01-01
  • 2019-06-19
  • 1970-01-01
  • 1970-01-01
  • 2015-07-19
  • 1970-01-01
  • 1970-01-01
  • 2019-10-20
  • 1970-01-01
相关资源
最近更新 更多