在没有rails的ruby中实现rails before_filter

时间:2013-02-22 22:16:57

标签: ruby sinatra ruby-1.9.3 before-filter

我在所有课程中都使用了一个记录器。 我希望每个msg都以类名和方法名开头,如下所示:

Class_name::Method_name

这就是我现在正在做的事情:

class FOO

 def initialize
 end

 def bar
   msg_prefix = "#{self.class}::#{__method__}"
   ... some code ...
   @logeer = "#{msg_prefix} msg ..."
 end

 def bar2
   msg_prefix = "#{self.class}::#{__method__}"
   ... some code 2 ...
   @logeer = "#{msg_prefix} msg2 ..."
 end

end

我想在rails中使用before_filter来防止两面性, 我使用的是sinatra,但这些类是普通的ruby 1.9.3

想法?

2 个答案:

答案 0 :(得分:7)

您可以使用Module#method_added创建任何方法的回调,将旧方法作为别名,然后定义一个先调用before_filter方法的新方法。这是我(非常)粗略的第一个概念:

module Filter
  def before_filter name
    @@filter = name
  end

  def method_added name
    return if @filtering # Don't add filters to original_ methods
    return if @@filter == name # Don't filter filters
    return if name == :initialize

    @filtering = true

    alias_method :"original_#{name}", name
    define_method name do |*args|
      self.send @@filter, name
      self.send :"original_#{name}", *args
    end
    @filtering = false
  end
end

class FilterTest
  extend Filter
  before_filter :prepare_logs

  def baz
    puts "#{@msg_prefix} message goes here"
  end

  def prepare_logs name
    @msg_prefix = "#{self.class}::#{name}"
  end
end

ft = FilterTest.new
ft.baz

通过__method__使用create_prefix,您将获得过滤方法的名称,而不是原始方法,因此您必须传入方法名称。可能还有其他名称解决方案让它更清洁。

答案 1 :(得分:2)

你可以使用ActiveModel::Callbacks获得before_filter - 就像普通Ruby类中的行为一样(尽管在你的情况下,只执行一行就太过分了):

require 'active_model'

class FOO
  extend ActiveModel::Callbacks

  define_model_callbacks :baz, only: :before

  before_baz :create_prefix

  def initialize
  end

  def bar
    run_callbacks :baz do
      ... some code ...
      @logeer = "#{@msg_prefix} msg ..."
    end
  end

  def bar2
    run_callbacks :baz do
      ... some code 2 ...
      @logeer = "#{@msg_prefix} msg2 ..."
    end
  end

  private

    def create_prefix
      @msg_prefix = "#{self.class}::#{__method__}"
    end
end