module CouchRest::Mixins::Callbacks::ClassMethods

Public Instance Methods

_alias_callbacks(callbacks, block) { |callback, options| ... } click to toggle source
# File lib/couchrest/mixins/callbacks.rb, line 524
def _alias_callbacks(callbacks, block)
  options = callbacks.last.is_a?(Hash) ? callbacks.pop : {}
  callbacks.push(block) if block
  callbacks.each do |callback|
    yield callback, options
  end
end
_create_keyed_callback(name, kind, obj, &blk) click to toggle source

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.

# File lib/couchrest/mixins/callbacks.rb, line 415
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) click to toggle source

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.

# File lib/couchrest/mixins/callbacks.rb, line 388
        def _define_runner(symbol)
          body = send("_#{symbol}_callback").
            compile(nil, :terminator => send("_#{symbol}_terminator"))

          body, line = "            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
", __LINE__ + 1

          undef_method "_run_#{symbol}_callbacks" if method_defined?("_run_#{symbol}_callbacks")
          class_eval body, __FILE__, line
        end
_reset_callbacks(name, filters = CallbackChain.new(name), block = nil) click to toggle source
Alias for: _update_callbacks
_update_callbacks(name, filters = CallbackChain.new(name), block = nil) { |callbacks, type, filters, options| ... } click to toggle source

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.

# File lib/couchrest/mixins/callbacks.rb, line 458
def _update_callbacks(name, filters = CallbackChain.new(name), block = nil)
  type = [:before, :after, :around].include?(filters.first) ? filters.shift : :before
  options = filters.last.is_a?(Hash) ? filters.pop : {}
  filters.unshift(block) if block

  callbacks = send("_#{name}_callback")
  yield callbacks, type, filters, options if block_given?

  _define_runner(name)
end
Also aliased as: _reset_callbacks
define_callbacks(*symbols) click to toggle source
# File lib/couchrest/mixins/callbacks.rb, line 499
        def define_callbacks(*symbols)
          terminator = symbols.pop if symbols.last.is_a?(String)
          symbols.each do |symbol|
            couchrest_inheritable_accessor("_#{symbol}_terminator") { terminator }

            couchrest_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 "                def self.#{filter}_#{symbol}(*symbols, &blk)
                  _alias_callbacks(symbols, blk) do |callback, options|
                    set_callback(:#{symbol}, :#{filter}, callback, options)
                  end
                end
", __FILE__, __LINE__ + 1
            end
          end
        end
set_callback(name, *filters, &block) click to toggle source
# File lib/couchrest/mixins/callbacks.rb, line 471
def set_callback(name, *filters, &block)
  _update_callbacks(name, filters, block) do |callbacks, type, filters, options|        
    filters.map! do |filter|
      # overrides parent class
      callbacks.delete_if {|c| c.matches?(type, filter) }
      Callback.new(filter, type, options.dup, self)
    end

    options[:prepend] ? callbacks.unshift(*filters) : callbacks.push(*filters)
  end
end
skip_callback(name, *filters, &block) click to toggle source
# File lib/couchrest/mixins/callbacks.rb, line 483
def skip_callback(name, *filters, &block)
  _update_callbacks(name, filters, block) do |callbacks, type, filters, options|
    filters.each do |filter|
      callbacks = send("_#{name}_callback=", callbacks.clone(self))

      filter = callbacks.find {|c| c.matches?(type, filter) }

      if filter && options.any?
        filter.recompile!(options, options[:per_key] || {})
      else
        callbacks.delete(filter)
      end
    end
  end
end