Module: CouchRest::Mixins::Callbacks::ClassMethods
- Defined in:
- lib/couchrest/mixins/callbacks.rb
Instance Method Summary collapse
- #_alias_callbacks(callbacks, block) ⇒ Object
-
#_create_keyed_callback(name, kind, obj, &blk) ⇒ Object
This is called the first time a callback is called with a particular key.
-
#_define_runner(symbol) ⇒ Object
Make the _run_save_callbacks method.
-
#_update_callbacks(name, filters = CallbackChain.new(name), block = nil) {|callbacks, type, filters, options| ... } ⇒ Object
(also: #_reset_callbacks)
Define callbacks.
- #define_callbacks(*symbols) ⇒ Object
- #set_callback(name, *filters, &block) ⇒ Object
- #skip_callback(name, *filters, &block) ⇒ Object
Instance Method Details
#_alias_callbacks(callbacks, block) ⇒ Object
522 523 524 525 526 527 528 |
# File 'lib/couchrest/mixins/callbacks.rb', line 522 def _alias_callbacks(callbacks, block) = callbacks.last.is_a?(Hash) ? callbacks.pop : {} callbacks.push(block) if block callbacks.each do |callback| yield callback, end end |
#_create_keyed_callback(name, kind, 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.
413 414 415 416 417 418 419 420 421 422 423 |
# File 'lib/couchrest/mixins/callbacks.rb', line 413 def _create_keyed_callback(name, kind, obj, &blk) @_keyed_callbacks ||= {} @_keyed_callbacks[name] ||= begin str = send("_#{kind}_callback"). compile(name, :object => obj, :terminator => send("_#{kind}_terminator")) class_eval "def #{name}() #{str} end", __FILE__, __LINE__ true end end |
#_define_runner(symbol) ⇒ 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.
386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 |
# File 'lib/couchrest/mixins/callbacks.rb', line 386 def _define_runner(symbol) body = send("_#{symbol}_callback"). compile(nil, :terminator => send("_#{symbol}_terminator")) body, line = <<-RUBY_EVAL, __LINE__ + 1 def _run_#{symbol}_callbacks(key = nil, &blk) if key name = "_run__\#{self.class.name.hash.abs}__#{symbol}__\#{key.hash.abs}__callbacks" unless respond_to?(name) self.class._create_keyed_callback(name, :#{symbol}, self, &blk) end send(name, &blk) else #{body} end end RUBY_EVAL undef_method "_run_#{symbol}_callbacks" if method_defined?("_run_#{symbol}_callbacks") class_eval body, __FILE__, line end |
#_update_callbacks(name, filters = CallbackChain.new(name), block = nil) {|callbacks, type, filters, options| ... } ⇒ Object Also known as: _reset_callbacks
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.
456 457 458 459 460 461 462 463 464 465 |
# File 'lib/couchrest/mixins/callbacks.rb', line 456 def _update_callbacks(name, filters = CallbackChain.new(name), block = nil) type = [:before, :after, :around].include?(filters.first) ? filters.shift : :before = filters.last.is_a?(Hash) ? filters.pop : {} filters.unshift(block) if block callbacks = send("_#{name}_callback") yield callbacks, type, filters, if block_given? _define_runner(name) end |
#define_callbacks(*symbols) ⇒ Object
497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 |
# File 'lib/couchrest/mixins/callbacks.rb', line 497 def define_callbacks(*symbols) terminator = symbols.pop if symbols.last.is_a?(String) symbols.each do |symbol| extlib_inheritable_accessor("_#{symbol}_terminator") { terminator } extlib_inheritable_accessor("_#{symbol}_callback") do CallbackChain.new(symbol) end _define_runner(symbol) # Define more convenient callback methods # set_callback(:save, :before) becomes before_save [:before, :after, :around].each do |filter| self.class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1 def self.#{filter}_#{symbol}(*symbols, &blk) _alias_callbacks(symbols, blk) do |callback, options| set_callback(:#{symbol}, :#{filter}, callback, options) end end RUBY_EVAL end end end |
#set_callback(name, *filters, &block) ⇒ Object
469 470 471 472 473 474 475 476 477 478 479 |
# File 'lib/couchrest/mixins/callbacks.rb', line 469 def set_callback(name, *filters, &block) _update_callbacks(name, filters, block) do |callbacks, type, filters, | filters.map! do |filter| # overrides parent class callbacks.delete_if {|c| c.matches?(type, filter) } Callback.new(filter, type, .dup, self) end [:prepend] ? callbacks.unshift(*filters) : callbacks.push(*filters) end end |
#skip_callback(name, *filters, &block) ⇒ Object
481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 |
# File 'lib/couchrest/mixins/callbacks.rb', line 481 def skip_callback(name, *filters, &block) _update_callbacks(name, filters, block) do |callbacks, type, filters, | filters.each do |filter| callbacks = send("_#{name}_callback=", callbacks.clone(self)) filter = callbacks.find {|c| c.matches?(type, filter) } if filter && .any? filter.recompile!(, [:per_key] || {}) else callbacks.delete(filter) end end end end |