state_machine 0.9.3 → 0.9.4
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.rdoc +8 -0
- data/Rakefile +1 -1
- data/lib/state_machine/integrations/active_model.rb +9 -2
- data/lib/state_machine/integrations/active_record.rb +25 -11
- data/lib/state_machine/integrations/data_mapper.rb +5 -6
- data/lib/state_machine/integrations/sequel.rb +12 -2
- data/lib/state_machine/machine.rb +21 -9
- data/lib/state_machine/transition.rb +4 -2
- data/test/unit/integrations/data_mapper_test.rb +3 -2
- metadata +2 -2
data/CHANGELOG.rdoc
CHANGED
@@ -1,5 +1,13 @@
|
|
1
1
|
== master
|
2
2
|
|
3
|
+
== 0.9.4 / 2010-08-01
|
4
|
+
|
5
|
+
* Fix validation / save hooks in Sequel 3.14.0+
|
6
|
+
* Fix integration with dirty attribute tracking on DataMapper 1.0.1+
|
7
|
+
* Fix DataMapper 1.0.1+ tests producing warnings
|
8
|
+
* Fix validation error warnings in ActiveModel / ActiveRecord 3.0.0 beta5+
|
9
|
+
* Fix mass-assignment sanitization breaking in ActiveRecord 3.0.0 beta5+ [Akira Matsuda]
|
10
|
+
|
3
11
|
== 0.9.3 / 2010-06-26
|
4
12
|
|
5
13
|
* Allow access to human state / event names in transitions and for the current state
|
data/Rakefile
CHANGED
@@ -6,7 +6,7 @@ require 'rake/gempackagetask'
|
|
6
6
|
|
7
7
|
spec = Gem::Specification.new do |s|
|
8
8
|
s.name = 'state_machine'
|
9
|
-
s.version = '0.9.
|
9
|
+
s.version = '0.9.4'
|
10
10
|
s.platform = Gem::Platform::RUBY
|
11
11
|
s.summary = 'Adds support for creating state machines for attributes on any Ruby class'
|
12
12
|
s.description = s.summary
|
@@ -222,7 +222,7 @@ module StateMachine
|
|
222
222
|
def extended(base) #:nodoc:
|
223
223
|
require 'state_machine/integrations/active_model/observer'
|
224
224
|
|
225
|
-
if
|
225
|
+
if defined?(I18n)
|
226
226
|
locale = "#{File.dirname(__FILE__)}/active_model/locale.rb"
|
227
227
|
I18n.load_path.unshift(locale) unless I18n.load_path.include?(locale)
|
228
228
|
end
|
@@ -267,7 +267,8 @@ module StateMachine
|
|
267
267
|
options
|
268
268
|
end
|
269
269
|
|
270
|
-
object
|
270
|
+
default_options = default_error_message_options(object, attribute, message)
|
271
|
+
object.errors.add(attribute, message, options.merge(default_options))
|
271
272
|
end
|
272
273
|
end
|
273
274
|
|
@@ -312,6 +313,12 @@ module StateMachine
|
|
312
313
|
owner_class.i18n_scope
|
313
314
|
end
|
314
315
|
|
316
|
+
# The default options to use when generating messages for validation
|
317
|
+
# errors
|
318
|
+
def default_error_message_options(object, attribute, message)
|
319
|
+
{:message => @messages[message]}
|
320
|
+
end
|
321
|
+
|
315
322
|
# Translates the given key / value combo. Translation keys are looked
|
316
323
|
# up in the following order:
|
317
324
|
# * <tt>#{i18n_scope}.state_machines.#{model_name}.#{machine_name}.#{plural_key}.#{value}</tt>
|
@@ -331,9 +331,9 @@ module StateMachine
|
|
331
331
|
|
332
332
|
::ActiveRecord::Observer.class_eval do
|
333
333
|
include StateMachine::Integrations::ActiveModel::Observer
|
334
|
-
end unless ::ActiveRecord::Observer
|
334
|
+
end unless ::ActiveRecord::Observer < StateMachine::Integrations::ActiveModel::Observer
|
335
335
|
|
336
|
-
if
|
336
|
+
if defined?(I18n)
|
337
337
|
locale = "#{File.dirname(__FILE__)}/active_record/locale.rb"
|
338
338
|
I18n.load_path.unshift(locale) unless I18n.load_path.include?(locale)
|
339
339
|
end
|
@@ -341,7 +341,7 @@ module StateMachine
|
|
341
341
|
|
342
342
|
# Adds a validation error to the given object
|
343
343
|
def invalidate(object, attribute, message, values = [])
|
344
|
-
if
|
344
|
+
if defined?(I18n)
|
345
345
|
super
|
346
346
|
else
|
347
347
|
object.errors.add(self.attribute(attribute), generate_message(message, values))
|
@@ -366,7 +366,7 @@ module StateMachine
|
|
366
366
|
|
367
367
|
# Only adds dirty tracking support if ActiveRecord supports it
|
368
368
|
def supports_dirty_tracking?(object)
|
369
|
-
defined?(::ActiveRecord::Dirty) && object.respond_to?("#{
|
369
|
+
defined?(::ActiveRecord::Dirty) && object.respond_to?("#{attribute}_changed?") || super
|
370
370
|
end
|
371
371
|
|
372
372
|
# Always uses the <tt>:activerecord</tt> translation scope
|
@@ -374,9 +374,19 @@ module StateMachine
|
|
374
374
|
:activerecord
|
375
375
|
end
|
376
376
|
|
377
|
+
# The default options to use when generating messages for validation
|
378
|
+
# errors
|
379
|
+
def default_error_message_options(object, attribute, message)
|
380
|
+
if ::ActiveRecord::VERSION::MAJOR >= 3
|
381
|
+
super
|
382
|
+
else
|
383
|
+
{:default => @messages[message]}
|
384
|
+
end
|
385
|
+
end
|
386
|
+
|
377
387
|
# Only allows translation of I18n is available
|
378
388
|
def translate(klass, key, value)
|
379
|
-
if
|
389
|
+
if defined?(I18n)
|
380
390
|
super
|
381
391
|
else
|
382
392
|
value ? value.to_s.humanize.downcase : 'nil'
|
@@ -384,9 +394,9 @@ module StateMachine
|
|
384
394
|
end
|
385
395
|
|
386
396
|
# Attempts to look up a class's ancestors via:
|
387
|
-
# * #lookup_ancestors
|
388
|
-
# * #self_and_descendants_from_active_record
|
389
|
-
# * #self_and_descendents_from_active_record
|
397
|
+
# * #lookup_ancestors (3.0.0+)
|
398
|
+
# * #self_and_descendants_from_active_record (2.3.2 - 2.3.x)
|
399
|
+
# * #self_and_descendents_from_active_record (2.0.0 - 2.3.1)
|
390
400
|
def ancestors_for(klass)
|
391
401
|
if ::ActiveRecord::VERSION::MAJOR >= 3
|
392
402
|
super
|
@@ -415,12 +425,16 @@ module StateMachine
|
|
415
425
|
if new_record? && !@initialized_state_machines
|
416
426
|
@initialized_state_machines = true
|
417
427
|
|
418
|
-
if new_attributes
|
428
|
+
ignore = if new_attributes
|
419
429
|
attributes = new_attributes.dup
|
420
430
|
attributes.stringify_keys!
|
421
|
-
|
431
|
+
if ::ActiveRecord::VERSION::MAJOR >= 3
|
432
|
+
sanitize_for_mass_assignment(attributes).keys
|
433
|
+
else
|
434
|
+
remove_attributes_protected_from_mass_assignment(attributes).keys
|
435
|
+
end
|
422
436
|
else
|
423
|
-
|
437
|
+
[]
|
424
438
|
end
|
425
439
|
|
426
440
|
initialize_state_machines(:dynamic => false, :ignore => ignore)
|
@@ -262,19 +262,18 @@ module StateMachine
|
|
262
262
|
# state value actually changed
|
263
263
|
def write(object, attribute, value)
|
264
264
|
if attribute == :state
|
265
|
-
# Force to Dirty state in 0.10.3+
|
266
|
-
if !(::DataMapper::VERSION =~ /^0\.(9\.|10\.[0-2]$)/)
|
267
|
-
object.persisted_state = ::DataMapper::Resource::State::Dirty.new(object) if object.persisted_state.is_a?(::DataMapper::Resource::State::Clean)
|
268
|
-
end
|
269
|
-
|
270
265
|
result = super
|
271
266
|
|
272
267
|
# Change original attributes in 0.9.4 - 0.10.2
|
273
268
|
if ::DataMapper::VERSION =~ /^0\.9\./
|
274
269
|
object.original_values[self.attribute] = "#{value}-ignored" if object.original_values[self.attribute] == value
|
275
|
-
elsif ::DataMapper::VERSION =~ /^0\.10
|
270
|
+
elsif ::DataMapper::VERSION =~ /^0\.10\./
|
276
271
|
property = owner_class.properties[self.attribute]
|
277
272
|
object.original_attributes[property] = "#{value}-ignored" unless object.original_attributes.include?(property)
|
273
|
+
else
|
274
|
+
object.persisted_state = ::DataMapper::Resource::State::Dirty.new(object) if object.persisted_state.is_a?(::DataMapper::Resource::State::Clean)
|
275
|
+
property = owner_class.properties[self.attribute]
|
276
|
+
object.persisted_state.original_attributes[property] = value unless object.persisted_state.original_attributes.include?(property)
|
278
277
|
end
|
279
278
|
else
|
280
279
|
result = super
|
@@ -297,7 +297,11 @@ module StateMachine
|
|
297
297
|
super(*args)
|
298
298
|
end
|
299
299
|
|
300
|
-
|
300
|
+
if defined?(::Sequel::MAJOR) && (::Sequel::MAJOR > 3 || ::Sequel::MAJOR == 3 && ::Sequel::MINOR > 13)
|
301
|
+
raise_on_failure?(args.first || {}) && !yielded && !result ? raise_hook_failure(:validation) : result
|
302
|
+
else
|
303
|
+
raise_on_save_failure && !yielded && !result ? save_failure(:validation) : result
|
304
|
+
end
|
301
305
|
end
|
302
306
|
|
303
307
|
define_method(defined?(::Sequel::MAJOR) && (::Sequel::MAJOR >= 3 || ::Sequel::MAJOR == 2 && ::Sequel::MINOR == 12) ? :_save : :save) do |*args|
|
@@ -307,7 +311,13 @@ module StateMachine
|
|
307
311
|
super(*args)
|
308
312
|
end
|
309
313
|
|
310
|
-
yielded || result
|
314
|
+
if yielded || result
|
315
|
+
result
|
316
|
+
elsif defined?(::Sequel::MAJOR) && (::Sequel::MAJOR > 3 || ::Sequel::MAJOR == 3 && ::Sequel::MINOR > 13)
|
317
|
+
raise_hook_failure(:save)
|
318
|
+
else
|
319
|
+
save_failure(:save)
|
320
|
+
end
|
311
321
|
end
|
312
322
|
end unless owner_class.state_machines.any? {|name, machine| machine.action == :save && machine != self}
|
313
323
|
else
|
@@ -483,7 +483,7 @@ module StateMachine
|
|
483
483
|
end
|
484
484
|
|
485
485
|
# Add class-/instance-level methods to the owner class for state initialization
|
486
|
-
unless owner_class
|
486
|
+
unless owner_class < StateMachine::InstanceMethods
|
487
487
|
owner_class.class_eval do
|
488
488
|
extend StateMachine::ClassMethods
|
489
489
|
include StateMachine::InstanceMethods
|
@@ -928,11 +928,15 @@ module StateMachine
|
|
928
928
|
# * <tt>park_transition</tt> - Gets the next transition that would be
|
929
929
|
# performed if the "park" event were to be fired now on the object or nil
|
930
930
|
# if no transitions can be performed.
|
931
|
-
# * <tt>park(run_action = true)</tt> - Fires the "park" event,
|
932
|
-
# from the current state to the next valid state.
|
933
|
-
#
|
934
|
-
#
|
935
|
-
#
|
931
|
+
# * <tt>park(..., run_action = true)</tt> - Fires the "park" event,
|
932
|
+
# transitioning from the current state to the next valid state. If the
|
933
|
+
# last argument is a boolean, it will control whether the machine's action
|
934
|
+
# gets run.
|
935
|
+
# * <tt>park!(..., run_action = true)</tt> - Fires the "park" event,
|
936
|
+
# transitioning from the current state to the next valid state. If the
|
937
|
+
# transition fails, then a StateMachine::InvalidTransition error will be
|
938
|
+
# raised. If the last argument is a boolean, it will control whether the
|
939
|
+
# machine's action gets run.
|
936
940
|
#
|
937
941
|
# With a namespace of "car", the above names map to the following methods:
|
938
942
|
# * <tt>can_park_car?</tt>
|
@@ -994,15 +998,23 @@ module StateMachine
|
|
994
998
|
# end
|
995
999
|
# end
|
996
1000
|
#
|
997
|
-
# Note that +super+ is called instead of <tt>super(*args)</tt>. This
|
998
|
-
#
|
999
|
-
#
|
1001
|
+
# Note that +super+ is called instead of <tt>super(*args)</tt>. This allows
|
1002
|
+
# the entire arguments list to be accessed by transition callbacks through
|
1003
|
+
# StateMachine::Transition#args like so:
|
1000
1004
|
#
|
1001
1005
|
# after_transition :on => :park do |vehicle, transition|
|
1002
1006
|
# kind = *transition.args
|
1003
1007
|
# ...
|
1004
1008
|
# end
|
1005
1009
|
#
|
1010
|
+
# *Remember* that if the last argument is a boolean, it will be used as the
|
1011
|
+
# +run_action+ parameter to the event action. Using the +park+ action
|
1012
|
+
# example from above, you can might call it like so:
|
1013
|
+
#
|
1014
|
+
# vehicle.park # => Uses default args and runs machine action
|
1015
|
+
# vehicle.park(:parallel) # => Specifies the +kind+ argument and runs the machine action
|
1016
|
+
# vehicle.park(:parallel, false) # => Specifies the +kind+ argument and *skips* the machine action
|
1017
|
+
#
|
1006
1018
|
# == Example
|
1007
1019
|
#
|
1008
1020
|
# class Vehicle
|
@@ -150,8 +150,10 @@ module StateMachine
|
|
150
150
|
#
|
151
151
|
# vehicle = Vehicle.new
|
152
152
|
# transition = StateMachine::Transition.new(vehicle, machine, :ignite, :parked, :idling)
|
153
|
-
# transition.perform
|
154
|
-
# transition.perform(false)
|
153
|
+
# transition.perform # => Runs the +save+ action after setting the state attribute
|
154
|
+
# transition.perform(false) # => Only sets the state attribute
|
155
|
+
# transition.perform(Time.now) # => Passes in additional arguments and runs the +save+ action
|
156
|
+
# transition.perform(Time.now, false) # => Passes in additional arguments and only sets the state attribute
|
155
157
|
def perform(*args)
|
156
158
|
run_action = [true, false].include?(args.last) ? args.pop : true
|
157
159
|
self.args = args
|
@@ -26,13 +26,14 @@ module DataMapperTest
|
|
26
26
|
def new_resource(create_table = :foo, &block)
|
27
27
|
table_name = create_table || :foo
|
28
28
|
|
29
|
-
resource = Class.new
|
29
|
+
resource = Class.new
|
30
|
+
resource.class_eval do
|
30
31
|
include DataMapper::Resource
|
31
32
|
|
32
33
|
storage_names[:default] = table_name.to_s
|
33
34
|
def self.name; "DataMapperTest::#{storage_names[:default].capitalize}"; end
|
34
35
|
|
35
|
-
property :id,
|
36
|
+
property :id, resource.class_eval('Serial')
|
36
37
|
property :state, String
|
37
38
|
|
38
39
|
auto_migrate! if create_table
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: state_machine
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.9.
|
4
|
+
version: 0.9.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Aaron Pfeifer
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2010-
|
12
|
+
date: 2010-08-01 00:00:00 -04:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|