state_machine 0.9.3 → 0.9.4

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.
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.3'
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 Object.const_defined?(:I18n)
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.errors.add(attribute, message, options.merge(:default => @messages[message]))
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.included_modules.include?(StateMachine::Integrations::ActiveModel::Observer)
334
+ end unless ::ActiveRecord::Observer < StateMachine::Integrations::ActiveModel::Observer
335
335
 
336
- if Object.const_defined?(:I18n)
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 Object.const_defined?(:I18n)
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?("#{self.attribute}_changed?") || super
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 Object.const_defined?(:I18n)
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
- ignore = remove_attributes_protected_from_mass_assignment(attributes).keys
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
- ignore = []
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\.[0-2]$/
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
- raise_on_save_failure && !yielded && !result ? save_failure(:validation) : result
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 ? result : save_failure(:save)
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.included_modules.include?(StateMachine::InstanceMethods)
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, transitioning
932
- # from the current state to the next valid state.
933
- # * <tt>park!(run_action = true)</tt> - Fires the "park" event, transitioning
934
- # from the current state to the next valid state. If the transition fails,
935
- # then a StateMachine::InvalidTransition error will be raised.
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
- # allows the entire arguments list to be accessed by transition callbacks
999
- # through StateMachine::Transition#args like so:
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 # => Runs the +save+ action after setting the state attribute
154
- # transition.perform(false) # => Only sets the state attribute
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 do
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, DataMapper::Types::Serial
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.3
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-06-27 00:00:00 -04:00
12
+ date: 2010-08-01 00:00:00 -04:00
13
13
  default_executable:
14
14
  dependencies: []
15
15