Merged in more new callback stuff from rails 3

This commit is contained in:
Peter Gumeson 2009-06-13 22:41:16 -07:00
parent db7829e996
commit f4f3946d86
2 changed files with 48 additions and 54 deletions

View file

@ -142,12 +142,12 @@ module CouchRest
end end
def normalize_options!(options) def normalize_options!(options)
options[:if] = Array(options[:if]) options[:if] = Array.wrap(options[:if])
options[:unless] = Array(options[:unless]) options[:unless] = Array.wrap(options[:unless])
options[:per_key] ||= {} options[:per_key] ||= {}
options[:per_key][:if] = Array(options[:per_key][:if]) options[:per_key][:if] = Array.wrap(options[:per_key][:if])
options[:per_key][:unless] = Array(options[:per_key][:unless]) options[:per_key][:unless] = Array.wrap(options[:per_key][:unless])
end end
def next_id def next_id
@ -204,9 +204,10 @@ module CouchRest
filter = <<-RUBY_EVAL filter = <<-RUBY_EVAL
unless halted unless halted
result = #{@filter} result = #{@filter}
halted ||= (#{terminator}) halted = (#{terminator})
end end
RUBY_EVAL RUBY_EVAL
[@compiled_options[0], filter, @compiled_options[1]].compact.join("\n") [@compiled_options[0], filter, @compiled_options[1]].compact.join("\n")
else else
# Compile around filters with conditions into proxy methods # Compile around filters with conditions into proxy methods
@ -225,7 +226,7 @@ module CouchRest
# end # end
name = "_conditional_callback_#{@kind}_#{next_id}" name = "_conditional_callback_#{@kind}_#{next_id}"
txt = <<-RUBY_EVAL txt, line = <<-RUBY_EVAL, __LINE__
def #{name}(halted) def #{name}(halted)
#{@compiled_options[0] || "if true"} && !halted #{@compiled_options[0] || "if true"} && !halted
#{@filter} do #{@filter} do
@ -236,7 +237,7 @@ module CouchRest
end end
end end
RUBY_EVAL RUBY_EVAL
@klass.class_eval(txt) @klass.class_eval(txt, __FILE__, line)
"#{name}(halted) do" "#{name}(halted) do"
end end
end end
@ -271,11 +272,11 @@ module CouchRest
conditions = [] conditions = []
unless options[:if].empty? unless options[:if].empty?
conditions << Array(_compile_filter(options[:if])) conditions << Array.wrap(_compile_filter(options[:if]))
end end
unless options[:unless].empty? unless options[:unless].empty?
conditions << Array(_compile_filter(options[:unless])).map {|f| "!#{f}"} conditions << Array.wrap(_compile_filter(options[:unless])).map {|f| "!#{f}"}
end end
["if #{conditions.flatten.join(" && ")}", "end"] ["if #{conditions.flatten.join(" && ")}", "end"]
@ -306,33 +307,14 @@ module CouchRest
filter.map {|f| _compile_filter(f)} filter.map {|f| _compile_filter(f)}
when Symbol when Symbol
filter filter
when String
"(#{filter})"
when Proc when Proc
@klass.send(:define_method, method_name, &filter) @klass.send(:define_method, method_name, &filter)
method_name << case filter.arity return method_name if filter.arity == 0
when 1
"(self)" method_name << (filter.arity == 1 ? "(self)" : " self, Proc.new ")
when 2
" self, Proc.new "
else
""
end
when Method
@klass.send(:define_method, "#{method_name}_method") { filter }
@klass.class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
def #{method_name}(&blk)
#{method_name}_method.call(self, &blk)
end
RUBY_EVAL
method_name
when String
@klass.class_eval <<-RUBY_EVAL
def #{method_name}
#{filter}
end
RUBY_EVAL
method_name
else else
kind = @kind
@klass.send(:define_method, "#{method_name}_object") { filter } @klass.send(:define_method, "#{method_name}_object") { filter }
_normalize_legacy_filter(kind, filter) _normalize_legacy_filter(kind, filter)
@ -349,7 +331,7 @@ module CouchRest
def _normalize_legacy_filter(kind, filter) def _normalize_legacy_filter(kind, filter)
if !filter.respond_to?(kind) && filter.respond_to?(:filter) if !filter.respond_to?(kind) && filter.respond_to?(:filter)
filter.metaclass.class_eval( filter.class_eval(
"def #{kind}(context, &block) filter(context, &block) end", "def #{kind}(context, &block) filter(context, &block) end",
__FILE__, __LINE__ - 1) __FILE__, __LINE__ - 1)
elsif filter.respond_to?(:before) && filter.respond_to?(:after) && kind == :around elsif filter.respond_to?(:before) && filter.respond_to?(:after) && kind == :around
@ -402,8 +384,9 @@ module CouchRest
# The _run_save_callbacks method can optionally take a key, which # The _run_save_callbacks method can optionally take a key, which
# will be used to compile an optimized callback method for each # will be used to compile an optimized callback method for each
# key. See #define_callbacks for more information. # key. See #define_callbacks for more information.
def _define_runner(symbol, callbacks) def _define_runner(symbol)
body = callbacks.compile(nil, :terminator => send("_#{symbol}_terminator")) body = send("_#{symbol}_callback").
compile(nil, :terminator => send("_#{symbol}_terminator"))
body, line = <<-RUBY_EVAL, __LINE__ body, line = <<-RUBY_EVAL, __LINE__
def _run_#{symbol}_callbacks(key = nil, &blk) def _run_#{symbol}_callbacks(key = nil, &blk)
@ -431,7 +414,7 @@ module CouchRest
def _create_keyed_callback(name, kind, obj, &blk) def _create_keyed_callback(name, kind, obj, &blk)
@_keyed_callbacks ||= {} @_keyed_callbacks ||= {}
@_keyed_callbacks[name] ||= begin @_keyed_callbacks[name] ||= begin
str = send("_#{kind}_callbacks"). str = send("_#{kind}_callback").
compile(name, :object => obj, :terminator => send("_#{kind}_terminator")) compile(name, :object => obj, :terminator => send("_#{kind}_terminator"))
class_eval "def #{name}() #{str} end", __FILE__, __LINE__ class_eval "def #{name}() #{str} end", __FILE__, __LINE__
@ -471,21 +454,21 @@ module CouchRest
# In that case, each action_name would get its own compiled callback # In that case, each action_name would get its own compiled callback
# method that took into consideration the per_key conditions. This # method that took into consideration the per_key conditions. This
# is a speed improvement for ActionPack. # is a speed improvement for ActionPack.
def update_callbacks(name, filters = CallbackChain.new(name), block = nil) def _update_callbacks(name, filters = CallbackChain.new(name), block = nil)
type = [:before, :after, :around].include?(filters.first) ? filters.shift : :before type = [:before, :after, :around].include?(filters.first) ? filters.shift : :before
options = filters.last.is_a?(Hash) ? filters.pop : {} options = filters.last.is_a?(Hash) ? filters.pop : {}
filters.unshift(block) if block filters.unshift(block) if block
responded = self.respond_to?(":_#{name}_callbacks")
callbacks = send("_#{name}_callbacks") callbacks = send("_#{name}_callback")
yield callbacks, type, filters, options if block_given? yield callbacks, type, filters, options if block_given?
_define_runner(name, callbacks) _define_runner(name)
end end
alias_method :_reset_callbacks, :_update_callbacks
def set_callback(name, *filters, &block) def set_callback(name, *filters, &block)
update_callbacks(name, filters, block) do |callbacks, type, filters, options| _update_callbacks(name, filters, block) do |callbacks, type, filters, options|
filters.map! do |filter| filters.map! do |filter|
# overrides parent class # overrides parent class
callbacks.delete_if {|c| c.matches?(type, filter) } callbacks.delete_if {|c| c.matches?(type, filter) }
@ -497,9 +480,9 @@ module CouchRest
end end
def skip_callback(name, *filters, &block) def skip_callback(name, *filters, &block)
update_callbacks(name, filters, block) do |callbacks, type, filters, options| _update_callbacks(name, filters, block) do |callbacks, type, filters, options|
filters.each do |filter| filters.each do |filter|
callbacks = send("_#{name}_callbacks=", callbacks.clone(self)) callbacks = send("_#{name}_callback=", callbacks.clone(self))
filter = callbacks.find {|c| c.matches?(type, filter) } filter = callbacks.find {|c| c.matches?(type, filter) }
@ -517,17 +500,11 @@ module CouchRest
symbols.each do |symbol| symbols.each do |symbol|
extlib_inheritable_accessor("_#{symbol}_terminator") { terminator } extlib_inheritable_accessor("_#{symbol}_terminator") { terminator }
extlib_inheritable_accessor("_#{symbol}_callbacks") do extlib_inheritable_accessor("_#{symbol}_callback") do
CallbackChain.new(symbol) CallbackChain.new(symbol)
end end
self.class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1 _define_runner(symbol)
def self.reset_#{symbol}_callbacks
update_callbacks(:#{symbol})
end
self.set_callback(:#{symbol}, :before)
RUBY_EVAL
# Define more convenient callback methods # Define more convenient callback methods
# set_callback(:save, :before) becomes before_save # set_callback(:save, :before) becomes before_save

View file

@ -168,6 +168,23 @@ class Array
# options(1, 2, :a => :b) # => {:a=>:b} # options(1, 2, :a => :b) # => {:a=>:b}
def extract_options! def extract_options!
last.is_a?(::Hash) ? pop : {} last.is_a?(::Hash) ? pop : {}
end unless Array.respond_to?(:extract_options!) end unless Array.new.respond_to?(:extract_options!)
# Wraps the object in an Array unless it's an Array. Converts the
# object to an Array using #to_ary if it implements that.
def self.wrap(object)
case object
when nil
[]
when self
object
else
if object.respond_to?(:to_ary)
object.to_ary
else
[object]
end
end
end unless Array.respond_to?(:wrap)
end end