aasm 4.2.0 → 4.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (97) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +4 -1
  3. data/Gemfile +2 -2
  4. data/PLANNED_CHANGES.md +24 -4
  5. data/README.md +75 -5
  6. data/lib/aasm/aasm.rb +50 -36
  7. data/lib/aasm/base.rb +36 -18
  8. data/lib/aasm/core/event.rb +6 -5
  9. data/lib/aasm/core/state.rb +3 -2
  10. data/lib/aasm/core/transition.rb +5 -4
  11. data/lib/aasm/errors.rb +7 -4
  12. data/lib/aasm/instance_base.rb +14 -13
  13. data/lib/aasm/localizer.rb +1 -1
  14. data/lib/aasm/persistence/active_record_persistence.rb +41 -66
  15. data/lib/aasm/persistence/base.rb +7 -7
  16. data/lib/aasm/persistence/mongo_mapper_persistence.rb +34 -51
  17. data/lib/aasm/persistence/mongoid_persistence.rb +15 -36
  18. data/lib/aasm/persistence/plain_persistence.rb +8 -7
  19. data/lib/aasm/persistence/sequel_persistence.rb +12 -10
  20. data/lib/aasm/state_machine.rb +11 -6
  21. data/lib/aasm/version.rb +1 -1
  22. data/spec/database.rb +27 -1
  23. data/spec/models/active_record/basic_active_record_two_state_machines_example.rb +25 -0
  24. data/spec/models/active_record/complex_active_record_example.rb +33 -0
  25. data/spec/models/active_record/derivate_new_dsl.rb +4 -0
  26. data/spec/models/active_record/false_state.rb +18 -0
  27. data/spec/models/active_record/gate.rb +20 -0
  28. data/spec/models/active_record/no_direct_assignment.rb +11 -0
  29. data/spec/models/active_record/no_scope.rb +11 -0
  30. data/spec/models/active_record/provided_and_persisted_state.rb +3 -3
  31. data/spec/models/active_record/simple_new_dsl.rb +9 -0
  32. data/spec/models/active_record/thief.rb +15 -0
  33. data/spec/models/active_record/with_enum.rb +20 -0
  34. data/spec/models/active_record/with_false_enum.rb +16 -0
  35. data/spec/models/active_record/with_true_enum.rb +20 -0
  36. data/spec/models/basic_two_state_machines_example.rb +25 -0
  37. data/spec/models/callbacks/basic_multiple.rb +75 -0
  38. data/spec/models/callbacks/guard_within_block_multiple.rb +66 -0
  39. data/spec/models/callbacks/multiple_transitions_transition_guard_multiple.rb +65 -0
  40. data/spec/models/callbacks/private_method_multiple.rb +44 -0
  41. data/spec/models/callbacks/with_args_multiple.rb +61 -0
  42. data/spec/models/callbacks/{with_state_args.rb → with_state_arg.rb} +0 -0
  43. data/spec/models/callbacks/with_state_arg_multiple.rb +26 -0
  44. data/spec/models/complex_example.rb +134 -0
  45. data/spec/models/conversation.rb +47 -1
  46. data/spec/models/foo.rb +57 -0
  47. data/spec/models/foo_callback_multiple.rb +45 -0
  48. data/spec/models/guardian_multiple.rb +48 -0
  49. data/spec/models/initial_state_proc.rb +16 -0
  50. data/spec/models/invalid_persistor.rb +15 -0
  51. data/spec/models/mongo_mapper/complex_mongo_mapper_example.rb +37 -0
  52. data/spec/models/mongo_mapper/no_scope_mongo_mapper.rb +11 -0
  53. data/spec/models/mongo_mapper/simple_mongo_mapper.rb +12 -0
  54. data/spec/models/mongo_mapper/simple_new_dsl_mongo_mapper.rb +13 -0
  55. data/spec/models/mongoid/complex_mongoid_example.rb +37 -0
  56. data/spec/models/mongoid/no_scope_mongoid.rb +11 -0
  57. data/spec/models/mongoid/simple_mongoid.rb +12 -0
  58. data/spec/models/mongoid/simple_new_dsl_mongoid.rb +13 -0
  59. data/spec/models/no_initial_state.rb +13 -0
  60. data/spec/models/parametrised_event.rb +1 -1
  61. data/spec/models/parametrised_event_multiple.rb +29 -0
  62. data/spec/models/provided_state.rb +3 -3
  63. data/spec/models/sequel/complex_sequel_example.rb +45 -0
  64. data/spec/models/sequel/sequel_multiple.rb +25 -0
  65. data/spec/models/sequel/sequel_simple.rb +25 -0
  66. data/spec/models/simple_multiple_example.rb +30 -0
  67. data/spec/models/sub_class.rb +4 -0
  68. data/spec/models/sub_class_with_more_states.rb +11 -0
  69. data/spec/models/super_class.rb +28 -0
  70. data/spec/models/transactor.rb +27 -0
  71. data/spec/models/valid_state_name.rb +12 -0
  72. data/spec/models/validator.rb +39 -0
  73. data/spec/unit/basic_two_state_machines_example_spec.rb +10 -0
  74. data/spec/unit/callback_multiple_spec.rb +295 -0
  75. data/spec/unit/callbacks_spec.rb +1 -1
  76. data/spec/unit/complex_multiple_example_spec.rb +99 -0
  77. data/spec/unit/edge_cases_spec.rb +16 -0
  78. data/spec/unit/event_multiple_spec.rb +73 -0
  79. data/spec/unit/event_spec.rb +11 -6
  80. data/spec/unit/guard_multiple_spec.rb +60 -0
  81. data/spec/unit/initial_state_multiple_spec.rb +15 -0
  82. data/spec/unit/inspection_multiple_spec.rb +201 -0
  83. data/spec/unit/persistence/active_record_persistence_multiple_spec.rb +560 -0
  84. data/spec/unit/persistence/active_record_persistence_spec.rb +17 -12
  85. data/spec/unit/persistence/mongo_mapper_persistence_multiple_spec.rb +146 -0
  86. data/spec/unit/persistence/{mongo_mapper_persistance_spec.rb → mongo_mapper_persistence_spec.rb} +7 -49
  87. data/spec/unit/persistence/mongoid_persistence_multiple_spec.rb +127 -0
  88. data/spec/unit/persistence/mongoid_persistence_spec.rb +79 -0
  89. data/spec/unit/persistence/sequel_persistence_multiple_spec.rb +153 -0
  90. data/spec/unit/persistence/sequel_persistence_spec.rb +7 -24
  91. data/spec/unit/reloading_spec.rb +1 -1
  92. data/spec/unit/simple_multiple_example_spec.rb +63 -0
  93. data/spec/unit/state_spec.rb +3 -1
  94. data/spec/unit/subclassing_multiple_spec.rb +39 -0
  95. data/spec/unit/transition_spec.rb +31 -22
  96. metadata +73 -9
  97. data/spec/unit/persistence/mongoid_persistance_spec.rb +0 -146
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: cd80c470206244734a77fe540848e299e87dab9f
4
- data.tar.gz: 28b464e9012345a46ddc5595d29541d52a358bf4
3
+ metadata.gz: 1b51607dcaee12f000a23ee83033925bf03dcee7
4
+ data.tar.gz: c367dd718de8264432f332ff626fc8aff05581e3
5
5
  SHA512:
6
- metadata.gz: 46d54cc3e2e66387916f7f1edfe03f3de9cb09578a8b485ea084bd68ba854f9003d1fd00de18a6d7c40984a0b0d2fe1b2d7bc4b3610e7d421c724e2f5af7a9f1
7
- data.tar.gz: cb2506c237a22fc3dc04869791d15f85614ac33096ccff60fa5a6dd40830d2325375ed13cdc3abf2adc02c958a336362027393c6ee0351bc463cf47cb0b9020f
6
+ metadata.gz: 4a3750ab5b7758679ed9ca66fc35f04cf69347a09bc03070fd514ccbd3c111f129f907e6c4e387cf253441daf7e8e79a1045ea64da43296803434711c56a2b84
7
+ data.tar.gz: d82ff5d11b0ebae4112277283706e3bd9774517e6f4a7bece806360deda054c811ccebccfefd59c05244dd05e5351f21672932ba8071a8c2626077ba76bc585d
@@ -1,6 +1,9 @@
1
1
  # CHANGELOG
2
2
 
3
- ## 4.3.0 (not yet released)
3
+ ## 4.3.0
4
+
5
+ * add support for multiple state machines per class (see [issue #158](https://github.com/aasm/aasm/issues/158) and [issue #240](https://github.com/aasm/aasm/issues/240) for details)
6
+ * special thanks to [@evadne](https://github.com/evadne) for testing this feature, and providing comments and patches (see [issue #245](https://github.com/aasm/aasm/issues/245) for details)
4
7
 
5
8
  ## 4.2.0
6
9
 
data/Gemfile CHANGED
@@ -9,7 +9,7 @@ gem 'mongoid', '~>4.0' if Gem::Version.create(RUBY_VERSION.dup) >= Gem::Version.
9
9
  gem 'sequel'
10
10
  # Since mongoid V4 requires incompatible bson V2, cannot have mongoid (V4 or greater)
11
11
  # and mongo_mapper ( or mongo ) in the same application
12
- #gem 'mongo_mapper', '~> 0.13'
13
- #gem 'bson_ext', :platforms => :ruby
12
+ # gem 'mongo_mapper', '~> 0.13'
13
+ # gem 'bson_ext', :platforms => :ruby
14
14
 
15
15
  gemspec
@@ -1,7 +1,27 @@
1
- # Planned changes for AASM 4.1
1
+ # Planned changes
2
2
 
3
- * remove support for `:on_transition` callback
3
+ ## later
4
4
 
5
- # Planned changes for AASM 4.0
5
+ * drop support for aasm_column ?
6
6
 
7
- * nothing left
7
+ # Currently working on
8
+
9
+
10
+ # Changes so far
11
+
12
+ ## version 4.3
13
+
14
+ * add support for multiple state machines per class
15
+ * class- and instance-level `aasm` methods accept a state machine selector
16
+ (aka the state machine _name_)
17
+ * if no selector/name is provided, `:default` will be used
18
+ * duplicate definitions of states and events will issue warnings
19
+ * check all tests
20
+ * _ActiveRecord_
21
+ * _Mongoid_
22
+ * _MongoMapper_
23
+ * _Sequel_
24
+ * what happen's if someone accesses `aasm`, but has defined a
25
+ state machine for `aasm(:my_name)`?
26
+ * documentation
27
+ * drop support for find_in_state, count_in_state, calculate_in_state, with_state_scope
data/README.md CHANGED
@@ -99,11 +99,11 @@ class Job
99
99
  state :running
100
100
 
101
101
  event :run, :after => :notify_somebody do
102
- transitions :from => :sleeping, :to => :running, :after => Proc.new {|*args| set_process(*args) } do
103
- before do
104
- log('Preparing to run')
105
- end
102
+ before do
103
+ log('Preparing to run')
106
104
  end
105
+
106
+ transitions :from => :sleeping, :to => :running, :after => Proc.new {|*args| set_process(*args) }
107
107
  end
108
108
 
109
109
  event :sleep do
@@ -312,9 +312,79 @@ job.stage1_completed
312
312
  job.aasm.current_state # stage3
313
313
  ```
314
314
 
315
+
316
+ ### Multiple state machine per class
317
+
318
+ Multiple state machines per class are supported. Be aware though, that _AASM_ has been
319
+ built with one state machine per class in mind. Nonetheless, here's how to do it:
320
+
321
+ ```ruby
322
+ class SimpleMultipleExample
323
+ include AASM
324
+ aasm(:move) do
325
+ state :standing, :initial => true
326
+ state :walking
327
+ state :running
328
+
329
+ event :walk do
330
+ transitions :from => :standing, :to => :walking
331
+ end
332
+ event :run do
333
+ transitions :from => [:standing, :walking], :to => :running
334
+ end
335
+ event :hold do
336
+ transitions :from => [:walking, :running], :to => :standing
337
+ end
338
+ end
339
+
340
+ aasm(:work) do
341
+ state :sleeping, :initial => true
342
+ state :processing
343
+
344
+ event :start do
345
+ transitions :from => :sleeping, :to => :processing
346
+ end
347
+ event :stop do
348
+ transitions :from => :processing, :to => :sleeping
349
+ end
350
+ end
351
+ end
352
+
353
+ simple = SimpleMultipleExample.new
354
+
355
+ simple.aasm(:move).current_state
356
+ # => :standing
357
+ simple.aasm(:work).current
358
+ # => :sleeping
359
+
360
+ simple.start
361
+ simple.aasm(:move).current_state
362
+ # => :standing
363
+ simple.aasm(:work).current
364
+ # => :processing
365
+
366
+ ```
367
+
368
+ _AASM_ doesn't prohibit to define the same event in both state machines. The
369
+ latest definition "wins" and overrides previous definitions. A warning is issued:
370
+ `SimpleMultipleExample: The event name run is already used!`.
371
+
372
+ All _AASM_ class- and instance-level `aasm` methods accept a state machine selector.
373
+ So, for example, to use inspection on a class level, you have to use
374
+
375
+ ```ruby
376
+ SimpleMultipleExample.aasm(:work).states
377
+ # => [:standing, :walking, :running]
378
+ ```
379
+
380
+ *Final note*: Support for multiple state machines per class is a pretty new feature
381
+ (since version `4.3`), so please bear with us in case it doesn't as expected.
382
+
383
+
384
+
315
385
  ### ActiveRecord
316
386
 
317
- AASM comes with support for ActiveRecord and allows automatical persisting of the object's
387
+ AASM comes with support for ActiveRecord and allows automatic persisting of the object's
318
388
  state in the database.
319
389
 
320
390
  ```ruby
@@ -8,36 +8,50 @@ module AASM
8
8
 
9
9
  # do not overwrite existing state machines, which could have been created by
10
10
  # inheritance, see class method inherited
11
- AASM::StateMachine[base] ||= AASM::StateMachine.new
11
+ AASM::StateMachine[base] ||= {}
12
12
 
13
13
  AASM::Persistence.load_persistence(base)
14
14
  super
15
15
  end
16
16
 
17
17
  module ClassMethods
18
-
19
18
  # make sure inheritance (aka subclassing) works with AASM
20
19
  def inherited(base)
21
- AASM::StateMachine[base] = AASM::StateMachine[self].clone
20
+ AASM::StateMachine[base] = {}
21
+ AASM::StateMachine[self].keys.each do |state_machine_name|
22
+ AASM::StateMachine[base][state_machine_name] = AASM::StateMachine[self][state_machine_name].clone
23
+ end
22
24
  super
23
25
  end
24
26
 
25
27
  # this is the entry point for all state and event definitions
26
- def aasm(options={}, &block)
27
- @aasm ||= AASM::Base.new(self, options)
28
- @aasm.instance_eval(&block) if block # new DSL
29
- @aasm
30
- end
28
+ def aasm(*args, &block)
29
+ if args[0].is_a?(Symbol) || args[0].is_a?(String)
30
+ # using custom name
31
+ state_machine_name = args[0].to_sym
32
+ options = args[1] || {}
33
+ else
34
+ # using the default state_machine_name
35
+ state_machine_name = :default
36
+ options = args[0] || {}
37
+ end
38
+
39
+ AASM::StateMachine[self][state_machine_name] ||= AASM::StateMachine.new(state_machine_name)
31
40
 
32
- # deprecated, remove in version 4.1
33
- def aasm_human_event_name(event) # event_name?
34
- warn '[DEPRECATION] AASM: aasm_human_event_name is deprecated, use aasm.human_event_name instead'
35
- aasm.human_event_name(event)
41
+ @aasm ||= {}
42
+ @aasm[state_machine_name] ||= AASM::Base.new(self, state_machine_name, AASM::StateMachine[self][state_machine_name], options)
43
+ @aasm[state_machine_name].instance_eval(&block) if block # new DSL
44
+ @aasm[state_machine_name]
36
45
  end
37
46
  end # ClassMethods
38
47
 
39
- def aasm
40
- @aasm ||= AASM::InstanceBase.new(self)
48
+ # this is the entry point for all instance-level access to AASM
49
+ def aasm(name=:default)
50
+ unless AASM::StateMachine[self.class][name.to_sym]
51
+ raise AASM::UnknownStateMachineError.new("There is no state machine with the name '#{name}' defined in #{self.class.name}!")
52
+ end
53
+ @aasm ||= {}
54
+ @aasm[name.to_sym] ||= AASM::InstanceBase.new(self, name.to_sym)
41
55
  end
42
56
 
43
57
  private
@@ -56,72 +70,72 @@ private
56
70
  return args
57
71
  end
58
72
 
59
- def aasm_fire_event(event_name, options, *args, &block)
60
- event = self.class.aasm.state_machine.events[event_name]
73
+ def aasm_fire_event(state_machine_name, event_name, options, *args, &block)
74
+ event = self.class.aasm(state_machine_name).state_machine.events[event_name]
61
75
  begin
62
- old_state = aasm.state_object_for_name(aasm.current_state)
76
+ old_state = aasm(state_machine_name).state_object_for_name(aasm(state_machine_name).current_state)
63
77
 
64
78
  # new event before callback
65
79
  event.fire_callbacks(
66
80
  :before,
67
81
  self,
68
- *process_args(event, aasm.current_state, *args)
82
+ *process_args(event, aasm(state_machine_name).current_state, *args)
69
83
  )
70
84
 
71
85
  if may_fire_to = event.may_fire?(self, *args)
72
86
  old_state.fire_callbacks(:before_exit, self,
73
- *process_args(event, aasm.current_state, *args))
87
+ *process_args(event, aasm(state_machine_name).current_state, *args))
74
88
  old_state.fire_callbacks(:exit, self,
75
- *process_args(event, aasm.current_state, *args)) # TODO: remove for AASM 4?
89
+ *process_args(event, aasm(state_machine_name).current_state, *args))
76
90
 
77
91
  if new_state_name = event.fire(self, {:may_fire => may_fire_to}, *args)
78
- aasm_fired(event, old_state, new_state_name, options, *args, &block)
92
+ aasm_fired(state_machine_name, event, old_state, new_state_name, options, *args, &block)
79
93
  else
80
- aasm_failed(event_name, old_state)
94
+ aasm_failed(state_machine_name, event_name, old_state)
81
95
  end
82
96
  else
83
- aasm_failed(event_name, old_state)
97
+ aasm_failed(state_machine_name, event_name, old_state)
84
98
  end
85
99
  rescue StandardError => e
86
- event.fire_callbacks(:error, self, e, *process_args(event, aasm.current_state, *args)) || raise(e)
100
+ event.fire_callbacks(:error, self, e, *process_args(event, aasm(state_machine_name).current_state, *args)) || raise(e)
87
101
  end
88
102
  end
89
103
 
90
- def aasm_fired(event, old_state, new_state_name, options, *args)
104
+ def aasm_fired(state_machine_name, event, old_state, new_state_name, options, *args)
91
105
  persist = options[:persist]
92
106
 
93
- new_state = aasm.state_object_for_name(new_state_name)
107
+ new_state = aasm(state_machine_name).state_object_for_name(new_state_name)
94
108
 
95
109
  new_state.fire_callbacks(:before_enter, self,
96
- *process_args(event, aasm.current_state, *args))
110
+ *process_args(event, aasm(state_machine_name).current_state, *args))
97
111
 
98
112
  new_state.fire_callbacks(:enter, self,
99
- *process_args(event, aasm.current_state, *args)) # TODO: remove for AASM 4?
113
+ *process_args(event, aasm(state_machine_name).current_state, *args)) # TODO: remove for AASM 4?
100
114
 
101
115
  persist_successful = true
102
116
  if persist
103
- persist_successful = aasm.set_current_state_with_persistence(new_state_name)
117
+ persist_successful = aasm(state_machine_name).set_current_state_with_persistence(new_state_name)
104
118
  if persist_successful
105
119
  yield if block_given?
106
120
  event.fire_callbacks(:success, self)
107
121
  end
108
122
  else
109
- aasm.current_state = new_state_name
123
+ aasm(state_machine_name).current_state = new_state_name
110
124
  yield if block_given?
111
125
  end
112
126
 
113
127
  if persist_successful
114
128
  old_state.fire_callbacks(:after_exit, self,
115
- *process_args(event, aasm.current_state, *args))
129
+ *process_args(event, aasm(state_machine_name).current_state, *args))
116
130
  new_state.fire_callbacks(:after_enter, self,
117
- *process_args(event, aasm.current_state, *args))
131
+ *process_args(event, aasm(state_machine_name).current_state, *args))
118
132
  event.fire_callbacks(
119
133
  :after,
120
134
  self,
121
135
  *process_args(event, old_state.name, *args)
122
136
  )
123
137
 
124
- self.aasm_event_fired(event.name, old_state.name, aasm.current_state) if self.respond_to?(:aasm_event_fired)
138
+ self.aasm_event_fired(event.name, old_state.name, aasm(state_machine_name).current_state) if self.respond_to?(:aasm_event_fired)
125
139
  else
126
140
  self.aasm_event_failed(event.name, old_state.name) if self.respond_to?(:aasm_event_failed)
127
141
  end
@@ -129,13 +143,13 @@ private
129
143
  persist_successful
130
144
  end
131
145
 
132
- def aasm_failed(event_name, old_state)
146
+ def aasm_failed(state_machine_name, event_name, old_state)
133
147
  if self.respond_to?(:aasm_event_failed)
134
148
  self.aasm_event_failed(event_name, old_state.name)
135
149
  end
136
150
 
137
- if AASM::StateMachine[self.class].config.whiny_transitions
138
- raise AASM::InvalidTransition.new(self, event_name)
151
+ if AASM::StateMachine[self.class][state_machine_name].config.whiny_transitions
152
+ raise AASM::InvalidTransition.new(self, event_name, state_machine_name)
139
153
  else
140
154
  false
141
155
  end
@@ -3,10 +3,12 @@ module AASM
3
3
 
4
4
  attr_reader :state_machine
5
5
 
6
- def initialize(klass, options={}, &block)
6
+ def initialize(klass, name, state_machine, options={}, &block)
7
7
  @klass = klass
8
- @state_machine = AASM::StateMachine[@klass]
9
- @state_machine.config.column ||= (options[:column] || :aasm_state).to_sym # aasm4
8
+ @name = name
9
+ # @state_machine = @klass.aasm(@name).state_machine
10
+ @state_machine = state_machine
11
+ @state_machine.config.column ||= (options[:column] || default_column).to_sym
10
12
  # @state_machine.config.column = options[:column].to_sym if options[:column] # master
11
13
  @options = options
12
14
 
@@ -31,7 +33,7 @@ module AASM
31
33
  # and attribute is directly assigned though
32
34
  @klass.class_eval %Q(
33
35
  def #{@state_machine.config.column}=(state_name)
34
- if self.class.aasm.state_machine.config.no_direct_assignment
36
+ if self.class.aasm(:#{@name}).state_machine.config.no_direct_assignment
35
37
  raise AASM::NoDirectAssignmentError.new(
36
38
  'direct assignment of AASM column has been disabled (see AASM configuration for this class)'
37
39
  )
@@ -64,10 +66,16 @@ module AASM
64
66
  def state(name, options={})
65
67
  @state_machine.add_state(name, @klass, options)
66
68
 
67
- @klass.send(:define_method, "#{name}?") do
68
- aasm.current_state == name
69
+ if @klass.instance_methods.include?("#{name}?")
70
+ warn "#{@klass.name}: The state name #{name} is already used!"
69
71
  end
70
72
 
73
+ @klass.class_eval <<-EORUBY, __FILE__, __LINE__ + 1
74
+ def #{name}?
75
+ aasm(:#{@name}).current_state == :#{name}
76
+ end
77
+ EORUBY
78
+
71
79
  unless @klass.const_defined?("STATE_#{name.upcase}")
72
80
  @klass.const_set("STATE_#{name.upcase}", name)
73
81
  end
@@ -75,24 +83,30 @@ module AASM
75
83
 
76
84
  # define an event
77
85
  def event(name, options={}, &block)
78
- @state_machine.events[name] = AASM::Core::Event.new(name, options, &block)
86
+ @state_machine.add_event(name, options, &block)
87
+
88
+ if @klass.instance_methods.include?("may_#{name}?".to_sym)
89
+ warn "#{@klass.name}: The event name #{name} is already used!"
90
+ end
79
91
 
80
92
  # an addition over standard aasm so that, before firing an event, you can ask
81
93
  # may_event? and get back a boolean that tells you whether the guard method
82
94
  # on the transition will let this happen.
83
- @klass.send(:define_method, "may_#{name}?") do |*args|
84
- aasm.may_fire_event?(name, *args)
85
- end
95
+ @klass.class_eval <<-EORUBY, __FILE__, __LINE__ + 1
96
+ def may_#{name}?(*args)
97
+ aasm(:#{@name}).may_fire_event?(:#{name}, *args)
98
+ end
86
99
 
87
- @klass.send(:define_method, "#{name}!") do |*args, &block|
88
- aasm.current_event = "#{name}!".to_sym
89
- aasm_fire_event(name, {:persist => true}, *args, &block)
90
- end
100
+ def #{name}!(*args, &block)
101
+ aasm(:#{@name}).current_event = :#{name}!
102
+ aasm_fire_event(:#{@name}, :#{name}, {:persist => true}, *args, &block)
103
+ end
91
104
 
92
- @klass.send(:define_method, "#{name}") do |*args, &block|
93
- aasm.current_event = name.to_sym
94
- aasm_fire_event(name, {:persist => false}, *args, &block)
95
- end
105
+ def #{name}(*args, &block)
106
+ aasm(:#{@name}).current_event = :#{name}
107
+ aasm_fire_event(:#{@name}, :#{name}, {:persist => false}, *args, &block)
108
+ end
109
+ EORUBY
96
110
  end
97
111
 
98
112
  def states
@@ -122,6 +136,10 @@ module AASM
122
136
 
123
137
  private
124
138
 
139
+ def default_column
140
+ @name.to_sym == :default ? :aasm_state : @name.to_sym
141
+ end
142
+
125
143
  def configure(key, default_value)
126
144
  if @options.key?(key)
127
145
  @state_machine.config.send("#{key}=", @options[key])
@@ -2,10 +2,11 @@ module AASM::Core
2
2
  class Event
3
3
  include DslHelper
4
4
 
5
- attr_reader :name, :options
5
+ attr_reader :name, :state_machine, :options
6
6
 
7
- def initialize(name, options = {}, &block)
7
+ def initialize(name, state_machine, options = {}, &block)
8
8
  @name = name
9
+ @state_machine = state_machine
9
10
  @transitions = []
10
11
  @guards = Array(options[:guard] || options[:guards] || options[:if])
11
12
  @unless = Array(options[:unless]) #TODO: This could use a better name
@@ -61,11 +62,11 @@ module AASM::Core
61
62
  if definitions # define new transitions
62
63
  # Create a separate transition for each from-state to the given state
63
64
  Array(definitions[:from]).each do |s|
64
- @transitions << AASM::Core::Transition.new(attach_event_guards(definitions.merge(:from => s.to_sym)), &block)
65
+ @transitions << AASM::Core::Transition.new(self, attach_event_guards(definitions.merge(:from => s.to_sym)), &block)
65
66
  end
66
67
  # Create a transition if :to is specified without :from (transitions from ANY state)
67
68
  if @transitions.empty? && definitions[:to]
68
- @transitions << AASM::Core::Transition.new(attach_event_guards(definitions), &block)
69
+ @transitions << AASM::Core::Transition.new(self, attach_event_guards(definitions), &block)
69
70
  end
70
71
  end
71
72
  @transitions
@@ -89,7 +90,7 @@ module AASM::Core
89
90
  def _fire(obj, options={}, to_state=nil, *args)
90
91
  result = options[:test_only] ? false : nil
91
92
  if @transitions.map(&:from).any?
92
- transitions = @transitions.select { |t| t.from == obj.aasm.current_state }
93
+ transitions = @transitions.select { |t| t.from == obj.aasm(state_machine.name).current_state }
93
94
  return result if transitions.size == 0
94
95
  else
95
96
  transitions = @transitions