From baceb4b53e296cd45ac3acbd5df291e14b2993aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johan=20S=C3=B8rensen?= Date: Fri, 6 Feb 2009 22:49:24 +0800 Subject: [PATCH 01/33] Ruby 1.9 compat Signed-off-by: Scott Barron --- lib/event.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/event.rb b/lib/event.rb index 1f3612e4..5589bf96 100644 --- a/lib/event.rb +++ b/lib/event.rb @@ -34,11 +34,11 @@ def transitions_from_state?(state) def execute_success_callback(obj) case success - when String, Symbol: + when String, Symbol obj.send(success) - when Array: + when Array success.each { |meth| obj.send(meth) } - when Proc: + when Proc success.call(obj) end end From f87565f2e4357481244e32863e5e73744b5a0056 Mon Sep 17 00:00:00 2001 From: Nathaniel Bibler Date: Thu, 26 Feb 2009 12:06:43 -0500 Subject: [PATCH 02/33] Added initial state Proc support. Added more complex example to README --- README.rdoc | 32 ++++++++++++++++++++ lib/aasm.rb | 13 +++++++- lib/persistence/active_record_persistence.rb | 2 +- spec/unit/aasm_spec.rb | 16 ++++++++++ spec/unit/active_record_persistence_spec.rb | 23 ++++++++++++++ 5 files changed, 84 insertions(+), 2 deletions(-) diff --git a/README.rdoc b/README.rdoc index 1bfaaa7e..588b016d 100644 --- a/README.rdoc +++ b/README.rdoc @@ -57,6 +57,38 @@ Here's a quick example highlighting some of the features. end end +== A Slightly More Complex Example + +This example uses a few of the more complex features available. + + class Relationship + include AASM + + aasm_initial_state Proc.new { |relationship| relationship.strictly_for_fun? ? :intimate : :dating } + + aasm_state :dating, :enter => :make_happy, :exit => :make_depressed + aasm_state :intimate, :enter => :make_very_happy, :exit => :never_speak_again + aasm_state :married, :enter => :give_up_intimacy, :exit => :buy_exotic_car_and_wear_a_combover + + aasm_event :get_intimate do + transitions :to => :intimate, :from => [:dating], :guard => :drunk? + end + + aasm_event :get_married do + transitions :to => :married, :from => [:dating, :intimate], :guard => :willing_to_give_up_manhood? + end + + def strictly_for_fun?; end + def drunk?; end + def willing_to_give_up_manhood?; end + def make_happy; end + def make_depressed; end + def make_very_happy; end + def never_speak_again; end + def give_up_intimacy; end + def buy_exotic_car_and_wear_a_combover; end + end + = Other Stuff Author:: Scott Barron diff --git a/lib/aasm.rb b/lib/aasm.rb index fdee2ff3..e4cebd4b 100644 --- a/lib/aasm.rb +++ b/lib/aasm.rb @@ -89,7 +89,7 @@ def aasm_current_state @aasm_current_state = aasm_read_state end return @aasm_current_state if @aasm_current_state - self.class.aasm_initial_state + aasm_determine_state_name(self.class.aasm_initial_state) end def aasm_events_for_current_state @@ -118,6 +118,17 @@ def aasm_current_state=(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} diff --git a/lib/persistence/active_record_persistence.rb b/lib/persistence/active_record_persistence.rb index 9ff12849..a628eb52 100644 --- a/lib/persistence/active_record_persistence.rb +++ b/lib/persistence/active_record_persistence.rb @@ -228,7 +228,7 @@ module ReadState # 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? ? 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 diff --git a/spec/unit/aasm_spec.rb b/spec/unit/aasm_spec.rb index 30cfe87d..19fd05a8 100644 --- a/spec/unit/aasm_spec.rb +++ b/spec/unit/aasm_spec.rb @@ -41,6 +41,17 @@ class Bar class Baz < Bar end +class Banker + include AASM + aasm_initial_state Proc.new { |banker| banker.rich? ? :retired : :selling_bad_mortgages } + aasm_state :retired + aasm_state :selling_bad_mortgages + RICH = 1_000_000 + attr_accessor :balance + def initialize(balance = 0); self.balance = balance; end + def rich?; self.balance >= RICH; end +end + describe AASM, '- class level definitions' do it 'should define a class level aasm_initial_state() method on its including class' do @@ -130,6 +141,11 @@ class Baz < Bar it 'should use the first state defined if no initial state is given' do @bar.aasm_current_state.should == :read end + + it 'should determine initial state from the Proc results' do + Banker.new(Banker::RICH - 1).aasm_current_state.should == :selling_bad_mortgages + Banker.new(Banker::RICH + 1).aasm_current_state.should == :retired + end end describe AASM, '- event firing with persistence' do diff --git a/spec/unit/active_record_persistence_spec.rb b/spec/unit/active_record_persistence_spec.rb index 0c1b0f4b..fed2d481 100644 --- a/spec/unit/active_record_persistence_spec.rb +++ b/spec/unit/active_record_persistence_spec.rb @@ -50,6 +50,14 @@ class June < ActiveRecord::Base class Beaver < June end + + class Thief < ActiveRecord::Base + include AASM + aasm_initial_state Proc.new { |thief| thief.skilled ? :rich : :jailed } + aasm_state :rich + aasm_state :jailed + attr_accessor :skilled, :aasm_state + end describe "aasm model", :shared => true do it "should include AASM::Persistence::ActiveRecordPersistence" do @@ -219,6 +227,21 @@ class NamedScopeExample < ActiveRecord::Base end end end + + describe 'Thieves' do + before(:each) do + connection = mock(Connection, :columns => []) + Thief.stub!(:connection).and_return(connection) + end + + it 'should be rich if they\'re skilled' do + Thief.new(:skilled => true).aasm_current_state.should == :rich + end + + it 'should be jailed if they\'re unskilled' do + Thief.new(:skilled => false).aasm_current_state.should == :jailed + end + end # TODO: figure out how to test ActiveRecord reload! without a database From 6685c773cae350dcc2aaed69f18a34f2610ae140 Mon Sep 17 00:00:00 2001 From: Scott Petersen Date: Thu, 26 Feb 2009 13:53:43 -0600 Subject: [PATCH 03/33] Added vim swapfiles to .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 5fa449f5..09e06c04 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ rdoc pkg coverage *~ +*.sw? From 06eacd00d2adb4b867b2cb9a378cf504941aeffb Mon Sep 17 00:00:00 2001 From: Scott Petersen Date: Thu, 26 Feb 2009 13:54:00 -0600 Subject: [PATCH 04/33] Added new callbacks with slightly more obvious semantics: state - before_exit state - after_exit state - before_enter state - after_enter event - before event - after These get called as implied just before or after the state has been updated. No ordering within the before or after groups is defined. --- lib/aasm.rb | 30 ++++++++++++++++++++++-------- lib/event.rb | 11 +++++++++++ 2 files changed, 33 insertions(+), 8 deletions(-) diff --git a/lib/aasm.rb b/lib/aasm.rb index fdee2ff3..fa59815a 100644 --- a/lib/aasm.rb +++ b/lib/aasm.rb @@ -126,23 +126,37 @@ def aasm_state_object_for_state(name) end def aasm_fire_event(name, persist, *args) - aasm_state_object_for_state(aasm_current_state).call_action(:exit, self) + old_state = aasm_state_object_for_state(aasm_current_state) + event = self.class.aasm_events[name] - new_state = self.class.aasm_events[name].fire(self, *args) + old_state.call_action(:exit, self) + + new_state_name = event.fire(self, *args) + + unless new_state_name.nil? + new_state = aasm_state_object_for_state(new_state_name) - unless new_state.nil? - aasm_state_object_for_state(new_state).call_action(:enter, self) + # new before_ callbacks + old_state.call_action(:before_exit, self) + new_state.call_action(:before_enter, self) + event.call_action(:before, self) + + new_state.call_action(:enter, self) persist_successful = true if persist - persist_successful = set_aasm_current_state_with_persistence(new_state) - self.class.aasm_events[name].execute_success_callback(self) if persist_successful + persist_successful = set_aasm_current_state_with_persistence(new_state_name) + event.execute_success_callback(self) if persist_successful else - self.aasm_current_state = new_state + self.aasm_current_state = new_state_name end if persist_successful - self.aasm_event_fired(self.aasm_current_state, new_state) if self.respond_to?(:aasm_event_fired) + old_state.call_action(:after_exit, self) + new_state.call_action(:after_enter, self) + event.call_action(:after, self) + + self.aasm_event_fired(self.aasm_current_state, new_state_name) if self.respond_to?(:aasm_event_fired) else self.aasm_event_failed(name) if self.respond_to?(:aasm_event_failed) end diff --git a/lib/event.rb b/lib/event.rb index 5589bf96..a842c6ce 100644 --- a/lib/event.rb +++ b/lib/event.rb @@ -9,6 +9,7 @@ def initialize(name, options = {}, &block) @name = name @success = options[:success] @transitions = [] + @options = options instance_eval(&block) if block end @@ -43,6 +44,16 @@ def execute_success_callback(obj) end end + def call_action(action, record) + action = @options[action] + case action + when Symbol, String + record.send(action) + when Proc + action.call(record) + end + end + private def transitions(trans_opts) Array(trans_opts[:from]).each do |s| From 17884eb9f280e73eef664818785ba1233446636e Mon Sep 17 00:00:00 2001 From: Scott Petersen Date: Thu, 26 Feb 2009 15:11:00 -0600 Subject: [PATCH 05/33] Added basic spec for new callbacks. --- spec/unit/before_after_callbacks_spec.rb | 71 ++++++++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 spec/unit/before_after_callbacks_spec.rb diff --git a/spec/unit/before_after_callbacks_spec.rb b/spec/unit/before_after_callbacks_spec.rb new file mode 100644 index 00000000..808f5b69 --- /dev/null +++ b/spec/unit/before_after_callbacks_spec.rb @@ -0,0 +1,71 @@ +require File.join(File.dirname(__FILE__), '..', 'spec_helper') + +class Foo2 + include AASM + aasm_initial_state :open + aasm_state :open, :before_enter => :before_enter_open, :before_exit => :before_exit_open, :after_enter => :after_enter_open, :after_exit => :after_exit_open + aasm_state :closed, :before_enter => :before_enter_closed, :before_exit => :before_exit_closed, :after_enter => :after_enter_closed, :after_exit => :after_exit_closed + + aasm_event :close, :before => :before, :after => :after do + transitions :to => :closed, :from => [:open] + end + + aasm_event :open, :before => :before, :after => :after do + transitions :to => :open, :from => :closed + end + + def before_enter_open + end + def before_exit_open + end + def after_enter_open + end + def after_exit_open + end + + def before_enter_closed + end + def before_exit_closed + end + def after_enter_closed + end + def after_exit_closed + end + + def before + end + def after + end +end + +describe Foo2, '- new callbacks' do + before(:each) do + @foo = Foo2.new + end + + it "should get close callbacks" do + @foo.should_receive(:before_exit_open).once.ordered # these should be before the state changes + @foo.should_receive(:before_enter_closed).once.ordered + @foo.should_receive(:before).once.ordered + @foo.should_receive(:aasm_write_state).once.ordered.and_return(true) # this is when the state changes + @foo.should_receive(:after_exit_open).once.ordered # these should be after the state changes + @foo.should_receive(:after_enter_closed).once.ordered + @foo.should_receive(:after).once.ordered + + @foo.close! + end + + it "should get open callbacks" do + @foo.close! + + @foo.should_receive(:before_exit_closed).once.ordered # these should be before the state changes + @foo.should_receive(:before_enter_open).once.ordered + @foo.should_receive(:before).once.ordered + @foo.should_receive(:aasm_write_state).once.ordered.and_return(true) # this is when the state changes + @foo.should_receive(:after_exit_closed).once.ordered # these should be after the state changes + @foo.should_receive(:after_enter_open).once.ordered + @foo.should_receive(:after).once.ordered + + @foo.open! + end +end From c96f0f38d4134fcb563addba38d70067c9a97a27 Mon Sep 17 00:00:00 2001 From: Scott Petersen Date: Thu, 26 Feb 2009 15:18:22 -0600 Subject: [PATCH 06/33] Updated some docs, etc --- README.rdoc | 35 ++++++++++++++++++++++++++--------- aasm.gemspec | 8 ++++---- 2 files changed, 30 insertions(+), 13 deletions(-) diff --git a/README.rdoc b/README.rdoc index 1bfaaa7e..c8901f04 100644 --- a/README.rdoc +++ b/README.rdoc @@ -11,14 +11,32 @@ AASM has the following features: * Events * Transitions -== Download +== New Callbacks -The latest AASM can currently be pulled from the git repository on github. +The only changes I've made are creating more callbacks with slightly more obvious semantics ;). + +The callback chain & order on a successful event looks like: + + oldstate:exit + transition:on_transition + newstate:enter + oldstate:before_exit + newstate:before_enter + event:before + __update state__ + oldstate:after_exit + oldstate:after_enter + event:after + event:success + obj:aasm_event_fired -* http://github.com/rubyist/aasm/tree/master +Note that the old callbacks haven't been removed and still have their same semantics. All of this behavior was added without removing any old behavior. -A release and a gem are forthcoming. +== Download + +The latest AASM can currently be pulled from the git repository on github. +* http://github.com/dunedain289/aasm/tree/master == Installation @@ -26,12 +44,12 @@ A release and a gem are forthcoming. === From GitHub hosted gems % sudo gem sources -a http://gems.github.com # (you only need to do this once) - % sudo gem install rubyist-aasm + % sudo gem install dunedain289-aasm === Building your own gems % rake gem - % sudo gem install pkg/aasm-2.0.1.gem + % sudo gem install pkg/aasm-2.1.gem == Simple Example @@ -60,11 +78,10 @@ Here's a quick example highlighting some of the features. = Other Stuff Author:: Scott Barron -License:: Copyright 2006, 2007, 2008 by Scott Barron. +License:: Original code Copyright 2006, 2007, 2008 by Scott Barron. + New changes Copyright 2009 by Scott Petersen. Released under an MIT-style license. See the LICENSE file included in the distribution. -Bugs:: http://rubyist.lighthouseapp.com/projects/13207-aasm/ -GitHub:: http://github.com/rubyist/aasm/tree/master == Warranty diff --git a/aasm.gemspec b/aasm.gemspec index 0e8ae535..0cbbc5d8 100644 --- a/aasm.gemspec +++ b/aasm.gemspec @@ -2,7 +2,7 @@ PKG_FILES = ["CHANGELOG", "MIT-LICENSE", "Rakefile", "README.rdoc", "TODO", "lib Gem::Specification.new do |s| s.name = 'aasm' - s.version = "2.0.5" + s.version = "2.1" s.summary = 'State machine mixin for Ruby objects' s.description = <<-EOF AASM is a continuation of the acts as state machine rails plugin, built for plain Ruby objects. @@ -13,7 +13,7 @@ EOF s.extra_rdoc_files = ['README.rdoc', 'MIT-LICENSE', 'TODO', 'CHANGELOG'] s.rdoc_options = ['--line-numbers', '--inline-source', '--main', 'README.rdoc', '--title', 'AASM'] - s.author = 'Scott Barron' - s.email = 'scott@elitists.net' - s.homepage = 'http://github.com/rubyist/aasm' + s.author = 'Scott Petersen' + s.email = 'petersen@dunedain289.com' + s.homepage = 'http://github.com/dunedain289/aasm' end From 6e16196f20d25a4575ecd90883825cdd157eef6a Mon Sep 17 00:00:00 2001 From: Scott Petersen Date: Fri, 27 Feb 2009 17:41:46 -0600 Subject: [PATCH 07/33] Added array option for new callbacks --- Rakefile | 6 +++--- aasm.gemspec | 2 +- lib/aasm.rb | 2 +- lib/event.rb | 2 ++ lib/state.rb | 2 ++ 5 files changed, 9 insertions(+), 5 deletions(-) diff --git a/Rakefile b/Rakefile index dc21a58d..b4bd5f24 100644 --- a/Rakefile +++ b/Rakefile @@ -53,9 +53,9 @@ else s.extra_rdoc_files = rd.rdoc_files.reject {|fn| fn =~ /\.rb$/}.to_a s.rdoc_options = rd.options - s.author = 'Scott Barron' - s.email = 'scott@elitists.net' - s.homepage = 'http://rubyi.st/aasm' + s.authors = ['Scott Barron', 'Scott Petersen'] + s.email = 'petersen@dunedain289.com' + s.homepage = 'http://github.com/dunedain289/aasm' end package_task = Rake::GemPackageTask.new(spec) do |pkg| diff --git a/aasm.gemspec b/aasm.gemspec index 0cbbc5d8..993c5a82 100644 --- a/aasm.gemspec +++ b/aasm.gemspec @@ -2,7 +2,7 @@ PKG_FILES = ["CHANGELOG", "MIT-LICENSE", "Rakefile", "README.rdoc", "TODO", "lib Gem::Specification.new do |s| s.name = 'aasm' - s.version = "2.1" + s.version = "2.1.1" s.summary = 'State machine mixin for Ruby objects' s.description = <<-EOF AASM is a continuation of the acts as state machine rails plugin, built for plain Ruby objects. diff --git a/lib/aasm.rb b/lib/aasm.rb index fa59815a..5e0fe009 100644 --- a/lib/aasm.rb +++ b/lib/aasm.rb @@ -5,7 +5,7 @@ module AASM def self.Version - '2.0.5' + '2.1.1' end class InvalidTransition < RuntimeError diff --git a/lib/event.rb b/lib/event.rb index a842c6ce..2c7bed32 100644 --- a/lib/event.rb +++ b/lib/event.rb @@ -51,6 +51,8 @@ def call_action(action, record) record.send(action) when Proc action.call(record) + when Array + action.each { |a| record.send(a) } end end diff --git a/lib/state.rb b/lib/state.rb index af74d742..477f7013 100644 --- a/lib/state.rb +++ b/lib/state.rb @@ -22,6 +22,8 @@ def call_action(action, record) record.send(action) when Proc action.call(record) + when Array + action.each { |a| record.send(a) } end end From 26a69e7894202d2dac468a2d50b3d87c104f10ee Mon Sep 17 00:00:00 2001 From: factorylabs Date: Mon, 2 Mar 2009 14:43:38 -0700 Subject: [PATCH 08/33] Fixed alias_method_chain calls in active_record_persistence so that AASM doesn't blow up with railroad. --- lib/persistence/active_record_persistence.rb | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/persistence/active_record_persistence.rb b/lib/persistence/active_record_persistence.rb index 9ff12849..aa299372 100644 --- a/lib/persistence/active_record_persistence.rb +++ b/lib/persistence/active_record_persistence.rb @@ -43,8 +43,10 @@ def self.included(base) base.class_eval do class << self - alias_method :aasm_state_without_named_scope, :aasm_state - alias_method :aasm_state, :aasm_state_with_named_scope + unless method_defined?(:aasm_state_without_named_scope) + alias_method :aasm_state_without_named_scope, :aasm_state + alias_method :aasm_state, :aasm_state_with_named_scope + end end end end From 8650fb673b5fd715957c76a51fda9f76ccc20c13 Mon Sep 17 00:00:00 2001 From: Scott Petersen Date: Mon, 2 Mar 2009 17:47:46 -0600 Subject: [PATCH 09/33] Adjusted new callback ordering and added extra accessors for inspection. --- README.rdoc | 15 +++++++++------ lib/aasm.rb | 4 +++- lib/event.rb | 10 +++++++++- 3 files changed, 21 insertions(+), 8 deletions(-) diff --git a/README.rdoc b/README.rdoc index c8901f04..223ea50a 100644 --- a/README.rdoc +++ b/README.rdoc @@ -17,18 +17,21 @@ The only changes I've made are creating more callbacks with slightly more obviou The callback chain & order on a successful event looks like: - oldstate:exit - transition:on_transition - newstate:enter + oldstate:exit* + event:before + __find transition, if possible__ + transition:on_transition* + newstate:enter* oldstate:before_exit newstate:before_enter - event:before __update state__ oldstate:after_exit oldstate:after_enter event:after - event:success - obj:aasm_event_fired + event:success* + obj:aasm_event_fired* + + (*) marks old callbacks Note that the old callbacks haven't been removed and still have their same semantics. All of this behavior was added without removing any old behavior. diff --git a/lib/aasm.rb b/lib/aasm.rb index 5e0fe009..54bb0028 100644 --- a/lib/aasm.rb +++ b/lib/aasm.rb @@ -131,6 +131,9 @@ def aasm_fire_event(name, persist, *args) old_state.call_action(:exit, self) + # new event before callback + event.call_action(:before, self) + new_state_name = event.fire(self, *args) unless new_state_name.nil? @@ -139,7 +142,6 @@ def aasm_fire_event(name, persist, *args) # new before_ callbacks old_state.call_action(:before_exit, self) new_state.call_action(:before_enter, self) - event.call_action(:before, self) new_state.call_action(:enter, self) diff --git a/lib/event.rb b/lib/event.rb index 2c7bed32..af24d30c 100644 --- a/lib/event.rb +++ b/lib/event.rb @@ -3,7 +3,7 @@ module AASM module SupportingClasses class Event - attr_reader :name, :success + attr_reader :name, :success, :options def initialize(name, options = {}, &block) @name = name @@ -32,6 +32,10 @@ def fire(obj, to_state=nil, *args) def transitions_from_state?(state) @transitions.any? { |t| t.from == state } end + + def transitions_from_state(state) + @transitions.select { |t| t.from == state } + end def execute_success_callback(obj) case success @@ -56,6 +60,10 @@ def call_action(action, record) end end + def all_transitions + @transitions + end + private def transitions(trans_opts) Array(trans_opts[:from]).each do |s| From 86b39983640611cdbfa4656e929fe3441fae1c0e Mon Sep 17 00:00:00 2001 From: Scott Petersen Date: Mon, 2 Mar 2009 17:49:12 -0600 Subject: [PATCH 10/33] Bump for gem build --- aasm.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aasm.gemspec b/aasm.gemspec index 993c5a82..c39da703 100644 --- a/aasm.gemspec +++ b/aasm.gemspec @@ -2,7 +2,7 @@ PKG_FILES = ["CHANGELOG", "MIT-LICENSE", "Rakefile", "README.rdoc", "TODO", "lib Gem::Specification.new do |s| s.name = 'aasm' - s.version = "2.1.1" + s.version = "2.1.2" s.summary = 'State machine mixin for Ruby objects' s.description = <<-EOF AASM is a continuation of the acts as state machine rails plugin, built for plain Ruby objects. From 923175e9e95d4b1db0ba639bcc28bc747bd39413 Mon Sep 17 00:00:00 2001 From: Scott Petersen Date: Mon, 2 Mar 2009 18:13:05 -0600 Subject: [PATCH 11/33] Bump again for gem build --- aasm.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aasm.gemspec b/aasm.gemspec index c39da703..5ee98026 100644 --- a/aasm.gemspec +++ b/aasm.gemspec @@ -2,7 +2,7 @@ PKG_FILES = ["CHANGELOG", "MIT-LICENSE", "Rakefile", "README.rdoc", "TODO", "lib Gem::Specification.new do |s| s.name = 'aasm' - s.version = "2.1.2" + s.version = "2.1.3" s.summary = 'State machine mixin for Ruby objects' s.description = <<-EOF AASM is a continuation of the acts as state machine rails plugin, built for plain Ruby objects. From 6b1e0f4949226b6c61c99de5a745d3ec090d3484 Mon Sep 17 00:00:00 2001 From: Rob Kaufman Date: Fri, 27 Mar 2009 14:29:35 -0700 Subject: [PATCH 12/33] Making the specs rcov runnable --- spec/functional/conversation_spec.rb | 1 + spec/spec_helper.rb | 1 + 2 files changed, 2 insertions(+) diff --git a/spec/functional/conversation_spec.rb b/spec/functional/conversation_spec.rb index 8fa5d4a6..372c9c39 100644 --- a/spec/functional/conversation_spec.rb +++ b/spec/functional/conversation_spec.rb @@ -1,3 +1,4 @@ +require File.join(File.dirname(__FILE__), "..", "spec_helper") describe Conversation, 'description' do it '.aasm_states should contain all of the states' do Conversation.aasm_states.should == [:needs_attention, :read, :closed, :awaiting_response, :junk] diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index f1e4f524..d8a95fae 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1 +1,2 @@ +require 'spec' require File.join(File.dirname(__FILE__), '..', 'aasm') From 27fc466e4fc7a8e4e151b693b6d1a488698149cc Mon Sep 17 00:00:00 2001 From: Joao Vitor Date: Thu, 9 Apr 2009 01:20:53 -0300 Subject: [PATCH 13/33] Conversation is required to make spec pass --- spec/functional/conversation_spec.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/spec/functional/conversation_spec.rb b/spec/functional/conversation_spec.rb index 8fa5d4a6..e64d7bcc 100644 --- a/spec/functional/conversation_spec.rb +++ b/spec/functional/conversation_spec.rb @@ -1,3 +1,5 @@ +require File.join(File.dirname(__FILE__), 'conversation') + describe Conversation, 'description' do it '.aasm_states should contain all of the states' do Conversation.aasm_states.should == [:needs_attention, :read, :closed, :awaiting_response, :junk] From e593ec20d7ae4e857f8b6a332e303a57fdee7012 Mon Sep 17 00:00:00 2001 From: Joao Vitor Date: Thu, 9 Apr 2009 02:25:16 -0300 Subject: [PATCH 14/33] removing extra spaces --- lib/aasm.rb | 22 +++++++++++----------- lib/event.rb | 2 +- lib/persistence.rb | 4 ++-- lib/state_machine.rb | 4 ++-- lib/state_transition.rb | 2 +- spec/unit/aasm_spec.rb | 16 ++++++++-------- spec/unit/state_spec.rb | 6 +++--- spec/unit/state_transition_spec.rb | 6 +++--- 8 files changed, 31 insertions(+), 31 deletions(-) diff --git a/lib/aasm.rb b/lib/aasm.rb index fdee2ff3..6512ec89 100644 --- a/lib/aasm.rb +++ b/lib/aasm.rb @@ -13,7 +13,7 @@ class InvalidTransition < RuntimeError class UndefinedState < RuntimeError end - + def self.included(base) #:nodoc: # TODO - need to ensure that a machine is being created because # AASM was either included or arrived at via inheritance. It @@ -36,11 +36,11 @@ def aasm_initial_state(set_state=nil) AASM::StateMachine[self].initial_state end end - + def aasm_initial_state=(state) AASM::StateMachine[self].initial_state = state end - + def aasm_state(name, options={}) sm = AASM::StateMachine[self] sm.create_state(name, options) @@ -50,10 +50,10 @@ def aasm_state(name, options={}) aasm_current_state == name end end - + def aasm_event(name, options = {}, &block) sm = AASM::StateMachine[self] - + unless sm.events.has_key?(name) sm.events[name] = AASM::SupportingClasses::Event.new(name, options, &block) end @@ -74,11 +74,11 @@ def aasm_states def aasm_events AASM::StateMachine[self].events end - + def aasm_states_for_select AASM::StateMachine[self].states.map { |state| state.for_select } end - + end # Instance methods @@ -129,10 +129,10 @@ def aasm_fire_event(name, persist, *args) aasm_state_object_for_state(aasm_current_state).call_action(:exit, self) new_state = self.class.aasm_events[name].fire(self, *args) - + unless new_state.nil? aasm_state_object_for_state(new_state).call_action(:enter, self) - + persist_successful = true if persist persist_successful = set_aasm_current_state_with_persistence(new_state) @@ -141,7 +141,7 @@ def aasm_fire_event(name, persist, *args) self.aasm_current_state = new_state end - if persist_successful + if persist_successful self.aasm_event_fired(self.aasm_current_state, new_state) if self.respond_to?(:aasm_event_fired) else self.aasm_event_failed(name) if self.respond_to?(:aasm_event_failed) @@ -152,7 +152,7 @@ def aasm_fire_event(name, persist, *args) if self.respond_to?(:aasm_event_failed) self.aasm_event_failed(name) end - + false end end diff --git a/lib/event.rb b/lib/event.rb index 5589bf96..e5274848 100644 --- a/lib/event.rb +++ b/lib/event.rb @@ -4,7 +4,7 @@ module AASM module SupportingClasses class Event attr_reader :name, :success - + def initialize(name, options = {}, &block) @name = name @success = options[:success] diff --git a/lib/persistence.rb b/lib/persistence.rb index f8969645..36fe24ab 100644 --- a/lib/persistence.rb +++ b/lib/persistence.rb @@ -1,12 +1,12 @@ module AASM module Persistence - + # Checks to see this class or any of it's superclasses inherit from # ActiveRecord::Base and if so includes ActiveRecordPersistence def self.set_persistence(base) # Use a fancier auto-loading thingy, perhaps. When there are more persistence engines. hierarchy = base.ancestors.map {|klass| klass.to_s} - + if hierarchy.include?("ActiveRecord::Base") require File.join(File.dirname(__FILE__), 'persistence', 'active_record_persistence') base.send(:include, AASM::Persistence::ActiveRecordPersistence) diff --git a/lib/state_machine.rb b/lib/state_machine.rb index 672aef5c..35e10047 100644 --- a/lib/state_machine.rb +++ b/lib/state_machine.rb @@ -10,10 +10,10 @@ def self.[]=(*args) val = args.pop (@machines ||= {})[args] = val end - + attr_accessor :states, :events, :initial_state, :config attr_reader :name - + def initialize(name) @name = name @initial_state = nil diff --git a/lib/state_transition.rb b/lib/state_transition.rb index f82f5d48..960f4e30 100644 --- a/lib/state_transition.rb +++ b/lib/state_transition.rb @@ -18,7 +18,7 @@ def perform(obj) true end end - + def execute(obj, *args) case @on_transition when Symbol, String diff --git a/spec/unit/aasm_spec.rb b/spec/unit/aasm_spec.rb index 30cfe87d..6ca181ee 100644 --- a/spec/unit/aasm_spec.rb +++ b/spec/unit/aasm_spec.rb @@ -54,11 +54,11 @@ class Baz < Bar it 'should define a class level aasm_event() method on its including class' do Foo.should respond_to(:aasm_event) end - + it 'should define a class level aasm_states() method on its including class' do Foo.should respond_to(:aasm_states) end - + it 'should define a class level aasm_states_for_select() method on its including class' do Foo.should respond_to(:aasm_states_for_select) end @@ -157,7 +157,7 @@ class Baz < Bar it 'should attempt to persist if aasm_write_state is defined' do foo = Foo.new - + def foo.aasm_write_state end @@ -168,7 +168,7 @@ def foo.aasm_write_state it 'should return true if aasm_write_state is defined and returns true' do foo = Foo.new - + def foo.aasm_write_state(state) true end @@ -178,7 +178,7 @@ def foo.aasm_write_state(state) it 'should return false if aasm_write_state is defined and returns false' do foo = Foo.new - + def foo.aasm_write_state(state) false end @@ -188,7 +188,7 @@ def foo.aasm_write_state(state) it "should not update the aasm_current_state if the write fails" do foo = Foo.new - + def foo.aasm_write_state false end @@ -217,7 +217,7 @@ def foo.aasm_write_state it 'should attempt to persist if aasm_write_state is defined' do foo = Foo.new - + def foo.aasm_write_state end @@ -372,7 +372,7 @@ def wear_clothes(shirt_color, trouser_type) it 'should transition to specified next state (sleeping to showering)' do cp = ChetanPatil.new cp.wakeup! :showering - + cp.aasm_current_state.should == :showering end diff --git a/spec/unit/state_spec.rb b/spec/unit/state_spec.rb index 6eb3a8ed..b01d6984 100644 --- a/spec/unit/state_spec.rb +++ b/spec/unit/state_spec.rb @@ -16,10 +16,10 @@ def new_state(options={}) state.name.should == :astate end - + it 'should set the options and expose them as options' do state = new_state - + state.options.should == @options end @@ -56,7 +56,7 @@ def new_state(options={}) record = mock('record') record.should_receive(:foobar) - + state.call_action(:entering, record) end end diff --git a/spec/unit/state_transition_spec.rb b/spec/unit/state_transition_spec.rb index 46b32b23..ba276549 100644 --- a/spec/unit/state_transition_spec.rb +++ b/spec/unit/state_transition_spec.rb @@ -31,7 +31,7 @@ st.should_not == obj end - + it 'should fail equality check if to are not the same' do opts = {:from => 'foo', :to => 'bar', :guard => 'g'} st = AASM::SupportingClasses::StateTransition.new(opts) @@ -58,7 +58,7 @@ obj = mock('object') obj.should_receive(:test) - + st.perform(obj) end @@ -68,7 +68,7 @@ obj = mock('object') obj.should_receive(:test) - + st.perform(obj) end From f2c9c28ae704c39bfe54e7d7b048bf3ea26b6dbd Mon Sep 17 00:00:00 2001 From: Joao Vitor Date: Thu, 9 Apr 2009 02:14:02 -0300 Subject: [PATCH 15/33] Adding support to have arrays of procs, strings and symbols --- lib/event.rb | 15 ++++++++------- spec/unit/event_spec.rb | 14 ++++++++++++++ 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/lib/event.rb b/lib/event.rb index e5274848..6029e678 100644 --- a/lib/event.rb +++ b/lib/event.rb @@ -31,15 +31,16 @@ def fire(obj, to_state=nil, *args) def transitions_from_state?(state) @transitions.any? { |t| t.from == state } end - - def execute_success_callback(obj) - case success + + def execute_success_callback(obj, success = nil) + callback = success || @success + case(callback) when String, Symbol - obj.send(success) - when Array - success.each { |meth| obj.send(meth) } + obj.send(callback) when Proc - success.call(obj) + callback.call(obj) + when Array + callback.each{|meth|self.execute_success_callback(obj, meth)} end end diff --git a/spec/unit/event_spec.rb b/spec/unit/event_spec.rb index 45d42998..7dd6e96e 100644 --- a/spec/unit/event_spec.rb +++ b/spec/unit/event_spec.rb @@ -98,6 +98,20 @@ class ThisNameBetterNotBeInUse model.with_array! end + it "should call each success callback if passed an array of strings and/or symbols and/or procs" do + ThisNameBetterNotBeInUse.instance_eval { + aasm_event :with_array_including_procs, :success => [:success_callback1, 'success_callback2', lambda { |obj| obj.proc_success_callback }] do + transitions :to => :array, :from => [:initial] + end + } + + model = ThisNameBetterNotBeInUse.new + model.should_receive(:success_callback1) + model.should_receive(:success_callback2) + model.should_receive(:proc_success_callback) + model.with_array_including_procs! + end + it "should call the success callback if it's a proc" do ThisNameBetterNotBeInUse.instance_eval { aasm_event :with_proc, :success => lambda { |obj| obj.proc_success_callback } do From bd338c76efa95f110a4c4615098ee5ebacd15f6b Mon Sep 17 00:00:00 2001 From: Joao Vitor Date: Thu, 9 Apr 2009 02:23:02 -0300 Subject: [PATCH 16/33] Changing signature of aasm_event_fired and aasm_event_failed. And ensuring that aasm_event_fired receive event, old_state and new_state --- lib/aasm.rb | 7 ++-- spec/unit/aasm_spec.rb | 78 +++++++++++++++++------------------------- 2 files changed, 36 insertions(+), 49 deletions(-) diff --git a/lib/aasm.rb b/lib/aasm.rb index 6512ec89..972cc6c2 100644 --- a/lib/aasm.rb +++ b/lib/aasm.rb @@ -128,6 +128,7 @@ def aasm_state_object_for_state(name) def aasm_fire_event(name, persist, *args) aasm_state_object_for_state(aasm_current_state).call_action(:exit, self) + old_state = self.aasm_current_state new_state = self.class.aasm_events[name].fire(self, *args) unless new_state.nil? @@ -142,15 +143,15 @@ def aasm_fire_event(name, persist, *args) end if persist_successful - self.aasm_event_fired(self.aasm_current_state, new_state) if self.respond_to?(:aasm_event_fired) + self.aasm_event_fired(name, old_state, self.aasm_current_state) if self.respond_to?(:aasm_event_fired) else - self.aasm_event_failed(name) if self.respond_to?(:aasm_event_failed) + self.aasm_event_failed(name, old_state) if self.respond_to?(:aasm_event_failed) end persist_successful else if self.respond_to?(:aasm_event_failed) - self.aasm_event_failed(name) + self.aasm_event_failed(name, old_state) end false diff --git a/spec/unit/aasm_spec.rb b/spec/unit/aasm_spec.rb index 6ca181ee..81576ee1 100644 --- a/spec/unit/aasm_spec.rb +++ b/spec/unit/aasm_spec.rb @@ -255,66 +255,52 @@ def foo.aasm_read_state end describe AASM, '- event callbacks' do - it 'should call aasm_event_fired if defined and successful for bang fire' do - foo = Foo.new - def foo.aasm_event_fired(from, to) + describe "with aasm_event_fired defined" do + before do + @foo = Foo.new + def @foo.aasm_event_fired(event, from, to) + end end - foo.should_receive(:aasm_event_fired) - - foo.close! - end - - it 'should not call aasm_event_fired if defined but persist fails for bang fire' do - foo = Foo.new - def foo.aasm_event_fired(from, to) + it 'should call it for successful bang fire' do + @foo.should_receive(:aasm_event_fired).with(:close, :open, :closed) + @foo.close! end - foo.stub!(:set_aasm_current_state_with_persistence).and_return(false) - - foo.should_not_receive(:aasm_event_fired) - foo.close! - end - - it 'should not call aasm_event_failed if defined and persist fails for bang fire' do - foo = Foo.new - def foo.aasm_event_failed(from, to) + it 'should call it for successful non-bang fire' do + @foo.should_receive(:aasm_event_fired) + @foo.close end - foo.stub!(:set_aasm_current_state_with_persistence).and_return(false) - - foo.should_receive(:aasm_event_failed) - - foo.close! - end - it 'should call aasm_event_fired if defined and successful for non-bang fire' do - foo = Foo.new - def foo.aasm_event_fired(from, to) + it 'should not call it for failing bang fire' do + @foo.stub!(:set_aasm_current_state_with_persistence).and_return(false) + @foo.should_not_receive(:aasm_event_fired) + @foo.close! end - - foo.should_receive(:aasm_event_fired) - - foo.close end - it 'should call aasm_event_failed if defined and transition failed for bang fire' do - foo = Foo.new - def foo.aasm_event_failed(event) + describe "with aasm_event_failed defined" do + before do + @foo = Foo.new + def @foo.aasm_event_failed(event, from) + end end - foo.should_receive(:aasm_event_failed) - - foo.null! - end - - it 'should call aasm_event_failed if defined and transition failed for non-bang fire' do - foo = Foo.new - def foo.aasm_event_failed(event) + it 'should call it when transition failed for bang fire' do + @foo.should_receive(:aasm_event_failed).with(:null, :open) + @foo.null! end - foo.should_receive(:aasm_event_failed) + it 'should call it when transition failed for non-bang fire' do + @foo.should_receive(:aasm_event_failed).with(:null, :open) + @foo.null + end - foo.null + it 'should not call it if persist fails for bang fire' do + @foo.stub!(:set_aasm_current_state_with_persistence).and_return(false) + @foo.should_receive(:aasm_event_failed) + @foo.close! + end end end From 14baaf6a1e9e4ebbb460debe24e24be50c7f7820 Mon Sep 17 00:00:00 2001 From: Joao Vitor Date: Thu, 9 Apr 2009 10:32:59 -0300 Subject: [PATCH 17/33] changing version --- lib/aasm.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/aasm.rb b/lib/aasm.rb index 972cc6c2..71a9ec24 100644 --- a/lib/aasm.rb +++ b/lib/aasm.rb @@ -5,7 +5,7 @@ module AASM def self.Version - '2.0.5' + '2.0.6' end class InvalidTransition < RuntimeError From b56c3e90674f75d73344f4eb4cfb94c51c285d43 Mon Sep 17 00:00:00 2001 From: joaovitor Date: Thu, 9 Apr 2009 06:51:23 -0700 Subject: [PATCH 18/33] changing version --- aasm.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aasm.gemspec b/aasm.gemspec index 0e8ae535..350fc1fc 100644 --- a/aasm.gemspec +++ b/aasm.gemspec @@ -2,7 +2,7 @@ PKG_FILES = ["CHANGELOG", "MIT-LICENSE", "Rakefile", "README.rdoc", "TODO", "lib Gem::Specification.new do |s| s.name = 'aasm' - s.version = "2.0.5" + s.version = "2.0.6" s.summary = 'State machine mixin for Ruby objects' s.description = <<-EOF AASM is a continuation of the acts as state machine rails plugin, built for plain Ruby objects. From 1ca1366d86dc0e5cffc531c1a6015f22977d6521 Mon Sep 17 00:00:00 2001 From: Christos Pappas Date: Fri, 24 Apr 2009 13:40:14 +1000 Subject: [PATCH 19/33] bypass validation on write state --- lib/persistence/active_record_persistence.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/persistence/active_record_persistence.rb b/lib/persistence/active_record_persistence.rb index 9ff12849..cf3cbc77 100644 --- a/lib/persistence/active_record_persistence.rb +++ b/lib/persistence/active_record_persistence.rb @@ -191,7 +191,7 @@ def aasm_write_state(state) old_value = read_attribute(self.class.aasm_column) write_attribute(self.class.aasm_column, state.to_s) - unless self.save + unless self.save(false) write_attribute(self.class.aasm_column, old_value) return false end From f9f07ff0f4e86b7fa2265334c21096aab9068a46 Mon Sep 17 00:00:00 2001 From: Stefan Botzenhart Date: Tue, 12 May 2009 22:19:28 +0200 Subject: [PATCH 20/33] named scopes now use table_name for prefixing aasm column in named. fixed bug in combination with norman-friendly_id --- lib/persistence/active_record_persistence.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/persistence/active_record_persistence.rb b/lib/persistence/active_record_persistence.rb index 9ff12849..5243fc39 100644 --- a/lib/persistence/active_record_persistence.rb +++ b/lib/persistence/active_record_persistence.rb @@ -238,7 +238,7 @@ def aasm_read_state module NamedScopeMethods def aasm_state_with_named_scope name, options = {} aasm_state_without_named_scope name, options - self.named_scope name, :conditions => {self.aasm_column => name.to_s} unless self.respond_to?(name) + self.named_scope name, :conditions => { "#{table_name}.#{self.aasm_column}" => name.to_s} unless self.respond_to?(name) end end end From 8c686902240e51482a51f1f4b4bea4010174d02d Mon Sep 17 00:00:00 2001 From: Daniel Brunne Date: Fri, 22 May 2009 14:12:15 +0200 Subject: [PATCH 21/33] Skip validations on saving state change --- lib/persistence/active_record_persistence.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/persistence/active_record_persistence.rb b/lib/persistence/active_record_persistence.rb index 9ff12849..cf3cbc77 100644 --- a/lib/persistence/active_record_persistence.rb +++ b/lib/persistence/active_record_persistence.rb @@ -191,7 +191,7 @@ def aasm_write_state(state) old_value = read_attribute(self.class.aasm_column) write_attribute(self.class.aasm_column, state.to_s) - unless self.save + unless self.save(false) write_attribute(self.class.aasm_column, old_value) return false end From 220b8f84e47ea39a0ed22e10b722696d6beee346 Mon Sep 17 00:00:00 2001 From: Joao Vitor Date: Sat, 23 May 2009 05:00:20 -0300 Subject: [PATCH 22/33] Removing lib/version.rb of package list --- aasm.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aasm.gemspec b/aasm.gemspec index 350fc1fc..8a2d99ef 100644 --- a/aasm.gemspec +++ b/aasm.gemspec @@ -1,4 +1,4 @@ -PKG_FILES = ["CHANGELOG", "MIT-LICENSE", "Rakefile", "README.rdoc", "TODO", "lib/aasm.rb", "lib/event.rb", "lib/persistence/active_record_persistence.rb", "lib/persistence.rb", "lib/state.rb", "lib/state_machine.rb", "lib/state_transition.rb", "lib/version.rb", "doc/jamis.rb"] +PKG_FILES = ["CHANGELOG", "MIT-LICENSE", "Rakefile", "README.rdoc", "TODO", "lib/aasm.rb", "lib/event.rb", "lib/persistence/active_record_persistence.rb", "lib/persistence.rb", "lib/state.rb", "lib/state_machine.rb", "lib/state_transition.rb", "doc/jamis.rb"] Gem::Specification.new do |s| s.name = 'aasm' From f62693b70c4d43beeaeda1f9e0b330716eba0003 Mon Sep 17 00:00:00 2001 From: Travis Tilley Date: Wed, 27 May 2009 20:32:02 -0400 Subject: [PATCH 23/33] whitespace ninja --- Rakefile | 11 ++++++----- aasm.gemspec | 5 +++-- lib/aasm.rb | 2 +- lib/persistence/active_record_persistence.rb | 2 +- spec/unit/aasm_spec.rb | 2 +- spec/unit/active_record_persistence_spec.rb | 8 ++++---- 6 files changed, 16 insertions(+), 14 deletions(-) diff --git a/Rakefile b/Rakefile index dc21a58d..83472740 100644 --- a/Rakefile +++ b/Rakefile @@ -22,8 +22,8 @@ end $package_version = CURRENT_VERSION PKG_FILES = FileList['[A-Z]*', -'lib/**/*.rb', -'doc/**/*' + 'lib/**/*.rb', + 'doc/**/*' ] desc 'Generate documentation for the acts as state machine plugin.' @@ -44,9 +44,10 @@ else s.name = 'aasm' s.version = $package_version s.summary = 'State machine mixin for Ruby objects' - s.description = <<-EOF - AASM is a continuation of the acts as state machine rails plugin, built for plain Ruby objects. - EOF + s.description = <= RICH; end it 'should use the first state defined if no initial state is given' do @bar.aasm_current_state.should == :read end - + it 'should determine initial state from the Proc results' do Banker.new(Banker::RICH - 1).aasm_current_state.should == :selling_bad_mortgages Banker.new(Banker::RICH + 1).aasm_current_state.should == :retired diff --git a/spec/unit/active_record_persistence_spec.rb b/spec/unit/active_record_persistence_spec.rb index fed2d481..5df1a997 100644 --- a/spec/unit/active_record_persistence_spec.rb +++ b/spec/unit/active_record_persistence_spec.rb @@ -50,7 +50,7 @@ class June < ActiveRecord::Base class Beaver < June end - + class Thief < ActiveRecord::Base include AASM aasm_initial_state Proc.new { |thief| thief.skilled ? :rich : :jailed } @@ -227,17 +227,17 @@ class NamedScopeExample < ActiveRecord::Base end end end - + describe 'Thieves' do before(:each) do connection = mock(Connection, :columns => []) Thief.stub!(:connection).and_return(connection) end - + it 'should be rich if they\'re skilled' do Thief.new(:skilled => true).aasm_current_state.should == :rich end - + it 'should be jailed if they\'re unskilled' do Thief.new(:skilled => false).aasm_current_state.should == :jailed end From c323e8a3b0af1a5702143a245145b5b40e0b77da Mon Sep 17 00:00:00 2001 From: Travis Tilley Date: Wed, 27 May 2009 20:12:25 -0400 Subject: [PATCH 24/33] bump version --- aasm.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aasm.gemspec b/aasm.gemspec index 1b6c6d8a..8bbccadc 100644 --- a/aasm.gemspec +++ b/aasm.gemspec @@ -2,7 +2,7 @@ PKG_FILES = ["CHANGELOG", "MIT-LICENSE", "Rakefile", "README.rdoc", "TODO", "lib Gem::Specification.new do |s| s.name = 'aasm' - s.version = "2.0.6" + s.version = "2.0.7" s.summary = 'State machine mixin for Ruby objects' s.description = < Date: Wed, 27 May 2009 20:46:29 -0400 Subject: [PATCH 25/33] ...lets try this again --- aasm.gemspec | 15 +++++++-------- lib/aasm.rb | 2 +- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/aasm.gemspec b/aasm.gemspec index 8bbccadc..75d2ab0d 100644 --- a/aasm.gemspec +++ b/aasm.gemspec @@ -2,19 +2,18 @@ PKG_FILES = ["CHANGELOG", "MIT-LICENSE", "Rakefile", "README.rdoc", "TODO", "lib Gem::Specification.new do |s| s.name = 'aasm' - s.version = "2.0.7" - s.summary = 'State machine mixin for Ruby objects' - s.description = < Date: Sun, 7 Jun 2009 03:41:04 -0400 Subject: [PATCH 26/33] make spec match reality --- spec/unit/before_after_callbacks_spec.rb | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/spec/unit/before_after_callbacks_spec.rb b/spec/unit/before_after_callbacks_spec.rb index 808f5b69..6d93254e 100644 --- a/spec/unit/before_after_callbacks_spec.rb +++ b/spec/unit/before_after_callbacks_spec.rb @@ -3,8 +3,16 @@ class Foo2 include AASM aasm_initial_state :open - aasm_state :open, :before_enter => :before_enter_open, :before_exit => :before_exit_open, :after_enter => :after_enter_open, :after_exit => :after_exit_open - aasm_state :closed, :before_enter => :before_enter_closed, :before_exit => :before_exit_closed, :after_enter => :after_enter_closed, :after_exit => :after_exit_closed + aasm_state :open, + :before_enter => :before_enter_open, + :before_exit => :before_exit_open, + :after_enter => :after_enter_open, + :after_exit => :after_exit_open + aasm_state :closed, + :before_enter => :before_enter_closed, + :before_exit => :before_exit_closed, + :after_enter => :after_enter_closed, + :after_exit => :after_exit_closed aasm_event :close, :before => :before, :after => :after do transitions :to => :closed, :from => [:open] @@ -44,9 +52,9 @@ def after end it "should get close callbacks" do + @foo.should_receive(:before).once.ordered @foo.should_receive(:before_exit_open).once.ordered # these should be before the state changes @foo.should_receive(:before_enter_closed).once.ordered - @foo.should_receive(:before).once.ordered @foo.should_receive(:aasm_write_state).once.ordered.and_return(true) # this is when the state changes @foo.should_receive(:after_exit_open).once.ordered # these should be after the state changes @foo.should_receive(:after_enter_closed).once.ordered @@ -58,9 +66,9 @@ def after it "should get open callbacks" do @foo.close! + @foo.should_receive(:before).once.ordered @foo.should_receive(:before_exit_closed).once.ordered # these should be before the state changes @foo.should_receive(:before_enter_open).once.ordered - @foo.should_receive(:before).once.ordered @foo.should_receive(:aasm_write_state).once.ordered.and_return(true) # this is when the state changes @foo.should_receive(:after_exit_closed).once.ordered # these should be after the state changes @foo.should_receive(:after_enter_open).once.ordered From 10a1f8f30bb519d52328f812e51b39262a95b17c Mon Sep 17 00:00:00 2001 From: Travis Tilley Date: Sun, 7 Jun 2009 03:49:39 -0400 Subject: [PATCH 27/33] make documentation reflect reality --- README.rdoc | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/README.rdoc b/README.rdoc index cf2bc352..9a24857c 100644 --- a/README.rdoc +++ b/README.rdoc @@ -13,33 +13,30 @@ AASM has the following features: == New Callbacks -The only changes I've made are creating more callbacks with slightly more obvious semantics ;). - The callback chain & order on a successful event looks like: oldstate:exit* event:before __find transition, if possible__ transition:on_transition* - newstate:enter* oldstate:before_exit newstate:before_enter + newstate:enter* __update state__ + event:success* oldstate:after_exit oldstate:after_enter event:after - event:success* obj:aasm_event_fired* (*) marks old callbacks -Note that the old callbacks haven't been removed and still have their same semantics. All of this behavior was added without removing any old behavior. == Download The latest AASM can currently be pulled from the git repository on github. -* http://github.com/dunedain289/aasm/tree/master +* http://github.com/ttilley/aasm/tree/master == Installation @@ -47,7 +44,7 @@ The latest AASM can currently be pulled from the git repository on github. === From GitHub hosted gems % sudo gem sources -a http://gems.github.com # (you only need to do this once) - % sudo gem install dunedain289-aasm + % sudo gem install ttilley-aasm === Building your own gems @@ -114,7 +111,6 @@ This example uses a few of the more complex features available. Author:: Scott Barron License:: Original code Copyright 2006, 2007, 2008 by Scott Barron. - New changes Copyright 2009 by Scott Petersen. Released under an MIT-style license. See the LICENSE file included in the distribution. From 48ff9a50dc9e1d605fce67e5de85286d63a69229 Mon Sep 17 00:00:00 2001 From: Scott Barron Date: Sat, 8 Aug 2009 09:36:19 -0400 Subject: [PATCH 28/33] Handle inheritance properly, there was different behavior depending on whether or not AASM was included in the child class or not. --- lib/aasm.rb | 7 +++---- spec/unit/aasm_spec.rb | 23 +++++++++++------------ 2 files changed, 14 insertions(+), 16 deletions(-) diff --git a/lib/aasm.rb b/lib/aasm.rb index fdee2ff3..711e79ad 100644 --- a/lib/aasm.rb +++ b/lib/aasm.rb @@ -15,12 +15,11 @@ class UndefinedState < RuntimeError end def self.included(base) #:nodoc: - # TODO - need to ensure that a machine is being created because - # AASM was either included or arrived at via inheritance. It - # cannot be both. base.extend AASM::ClassMethods AASM::Persistence.set_persistence(base) - AASM::StateMachine[base] = AASM::StateMachine.new('') + unless AASM::StateMachine[base] + AASM::StateMachine[base] = AASM::StateMachine.new('') + end end module ClassMethods diff --git a/spec/unit/aasm_spec.rb b/spec/unit/aasm_spec.rb index 30cfe87d..efa99308 100644 --- a/spec/unit/aasm_spec.rb +++ b/spec/unit/aasm_spec.rb @@ -27,6 +27,11 @@ def exit end end +class FooTwo < Foo + include AASM + aasm_state :foo +end + class Bar include AASM @@ -71,20 +76,14 @@ class Baz < Bar describe AASM, '- subclassing' do - before(:each) do - @parent = Class.new do - include AASM + it 'should have the parent states' do + Foo.aasm_states.each do |state| + FooTwo.aasm_states.should include(state) end end - - it 'should invoke the original inherited callback' do - @parent.should_receive(:inherited) - Class.new(@parent) - end - - it 'should have a unique states hash' do - child = Class.new(@parent) - child.aasm_states.equal?(@parent.aasm_states).should be_false + + it 'should not add the child states to the parent machine' do + Foo.aasm_states.should_not include(:foo) end end From 0f90e5a680c6ba13f101bc06094ec1ea6b89d63f Mon Sep 17 00:00:00 2001 From: Scott Barron Date: Sat, 8 Aug 2009 09:39:11 -0400 Subject: [PATCH 29/33] bump version and fix gemspec --- aasm.gemspec | 4 ++-- lib/aasm.rb | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/aasm.gemspec b/aasm.gemspec index 0e8ae535..8a2d99ef 100644 --- a/aasm.gemspec +++ b/aasm.gemspec @@ -1,8 +1,8 @@ -PKG_FILES = ["CHANGELOG", "MIT-LICENSE", "Rakefile", "README.rdoc", "TODO", "lib/aasm.rb", "lib/event.rb", "lib/persistence/active_record_persistence.rb", "lib/persistence.rb", "lib/state.rb", "lib/state_machine.rb", "lib/state_transition.rb", "lib/version.rb", "doc/jamis.rb"] +PKG_FILES = ["CHANGELOG", "MIT-LICENSE", "Rakefile", "README.rdoc", "TODO", "lib/aasm.rb", "lib/event.rb", "lib/persistence/active_record_persistence.rb", "lib/persistence.rb", "lib/state.rb", "lib/state_machine.rb", "lib/state_transition.rb", "doc/jamis.rb"] Gem::Specification.new do |s| s.name = 'aasm' - s.version = "2.0.5" + s.version = "2.0.6" s.summary = 'State machine mixin for Ruby objects' s.description = <<-EOF AASM is a continuation of the acts as state machine rails plugin, built for plain Ruby objects. diff --git a/lib/aasm.rb b/lib/aasm.rb index 711e79ad..e12ec7ed 100644 --- a/lib/aasm.rb +++ b/lib/aasm.rb @@ -5,7 +5,7 @@ module AASM def self.Version - '2.0.5' + '2.0.6' end class InvalidTransition < RuntimeError From 6596b98a5375f0898e62a055a8a3eb9c93a1cdbe Mon Sep 17 00:00:00 2001 From: Scott Barron Date: Sat, 8 Aug 2009 10:56:44 -0400 Subject: [PATCH 30/33] reorganize things a bit --- Rakefile | 2 +- aasm.gemspec | 4 +- aasm.rb | 1 - lib/aasm.rb | 159 +----------------- lib/aasm/aasm.rb | 158 +++++++++++++++++ lib/{ => aasm}/event.rb | 0 lib/{ => aasm}/persistence.rb | 0 .../persistence/active_record_persistence.rb | 0 lib/{ => aasm}/state.rb | 0 lib/{ => aasm}/state_machine.rb | 0 lib/{ => aasm}/state_transition.rb | 0 spec/spec_helper.rb | 2 +- 12 files changed, 163 insertions(+), 163 deletions(-) delete mode 100644 aasm.rb create mode 100644 lib/aasm/aasm.rb rename lib/{ => aasm}/event.rb (100%) rename lib/{ => aasm}/persistence.rb (100%) rename lib/{ => aasm}/persistence/active_record_persistence.rb (100%) rename lib/{ => aasm}/state.rb (100%) rename lib/{ => aasm}/state_machine.rb (100%) rename lib/{ => aasm}/state_transition.rb (100%) diff --git a/Rakefile b/Rakefile index dc21a58d..f2902ad9 100644 --- a/Rakefile +++ b/Rakefile @@ -34,7 +34,7 @@ rd = Rake::RDocTask.new(:rdoc) do |rdoc| rdoc.title = 'AASM' rdoc.options << '--line-numbers' << '--inline-source' << '--main' << 'README.rdoc' << '--title' << 'AASM' rdoc.rdoc_files.include('README.rdoc', 'MIT-LICENSE', 'TODO', 'CHANGELOG') - rdoc.rdoc_files.include('lib/**/*.rb', 'doc/**/*.rdoc') + rdoc.rdoc_files.include('lib/*.rb', 'lib/**/*.rb', 'doc/**/*.rdoc') end if !defined?(Gem) diff --git a/aasm.gemspec b/aasm.gemspec index 8a2d99ef..53384217 100644 --- a/aasm.gemspec +++ b/aasm.gemspec @@ -1,8 +1,8 @@ -PKG_FILES = ["CHANGELOG", "MIT-LICENSE", "Rakefile", "README.rdoc", "TODO", "lib/aasm.rb", "lib/event.rb", "lib/persistence/active_record_persistence.rb", "lib/persistence.rb", "lib/state.rb", "lib/state_machine.rb", "lib/state_transition.rb", "doc/jamis.rb"] +PKG_FILES = ["CHANGELOG", "MIT-LICENSE", "Rakefile", "README.rdoc", "TODO", "lib/aasm.rb", "lib/aasm/aasm.rb", "lib/aasm/event.rb", "lib/aasm/persistence/active_record_persistence.rb", "lib/aasm/persistence.rb", "lib/aasm/state.rb", "lib/aasm/state_machine.rb", "lib/aasm/state_transition.rb", "doc/jamis.rb"] Gem::Specification.new do |s| s.name = 'aasm' - s.version = "2.0.6" + s.version = "2.0.7" s.summary = 'State machine mixin for Ruby objects' s.description = <<-EOF AASM is a continuation of the acts as state machine rails plugin, built for plain Ruby objects. diff --git a/aasm.rb b/aasm.rb deleted file mode 100644 index 2d025908..00000000 --- a/aasm.rb +++ /dev/null @@ -1 +0,0 @@ -require File.join(File.dirname(__FILE__), 'lib', 'aasm') diff --git a/lib/aasm.rb b/lib/aasm.rb index e12ec7ed..09d4a7c5 100644 --- a/lib/aasm.rb +++ b/lib/aasm.rb @@ -1,158 +1 @@ -require File.join(File.dirname(__FILE__), 'event') -require File.join(File.dirname(__FILE__), 'state') -require File.join(File.dirname(__FILE__), 'state_machine') -require File.join(File.dirname(__FILE__), 'persistence') - -module AASM - def self.Version - '2.0.6' - end - - class InvalidTransition < RuntimeError - end - - class UndefinedState < RuntimeError - end - - def self.included(base) #:nodoc: - base.extend AASM::ClassMethods - AASM::Persistence.set_persistence(base) - unless AASM::StateMachine[base] - AASM::StateMachine[base] = AASM::StateMachine.new('') - end - end - - module ClassMethods - def inherited(klass) - AASM::StateMachine[klass] = AASM::StateMachine[self].clone - super - end - - def aasm_initial_state(set_state=nil) - if set_state - AASM::StateMachine[self].initial_state = set_state - else - AASM::StateMachine[self].initial_state - end - end - - def aasm_initial_state=(state) - AASM::StateMachine[self].initial_state = state - end - - def aasm_state(name, options={}) - sm = AASM::StateMachine[self] - sm.create_state(name, options) - sm.initial_state = name unless sm.initial_state - - define_method("#{name.to_s}?") do - aasm_current_state == name - end - end - - def aasm_event(name, options = {}, &block) - sm = AASM::StateMachine[self] - - unless sm.events.has_key?(name) - sm.events[name] = AASM::SupportingClasses::Event.new(name, options, &block) - end - - define_method("#{name.to_s}!") do |*args| - aasm_fire_event(name, true, *args) - end - - define_method("#{name.to_s}") do |*args| - aasm_fire_event(name, false, *args) - end - end - - def aasm_states - AASM::StateMachine[self].states - end - - def aasm_events - AASM::StateMachine[self].events - end - - def aasm_states_for_select - AASM::StateMachine[self].states.map { |state| state.for_select } - end - - end - - # Instance methods - def aasm_current_state - return @aasm_current_state if @aasm_current_state - - if self.respond_to?(:aasm_read_state) || self.private_methods.include?('aasm_read_state') - @aasm_current_state = aasm_read_state - end - return @aasm_current_state if @aasm_current_state - self.class.aasm_initial_state - end - - def aasm_events_for_current_state - aasm_events_for_state(aasm_current_state) - 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} - end - - private - def set_aasm_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 - - 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_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_fire_event(name, persist, *args) - aasm_state_object_for_state(aasm_current_state).call_action(:exit, self) - - new_state = self.class.aasm_events[name].fire(self, *args) - - unless new_state.nil? - aasm_state_object_for_state(new_state).call_action(:enter, self) - - persist_successful = true - if persist - persist_successful = set_aasm_current_state_with_persistence(new_state) - self.class.aasm_events[name].execute_success_callback(self) if persist_successful - else - self.aasm_current_state = new_state - end - - if persist_successful - self.aasm_event_fired(self.aasm_current_state, new_state) if self.respond_to?(:aasm_event_fired) - else - self.aasm_event_failed(name) if self.respond_to?(:aasm_event_failed) - end - - persist_successful - else - if self.respond_to?(:aasm_event_failed) - self.aasm_event_failed(name) - end - - false - end - end -end +require File.join(File.dirname(__FILE__), 'aasm', 'aasm') diff --git a/lib/aasm/aasm.rb b/lib/aasm/aasm.rb new file mode 100644 index 00000000..e37a394c --- /dev/null +++ b/lib/aasm/aasm.rb @@ -0,0 +1,158 @@ +require File.join(File.dirname(__FILE__), 'event') +require File.join(File.dirname(__FILE__), 'state') +require File.join(File.dirname(__FILE__), 'state_machine') +require File.join(File.dirname(__FILE__), 'persistence') + +module AASM + def self.Version + '2.0.7' + end + + class InvalidTransition < RuntimeError + end + + class UndefinedState < RuntimeError + end + + def self.included(base) #:nodoc: + base.extend AASM::ClassMethods + AASM::Persistence.set_persistence(base) + unless AASM::StateMachine[base] + AASM::StateMachine[base] = AASM::StateMachine.new('') + end + end + + module ClassMethods + def inherited(klass) + AASM::StateMachine[klass] = AASM::StateMachine[self].clone + super + end + + def aasm_initial_state(set_state=nil) + if set_state + AASM::StateMachine[self].initial_state = set_state + else + AASM::StateMachine[self].initial_state + end + end + + def aasm_initial_state=(state) + AASM::StateMachine[self].initial_state = state + end + + def aasm_state(name, options={}) + sm = AASM::StateMachine[self] + sm.create_state(name, options) + sm.initial_state = name unless sm.initial_state + + define_method("#{name.to_s}?") do + aasm_current_state == name + end + end + + def aasm_event(name, options = {}, &block) + sm = AASM::StateMachine[self] + + unless sm.events.has_key?(name) + sm.events[name] = AASM::SupportingClasses::Event.new(name, options, &block) + end + + define_method("#{name.to_s}!") do |*args| + aasm_fire_event(name, true, *args) + end + + define_method("#{name.to_s}") do |*args| + aasm_fire_event(name, false, *args) + end + end + + def aasm_states + AASM::StateMachine[self].states + end + + def aasm_events + AASM::StateMachine[self].events + end + + def aasm_states_for_select + AASM::StateMachine[self].states.map { |state| state.for_select } + end + + end + + # Instance methods + def aasm_current_state + return @aasm_current_state if @aasm_current_state + + if self.respond_to?(:aasm_read_state) || self.private_methods.include?('aasm_read_state') + @aasm_current_state = aasm_read_state + end + return @aasm_current_state if @aasm_current_state + self.class.aasm_initial_state + end + + def aasm_events_for_current_state + aasm_events_for_state(aasm_current_state) + 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} + end + + private + def set_aasm_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 + + 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_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_fire_event(name, persist, *args) + aasm_state_object_for_state(aasm_current_state).call_action(:exit, self) + + new_state = self.class.aasm_events[name].fire(self, *args) + + unless new_state.nil? + aasm_state_object_for_state(new_state).call_action(:enter, self) + + persist_successful = true + if persist + persist_successful = set_aasm_current_state_with_persistence(new_state) + self.class.aasm_events[name].execute_success_callback(self) if persist_successful + else + self.aasm_current_state = new_state + end + + if persist_successful + self.aasm_event_fired(self.aasm_current_state, new_state) if self.respond_to?(:aasm_event_fired) + else + self.aasm_event_failed(name) if self.respond_to?(:aasm_event_failed) + end + + persist_successful + else + if self.respond_to?(:aasm_event_failed) + self.aasm_event_failed(name) + end + + false + end + end +end diff --git a/lib/event.rb b/lib/aasm/event.rb similarity index 100% rename from lib/event.rb rename to lib/aasm/event.rb diff --git a/lib/persistence.rb b/lib/aasm/persistence.rb similarity index 100% rename from lib/persistence.rb rename to lib/aasm/persistence.rb diff --git a/lib/persistence/active_record_persistence.rb b/lib/aasm/persistence/active_record_persistence.rb similarity index 100% rename from lib/persistence/active_record_persistence.rb rename to lib/aasm/persistence/active_record_persistence.rb diff --git a/lib/state.rb b/lib/aasm/state.rb similarity index 100% rename from lib/state.rb rename to lib/aasm/state.rb diff --git a/lib/state_machine.rb b/lib/aasm/state_machine.rb similarity index 100% rename from lib/state_machine.rb rename to lib/aasm/state_machine.rb diff --git a/lib/state_transition.rb b/lib/aasm/state_transition.rb similarity index 100% rename from lib/state_transition.rb rename to lib/aasm/state_transition.rb diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index f1e4f524..c632ec92 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1 +1 @@ -require File.join(File.dirname(__FILE__), '..', 'aasm') +require File.join(File.dirname(__FILE__), '..', 'lib', 'aasm', 'aasm') From 904b6b43d63c90528d6295bba88e0ca0fc0142ba Mon Sep 17 00:00:00 2001 From: Scott Barron Date: Sat, 8 Aug 2009 09:36:19 -0400 Subject: [PATCH 31/33] Handle inheritance properly, there was different behavior depending on whether or not AASM was included in the child class or not. (cherry picked from commit 48ff9a50dc9e1d605fce67e5de85286d63a69229) --- lib/aasm.rb | 7 +++---- spec/unit/aasm_spec.rb | 23 +++++++++++------------ 2 files changed, 14 insertions(+), 16 deletions(-) diff --git a/lib/aasm.rb b/lib/aasm.rb index fb6648f8..2e1de3b5 100644 --- a/lib/aasm.rb +++ b/lib/aasm.rb @@ -15,12 +15,11 @@ class UndefinedState < RuntimeError end def self.included(base) #:nodoc: - # TODO - need to ensure that a machine is being created because - # AASM was either included or arrived at via inheritance. It - # cannot be both. base.extend AASM::ClassMethods AASM::Persistence.set_persistence(base) - AASM::StateMachine[base] = AASM::StateMachine.new('') + unless AASM::StateMachine[base] + AASM::StateMachine[base] = AASM::StateMachine.new('') + end end module ClassMethods diff --git a/spec/unit/aasm_spec.rb b/spec/unit/aasm_spec.rb index cb79b2a8..e0066d1a 100644 --- a/spec/unit/aasm_spec.rb +++ b/spec/unit/aasm_spec.rb @@ -27,6 +27,11 @@ def exit end end +class FooTwo < Foo + include AASM + aasm_state :foo +end + class Bar include AASM @@ -82,20 +87,14 @@ def rich?; self.balance >= RICH; end describe AASM, '- subclassing' do - before(:each) do - @parent = Class.new do - include AASM + it 'should have the parent states' do + Foo.aasm_states.each do |state| + FooTwo.aasm_states.should include(state) end end - - it 'should invoke the original inherited callback' do - @parent.should_receive(:inherited) - Class.new(@parent) - end - - it 'should have a unique states hash' do - child = Class.new(@parent) - child.aasm_states.equal?(@parent.aasm_states).should be_false + + it 'should not add the child states to the parent machine' do + Foo.aasm_states.should_not include(:foo) end end From 1e4c038eeec9c6a2a751196a9e36f165e144b721 Mon Sep 17 00:00:00 2001 From: Travis Tilley Date: Sat, 8 Aug 2009 16:53:47 -0400 Subject: [PATCH 32/33] reorganize to match rubyist/aasm --- Rakefile | 8 +- aasm.gemspec | 4 +- aasm.rb | 1 - lib/aasm.rb | 186 +----------------- lib/aasm/aasm.rb | 185 +++++++++++++++++ lib/{ => aasm}/event.rb | 0 lib/{ => aasm}/persistence.rb | 0 .../persistence/active_record_persistence.rb | 0 lib/{ => aasm}/state.rb | 0 lib/{ => aasm}/state_machine.rb | 0 lib/{ => aasm}/state_transition.rb | 0 spec/spec_helper.rb | 2 +- 12 files changed, 193 insertions(+), 193 deletions(-) delete mode 100644 aasm.rb create mode 100644 lib/aasm/aasm.rb rename lib/{ => aasm}/event.rb (100%) rename lib/{ => aasm}/persistence.rb (100%) rename lib/{ => aasm}/persistence/active_record_persistence.rb (100%) rename lib/{ => aasm}/state.rb (100%) rename lib/{ => aasm}/state_machine.rb (100%) rename lib/{ => aasm}/state_transition.rb (100%) diff --git a/Rakefile b/Rakefile index 8f4c7f61..a5472159 100644 --- a/Rakefile +++ b/Rakefile @@ -34,7 +34,7 @@ rd = Rake::RDocTask.new(:rdoc) do |rdoc| rdoc.title = 'AASM' rdoc.options << '--line-numbers' << '--inline-source' << '--main' << 'README.rdoc' << '--title' << 'AASM' rdoc.rdoc_files.include('README.rdoc', 'MIT-LICENSE', 'TODO', 'CHANGELOG') - rdoc.rdoc_files.include('lib/**/*.rb', 'doc/**/*.rdoc') + rdoc.rdoc_files.include('lib/*.rb', 'lib/**/*.rb', 'doc/**/*.rdoc') end if !defined?(Gem) @@ -54,9 +54,9 @@ EOF s.extra_rdoc_files = rd.rdoc_files.reject {|fn| fn =~ /\.rb$/}.to_a s.rdoc_options = rd.options - s.authors = ['Scott Barron', 'Scott Petersen'] - s.email = 'petersen@dunedain289.com' - s.homepage = 'http://github.com/dunedain289/aasm' + s.authors = ['Scott Barron', 'Scott Petersen', 'Travis Tilley'] + s.email = 'ttilley@gmail.com' + s.homepage = 'http://github.com/ttilley/aasm' end package_task = Rake::GemPackageTask.new(spec) do |pkg| diff --git a/aasm.gemspec b/aasm.gemspec index df7d5c98..c6dc2e27 100644 --- a/aasm.gemspec +++ b/aasm.gemspec @@ -1,8 +1,8 @@ -PKG_FILES = ["CHANGELOG", "MIT-LICENSE", "Rakefile", "README.rdoc", "TODO", "lib/aasm.rb", "lib/event.rb", "lib/persistence/active_record_persistence.rb", "lib/persistence.rb", "lib/state.rb", "lib/state_machine.rb", "lib/state_transition.rb", "doc/jamis.rb"] +PKG_FILES = ["CHANGELOG", "MIT-LICENSE", "Rakefile", "README.rdoc", "TODO", "lib/aasm/aasm.rb", "lib/aasm/event.rb", "lib/aasm/persistence/active_record_persistence.rb", "lib/aasm/persistence.rb", "lib/aasm/state.rb", "lib/aasm/state_machine.rb", "lib/aasm/state_transition.rb", "lib/aasm.rb", "doc/jamis.rb"] Gem::Specification.new do |s| s.name = 'aasm' - s.version = "2.1.0" + s.version = "2.1.1" s.summary = %q{State machine mixin for Ruby objects} s.description = %q{AASM is a continuation of the acts as state machine rails plugin, built for plain Ruby objects.} diff --git a/aasm.rb b/aasm.rb deleted file mode 100644 index 2d025908..00000000 --- a/aasm.rb +++ /dev/null @@ -1 +0,0 @@ -require File.join(File.dirname(__FILE__), 'lib', 'aasm') diff --git a/lib/aasm.rb b/lib/aasm.rb index 2e1de3b5..09d4a7c5 100644 --- a/lib/aasm.rb +++ b/lib/aasm.rb @@ -1,185 +1 @@ -require File.join(File.dirname(__FILE__), 'event') -require File.join(File.dirname(__FILE__), 'state') -require File.join(File.dirname(__FILE__), 'state_machine') -require File.join(File.dirname(__FILE__), 'persistence') - -module AASM - def self.Version - '2.1.0' - end - - class InvalidTransition < RuntimeError - end - - class UndefinedState < RuntimeError - end - - def self.included(base) #:nodoc: - base.extend AASM::ClassMethods - AASM::Persistence.set_persistence(base) - unless AASM::StateMachine[base] - AASM::StateMachine[base] = AASM::StateMachine.new('') - end - end - - module ClassMethods - def inherited(klass) - AASM::StateMachine[klass] = AASM::StateMachine[self].clone - super - end - - def aasm_initial_state(set_state=nil) - if set_state - AASM::StateMachine[self].initial_state = set_state - else - AASM::StateMachine[self].initial_state - end - end - - def aasm_initial_state=(state) - AASM::StateMachine[self].initial_state = state - end - - def aasm_state(name, options={}) - sm = AASM::StateMachine[self] - sm.create_state(name, options) - sm.initial_state = name unless sm.initial_state - - define_method("#{name.to_s}?") do - aasm_current_state == name - end - end - - def aasm_event(name, options = {}, &block) - sm = AASM::StateMachine[self] - - unless sm.events.has_key?(name) - sm.events[name] = AASM::SupportingClasses::Event.new(name, options, &block) - end - - define_method("#{name.to_s}!") do |*args| - aasm_fire_event(name, true, *args) - end - - define_method("#{name.to_s}") do |*args| - aasm_fire_event(name, false, *args) - end - end - - def aasm_states - AASM::StateMachine[self].states - end - - def aasm_events - AASM::StateMachine[self].events - end - - def aasm_states_for_select - AASM::StateMachine[self].states.map { |state| state.for_select } - end - - end - - # Instance methods - def aasm_current_state - return @aasm_current_state if @aasm_current_state - - if self.respond_to?(:aasm_read_state) || self.private_methods.include?('aasm_read_state') - @aasm_current_state = aasm_read_state - end - return @aasm_current_state if @aasm_current_state - aasm_determine_state_name(self.class.aasm_initial_state) - end - - def aasm_events_for_current_state - aasm_events_for_state(aasm_current_state) - 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} - end - - private - def set_aasm_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 - - 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_fire_event(name, persist, *args) - old_state = aasm_state_object_for_state(aasm_current_state) - event = self.class.aasm_events[name] - - old_state.call_action(:exit, self) - - # new event before callback - event.call_action(:before, self) - - new_state_name = event.fire(self, *args) - - unless new_state_name.nil? - new_state = aasm_state_object_for_state(new_state_name) - - # new before_ callbacks - old_state.call_action(:before_exit, self) - new_state.call_action(:before_enter, self) - - new_state.call_action(:enter, self) - - persist_successful = true - if persist - persist_successful = set_aasm_current_state_with_persistence(new_state_name) - event.execute_success_callback(self) if persist_successful - else - self.aasm_current_state = new_state_name - end - - if persist_successful - old_state.call_action(:after_exit, self) - new_state.call_action(:after_enter, self) - event.call_action(:after, self) - - self.aasm_event_fired(name, old_state.name, self.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 - - persist_successful - else - if self.respond_to?(:aasm_event_failed) - self.aasm_event_failed(name, old_state.name) - end - - false - end - end -end +require File.join(File.dirname(__FILE__), 'aasm', 'aasm') diff --git a/lib/aasm/aasm.rb b/lib/aasm/aasm.rb new file mode 100644 index 00000000..9c23162a --- /dev/null +++ b/lib/aasm/aasm.rb @@ -0,0 +1,185 @@ +require File.join(File.dirname(__FILE__), 'event') +require File.join(File.dirname(__FILE__), 'state') +require File.join(File.dirname(__FILE__), 'state_machine') +require File.join(File.dirname(__FILE__), 'persistence') + +module AASM + def self.Version + '2.1.1' + end + + class InvalidTransition < RuntimeError + end + + class UndefinedState < RuntimeError + end + + def self.included(base) #:nodoc: + base.extend AASM::ClassMethods + AASM::Persistence.set_persistence(base) + unless AASM::StateMachine[base] + AASM::StateMachine[base] = AASM::StateMachine.new('') + end + end + + module ClassMethods + def inherited(klass) + AASM::StateMachine[klass] = AASM::StateMachine[self].clone + super + end + + def aasm_initial_state(set_state=nil) + if set_state + AASM::StateMachine[self].initial_state = set_state + else + AASM::StateMachine[self].initial_state + end + end + + def aasm_initial_state=(state) + AASM::StateMachine[self].initial_state = state + end + + def aasm_state(name, options={}) + sm = AASM::StateMachine[self] + sm.create_state(name, options) + sm.initial_state = name unless sm.initial_state + + define_method("#{name.to_s}?") do + aasm_current_state == name + end + end + + def aasm_event(name, options = {}, &block) + sm = AASM::StateMachine[self] + + unless sm.events.has_key?(name) + sm.events[name] = AASM::SupportingClasses::Event.new(name, options, &block) + end + + define_method("#{name.to_s}!") do |*args| + aasm_fire_event(name, true, *args) + end + + define_method("#{name.to_s}") do |*args| + aasm_fire_event(name, false, *args) + end + end + + def aasm_states + AASM::StateMachine[self].states + end + + def aasm_events + AASM::StateMachine[self].events + end + + def aasm_states_for_select + AASM::StateMachine[self].states.map { |state| state.for_select } + end + + end + + # Instance methods + def aasm_current_state + return @aasm_current_state if @aasm_current_state + + if self.respond_to?(:aasm_read_state) || self.private_methods.include?('aasm_read_state') + @aasm_current_state = aasm_read_state + end + return @aasm_current_state if @aasm_current_state + aasm_determine_state_name(self.class.aasm_initial_state) + end + + def aasm_events_for_current_state + aasm_events_for_state(aasm_current_state) + 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} + end + + private + def set_aasm_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 + + 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_fire_event(name, persist, *args) + old_state = aasm_state_object_for_state(aasm_current_state) + event = self.class.aasm_events[name] + + old_state.call_action(:exit, self) + + # new event before callback + event.call_action(:before, self) + + new_state_name = event.fire(self, *args) + + unless new_state_name.nil? + new_state = aasm_state_object_for_state(new_state_name) + + # new before_ callbacks + old_state.call_action(:before_exit, self) + new_state.call_action(:before_enter, self) + + new_state.call_action(:enter, self) + + persist_successful = true + if persist + persist_successful = set_aasm_current_state_with_persistence(new_state_name) + event.execute_success_callback(self) if persist_successful + else + self.aasm_current_state = new_state_name + end + + if persist_successful + old_state.call_action(:after_exit, self) + new_state.call_action(:after_enter, self) + event.call_action(:after, self) + + self.aasm_event_fired(name, old_state.name, self.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 + + persist_successful + else + if self.respond_to?(:aasm_event_failed) + self.aasm_event_failed(name, old_state.name) + end + + false + end + end +end diff --git a/lib/event.rb b/lib/aasm/event.rb similarity index 100% rename from lib/event.rb rename to lib/aasm/event.rb diff --git a/lib/persistence.rb b/lib/aasm/persistence.rb similarity index 100% rename from lib/persistence.rb rename to lib/aasm/persistence.rb diff --git a/lib/persistence/active_record_persistence.rb b/lib/aasm/persistence/active_record_persistence.rb similarity index 100% rename from lib/persistence/active_record_persistence.rb rename to lib/aasm/persistence/active_record_persistence.rb diff --git a/lib/state.rb b/lib/aasm/state.rb similarity index 100% rename from lib/state.rb rename to lib/aasm/state.rb diff --git a/lib/state_machine.rb b/lib/aasm/state_machine.rb similarity index 100% rename from lib/state_machine.rb rename to lib/aasm/state_machine.rb diff --git a/lib/state_transition.rb b/lib/aasm/state_transition.rb similarity index 100% rename from lib/state_transition.rb rename to lib/aasm/state_transition.rb diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index d8a95fae..76194126 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,2 +1,2 @@ require 'spec' -require File.join(File.dirname(__FILE__), '..', 'aasm') +require File.join(File.dirname(__FILE__), '..', 'lib', 'aasm', 'aasm') From dfc2874972daf601f3eeb4cd2bff589290cc2521 Mon Sep 17 00:00:00 2001 From: rubyist Date: Sat, 5 Sep 2009 19:54:52 -0700 Subject: [PATCH 33/33] Correct official fork in README [herestomwiththeweather] --- README.rdoc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.rdoc b/README.rdoc index 9a24857c..ca138db1 100644 --- a/README.rdoc +++ b/README.rdoc @@ -36,7 +36,7 @@ The callback chain & order on a successful event looks like: The latest AASM can currently be pulled from the git repository on github. -* http://github.com/ttilley/aasm/tree/master +* http://github.com/rubyist/aasm/tree/master == Installation @@ -44,7 +44,7 @@ The latest AASM can currently be pulled from the git repository on github. === From GitHub hosted gems % sudo gem sources -a http://gems.github.com # (you only need to do this once) - % sudo gem install ttilley-aasm + % sudo gem install rubyist-aasm === Building your own gems