From f66f2a1e76584b899e93ce5b6c505a8cee91656e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thorsten=20Bo=CC=88ttger?= Date: Fri, 22 Feb 2013 18:04:48 +1300 Subject: [PATCH] started to refactor instance methods for AASM objects --- lib/aasm.rb | 1 + lib/aasm/aasm.rb | 82 ++++++++++-------------------- lib/aasm/base.rb | 2 +- lib/aasm/instance_base.rb | 57 +++++++++++++++++++++ lib/aasm/persistence/read_state.rb | 2 +- 5 files changed, 88 insertions(+), 56 deletions(-) create mode 100644 lib/aasm/instance_base.rb diff --git a/lib/aasm.rb b/lib/aasm.rb index 812d6ae..5059104 100644 --- a/lib/aasm.rb +++ b/lib/aasm.rb @@ -4,6 +4,7 @@ require 'ostruct' require File.join(File.dirname(__FILE__), 'aasm', 'version') require File.join(File.dirname(__FILE__), 'aasm', 'errors') require File.join(File.dirname(__FILE__), 'aasm', 'base') +require File.join(File.dirname(__FILE__), 'aasm', 'instance_base') require File.join(File.dirname(__FILE__), 'aasm', 'transition') require File.join(File.dirname(__FILE__), 'aasm', 'event') require File.join(File.dirname(__FILE__), 'aasm', 'state') diff --git a/lib/aasm/aasm.rb b/lib/aasm/aasm.rb index 169c3ee..2a73cc7 100644 --- a/lib/aasm/aasm.rb +++ b/lib/aasm/aasm.rb @@ -77,96 +77,70 @@ module AASM end end # ClassMethods - # this method does what? does it deliver the current state? - def aasm_current_state - @aasm_current_state ||= - aasm_persistable? ? aasm_read_state : aasm_enter_initial_state + def aasm + @aasm ||= AASM::InstanceBase.new(self) + end + + # deprecated + def aasm_current_state + # warn "#aasm_current_state is deprecated and will be removed in version 3.2.0; please use #aasm.state instead!" + aasm.current_state end - # private? def aasm_enter_initial_state - state_name = aasm_determine_state_name(self.class.aasm_initial_state) - state = aasm_state_object_for_state(state_name) + state_name = aasm.determine_state_name(self.class.aasm_initial_state) + state = aasm.state_object_for_name(state_name) state.fire_callbacks(:before_enter, self) state.fire_callbacks(:enter, self) - self.aasm_current_state = state_name + aasm.current_state = state_name state.fire_callbacks(:after_enter, self) state_name end - # private? + # deprecated def aasm_events_for_current_state - aasm_events_for_state(aasm_current_state) + # warn "#aasm_events_for_current_state is deprecated and will be removed in version 3.2.0; please use #aasm.events instead!" + aasm.events(aasm.current_state) end # filters the results of events_for_current_state so that only those that # are really currently possible (given transition guards) are shown. def aasm_permissible_events_for_current_state - aasm_events_for_current_state.select{ |e| self.send(("may_" + e.to_s + "?").to_sym) } + aasm.events(aasm.current_state).select{ |e| self.send(("may_" + e.to_s + "?").to_sym) } end - def aasm_events_for_state(state) - events = self.class.aasm_events.values.select {|event| event.transitions_from_state?(state) } - events.map {|event| event.name} + # deprecated + def aasm_events_for_state(state_name) + # warn "#aasm_events_for_state(state_name) is deprecated and will be removed in version 3.2.0; please use #aasm.events(state_name) instead!" + aasm.events(state_name) end + # deprecated def aasm_human_state - AASM::Localizer.new.human_state_name(self.class, aasm_current_state) + # warn "#aasm_human_state is deprecated and will be removed in version 3.2.0; please use #aasm.human_state instead!" + aasm.human_state end private - def aasm_persistable? - self.respond_to?(:aasm_read_state) || self.private_methods.include?('aasm_read_state') - end - def aasm_set_current_state_with_persistence(state) save_success = true if self.respond_to?(:aasm_write_state) || self.private_methods.include?('aasm_write_state') save_success = aasm_write_state(state) end - self.aasm_current_state = state if save_success + aasm.current_state = state if save_success save_success end - def aasm_current_state=(state) - if self.respond_to?(:aasm_write_state_without_persistence) || self.private_methods.include?('aasm_write_state_without_persistence') - aasm_write_state_without_persistence(state) - end - @aasm_current_state = state - end - - def aasm_determine_state_name(state) - case state - when Symbol, String - state - when Proc - state.call(self) - else - raise NotImplementedError, "Unrecognized state-type given. Expected Symbol, String, or Proc." - end - end - - def aasm_state_object_for_state(name) - obj = self.class.aasm_states.find {|s| s == name} - raise AASM::UndefinedState, "State :#{name} doesn't exist" if obj.nil? - obj - end - - def aasm_may_fire_event?(name, *args) - event = self.class.aasm_events[name] - event.may_fire?(self, *args) - end - def aasm_fire_event(name, options, *args) persist = options[:persist] event = self.class.aasm_events[name] begin - old_state = aasm_state_object_for_state(aasm_current_state) + old_state = aasm.state_object_for_name(aasm.current_state) old_state.fire_callbacks(:exit, self) @@ -175,7 +149,7 @@ private event.fire_callbacks(:before, self) if new_state_name = event.fire(self, *args) - new_state = aasm_state_object_for_state(new_state_name) + new_state = aasm.state_object_for_name(new_state_name) # new before_ callbacks old_state.fire_callbacks(:before_exit, self) @@ -188,7 +162,7 @@ private persist_successful = aasm_set_current_state_with_persistence(new_state_name) event.fire_callbacks(:success, self) if persist_successful else - self.aasm_current_state = new_state_name + aasm.current_state = new_state_name end if persist_successful @@ -196,7 +170,7 @@ private new_state.fire_callbacks(:after_enter, self) event.fire_callbacks(:after, self) - self.aasm_event_fired(name, old_state.name, self.aasm_current_state) if self.respond_to?(:aasm_event_fired) + self.aasm_event_fired(name, old_state.name, aasm.current_state) if self.respond_to?(:aasm_event_fired) else self.aasm_event_failed(name, old_state.name) if self.respond_to?(:aasm_event_failed) end @@ -209,7 +183,7 @@ private end if AASM::StateMachine[self.class].config.whiny_transitions - raise AASM::InvalidTransition, "Event '#{event.name}' cannot transition from '#{self.aasm_current_state}'" + raise AASM::InvalidTransition, "Event '#{event.name}' cannot transition from '#{aasm.current_state}'" else false end diff --git a/lib/aasm/base.rb b/lib/aasm/base.rb index 644622e..770f418 100644 --- a/lib/aasm/base.rb +++ b/lib/aasm/base.rb @@ -46,7 +46,7 @@ module AASM # may_event? and get back a boolean that tells you whether the guard method # on the transition will let this happen. @clazz.send(:define_method, "may_#{name.to_s}?") do |*args| - aasm_may_fire_event?(name, *args) + aasm.may_fire_event?(name, *args) end @clazz.send(:define_method, "#{name.to_s}!") do |*args| diff --git a/lib/aasm/instance_base.rb b/lib/aasm/instance_base.rb new file mode 100644 index 0000000..856819a --- /dev/null +++ b/lib/aasm/instance_base.rb @@ -0,0 +1,57 @@ +module AASM + class InstanceBase + + def initialize(instance) + @instance = instance + end + + def current_state + @current_state ||= persistable? ? @instance.aasm_read_state : @instance.aasm_enter_initial_state + end + + def current_state=(state) + if @instance.respond_to?(:aasm_write_state_without_persistence) || @instance.private_methods.include?('aasm_write_state_without_persistence') + @instance.aasm_write_state_without_persistence(state) + end + @current_state = state + end + + def human_state + AASM::Localizer.new.human_state_name(@instance.class, current_state) + end + + def events(state=current_state) + events = @instance.class.aasm_events.values.select {|e| e.transitions_from_state?(state) } + events.map {|e| e.name} + end + + def state_object_for_name(name) + obj = @instance.class.aasm.states.find {|s| s == name} + raise AASM::UndefinedState, "State :#{name} doesn't exist" if obj.nil? + obj + end + + def determine_state_name(state) + case state + when Symbol, String + state + when Proc + state.call(@instance) + else + raise NotImplementedError, "Unrecognized state-type given. Expected Symbol, String, or Proc." + end + end + + def may_fire_event?(name, *args) + event = @instance.class.aasm.events[name] + event.may_fire?(@instance, *args) + end + + private + + def persistable? + @instance.respond_to?(:aasm_read_state) || @instance.private_methods.include?('aasm_read_state') + end + + end +end diff --git a/lib/aasm/persistence/read_state.rb b/lib/aasm/persistence/read_state.rb index 5df77b0..74bdf4a 100644 --- a/lib/aasm/persistence/read_state.rb +++ b/lib/aasm/persistence/read_state.rb @@ -29,7 +29,7 @@ module AASM # This allows for nil aasm states - be sure to add validation to your model def aasm_read_state if new_record? - send(self.class.aasm_column).blank? ? aasm_determine_state_name(self.class.aasm_initial_state) : send(self.class.aasm_column).to_sym + send(self.class.aasm_column).blank? ? aasm.determine_state_name(self.class.aasm_initial_state) : send(self.class.aasm_column).to_sym else send(self.class.aasm_column).nil? ? nil : send(self.class.aasm_column).to_sym end