aasm 5.1.0 → 5.3.0

Sign up to get free protection for your applications and to get access to all the features.
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