在Rails中执行类似before_filter的方法

时间:2014-05-15 13:36:17

标签: ruby metaprogramming

我尝试编写一个元编程来执行一个方法,然后才能掌握'方法。为什么?因为,我有几个课程,并且在method

的头部重复这个电话很难看

案例:

class MyClass
  include MySuperModule
  before :method, call: before_method

  def before_method
    puts "Before.."
  end
end

class SomeClass < MyClass
  def method
    puts "Method.."
  end
end

module MySuperModule
  # the awesome code
end

输出:

SomeClass.new.method => "Before.. Method.."

因此,我尝试使用ClassMethodsmethod_missing编写模块但未成功。

6 个答案:

答案 0 :(得分:5)

你不需要像这样的简单元编程宝石。你可以做的是重新定义&#34;&#34;&#34; &#34;之前调用&#34;的方法方法然后原来&#34;之后&#34;方法

即使在同一方法上多次使用before或创建一系列before来电时,此功能仍然有用。

module MySuperModule
  def before meth, opts
    old_method = instance_method(meth)
    define_method(meth) do
      send opts[:call]
      old_method.bind(self).call
    end
  end
end

class MyClass
  extend MySuperModule

  def foo
    puts "foo"
  end

  def bar
    puts "bar"
  end

  def baz
    puts "baz"
  end

  before :foo, call: :bar
  before :bar, call: :baz
end

MyClass.new.foo
# baz
# bar
# foo

答案 1 :(得分:1)

如果仅用于子类化,您可以利用Module#prepend

class Superclass
  def self.inherited(subclass)
    # subclass.send :prepend, Module.new { on Ruby < 2.1
    subclass.prepend Module.new {
      def method
        before_method
        super
      end
    }
  end

  def before_method
    puts 'Before'
  end
end

class Subclass < Superclass
  def method
    puts 'Method'
  end
end

Subclass.new.method
#=> Before
#=> Method

答案 2 :(得分:0)

您正在寻找的是Aspect oriented programming对红宝石的支持。有几个宝石实现了这一点,比如aquarium

答案 3 :(得分:0)

另一种方法是使用rcapture gem。 非常棒。

例如:

require 'rcapture'
class A
  # Makes the class intercept able
  include RCapture::Interceptable
  def first
    puts 'first'
  end
  def second
    puts 'second'
  end
end

# injects methods to be called before each specified instance method.
A.capture_pre :methods => [:first, :second] do
  puts "hello"
end

n = A.new
n.first
n.second

产生

hello
first
hello
second

答案 4 :(得分:0)

也许你可以使用装饰器。在红宝石中有一种叫做“褶皱”的漂亮宝石。见Drapper Link

答案 5 :(得分:-1)

ruby​​中的每个调用都会运行set_trace_func,因此您可以挂钩并调用您想要的内容。不是最漂亮的解决方案,有更好的方法,但它确实有效。另一种选择是Hooks gem,虽然我自己没有尝试过,看起来它应该让你有能力做你想做的事。

module MySuperModule
  # the awesome code
end

class MyClass
  include MySuperModule

  def before_method
    puts "Before.."
  end
end

class SomeClass < MyClass
  def method
    puts "Method.."
  end
end

set_trace_func proc { |event, file, line, id, binding, class_name|
  if event == "call" && class_name == SomeClass && id == :method
    caller = binding.eval("self")
    caller.send(:before_method)
  end
}

SomeClass.new.method
  #=> Before..
  #=> Method..