lib/surrounded/context.rb in surrounded-0.8.4 vs lib/surrounded/context.rb in surrounded-0.9.0

- old
+ new

@@ -1,9 +1,10 @@ require 'set' require 'surrounded/context/role_map' require 'surrounded/context/role_builders' require 'surrounded/context/initializing' +require 'surrounded/context/trigger_controls' require 'surrounded/access_control' require 'surrounded/shortcuts' require 'surrounded/east_oriented' # Extend your classes with Surrounded::Context to handle their @@ -13,133 +14,62 @@ # The purpose of this module is to help you create context objects # which encapsulate the interaction and behavior of objects inside. module Surrounded module Context def self.extended(base) - base.extend RoleBuilders, Initializing base.class_eval { + extend RoleBuilders, Initializing + @triggers = Set.new include InstanceMethods + + trigger_mod = Module.new + const_set('TriggerMethods', trigger_mod) + include trigger_mod + + extend TriggerControls } end - # Provides a Set of all available trigger methods where - # behaviors will be applied to the roles before execution - # and removed afterward. - def triggers - @triggers.dup - end - private # Set the default type of implementation for role methods for all contexts. def self.default_role_type @default_role_type ||= :module end class << self attr_writer :default_role_type end - - # Provide the ability to create access control methods for your triggers. - def protect_triggers; self.extend(::Surrounded::AccessControl); end - - # Automatically create class methods for each trigger method. - def shortcut_triggers; self.extend(::Surrounded::Shortcuts); end - - # Automatically return the context object from trigger methods. - def east_oriented_triggers; self.extend(::Surrounded::EastOriented); end def default_role_type @default_role_type ||= Surrounded::Context.default_role_type end # Set the default type of implementation for role method for an individual context. def default_role_type=(type) @default_role_type = type end + + # Provide the ability to create access control methods for your triggers. + def protect_triggers; self.extend(::Surrounded::AccessControl); end - # Set the time to apply roles to objects. Either :trigger or :initialize. - # Defaults to :trigger - def apply_roles_on(which) - @__apply_role_policy = which - end + # Automatically create class methods for each trigger method. + def shortcut_triggers; self.extend(::Surrounded::Shortcuts); end - def __apply_role_policy - @__apply_role_policy ||= :trigger - end + # Automatically return the context object from trigger methods. + def east_oriented_triggers; self.extend(::Surrounded::EastOriented); end - # Creates a context instance method which will apply behaviors to role players - # before execution and remove the behaviors after execution. - # - # Alternatively you may define your own methods then declare them as triggers - # afterward. - # - # Example: - # trigger :some_event do - # # code here - # end - # - # def some_event - # # code here - # end - # trigger :some_event - # - def trigger(*names, &block) - if block.nil? - names.each do |name| - convert_method_to_trigger(name) - end - else - name = names.first - define_method(name, &block) - convert_method_to_trigger(name) - end - end + # === Utility shortcuts - def store_trigger(*names) - @triggers.merge(names) + def role_const_defined?(name) + const_defined?(name, false) end - def convert_method_to_trigger(name) - unless triggers.include?(name) || name.nil? - alias_method :"__trigger_#{name}", :"#{name}" - private :"__trigger_#{name}" - remove_method :"#{name}" - define_trigger_wrap_method(name) - store_trigger(name) - end - end - - def define_trigger_wrap_method(name) - mod = Module.new - line = __LINE__ - mod.class_eval %{ - def #{name}(*args, &block) - begin - apply_roles if __apply_role_policy == :trigger - - #{trigger_return_content(name)} - - ensure - remove_roles if __apply_role_policy == :trigger - end - end - }, __FILE__, line - const_set("SurroundedTrigger#{name.to_s.upcase.sub(/\?\z/,'Query')}", mod) - include mod - end - - def trigger_return_content(name, *args, &block) - %{self.send("__trigger_#{name}", *args, &block)} - end - - # === Utility shortcuts - # Set a named constant and make it private def private_const_set(name, const) - unless self.const_defined?(name, false) + unless role_const_defined?(name) const = const_set(name, const) private_constant name.to_sym end const end @@ -155,14 +85,10 @@ if role_const_defined?(name) const_get(name) end end - def role_const_defined?(name) - const_defined?(name, false) - end - module InstanceMethods # Check whether a given name is a role inside the context. # The provided block is used to evaluate whether or not the caller # is allowed to inquire about the roles. def role?(name, &block) @@ -181,18 +107,10 @@ self.class.triggers end private - def preinitialize - @__apply_role_policy = self.class.send(:__apply_role_policy) - end - - def postinitialize - apply_roles if __apply_role_policy == :initialize - end - def role_map @role_map ||= RoleMap.new end def map_roles(role_object_array) @@ -219,62 +137,68 @@ def map_role(role, mod_name, object) instance_variable_set("@#{role}", object) role_map.update(role, role_module_basename(mod_name), object) end - def __apply_role_policy - @__apply_role_policy - end - - def add_interface(role, behavior, object) + def apply_behavior(role, behavior, object) if behavior && role_const_defined?(behavior) - applicator = role_const(behavior).is_a?(Class) ? method(:add_class_interface) : method(:add_module_interface) + applicator = if self.respond_to?("apply_behavior_#{role}") + method("apply_behavior_#{role}") + elsif role_const(behavior).is_a?(Class) + method(:apply_class_behavior) + else + method(:apply_module_behavior) + end - role_player = applicator.call(object, role_const(behavior)) + role_player = applicator.call(role_const(behavior), object) map_role(role, behavior, role_player) end role_player || object end - def add_module_interface(obj, mod) + def apply_module_behavior(mod, obj) adder_name = module_extension_methods.find{|meth| obj.respond_to?(meth) } - return obj if !adder_name + return obj unless adder_name obj.method(adder_name).call(mod) obj end - def add_class_interface(obj, klass) + def apply_class_behavior(klass, obj) wrapper_name = wrap_methods.find{|meth| klass.respond_to?(meth) } return obj if !wrapper_name klass.method(wrapper_name).call(obj) end - - def remove_interface(role, behavior, object) + + def remove_behavior(role, behavior, object) if behavior && role_const_defined?(behavior) - remover_name = (module_removal_methods + unwrap_methods).find{|meth| object.respond_to?(meth) } + remover_name = (module_removal_methods + unwrap_methods).find do |meth| + object.respond_to?(meth) + end end - if remover_name - role_player = object.send(remover_name) - end + role_player = if self.respond_to?("remove_behavior_#{role}") + self.send("remove_behavior_#{role}", role_const(behavior), object) + elsif remover_name + object.send(remover_name) + end role_player || object end - def apply_roles + def apply_behaviors role_map.each do |role, mod_name, object| - player = add_interface(role, mod_name, object) + player = apply_behavior(role, mod_name, object) player.send(:store_context, self) do; end end end - def remove_roles + def remove_behaviors role_map.each do |role, mod_name, player| if player.respond_to?(:remove_context, true) player.send(:remove_context) do; end end - remove_interface(role, mod_name, player) + remove_behavior(role, mod_name, player) end end # List of possible methods to use to add behavior to an object from a module. def module_extension_methods \ No newline at end of file