问题
class Foo
def do_before
...
end
def do_something
...
Is there a way to run do_before
method before each other method in the Foo
class (like do_something
)?
It seems that the Sinatra before
block runs before each HTTP request, which has nothing to do with this class.
EDIT: As Michael pointed out in the comments, the only similar functionality that Rails offers is in the Controller. However, both Rails and Sinatra offer something similar to this functionality.
回答1:
As iain pointed out in the comments, the example you specify is not specific to Rails/Sinatra. I'm assuming you want before filter like the ones in Rails and this is what Sinatra offers:
Sinatra's modular apps:
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
In your config.rb
file,
require 'foo.rb'
require 'bar.rb'
map '/foo' do
run Foo
end
map '/bar' do
run Bar
end
This is the nearest analogy for a Rails controller in Sinatra. Create more classes like this and you'll have a similar functionality (similar, but may not be the same as you might expect in Rails world).
回答2:
You can also use a bit of meta-programming to create a before filter. For instance:
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"
In this case, the preprocess_method
(that is the do_before on your example) will be called before each call to any instance method defined within the Foo class.
回答3:
Not knowing what you're doing makes it difficult to know how to answer, but to increase the information out there on the web;) I'll give an alternative to @fmendez's answer:
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
output:
Before…
# => 12
来源:https://stackoverflow.com/questions/16115358/how-to-create-a-rails-like-before-filter-in-sinatra