aasm 2.0.0 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/CHANGELOG CHANGED
@@ -1,5 +1,15 @@
1
+ * In AR persistence, move state column from class level variables into the StateMachine object for the class
2
+
3
+ * allowed :to array and :on_transition callback [Kevin Triplett]
4
+
5
+ * Support enter and exit actions on states
6
+
7
+ * Use named_scope in AR persistence layer, if available [Jan De Poorter]
8
+
1
9
  * Incremented version number
10
+
2
11
  * Cleaned up aasm_states_for_select to return the value as a string
12
+
3
13
  * Specs and bug fixes for the ActiveRecordPersistence, keeping persistence columns in sync
4
14
  Allowing for nil values in states for active record
5
15
  Only set state to default state before_validation_on_create
@@ -63,6 +63,8 @@ Author:: Scott Barron <scott at elitists dot net>
63
63
  License:: Copyright 2006, 2007, 2008 by Scott Barron.
64
64
  Released under an MIT-style license. See the LICENSE file
65
65
  included in the distribution.
66
+ Bugs:: http://rubyist.lighthouseapp.com/projects/13207-aasm/
67
+ GitHub:: http://github.com/rubyist/aasm/tree/master
66
68
 
67
69
  == Warranty
68
70
 
data/Rakefile CHANGED
@@ -71,7 +71,7 @@ else
71
71
  Spec::Rake::SpecTask.new('cruise') do |t|
72
72
  t.spec_files = FileList['spec/**/*.rb']
73
73
  t.rcov = true
74
- t.rcov_opts = ['--exclude', 'spec']
74
+ t.rcov_opts = ['--exclude', 'spec', '--exclude', 'Library']
75
75
  end
76
76
 
77
77
  desc "Run all examples"
data/TODO CHANGED
@@ -1,10 +1,8 @@
1
1
  Before Next Release:
2
2
 
3
- * Add state actions (enter, exit, after)
4
3
  * Add #aasm_next_state_for_event
5
4
  * Add #aasm_next_states_for_event
6
5
 
7
-
8
6
  Cool ideas from users:
9
7
 
10
8
  * Support multiple state machines on one object (Chris Nelson)
@@ -1,5 +1,6 @@
1
1
  require File.join(File.dirname(__FILE__), 'event')
2
2
  require File.join(File.dirname(__FILE__), 'state')
3
+ require File.join(File.dirname(__FILE__), 'state_machine')
3
4
  require File.join(File.dirname(__FILE__), 'persistence')
4
5
 
5
6
  module AASM
@@ -7,26 +8,37 @@ module AASM
7
8
  end
8
9
 
9
10
  def self.included(base) #:nodoc:
11
+ # TODO - need to ensure that a machine is being created because
12
+ # AASM was either included or arrived at via inheritance. It
13
+ # cannot be both.
10
14
  base.extend AASM::ClassMethods
11
15
  AASM::Persistence.set_persistence(base)
16
+ AASM::StateMachine[base] = AASM::StateMachine.new('')
17
+
18
+ base.class_eval do
19
+ def base.inherited(klass)
20
+ AASM::StateMachine[klass] = AASM::StateMachine[self].dup
21
+ end
22
+ end
12
23
  end
13
24
 
14
25
  module ClassMethods
15
26
  def aasm_initial_state(set_state=nil)
16
27
  if set_state
17
- aasm_initial_state = set_state
28
+ AASM::StateMachine[self].initial_state = set_state
18
29
  else
19
- @aasm_initial_state
30
+ AASM::StateMachine[self].initial_state
20
31
  end
21
32
  end
22
33
 
23
34
  def aasm_initial_state=(state)
24
- @aasm_initial_state = state
35
+ AASM::StateMachine[self].initial_state = state
25
36
  end
26
37
 
27
38
  def aasm_state(name, options={})
28
- aasm_states << name unless aasm_states.include?(name)
29
- self.aasm_initial_state = name unless self.aasm_initial_state
39
+ sm = AASM::StateMachine[self]
40
+ sm.create_state(name, options)
41
+ sm.initial_state = name unless sm.initial_state
30
42
 
31
43
  define_method("#{name.to_s}?") do
32
44
  aasm_current_state == name
@@ -34,61 +46,31 @@ module AASM
34
46
  end
35
47
 
36
48
  def aasm_event(name, options = {}, &block)
37
- unless aasm_events.has_key?(name)
38
- aasm_events[name] = AASM::SupportingClasses::Event.new(name, options, &block)
49
+ sm = AASM::StateMachine[self]
50
+
51
+ unless sm.events.has_key?(name)
52
+ sm.events[name] = AASM::SupportingClasses::Event.new(name, options, &block)
39
53
  end
40
54
 
41
- define_method("#{name.to_s}!") do
42
- new_state = self.class.aasm_events[name].fire(self)
43
- unless new_state.nil?
44
- if self.respond_to?(:aasm_event_fired)
45
- self.aasm_event_fired(self.aasm_current_state, new_state)
46
- end
47
-
48
- self.aasm_current_state_with_persistence = new_state
49
-
50
- self.send(self.class.aasm_events[name].success) if self.class.aasm_events[name].success
51
-
52
- true
53
- else
54
- if self.respond_to?(:aasm_event_failed)
55
- self.aasm_event_failed(name)
56
- end
57
-
58
- false
59
- end
55
+ define_method("#{name.to_s}!") do |*args|
56
+ aasm_fire_event(name, true, *args)
60
57
  end
61
58
 
62
- define_method("#{name.to_s}") do
63
- new_state = self.class.aasm_events[name].fire(self)
64
- unless new_state.nil?
65
- if self.respond_to?(:aasm_event_fired)
66
- self.aasm_event_fired(self.aasm_current_state, new_state)
67
- end
68
-
69
- self.aasm_current_state = new_state
70
- true
71
- else
72
- if self.respond_to?(:aasm_event_failed)
73
- self.aasm_event_failed(name)
74
- end
75
-
76
- false
77
- end
59
+ define_method("#{name.to_s}") do |*args|
60
+ aasm_fire_event(name, false, *args)
78
61
  end
79
-
80
62
  end
81
63
 
82
64
  def aasm_states
83
- @aasm_states ||= []
65
+ AASM::StateMachine[self].states
84
66
  end
85
67
 
86
68
  def aasm_events
87
- @aasm_events ||= {}
69
+ AASM::StateMachine[self].events
88
70
  end
89
71
 
90
72
  def aasm_states_for_select
91
- aasm_states.collect { |state| [state.to_s.gsub(/_/, ' ').capitalize, state.to_s] }
73
+ AASM::StateMachine[self].states.map { |state| state.for_select }
92
74
  end
93
75
 
94
76
  end
@@ -128,4 +110,36 @@ module AASM
128
110
  @aasm_current_state = state
129
111
  end
130
112
 
113
+ def aasm_state_object_for_state(name)
114
+ self.class.aasm_states.find {|s| s == name}
115
+ end
116
+
117
+ def aasm_fire_event(name, persist, *args)
118
+ aasm_state_object_for_state(aasm_current_state).call_action(:exit, self)
119
+
120
+ new_state = self.class.aasm_events[name].fire(self, *args)
121
+
122
+ unless new_state.nil?
123
+ aasm_state_object_for_state(new_state).call_action(:enter, self)
124
+
125
+ if self.respond_to?(:aasm_event_fired)
126
+ self.aasm_event_fired(self.aasm_current_state, new_state)
127
+ end
128
+
129
+ if persist
130
+ self.aasm_current_state_with_persistence = new_state
131
+ self.send(self.class.aasm_events[name].success) if self.class.aasm_events[name].success
132
+ else
133
+ self.aasm_current_state = new_state
134
+ end
135
+
136
+ true
137
+ else
138
+ if self.respond_to?(:aasm_event_failed)
139
+ self.aasm_event_failed(name)
140
+ end
141
+
142
+ false
143
+ end
144
+ end
131
145
  end
@@ -12,14 +12,16 @@ module AASM
12
12
  instance_eval(&block) if block
13
13
  end
14
14
 
15
- def fire(obj)
15
+ def fire(obj, to_state=nil, *args)
16
16
  transitions = @transitions.select { |t| t.from == obj.aasm_current_state }
17
17
  raise AASM::InvalidTransition if transitions.size == 0
18
18
 
19
19
  next_state = nil
20
20
  transitions.each do |transition|
21
+ next if to_state and !Array(transition.to).include?(to_state)
21
22
  if transition.perform(obj)
22
- next_state = transition.to
23
+ next_state = to_state || Array(transition.to).first
24
+ transition.execute(obj, *args)
23
25
  break
24
26
  end
25
27
  end
@@ -36,7 +36,19 @@ module AASM
36
36
  base.send(:include, AASM::Persistence::ActiveRecordPersistence::InstanceMethods)
37
37
  base.send(:include, AASM::Persistence::ActiveRecordPersistence::ReadState) unless base.method_defined?(:aasm_read_state)
38
38
  base.send(:include, AASM::Persistence::ActiveRecordPersistence::WriteState) unless base.method_defined?(:aasm_write_state)
39
- base.send(:include, AASM::Persistence::ActiveRecordPersistence::WriteStateWithoutPersistence) unless base.method_defined?(:aasm_write_state_without_persistence)
39
+ base.send(:include, AASM::Persistence::ActiveRecordPersistence::WriteStateWithoutPersistence) unless base.method_defined?(:aasm_write_state_without_persistence)
40
+
41
+ if base.respond_to?(:named_scope)
42
+ base.extend(AASM::Persistence::ActiveRecordPersistence::NamedScopeMethods)
43
+
44
+ base.class_eval do
45
+ class << self
46
+ alias_method :aasm_state_without_named_scope, :aasm_state
47
+ alias_method :aasm_state, :aasm_state_with_named_scope
48
+ end
49
+ end
50
+ end
51
+
40
52
  base.before_validation_on_create :aasm_ensure_initial_state
41
53
  end
42
54
 
@@ -67,13 +79,40 @@ module AASM
67
79
  # This method is both a getter and a setter
68
80
  def aasm_column(column_name=nil)
69
81
  if column_name
70
- @aasm_column = column_name.to_sym
82
+ AASM::StateMachine[self].config.column = column_name.to_sym
83
+ # @aasm_column = column_name.to_sym
71
84
  else
72
- @aasm_column ||= :aasm_state
85
+ AASM::StateMachine[self].config.column ||= :aasm_state
86
+ # @aasm_column ||= :aasm_state
73
87
  end
74
- @aasm_column
88
+ # @aasm_column
89
+ AASM::StateMachine[self].config.column
75
90
  end
76
91
 
92
+ def find_in_state(number, state, *args)
93
+ with_state_scope state do
94
+ find(number, *args)
95
+ end
96
+ end
97
+
98
+ def count_in_state(state, *args)
99
+ with_state_scope state do
100
+ count(*args)
101
+ end
102
+ end
103
+
104
+ def calculate_in_state(state, *args)
105
+ with_state_scope state do
106
+ calculate(*args)
107
+ end
108
+ end
109
+
110
+ protected
111
+ def with_state_scope(state)
112
+ with_scope :find => {:conditions => ["#{table_name}.#{aasm_column} = ?", state.to_s]} do
113
+ yield if block_given?
114
+ end
115
+ end
77
116
  end
78
117
 
79
118
  module InstanceMethods
@@ -187,6 +226,13 @@ module AASM
187
226
  end
188
227
  end
189
228
  end
229
+
230
+ module NamedScopeMethods
231
+ def aasm_state_with_named_scope name, options = {}
232
+ aasm_state_without_named_scope name, options
233
+ self.named_scope name, :conditions => {self.aasm_column => name.to_s} unless self.scopes.include?(name)
234
+ end
235
+ end
190
236
  end
191
237
  end
192
238
  end
@@ -7,22 +7,26 @@ module AASM
7
7
  @name, @options = name, options
8
8
  end
9
9
 
10
- def entering(record)
11
- enteract = @options[:enter]
12
- record.send(:run_transition_action, enteract) if enteract
10
+ def ==(state)
11
+ if state.is_a? Symbol
12
+ name == state
13
+ else
14
+ name == state.name
15
+ end
13
16
  end
14
17
 
15
- def entered(record)
16
- afteractions = @options[:after]
17
- return unless afteractions
18
- Array(afteractions).each do |afteract|
19
- record.send(:run_transition_action, afteract)
18
+ def call_action(action, record)
19
+ action = @options[action]
20
+ case action
21
+ when Symbol, String
22
+ record.send(action)
23
+ when Proc
24
+ action.call(record)
20
25
  end
21
26
  end
22
27
 
23
- def exited(record)
24
- exitact = @options[:exit]
25
- record.send(:run_transition_action, exitact) if exitact
28
+ def for_select
29
+ [name.to_s.gsub(/_/, ' ').capitalize, name.to_s]
26
30
  end
27
31
  end
28
32
  end
@@ -0,0 +1,29 @@
1
+ require 'ostruct'
2
+
3
+ module AASM
4
+ class StateMachine
5
+ def self.[](*args)
6
+ (@machines ||= {})[args]
7
+ end
8
+
9
+ def self.[]=(*args)
10
+ val = args.pop
11
+ (@machines ||= {})[args] = val
12
+ end
13
+
14
+ attr_accessor :states, :events, :initial_state, :config
15
+ attr_reader :name
16
+
17
+ def initialize(name)
18
+ @name = name
19
+ @initial_state = nil
20
+ @states = []
21
+ @events = {}
22
+ @config = OpenStruct.new
23
+ end
24
+
25
+ def create_state(name, options)
26
+ @states << AASM::SupportingClasses::State.new(name, options) unless @states.include?(name)
27
+ end
28
+ end
29
+ end
@@ -4,7 +4,7 @@ module AASM
4
4
  attr_reader :from, :to, :opts
5
5
 
6
6
  def initialize(opts)
7
- @from, @to, @guard = opts[:from], opts[:to], opts[:guard]
7
+ @from, @to, @guard, @on_transition = opts[:from], opts[:to], opts[:guard], opts[:on_transition]
8
8
  @opts = opts
9
9
  end
10
10
 
@@ -19,6 +19,15 @@ module AASM
19
19
  end
20
20
  end
21
21
 
22
+ def execute(obj, *args)
23
+ case @on_transition
24
+ when Symbol, String
25
+ obj.send(@on_transition, *args)
26
+ when Proc
27
+ @on_transition.call(obj, *args)
28
+ end
29
+ end
30
+
22
31
  def ==(obj)
23
32
  @from == obj.from && @to == obj.to
24
33
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: aasm
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0
4
+ version: 2.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Scott Barron
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2008-05-14 03:00:00 -04:00
12
+ date: 2008-07-08 03:00:00 -04:00
13
13
  default_executable:
14
14
  dependencies: []
15
15
 
@@ -35,6 +35,7 @@ files:
35
35
  - lib/persistence/active_record_persistence.rb
36
36
  - lib/persistence.rb
37
37
  - lib/state.rb
38
+ - lib/state_machine.rb
38
39
  - lib/state_transition.rb
39
40
  - lib/version.rb
40
41
  - doc/jamis.rb