aasm 5.1.0 → 5.3.0

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.
Files changed (61) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/build.yml +100 -0
  3. data/Appraisals +18 -34
  4. data/CHANGELOG.md +28 -0
  5. data/Gemfile +3 -2
  6. data/README.md +93 -15
  7. data/aasm.gemspec +1 -1
  8. data/gemfiles/norails.gemfile +1 -0
  9. data/gemfiles/rails_4.2.gemfile +2 -2
  10. data/gemfiles/rails_4.2_mongoid_5.gemfile +2 -2
  11. data/gemfiles/rails_4.2_nobrainer.gemfile +2 -1
  12. data/gemfiles/rails_5.2.gemfile +2 -2
  13. data/gemfiles/rails_6.0.gemfile +14 -0
  14. data/gemfiles/rails_6.1.gemfile +14 -0
  15. data/gemfiles/rails_7.0.gemfile +14 -0
  16. data/lib/aasm/base.rb +44 -12
  17. data/lib/aasm/configuration.rb +3 -0
  18. data/lib/aasm/core/event.rb +12 -6
  19. data/lib/aasm/core/state.rb +6 -5
  20. data/lib/aasm/core/transition.rb +1 -1
  21. data/lib/aasm/dsl_helper.rb +24 -22
  22. data/lib/aasm/instance_base.rb +14 -4
  23. data/lib/aasm/localizer.rb +13 -3
  24. data/lib/aasm/persistence/active_record_persistence.rb +18 -13
  25. data/lib/aasm/persistence/base.rb +13 -2
  26. data/lib/aasm/persistence/orm.rb +1 -1
  27. data/lib/aasm/version.rb +1 -1
  28. data/lib/aasm.rb +0 -2
  29. data/lib/generators/active_record/templates/migration.rb +1 -1
  30. data/spec/database.rb +9 -11
  31. data/spec/en.yml +0 -3
  32. data/spec/{en_deprecated_style.yml → localizer_test_model_deprecated_style.yml} +6 -3
  33. data/spec/localizer_test_model_new_style.yml +11 -0
  34. data/spec/models/active_record/localizer_test_model.rb +11 -3
  35. data/spec/models/active_record/namespaced.rb +16 -0
  36. data/spec/models/active_record/timestamp_example.rb +16 -0
  37. data/spec/models/default_state.rb +1 -1
  38. data/spec/models/event_with_keyword_arguments.rb +16 -0
  39. data/spec/models/mongoid/timestamp_example_mongoid.rb +20 -0
  40. data/spec/models/timestamps_example.rb +19 -0
  41. data/spec/models/timestamps_with_named_machine_example.rb +13 -0
  42. data/spec/spec_helper.rb +5 -0
  43. data/spec/spec_helpers/dynamoid.rb +5 -1
  44. data/spec/unit/api_spec.rb +4 -0
  45. data/spec/unit/callbacks_spec.rb +34 -4
  46. data/spec/unit/complex_example_spec.rb +8 -0
  47. data/spec/unit/event_with_keyword_arguments_spec.rb +10 -0
  48. data/spec/unit/inspection_multiple_spec.rb +9 -5
  49. data/spec/unit/inspection_spec.rb +7 -3
  50. data/spec/unit/localizer_spec.rb +49 -18
  51. data/spec/unit/persistence/active_record_persistence_multiple_spec.rb +17 -0
  52. data/spec/unit/persistence/active_record_persistence_spec.rb +12 -0
  53. data/spec/unit/persistence/mongoid_persistence_spec.rb +12 -0
  54. data/spec/unit/state_spec.rb +21 -5
  55. data/spec/unit/timestamps_spec.rb +32 -0
  56. data/test/minitest_helper.rb +5 -1
  57. metadata +28 -16
  58. data/.travis.yml +0 -93
  59. data/gemfiles/rails_5.0.gemfile +0 -14
  60. data/gemfiles/rails_5.0_nobrainer.gemfile +0 -9
  61. data/gemfiles/rails_5.1.gemfile +0 -14
data/lib/aasm/base.rb CHANGED
@@ -37,6 +37,9 @@ module AASM
37
37
  # string for a specific lock type i.e. FOR UPDATE NOWAIT
38
38
  configure :requires_lock, false
39
39
 
40
+ # automatically set `"#{state_name}_at" = ::Time.now` on state changes
41
+ configure :timestamps, false
42
+
40
43
  # set to true to forbid direct assignment of aasm_state column (in ActiveRecord)
41
44
  configure :no_direct_assignment, false
42
45
 
@@ -51,19 +54,12 @@ module AASM
51
54
  # Configure a logger, with default being a Logger to STDERR
52
55
  configure :logger, Logger.new(STDERR)
53
56
 
57
+ # setup timestamp-setting callback if enabled
58
+ setup_timestamps(@name)
59
+
54
60
  # make sure to raise an error if no_direct_assignment is enabled
55
61
  # and attribute is directly assigned though
56
- aasm_name = @name
57
-
58
- if @state_machine.config.no_direct_assignment
59
- @klass.send(:define_method, "#{@state_machine.config.column}=") do |state_name|
60
- if self.class.aasm(:"#{aasm_name}").state_machine.config.no_direct_assignment
61
- raise AASM::NoDirectAssignmentError.new('direct assignment of AASM column has been disabled (see AASM configuration for this class)')
62
- else
63
- super(state_name)
64
- end
65
- end
66
- end
62
+ setup_no_direct_assignment(@name)
67
63
  end
68
64
 
69
65
  # This method is both a getter and a setter
@@ -227,7 +223,20 @@ module AASM
227
223
  end
228
224
  end
229
225
 
230
- klass.send(:define_method, method_name, method_definition)
226
+ klass.send(:define_method, method_name, method_definition).tap do |sym|
227
+ apply_ruby2_keyword(klass, sym)
228
+ end
229
+ end
230
+
231
+ def apply_ruby2_keyword(klass, sym)
232
+ if RUBY_VERSION >= '2.7.1'
233
+ if klass.instance_method(sym).parameters.find { |type, _| type.to_s.start_with?('rest') }
234
+ # If there is a place where you are receiving in *args, do ruby2_keywords.
235
+ klass.module_eval do
236
+ ruby2_keywords sym
237
+ end
238
+ end
239
+ end
231
240
  end
232
241
 
233
242
  def namespace?
@@ -267,5 +276,28 @@ module AASM
267
276
  end
268
277
  end
269
278
 
279
+ def setup_timestamps(aasm_name)
280
+ return unless @state_machine.config.timestamps
281
+
282
+ after_all_transitions do
283
+ if self.class.aasm(:"#{aasm_name}").state_machine.config.timestamps
284
+ ts_setter = "#{aasm(aasm_name).to_state}_at="
285
+ respond_to?(ts_setter) && send(ts_setter, ::Time.now)
286
+ end
287
+ end
288
+ end
289
+
290
+ def setup_no_direct_assignment(aasm_name)
291
+ return unless @state_machine.config.no_direct_assignment
292
+
293
+ @klass.send(:define_method, "#{@state_machine.config.column}=") do |state_name|
294
+ if self.class.aasm(:"#{aasm_name}").state_machine.config.no_direct_assignment
295
+ raise AASM::NoDirectAssignmentError.new('direct assignment of AASM column has been disabled (see AASM configuration for this class)')
296
+ else
297
+ super(state_name)
298
+ end
299
+ end
300
+ end
301
+
270
302
  end
271
303
  end
@@ -24,6 +24,9 @@ module AASM
24
24
  # for ActiveRecord: use pessimistic locking
25
25
  attr_accessor :requires_lock
26
26
 
27
+ # automatically set `"#{state_name}_at" = ::Time.now` on state changes
28
+ attr_accessor :timestamps
29
+
27
30
  # forbid direct assignment in aasm_state column (in ActiveRecord)
28
31
  attr_accessor :no_direct_assignment
29
32
 
@@ -2,17 +2,18 @@
2
2
 
3
3
  module AASM::Core
4
4
  class Event
5
- include DslHelper
5
+ include AASM::DslHelper
6
6
 
7
- attr_reader :name, :state_machine, :options
7
+ attr_reader :name, :state_machine, :options, :default_display_name
8
8
 
9
9
  def initialize(name, state_machine, options = {}, &block)
10
10
  @name = name
11
11
  @state_machine = state_machine
12
12
  @transitions = []
13
- @valid_transitions = {}
13
+ @valid_transitions = Hash.new { |h, k| h[k] = {} }
14
14
  @guards = Array(options[:guard] || options[:guards] || options[:if])
15
15
  @unless = Array(options[:unless]) #TODO: This could use a better name
16
+ @default_display_name = name.to_s.gsub(/_/, ' ').capitalize
16
17
 
17
18
  # from aasm4
18
19
  @options = options # QUESTION: .dup ?
@@ -78,8 +79,9 @@ module AASM::Core
78
79
 
79
80
  def fire_transition_callbacks(obj, *args)
80
81
  from_state = obj.aasm(state_machine.name).current_state
81
- transition = @valid_transitions[from_state]
82
- @valid_transitions[from_state].invoke_success_callbacks(obj, *args) if transition
82
+ transition = @valid_transitions[obj.object_id][from_state]
83
+ transition.invoke_success_callbacks(obj, *args) if transition
84
+ @valid_transitions.delete(obj.object_id)
83
85
  end
84
86
 
85
87
  def ==(event)
@@ -109,6 +111,10 @@ module AASM::Core
109
111
  transitions.flat_map(&:failures)
110
112
  end
111
113
 
114
+ def to_s
115
+ name.to_s
116
+ end
117
+
112
118
  private
113
119
 
114
120
  def attach_event_guards(definitions)
@@ -148,7 +154,7 @@ module AASM::Core
148
154
  result = transition
149
155
  else
150
156
  result = to_state || Array(transition.to).first
151
- Array(transition.to).each {|to| @valid_transitions[to] = transition }
157
+ Array(transition.to).each {|to| @valid_transitions[obj.object_id][to] = transition }
152
158
  transition.execute(obj, *args)
153
159
  end
154
160
 
@@ -2,12 +2,13 @@
2
2
 
3
3
  module AASM::Core
4
4
  class State
5
- attr_reader :name, :state_machine, :options
5
+ attr_reader :name, :state_machine, :options, :default_display_name
6
6
 
7
7
  def initialize(name, klass, state_machine, options={})
8
8
  @name = name
9
9
  @klass = klass
10
10
  @state_machine = state_machine
11
+ @default_display_name = name.to_s.gsub(/_/, ' ').capitalize
11
12
  update(options)
12
13
  end
13
14
 
@@ -54,11 +55,11 @@ module AASM::Core
54
55
  end
55
56
 
56
57
  def display_name
57
- @display_name ||= begin
58
+ @display_name = begin
58
59
  if Module.const_defined?(:I18n)
59
60
  localized_name
60
61
  else
61
- name.to_s.gsub(/_/, ' ').capitalize
62
+ @default_display_name
62
63
  end
63
64
  end
64
65
  end
@@ -75,8 +76,8 @@ module AASM::Core
75
76
  private
76
77
 
77
78
  def update(options = {})
78
- if options.key?(:display) then
79
- @display_name = options.delete(:display)
79
+ if options.key?(:display)
80
+ @default_display_name = options.delete(:display)
80
81
  end
81
82
  @options = options
82
83
  self
@@ -2,7 +2,7 @@
2
2
 
3
3
  module AASM::Core
4
4
  class Transition
5
- include DslHelper
5
+ include AASM::DslHelper
6
6
 
7
7
  attr_reader :from, :to, :event, :opts, :failures
8
8
  alias_method :options, :opts
@@ -1,30 +1,32 @@
1
- module DslHelper
1
+ module AASM
2
+ module DslHelper
2
3
 
3
- class Proxy
4
- attr_accessor :options
4
+ class Proxy
5
+ attr_accessor :options
5
6
 
6
- def initialize(options, valid_keys, source)
7
- @valid_keys = valid_keys
8
- @source = source
7
+ def initialize(options, valid_keys, source)
8
+ @valid_keys = valid_keys
9
+ @source = source
9
10
 
10
- @options = options
11
- end
11
+ @options = options
12
+ end
12
13
 
13
- def method_missing(name, *args, &block)
14
- if @valid_keys.include?(name)
15
- options[name] = Array(options[name])
16
- options[name] << block if block
17
- options[name] += Array(args)
18
- else
19
- @source.send name, *args, &block
14
+ def method_missing(name, *args, &block)
15
+ if @valid_keys.include?(name)
16
+ options[name] = Array(options[name])
17
+ options[name] << block if block
18
+ options[name] += Array(args)
19
+ else
20
+ @source.send name, *args, &block
21
+ end
20
22
  end
21
23
  end
22
- end
23
24
 
24
- def add_options_from_dsl(options, valid_keys, &block)
25
- proxy = Proxy.new(options, valid_keys, self)
26
- proxy.instance_eval(&block)
27
- proxy.options
28
- end
25
+ def add_options_from_dsl(options, valid_keys, &block)
26
+ proxy = Proxy.new(options, valid_keys, self)
27
+ proxy.instance_eval(&block)
28
+ proxy.options
29
+ end
29
30
 
30
- end
31
+ end
32
+ end
@@ -1,6 +1,5 @@
1
1
  module AASM
2
2
  class InstanceBase
3
-
4
3
  attr_accessor :from_state, :to_state, :current_event
5
4
 
6
5
  def initialize(instance, name=:default) # instance of the class including AASM, name of the state machine
@@ -28,7 +27,7 @@ module AASM
28
27
  end
29
28
 
30
29
  def human_state
31
- AASM::Localizer.new.human_state_name(@instance.class, state_object_for_name(current_state))
30
+ state_object_for_name(current_state).display_name
32
31
  end
33
32
 
34
33
  def states(options={}, *args)
@@ -115,12 +114,15 @@ module AASM
115
114
  end
116
115
 
117
116
  def fire(event_name, *args, &block)
117
+ event_exists?(event_name)
118
+
118
119
  @instance.send(event_name, *args, &block)
119
120
  end
120
121
 
121
122
  def fire!(event_name, *args, &block)
122
- event_name = event_name.to_s.+("!").to_sym
123
- @instance.send(event_name, *args, &block)
123
+ event_exists?(event_name, true)
124
+ bang_event_name = "#{event_name}!".to_sym
125
+ @instance.send(bang_event_name, *args, &block)
124
126
  end
125
127
 
126
128
  def set_current_state_with_persistence(state)
@@ -129,5 +131,13 @@ module AASM
129
131
  save_success
130
132
  end
131
133
 
134
+ private
135
+
136
+ def event_exists?(event_name, bang = false)
137
+ event = @instance.class.aasm(@name).state_machine.events[event_name]
138
+ event_error = bang ? "#{event_name}!" : event_name
139
+
140
+ raise AASM::UndefinedState, "State :#{event_error} doesn't exist" if event.nil?
141
+ end
132
142
  end
133
143
  end
@@ -5,7 +5,7 @@ module AASM
5
5
  list << :"#{i18n_scope(klass)}.events.#{i18n_klass(ancestor)}.#{event}"
6
6
  list
7
7
  end
8
- translate_queue(checklist) || I18n.translate(checklist.shift, :default => event.to_s.humanize)
8
+ translate_queue(checklist) || I18n.translate(checklist.shift, :default => default_display_name(event))
9
9
  end
10
10
 
11
11
  def human_state_name(klass, state)
@@ -14,7 +14,7 @@ module AASM
14
14
  list << item_for(klass, state, ancestor, :old_style => true)
15
15
  list
16
16
  end
17
- translate_queue(checklist) || I18n.translate(checklist.shift, :default => state.to_s.humanize)
17
+ translate_queue(checklist) || I18n.translate(checklist.shift, :default => default_display_name(state))
18
18
  end
19
19
 
20
20
  private
@@ -46,8 +46,18 @@ module AASM
46
46
  end
47
47
 
48
48
  def ancestors_list(klass)
49
+ has_active_record_base = defined?(::ActiveRecord::Base)
49
50
  klass.ancestors.select do |ancestor|
50
- ancestor.respond_to?(:model_name) unless ancestor.name == 'ActiveRecord::Base'
51
+ not_active_record_base = has_active_record_base ? (ancestor != ::ActiveRecord::Base) : true
52
+ ancestor.respond_to?(:model_name) && not_active_record_base
53
+ end
54
+ end
55
+
56
+ def default_display_name(object) # Can use better arguement name
57
+ if object.respond_to?(:default_display_name)
58
+ object.default_display_name
59
+ else
60
+ object.to_s.gsub(/_/, ' ').capitalize
51
61
  end
52
62
  end
53
63
  end
@@ -28,19 +28,6 @@ module AASM
28
28
  # end
29
29
  #
30
30
  def self.included(base)
31
- begin
32
- require 'after_commit_everywhere'
33
- raise LoadError unless Gem::Version.new(::AfterCommitEverywhere::VERSION) >= Gem::Version.new('0.1.5')
34
-
35
- base.send(:include, ::AfterCommitEverywhere) unless base.include?(::AfterCommitEverywhere)
36
- base.send(:alias_method, :aasm_execute_after_commit, :after_commit)
37
- rescue LoadError
38
- warn <<-MSG
39
- [DEPRECATION] :after_commit AASM callback is not safe in terms of race conditions and redundant calls.
40
- Please add `gem 'after_commit_everywhere', '~> 0.1', '>= 0.1.5'` to your Gemfile in order to fix that.
41
- MSG
42
- end
43
-
44
31
  base.send(:include, AASM::Persistence::Base)
45
32
  base.send(:include, AASM::Persistence::ORM)
46
33
  base.send(:include, AASM::Persistence::ActiveRecordPersistence::InstanceMethods)
@@ -74,6 +61,24 @@ module AASM
74
61
 
75
62
  private
76
63
 
64
+ def aasm_execute_after_commit
65
+ begin
66
+ require 'after_commit_everywhere'
67
+ raise LoadError unless Gem::Version.new(::AfterCommitEverywhere::VERSION) >= Gem::Version.new('0.1.5')
68
+
69
+ self.extend ::AfterCommitEverywhere
70
+ after_commit do
71
+ yield
72
+ end
73
+ rescue LoadError
74
+ warn <<-MSG
75
+ [DEPRECATION] :after_commit AASM callback is not safe in terms of race conditions and redundant calls.
76
+ Please add `gem 'after_commit_everywhere', '~> 1.0'` to your Gemfile in order to fix that.
77
+ MSG
78
+ yield
79
+ end
80
+ end
81
+
77
82
  def aasm_raise_invalid_record
78
83
  raise ActiveRecord::RecordInvalid.new(self)
79
84
  end
@@ -59,7 +59,9 @@ module AASM
59
59
  # make sure to create a (named) scope for each state
60
60
  def state_with_scope(*args)
61
61
  names = state_without_scope(*args)
62
- names.each { |name| create_scope(name) if create_scope?(name) }
62
+ names.each do |name|
63
+ create_scopes(name)
64
+ end
63
65
  end
64
66
  alias_method :state_without_scope, :state
65
67
  alias_method :state, :state_with_scope
@@ -71,7 +73,16 @@ module AASM
71
73
  end
72
74
 
73
75
  def create_scope(name)
74
- @klass.aasm_create_scope(@name, name)
76
+ @klass.aasm_create_scope(@name, name) if create_scope?(name)
77
+ end
78
+
79
+ def create_scopes(name)
80
+ if namespace?
81
+ # Create default scopes even when namespace? for backward compatibility
82
+ namepaced_name = "#{namespace}_#{name}"
83
+ create_scope(namepaced_name)
84
+ end
85
+ create_scope(name)
75
86
  end
76
87
  end # Base
77
88
 
@@ -135,7 +135,7 @@ module AASM
135
135
  super
136
136
  end
137
137
 
138
- if success
138
+ if success && !(event.options.keys & [:after_commit, :after_all_commits]).empty?
139
139
  aasm_execute_after_commit do
140
140
  event.fire_callbacks(:after_commit, self, *args)
141
141
  event.fire_global_callbacks(:after_all_commits, self, *args)
data/lib/aasm/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module AASM
2
- VERSION = "5.1.0"
2
+ VERSION = "5.3.0"
3
3
  end
data/lib/aasm.rb CHANGED
@@ -1,5 +1,3 @@
1
- require 'ostruct'
2
-
3
1
  require 'aasm/version'
4
2
  require 'aasm/errors'
5
3
  require 'aasm/configuration'
@@ -1,4 +1,4 @@
1
- class AASMCreate<%= table_name.camelize %> < ActiveRecord::Migration[<%= ActiveRecord::VERSION::STRING.to_f %>]
1
+ class AasmCreate<%= table_name.camelize %> < ActiveRecord::Migration[<%= ActiveRecord::VERSION::STRING.to_f %>]
2
2
  def change
3
3
  create_table(:<%= table_name %>) do |t|
4
4
  t.string :<%= column_name %>
data/spec/database.rb CHANGED
@@ -5,17 +5,10 @@ ActiveRecord::Migration.suppress_messages do
5
5
  end
6
6
  end
7
7
 
8
- ActiveRecord::Migration.create_table "simple_new_dsls", :force => true do |t|
9
- t.string "status"
10
- end
11
- ActiveRecord::Migration.create_table "multiple_simple_new_dsls", :force => true do |t|
12
- t.string "status"
13
- end
14
- ActiveRecord::Migration.create_table "implemented_abstract_class_dsls", :force => true do |t|
15
- t.string "status"
16
- end
17
- ActiveRecord::Migration.create_table "users", :force => true do |t|
18
- t.string "status"
8
+ %w(simple_new_dsls multiple_simple_new_dsls implemented_abstract_class_dsls users multiple_namespaceds).each do |table_name|
9
+ ActiveRecord::Migration.create_table table_name, :force => true do |t|
10
+ t.string "status"
11
+ end
19
12
  end
20
13
 
21
14
  ActiveRecord::Migration.create_table "complex_active_record_examples", :force => true do |t|
@@ -56,4 +49,9 @@ ActiveRecord::Migration.suppress_messages do
56
49
  t.string "state"
57
50
  t.string "some_string"
58
51
  end
52
+
53
+ ActiveRecord::Migration.create_table "timestamp_examples", :force => true do |t|
54
+ t.string "aasm_state"
55
+ t.datetime "opened_at"
56
+ end
59
57
  end
data/spec/en.yml CHANGED
@@ -4,9 +4,6 @@ en:
4
4
  localizer_test_model:
5
5
  close: "Let's close it!"
6
6
 
7
- attributes:
8
- localizer_test_model:
9
- aasm_state/opened: "It's open now!"
10
7
  errors:
11
8
  messages:
12
9
  record_invalid: "Invalid record"
@@ -1,10 +1,13 @@
1
1
  en:
2
2
  activerecord:
3
- events:
3
+ attributes:
4
4
  localizer_test_model:
5
- close: "Let's close it!"
5
+ aasm_state:
6
+ opened: "It's open now!"
6
7
 
8
+ fr:
9
+ activerecord:
7
10
  attributes:
8
11
  localizer_test_model:
9
12
  aasm_state:
10
- opened: "It's open now!"
13
+ opened: "C'est ouvert maintenant!"
@@ -0,0 +1,11 @@
1
+ en:
2
+ activerecord:
3
+ attributes:
4
+ localizer_test_model:
5
+ aasm_state/opened: "It's open now!"
6
+
7
+ fr:
8
+ activerecord:
9
+ attributes:
10
+ localizer_test_model:
11
+ aasm_state/opened: "C'est ouvert maintenant!"
@@ -11,24 +11,32 @@ end
11
11
 
12
12
  describe 'localized state names' do
13
13
  before(:all) do
14
- I18n.load_path << 'spec/en.yml'
15
- I18n.default_locale = :en
14
+ I18n.load_path << 'spec/localizer_test_model_new_style.yml'
16
15
  I18n.reload!
17
16
  end
18
17
 
19
18
  after(:all) do
20
- I18n.load_path.clear
19
+ I18n.load_path.delete('spec/localizer_test_model_new_style.yml')
20
+ I18n.backend.load_translations
21
21
  end
22
22
 
23
23
  it 'should localize' do
24
24
  state = LocalizerTestModel.aasm.states.detect {|s| s == :opened}
25
25
  expect(state.localized_name).to eq("It's open now!")
26
26
  expect(state.human_name).to eq("It's open now!")
27
+ expect(state.display_name).to eq("It's open now!")
28
+
29
+ I18n.with_locale(:fr) do
30
+ expect(state.localized_name).to eq("C'est ouvert maintenant!")
31
+ expect(state.human_name).to eq("C'est ouvert maintenant!")
32
+ expect(state.display_name).to eq("C'est ouvert maintenant!")
33
+ end
27
34
  end
28
35
 
29
36
  it 'should use fallback' do
30
37
  state = LocalizerTestModel.aasm.states.detect {|s| s == :closed}
31
38
  expect(state.localized_name).to eq('Closed')
32
39
  expect(state.human_name).to eq('Closed')
40
+ expect(state.display_name).to eq('Closed')
33
41
  end
34
42
  end
@@ -0,0 +1,16 @@
1
+ class MultipleNamespaced < ActiveRecord::Base
2
+ include AASM
3
+
4
+ aasm(:status, namespace: :car) do
5
+ state :unsold, initial: true
6
+ state :sold
7
+
8
+ event :sell do
9
+ transitions from: :unsold, to: :sold
10
+ end
11
+
12
+ event :return do
13
+ transitions from: :sold, to: :unsold
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,16 @@
1
+ class TimestampExample < ActiveRecord::Base
2
+ include AASM
3
+
4
+ aasm column: :aasm_state, timestamps: true do
5
+ state :opened
6
+ state :closed
7
+
8
+ event :open do
9
+ transitions to: :opened
10
+ end
11
+
12
+ event :close do
13
+ transitions to: :closed
14
+ end
15
+ end
16
+ end
@@ -2,7 +2,7 @@ class DefaultState
2
2
  attr_accessor :transient_store, :persisted_store
3
3
  include AASM
4
4
  aasm do
5
- state :alpha, :initial => true
5
+ state :alpha, :initial => true, display: 'ALPHA'
6
6
  state :beta
7
7
  state :gamma
8
8
  event :release do
@@ -0,0 +1,16 @@
1
+ class EventWithKeywordArguments
2
+ include AASM
3
+
4
+ aasm do
5
+ state :open, :initial => true, :column => :status
6
+ state :closed
7
+
8
+ event :close do
9
+ before :_before_close
10
+ transitions from: :open, to: :closed
11
+ end
12
+ end
13
+
14
+ def _before_close(key:)
15
+ end
16
+ end
@@ -0,0 +1,20 @@
1
+ class TimestampExampleMongoid
2
+ include Mongoid::Document
3
+ include AASM
4
+
5
+ field :status, type: String
6
+ field :opened_at, type: Time
7
+
8
+ aasm column: :status, timestamps: true do
9
+ state :opened
10
+ state :closed
11
+
12
+ event :open do
13
+ transitions to: :opened
14
+ end
15
+
16
+ event :close do
17
+ transitions to: :closed
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,19 @@
1
+ class TimestampsExample
2
+ include AASM
3
+
4
+ attr_accessor :opened_at
5
+ attr_reader :closed_at
6
+
7
+ aasm timestamps: true do
8
+ state :opened
9
+ state :closed
10
+
11
+ event :open do
12
+ transitions to: :opened
13
+ end
14
+
15
+ event :close do
16
+ transitions to: :closed
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,13 @@
1
+ class TimestampsWithNamedMachineExample
2
+ include AASM
3
+
4
+ attr_accessor :opened_at
5
+
6
+ aasm :my_state, timestamps: true do
7
+ state :opened
8
+
9
+ event :open do
10
+ transitions to: :opened
11
+ end
12
+ end
13
+ end