Module: CouchRest::Callbacks::ClassMethods
- Defined in:
- lib/couchrest/mixins/callbacks.rb
Constant Summary collapse
- CHAINS =
{:before => :before, :around => :before, :after => :after}
Instance Method Summary collapse
-
#_create_and_run_keyed_callback(klass, kind, key, obj, &blk) ⇒ Object
This is called the first time a callback is called with a particular key.
-
#_define_runner(symbol, str, options) ⇒ Object
Make the _run_save_callbacks method.
-
#define_callbacks(*symbols) ⇒ Object
Define callbacks.
Instance Method Details
#_create_and_run_keyed_callback(klass, kind, key, obj, &blk) ⇒ Object
This is called the first time a callback is called with a particular key. It creates a new callback method for the key, calculating which callbacks can be omitted because of per_key conditions.
359 360 361 362 363 364 365 366 367 368 369 370 371 |
# File 'lib/couchrest/mixins/callbacks.rb', line 359 def _create_and_run_keyed_callback(klass, kind, key, obj, &blk) @_keyed_callbacks ||= {} @_keyed_callbacks[[kind, key]] ||= begin str = self.send("_#{kind}_callbacks").compile(key, obj) self.class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1 def _run_#{klass}_#{kind}_#{key}_callbacks #{str} end RUBY_EVAL true end obj.send("_run_#{klass}_#{kind}_#{key}_callbacks", &blk) end |
#_define_runner(symbol, str, options) ⇒ Object
Make the _run_save_callbacks method. The generated method takes a block that it’ll yield to. It’ll call the before and around filters in order, yield the block, and then run the after filters.
_run_save_callbacks do
save
end
The _run_save_callbacks method can optionally take a key, which will be used to compile an optimized callback method for each key. See #define_callbacks for more information.
341 342 343 344 345 346 347 348 349 350 351 352 353 354 |
# File 'lib/couchrest/mixins/callbacks.rb', line 341 def _define_runner(symbol, str, ) self.class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1 def _run_#{symbol}_callbacks(key = nil) if key send("_run_\#{self.class}_#{symbol}_\#{key}_callbacks") { yield } else #{str} end end RUBY_EVAL before_name, around_name, after_name = .values_at(:before, :after, :around) end |
#define_callbacks(*symbols) ⇒ Object
Define callbacks.
Creates a <name>_callback method that you can use to add callbacks.
Syntax:
save_callback :before, :before_meth
save_callback :after, :after_meth, :if => :condition
save_callback :around {|r| stuff; yield; stuff }
The <name>_callback method also updates the run<name>_callbacks method, which is the public API to run the callbacks.
Also creates a skip_<name>_callback method that you can use to skip callbacks.
When creating or skipping callbacks, you can specify conditions that are always the same for a given key. For instance, in ActionPack, we convert :only and :except conditions into per-key conditions.
before_filter :authenticate, :except => "index"
becomes
dispatch_callback :before, :authenticate, :per_key => {:unless => proc {|c| c.action_name == "index"}}
Per-Key conditions are evaluated only once per use of a given key. In the case of the above example, you would do:
run_dispatch_callbacks(action_name) { ... dispatch stuff ... }
In that case, each action_name would get its own compiled callback method that took into consideration the per_key conditions. This is a speed improvement for ActionPack.
404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 |
# File 'lib/couchrest/mixins/callbacks.rb', line 404 def define_callbacks(*symbols) symbols.each do |symbol| self.class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1 class_inheritable_accessor :_#{symbol}_callbacks self._#{symbol}_callbacks = CallbackChain.new def self.#{symbol}_callback(type, *filters, &blk) options = filters.last.is_a?(Hash) ? filters.pop : {} filters.unshift(blk) if block_given? filters.map! {|f| Callback.new(f, type, options.dup, self, :#{symbol})} self._#{symbol}_callbacks.push(*filters) _define_runner(:#{symbol}, self._#{symbol}_callbacks.compile, options) end def self.skip_#{symbol}_callback(type, *filters, &blk) options = filters.last.is_a?(Hash) ? filters.pop : {} filters.unshift(blk) if block_given? filters.each do |filter| self._#{symbol}_callbacks = self._#{symbol}_callbacks.clone(self) filter = self._#{symbol}_callbacks.find {|c| c.matches?(type, :#{symbol}, filter) } per_key = options[:per_key] || {} if filter filter.recompile!(options, per_key) else self._#{symbol}_callbacks.delete(filter) end _define_runner(:#{symbol}, self._#{symbol}_callbacks.compile, options) end end self.#{symbol}_callback(:before) RUBY_EVAL end end |