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 # => [#] # 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 :before_save. # It can either be prepended (default) or appended. # # Returns the chain itself. # # Valid verbs are :prepend and :append. 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 :before_create. # It can either be prepended (default) or appended. # # Returns the chain itself. # # Valid verbs are :prepend and :append. 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 :before_update. # It can either be prepended (default) or appended. # # Returns the chain itself. # # Valid verbs are :prepend and :append. 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 :before_destroy. # It can either be prepended (default) or appended. # # Returns the chain itself. # # Valid verbs are :prepend and :append. 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 :after_save. # It can either be prepended or appended (default). # # Returns the chain itself. # # Valid verbs are :prepend and :append. 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 :after_create. # It can either be prepended or appended (default). # # Returns the chain itself. # # Valid verbs are :prepend and :append. 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 :after_update. # It can either be prepended or appended (default). # # Returns the chain itself. # # Valid verbs are :prepend and :append. 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 :after_destroy. # It can either be prepended or appended (default). # # Returns the chain itself. # # Valid verbs are :prepend and :append. 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 instance_eval. 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