require 'set' require 'forwardable' require 'active_support/concern' require 'active_support/callbacks' require 'active_support/core_ext/module/aliasing' require 'active_support/core_ext/array/extract_options' module Dionysus module ConfigurationCallbacks extend ActiveSupport::Concern included do # TODO validate self.config inherits from AS::Configurable::Configuration and is an anonymous class self.config.class.send(:include, Configuration) end module Configuration extend ActiveSupport::Concern include ActiveSupport::Callbacks included do alias_method :_set, :[]= # preserve the original #[] method protected :_set # make it protected extend Forwardable end def respond_to?(name, include_private=false) if name.to_s =~ /^_/ include_private ? method_defined?(name) : public_method_defined?(name) else true end end def before(get_set, key, *args, &block) name = _setup_for_callback(get_set, key) self.class.set_callback(name, :before, *args, &block) end def after(get_set, key, *args, &block) name = _setup_for_callback(get_set, key) self.class.set_callback(name, :after, *args, &block) end def around(get_set, key, *args, &block) name = _setup_for_callback(get_set, key) self.class.set_callback(name, :around, *args, &block) end def forward(get_set, key, to_accessor, to_method) case get_set.to_sym when :get self.class.def_delegator(to_accessor, to_method, key) when :set self.class.def_delegator(to_accessor, to_method, "#{key}=") else raise ArgumentError, "Invalid get_set parameter %p"%[get_set] end end private def _setup_for_callback(get_set, key) key = key.to_sym name = "#{get_set}_#{key}" case get_set.to_sym when :get if method_defined?(key) warn "Cannot setup callbacks for #{self}##{key}. Method already defined." else class_eval <<-EOS, __FILE__, __LINE__ + 1 def #{key}() run_callbacks(#{name.inspect}) { _get(#{key.inspect}) }; end EOS end when :set if method_defined?(:"#{key}=") warn "Cannot setup callbacks for #{self}##{key}. Method already defined." else class_eval <<-EOS, __FILE__, __LINE__ + 1 def #{key}=(val) run_callbacks(#{name.inspect}) { _set(#{key.inspect}, val) }; end EOS end else raise ArgumentError, "Invalid get_set parameter %p"%[get_set] end self.class.define_callbacks(name) return name end end end end