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.
378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 |
# File 'lib/couchrest/mixins/callbacks.rb', line 378 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, :object => obj, :terminator => self.send("_#{kind}_terminator")) self.class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1 def _run__#{klass.split("::").last}__#{kind}__#{key}__callbacks #{str} end RUBY_EVAL true end obj.send("_run__#{klass.split("::").last}__#{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.
358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 |
# File 'lib/couchrest/mixins/callbacks.rb', line 358 def _define_runner(symbol, str, ) str = <<-RUBY_EVAL def _run_#{symbol}_callbacks(key = nil) if key send("_run__\#{self.class.name.split("::").last}__#{symbol}__\#{key}__callbacks") { yield if block_given? } else #{str} end end RUBY_EVAL class_eval str, __FILE__, __LINE__ + 1 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.
426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 |
# File 'lib/couchrest/mixins/callbacks.rb', line 426 def define_callbacks(*symbols) terminator = symbols.pop if symbols.last.is_a?(String) symbols.each do |symbol| self.extlib_inheritable_accessor("_#{symbol}_terminator") self.send("_#{symbol}_terminator=", terminator) self.class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1 extlib_inheritable_accessor :_#{symbol}_callbacks self._#{symbol}_callbacks = CallbackChain.new(:#{symbol}) def self.#{symbol}_callback(*filters, &blk) type = [:before, :after, :around].include?(filters.first) ? filters.shift : :before options = filters.last.is_a?(Hash) ? filters.pop : {} filters.unshift(blk) if block_given? filters.map! do |filter| # overrides parent class self._#{symbol}_callbacks.delete_if {|c| c.matches?(type, :#{symbol}, filter)} Callback.new(filter, type, options.dup, self, :#{symbol}) end self._#{symbol}_callbacks.push(*filters) _define_runner(:#{symbol}, self._#{symbol}_callbacks.compile(nil, :terminator => _#{symbol}_terminator), options) end def self.skip_#{symbol}_callback(*filters, &blk) type = [:before, :after, :around].include?(filters.first) ? filters.shift : :before 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(nil, :terminator => _#{symbol}_terminator), options) end end def self.reset_#{symbol}_callbacks self._#{symbol}_callbacks = CallbackChain.new(:#{symbol}) _define_runner(:#{symbol}, self._#{symbol}_callbacks.compile, {}) end self.#{symbol}_callback(:before) RUBY_EVAL end end |