module Sequel class Model class ChainBroken < RuntimeError # :nodoc: end # This Hash translates verbs to methodnames used in chain manipulation # methods. VERB_TO_METHOD = {:prepend => :unshift, :append => :push} # Returns @hooks which is an instance of Hash with its hook identifier # (Symbol) as key and the chain of hooks (Array) as value. # # If it is not already set it'll be with an empty set of hooks. # This behaviour will change in the future to allow inheritance. # # For the time being, you should be able to do: # # class A < Sequel::Model(:a) # before_save { 'Do something...' } # end # # class B < A # @hooks = superclass.hooks.clone # before_save # => [#<Proc:0x0000c6e8@(example.rb):123>] # end # # In this case you should remember that the clone doesn't create any new # instances of your chains, so if you change the chain here it changes in # its superclass, too. def self.hooks @hooks ||= Hash.new { |h, k| h[k] = [] } end # Adds block to chain of Hooks for <tt>:before_save</tt>. # It can either be prepended (default) or appended. # # Returns the chain itself. # # Valid verbs are <tt>:prepend</tt> and <tt>:append</tt>. def self.before_save(verb = :prepend, &block) hooks[:before_save].send VERB_TO_METHOD.fetch(verb), block if block hooks[:before_save] end # Adds block to chain of Hooks for <tt>:before_create</tt>. # It can either be prepended (default) or appended. # # Returns the chain itself. # # Valid verbs are <tt>:prepend</tt> and <tt>:append</tt>. def self.before_create(verb = :prepend, &block) hooks[:before_create].send VERB_TO_METHOD.fetch(verb), block if block hooks[:before_create] end # Adds block to chain of Hooks for <tt>:before_update</tt>. # It can either be prepended (default) or appended. # # Returns the chain itself. # # Valid verbs are <tt>:prepend</tt> and <tt>:append</tt>. def self.before_update(verb = :prepend, &block) hooks[:before_update].send VERB_TO_METHOD.fetch(verb), block if block hooks[:before_update] end # Adds block to chain of Hooks for <tt>:before_destroy</tt>. # It can either be prepended (default) or appended. # # Returns the chain itself. # # Valid verbs are <tt>:prepend</tt> and <tt>:append</tt>. def self.before_destroy(verb = :prepend, &block) hooks[:before_destroy].send VERB_TO_METHOD.fetch(verb), block if block hooks[:before_destroy] end # Adds block to chain of Hooks for <tt>:after_save</tt>. # It can either be prepended or appended (default). # # Returns the chain itself. # # Valid verbs are <tt>:prepend</tt> and <tt>:append</tt>. def self.after_save(verb = :append, &block) hooks[:after_save].send VERB_TO_METHOD.fetch(verb), block if block hooks[:after_save] end # Adds block to chain of Hooks for <tt>:after_create</tt>. # It can either be prepended or appended (default). # # Returns the chain itself. # # Valid verbs are <tt>:prepend</tt> and <tt>:append</tt>. def self.after_create(verb = :append, &block) hooks[:after_create].send VERB_TO_METHOD.fetch(verb), block if block hooks[:after_create] end # Adds block to chain of Hooks for <tt>:after_update</tt>. # It can either be prepended or appended (default). # # Returns the chain itself. # # Valid verbs are <tt>:prepend</tt> and <tt>:append</tt>. def self.after_update(verb = :append, &block) hooks[:after_update].send VERB_TO_METHOD.fetch(verb), block if block hooks[:after_update] end # Adds block to chain of Hooks for <tt>:after_destroy</tt>. # It can either be prepended or appended (default). # # Returns the chain itself. # # Valid verbs are <tt>:prepend</tt> and <tt>:append</tt>. def self.after_destroy(verb = :append, &block) hooks[:after_destroy].send VERB_TO_METHOD.fetch(verb), block if block hooks[:after_destroy] end # Evaluates specified chain of Hooks through <tt>instance_eval</tt>. def run_hooks(key) model.hooks[key].each {|h| instance_eval(&h)} end def self.has_hooks?(key) hooks[key] && !hooks[key].empty? end end end