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 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