2013-04-20 64 views
1
class Foo 
    def do_before 
    ... 
    end 

    def do_something 
    ... 

有沒有辦法在Foo類(如do_something)彼此方法之前運行do_before方法?如何在Sinatra中創建類似Rails的過濾器?

似乎Sinatra before塊在每個HTTP請求之前運行,這與此類無關。

編輯:正如Michael在評論中指出的那樣,Rails提供的唯一類似功能就是在Controller中。但是,Rails和Sinatra都提供了與此功能類似的功能。

+2

這是什麼得到了與西納特拉辦?如果過濾器沒有鏈接到HTTP請求,那麼這是關於Ruby而不是任何框架。 – iain 2013-04-20 04:49:42

+1

是的,我不認爲Rails提供這個。過濾器用於控制器請求。這聽起來像是你正在做的事情可能不是最佳的。 – 2013-04-20 05:08:26

+0

@iain - 我在Sinatra工作,所以如果有Sinatra做這件事的方法,那麼它會很有用。 – 2013-04-21 22:36:54

回答

5

由於iain在註釋中指出,您指定的示例並不特定於Rails/Sinatra。我假設你喜歡Rails中的那些過濾器之前想,這是什麼西納特拉提供:

Sinatra的模塊化應用:

class Foo < Sinatra::Base 

    before do 
    "Do something" 
    end 

    get '/' do 
    "Hello World" 
    end 
end 

class Bar < Sinatra::Base 

    before do 
    "Do something else" 
    end 

    get '/' do 
    "Hello World" 
    end 
end 

在你config.rb文件,

require 'foo.rb' 
require 'bar.rb' 

map '/foo' do 
    run Foo 
end 

map '/bar' do 
    run Bar 
end 

這是最接近Sinatra Rails控制器的類比。創建更多這樣的類,你會得到類似的功能(類似,但可能不像你在Rails世界中所期望的那樣)。

3

您還可以使用一些元編程來創建一個之前的過濾器。例如:

class Foo 
    def method_1; p "Method 1"; end 
    def method_2; p "Method 2"; end 
    def preprocess_method; p "Pre-Processing method"; end 

    def self.before_filter m 
    current_methods = instance_methods(false) - [m] 
    self.new.instance_eval do 
     current_methods.each do |meth| 
     inst_method = public_method(meth) 
     self.class.send :define_method,inst_method.name do 
      public_send m 
      inst_method.call 
     end 
     end 
    end 
    end 
    before_filter :preprocess_method 
end 

o = Foo.new 
o.method_1 
#output: 
"Pre-Processing method" 
"Method 1" 

o.method_2 
#outputs 
"Pre-Processing method" 
"Method 2" 

在這種情況下,preprocess_method(即上您的示例do_before)將每次調用Foo類中定義的任何實例的方法之前被調用。

3

不知道你在做什麼使得它很難知道如何回答,但增加了信息在那裏在網絡上;)我給@ fmendez的答案替代:

module Filterable 
    def self.included(base) 
    base.extend ClassMethods 
    end 
    module ClassMethods 
    def do_before(name, &block) 
     before_filters[name.to_sym] = block 
    end 
    def before_filters 
     @before_filters ||= {} 
    end 
    def method_added(name) 
     return if name.to_s.start_with?("unfiltered_") 
     return if before_filters.has_key? name 
     before_filters[name.to_sym] ||= nil 
     alias_method "unfiltered_#{name}", name 
     define_method name do |*args,&block| 
     self.class.before_filters[name.to_sym].call if self.class.before_filters[name.to_sym] 
     send "unfiltered_#{name}", *args, &block 
     end 
    end 
    end 
end 

class Foo 
    include Filterable 

    def something(x) 
    x * 3 
    end 

    do_before :something do 
    puts "Before…" 
    end 
end 

Foo.new.something 4 

輸出:

之前...
#=> 12

+0

這實際上是目前爲止的最佳答案。執行之前過濾器的模塊是完美的。看起來這段代碼確實有點複雜,並且不需要複雜的... – 2013-04-21 22:42:23

+0

@BSeven我有點困惑,你說這是最好的答案,但不需要複雜性?無論哪種方式,我認爲你需要充實你的問題,你想達到什麼目的,如果它不是一個鏈接到請求的[filter](http://www.sinatrarb.com/intro#Filters),什麼是它? – iain 2013-04-21 23:37:13

相關問題