aasm 3.0.13 → 3.0.14

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,46 @@
1
+ module AASM
2
+ module Persistence
3
+ module Base
4
+
5
+ module ClassMethods
6
+ # Maps to the aasm_column in the database. Defaults to "aasm_state". You can write
7
+ # (example provided here for ActiveRecord, but it's true for Mongoid as well):
8
+ #
9
+ # create_table :foos do |t|
10
+ # t.string :name
11
+ # t.string :aasm_state
12
+ # end
13
+ #
14
+ # class Foo < ActiveRecord::Base
15
+ # include AASM
16
+ # end
17
+ #
18
+ # OR:
19
+ #
20
+ # create_table :foos do |t|
21
+ # t.string :name
22
+ # t.string :status
23
+ # end
24
+ #
25
+ # class Foo < ActiveRecord::Base
26
+ # include AASM
27
+ # aasm_column :status
28
+ # end
29
+ #
30
+ # This method is both a getter and a setter
31
+ def aasm_column(column_name=nil)
32
+ if column_name
33
+ AASM::StateMachine[self].config.column = column_name.to_sym
34
+ # @aasm_column = column_name.to_sym
35
+ else
36
+ AASM::StateMachine[self].config.column ||= :aasm_state
37
+ # @aasm_column ||= :aasm_state
38
+ end
39
+ # @aasm_column
40
+ AASM::StateMachine[self].config.column
41
+ end
42
+ end
43
+
44
+ end # Base
45
+ end # Persistence
46
+ end # AASM
@@ -34,15 +34,16 @@ module AASM
34
34
  # end
35
35
  #
36
36
  def self.included(base)
37
+ base.extend AASM::Persistence::Base::ClassMethods
37
38
  base.extend AASM::Persistence::MongoidPersistence::ClassMethods
38
39
  base.send(:include, AASM::Persistence::MongoidPersistence::InstanceMethods)
39
- base.send(:include, AASM::Persistence::MongoidPersistence::ReadState) unless base.method_defined?(:aasm_read_state)
40
+ base.send(:include, AASM::Persistence::ReadState) unless base.method_defined?(:aasm_read_state)
40
41
  base.send(:include, AASM::Persistence::MongoidPersistence::WriteState) unless base.method_defined?(:aasm_write_state)
41
42
  base.send(:include, AASM::Persistence::MongoidPersistence::WriteStateWithoutPersistence) unless base.method_defined?(:aasm_write_state_without_persistence)
42
43
 
43
44
  # if base.respond_to?(:named_scope)
44
45
  # base.extend(AASM::Persistence::MongoidPersistence::NamedScopeMethods)
45
- #
46
+ #
46
47
  # base.class_eval do
47
48
  # class << self
48
49
  # unless method_defined?(:aasm_state_without_named_scope)
@@ -59,60 +60,6 @@ module AASM
59
60
  end
60
61
 
61
62
  module ClassMethods
62
- # Maps to the aasm_column in the database. Deafults to "aasm_state". You can write:
63
- #
64
- # class Foo
65
- # include Mongoid::Document
66
- # include AASM
67
- # field :aasm_state
68
- # end
69
- #
70
- # OR:
71
- #
72
- # class Foo
73
- # include Mongoid::Document
74
- # include AASM
75
- # field :status
76
- # aasm_column :status
77
- # end
78
- #
79
- # This method is both a getter and a setter
80
- def aasm_column(column_name=nil)
81
- if column_name
82
- AASM::StateMachine[self].config.column = column_name.to_sym
83
- # @aasm_column = column_name.to_sym
84
- else
85
- AASM::StateMachine[self].config.column ||= :aasm_state
86
- # @aasm_column ||= :aasm_state
87
- end
88
- # @aasm_column
89
- AASM::StateMachine[self].config.column
90
- end
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
116
63
  end
117
64
 
118
65
  module InstanceMethods
@@ -200,42 +147,6 @@ module AASM
200
147
  end
201
148
  end
202
149
 
203
- module ReadState
204
-
205
- # Returns the value of the aasm_column - called from <tt>aasm_current_state</tt>
206
- #
207
- # If it's a new record, and the aasm state column is blank it returns the initial state:
208
- #
209
- # class Foo
210
- # include Mongoid::Document
211
- # include AASM
212
- # aasm_column :status
213
- # aasm_state :opened
214
- # aasm_state :closed
215
- # end
216
- #
217
- # foo = Foo.new
218
- # foo.current_state # => :opened
219
- # foo.close
220
- # foo.current_state # => :closed
221
- #
222
- # foo = Foo.find(1)
223
- # foo.current_state # => :opened
224
- # foo.aasm_state = nil
225
- # foo.current_state # => nil
226
- #
227
- # NOTE: intended to be called from an event
228
- #
229
- # This allows for nil aasm states - be sure to add validation to your model
230
- def aasm_read_state
231
- if new_record?
232
- send(self.class.aasm_column).blank? ? aasm_determine_state_name(self.class.aasm_initial_state) : send(self.class.aasm_column).to_sym
233
- else
234
- send(self.class.aasm_column).nil? ? nil : send(self.class.aasm_column).to_sym
235
- end
236
- end
237
- end
238
-
239
150
  module NamedScopeMethods
240
151
  def aasm_state_with_named_scope name, options = {}
241
152
  aasm_state_without_named_scope name, options
@@ -0,0 +1,40 @@
1
+ module AASM
2
+ module Persistence
3
+ module ReadState
4
+
5
+ # Returns the value of the aasm_column - called from <tt>aasm_current_state</tt>
6
+ #
7
+ # If it's a new record, and the aasm state column is blank it returns the initial state
8
+ # (example provided here for ActiveRecord, but it's true for Mongoid as well):
9
+ #
10
+ # class Foo < ActiveRecord::Base
11
+ # include AASM
12
+ # aasm_column :status
13
+ # aasm_state :opened
14
+ # aasm_state :closed
15
+ # end
16
+ #
17
+ # foo = Foo.new
18
+ # foo.current_state # => :opened
19
+ # foo.close
20
+ # foo.current_state # => :closed
21
+ #
22
+ # foo = Foo.find(1)
23
+ # foo.current_state # => :opened
24
+ # foo.aasm_state = nil
25
+ # foo.current_state # => nil
26
+ #
27
+ # NOTE: intended to be called from an event
28
+ #
29
+ # This allows for nil aasm states - be sure to add validation to your model
30
+ def aasm_read_state
31
+ if new_record?
32
+ send(self.class.aasm_column).blank? ? aasm_determine_state_name(self.class.aasm_initial_state) : send(self.class.aasm_column).to_sym
33
+ else
34
+ send(self.class.aasm_column).nil? ? nil : send(self.class.aasm_column).to_sym
35
+ end
36
+ end
37
+
38
+ end # ReadState
39
+ end # Persistence
40
+ end # AASM
@@ -15,19 +15,23 @@ module AASM
15
15
  def may_fire?(obj, to_state=nil, *args)
16
16
  _fire(obj, true, to_state, *args) # true indicates test firing
17
17
  end
18
-
18
+
19
19
  def fire(obj, to_state=nil, *args)
20
20
  _fire(obj, false, to_state, *args) # false indicates this is not a test (fire!)
21
21
  end
22
22
 
23
23
  def transitions_from_state?(state)
24
- @transitions.any? { |t| t.from == state }
24
+ transitions_from_state(state).any?
25
25
  end
26
26
 
27
27
  def transitions_from_state(state)
28
28
  @transitions.select { |t| t.from == state }
29
29
  end
30
30
 
31
+ def transitions_to_state?(state)
32
+ transitions_to_state(state).any?
33
+ end
34
+
31
35
  def transitions_to_state(state)
32
36
  @transitions.select { |t| t.to == state }
33
37
  end
@@ -6,23 +6,27 @@ module AASM
6
6
  list << :"#{i18n_scope(klass)}.events.#{i18n_klass(ancestor)}.#{event}"
7
7
  list
8
8
  end
9
- (0...(checklist.size-1)).each do |i|
10
- begin
11
- return I18n.translate(checklist.shift, :raise => true)
12
- rescue I18n::MissingTranslationData
13
- # that's okay
14
- end
15
- end
16
- I18n.translate(checklist.shift, :default => event.to_s.humanize)
9
+ translate_queue(checklist) || I18n.translate(checklist.shift, :default => event.to_s.humanize)
17
10
  end
18
11
 
19
12
  def human_state(obj)
20
13
  klass = obj.class
21
14
  checklist = ancestors_list(klass).inject([]) do |list, ancestor|
22
- list << :"#{i18n_scope(klass)}.attributes.#{i18n_klass(ancestor)}.#{klass.aasm_column}/#{obj.aasm_current_state}"
23
- list << :"#{i18n_scope(klass)}.attributes.#{i18n_klass(ancestor)}.#{klass.aasm_column}.#{obj.aasm_current_state}"
15
+ list << item_for(obj, klass, ancestor)
16
+ list << item_for(obj, klass, ancestor, :old_style => true)
24
17
  list
25
18
  end
19
+ translate_queue(checklist) || I18n.translate(checklist.shift, :default => obj.aasm_current_state.to_s.humanize)
20
+ end
21
+
22
+ private
23
+
24
+ def item_for(obj, klass, ancestor, options={})
25
+ separator = options[:old_style] ? '.' : '/'
26
+ :"#{i18n_scope(klass)}.attributes.#{i18n_klass(ancestor)}.#{klass.aasm_column}#{separator}#{obj.aasm_current_state}"
27
+ end
28
+
29
+ def translate_queue(checklist)
26
30
  (0...(checklist.size-1)).each do |i|
27
31
  begin
28
32
  return I18n.translate(checklist.shift, :raise => true)
@@ -30,11 +34,9 @@ module AASM
30
34
  # that's okay
31
35
  end
32
36
  end
33
- I18n.translate(checklist.shift, :default => obj.aasm_current_state.to_s.humanize)
37
+ nil
34
38
  end
35
39
 
36
- private
37
-
38
40
  # added for rails 2.x compatibility
39
41
  def i18n_scope(klass)
40
42
  klass.respond_to?(:i18n_scope) ? klass.i18n_scope : :activerecord
@@ -16,6 +16,14 @@ module AASM
16
16
  end
17
17
  end
18
18
 
19
+ def <=>(state)
20
+ if state.is_a? Symbol
21
+ name <=> state
22
+ else
23
+ name <=> state.name
24
+ end
25
+ end
26
+
19
27
  def fire_callbacks(action, record)
20
28
  action = @options[action]
21
29
  catch :halt_aasm_chain do
@@ -1,3 +1,3 @@
1
1
  module AASM
2
- VERSION = "3.0.13"
2
+ VERSION = "3.0.14"
3
3
  end
@@ -0,0 +1,84 @@
1
+ class AuthMachine
2
+ include AASM
3
+
4
+ attr_accessor :activation_code, :activated_at, :deleted_at
5
+
6
+ aasm do
7
+ state :passive
8
+ state :pending, :initial => true, :enter => :make_activation_code
9
+ state :active, :enter => :do_activate
10
+ state :suspended
11
+ state :deleted, :enter => :do_delete, :exit => :do_undelete
12
+ state :waiting
13
+
14
+ event :register do
15
+ transitions :from => :passive, :to => :pending, :guard => Proc.new {|u| u.can_register? }
16
+ end
17
+
18
+ event :activate do
19
+ transitions :from => :pending, :to => :active
20
+ end
21
+
22
+ event :suspend do
23
+ transitions :from => [:passive, :pending, :active], :to => :suspended
24
+ end
25
+
26
+ event :delete do
27
+ transitions :from => [:passive, :pending, :active, :suspended], :to => :deleted
28
+ end
29
+
30
+ # a dummy event that can never happen
31
+ event :unpassify do
32
+ transitions :from => :passive, :to => :active, :guard => Proc.new {|u| false }
33
+ end
34
+
35
+ event :unsuspend do
36
+ transitions :from => :suspended, :to => :active, :guard => Proc.new {|u| u.has_activated? }
37
+ transitions :from => :suspended, :to => :pending, :guard => Proc.new {|u| u.has_activation_code? }
38
+ transitions :from => :suspended, :to => :passive
39
+ end
40
+
41
+ event :wait do
42
+ transitions :from => :suspended, :to => :waiting, :guard => :if_polite?
43
+ end
44
+ end
45
+
46
+ def initialize
47
+ # the AR backend uses a before_validate_on_create :aasm_ensure_initial_state
48
+ # lets do something similar here for testing purposes.
49
+ aasm_enter_initial_state
50
+ end
51
+
52
+ def make_activation_code
53
+ @activation_code = 'moo'
54
+ end
55
+
56
+ def do_activate
57
+ @activated_at = Time.now
58
+ @activation_code = nil
59
+ end
60
+
61
+ def do_delete
62
+ @deleted_at = Time.now
63
+ end
64
+
65
+ def do_undelete
66
+ @deleted_at = false
67
+ end
68
+
69
+ def can_register?
70
+ true
71
+ end
72
+
73
+ def has_activated?
74
+ !!@activated_at
75
+ end
76
+
77
+ def has_activation_code?
78
+ !!@activation_code
79
+ end
80
+
81
+ def if_polite?(phrase = nil)
82
+ phrase == :please
83
+ end
84
+ end
@@ -0,0 +1,38 @@
1
+ class CallbackNewDsl
2
+ include AASM
3
+
4
+ aasm do
5
+ state :open, :initial => true,
6
+ :before_enter => :before_enter_open,
7
+ :after_enter => :after_enter_open,
8
+ :before_exit => :before_exit_open,
9
+ :after_exit => :after_exit_open
10
+
11
+ state :closed,
12
+ :before_enter => :before_enter_closed,
13
+ :after_enter => :after_enter_closed,
14
+ :before_exit => :before_exit_closed,
15
+ :after_exit => :after_exit_closed
16
+
17
+ event :close, :before => :before, :after => :after do
18
+ transitions :to => :closed, :from => [:open]
19
+ end
20
+
21
+ event :open, :before => :before, :after => :after do
22
+ transitions :to => :open, :from => :closed
23
+ end
24
+ end
25
+
26
+ def before_enter_open; end
27
+ def before_exit_open; end
28
+ def after_enter_open; end
29
+ def after_exit_open; end
30
+
31
+ def before_enter_closed; end
32
+ def before_exit_closed; end
33
+ def after_enter_closed; end
34
+ def after_exit_closed; end
35
+
36
+ def before; end
37
+ def after; end
38
+ end
@@ -0,0 +1,36 @@
1
+ class CallbackOldDsl
2
+ include AASM
3
+
4
+ aasm_initial_state :open
5
+ aasm_state :open,
6
+ :before_enter => :before_enter_open,
7
+ :before_exit => :before_exit_open,
8
+ :after_enter => :after_enter_open,
9
+ :after_exit => :after_exit_open
10
+ aasm_state :closed,
11
+ :before_enter => :before_enter_closed,
12
+ :before_exit => :before_exit_closed,
13
+ :after_enter => :after_enter_closed,
14
+ :after_exit => :after_exit_closed
15
+
16
+ aasm_event :close, :before => :before, :after => :after do
17
+ transitions :to => :closed, :from => [:open]
18
+ end
19
+
20
+ aasm_event :open, :before => :before, :after => :after do
21
+ transitions :to => :open, :from => :closed
22
+ end
23
+
24
+ def before_enter_open; end
25
+ def before_exit_open; end
26
+ def after_enter_open; end
27
+ def after_exit_open; end
28
+
29
+ def before_enter_closed; end
30
+ def before_exit_closed; end
31
+ def after_enter_closed; end
32
+ def after_exit_closed; end
33
+
34
+ def before; end
35
+ def after; end
36
+ end