state_machine 0.9.0 → 0.9.1

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,12 @@
1
1
  == master
2
2
 
3
+ == 0.9.1 / 2010-05-02
4
+
5
+ * Fix ActiveRecord 2.0.0 - 2.2.3 integrations failing if version info isn't already loaded
6
+ * Fix integration with dirty attribute tracking on DataMapper 0.10.3
7
+ * Fix observers failing in ActiveRecord 3.0.0.beta4+ integrations
8
+ * Fix deprecation warning in Rails 3 railtie [Chris Yuan]
9
+
3
10
  == 0.9.0 / 2010-04-12
4
11
 
5
12
  * Use attribute-based event transitions whenever possible to ensure consistency
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.0'
9
+ s.version = '0.9.1'
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
data/lib/state_machine.rb CHANGED
@@ -295,8 +295,8 @@ module StateMachine
295
295
  #
296
296
  # Within the +state_machine+ block, you can also define callbacks for
297
297
  # transitions. For more information about defining these callbacks,
298
- # see StateMachine::Machine#before_transition and
299
- # StateMachine::Machine#after_transition.
298
+ # see StateMachine::Machine#before_transition, StateMachine::Machine#after_transition,
299
+ # and StateMachine::Machine#around_transition.
300
300
  #
301
301
  # == Namespaces
302
302
  #
@@ -204,8 +204,8 @@ module StateMachine
204
204
  def bound_method(block)
205
205
  type = self.type
206
206
  arity = block.arity
207
- arity += 1 if arity >= 0
208
- arity += 1 if arity == 1 && type == :around
207
+ arity += 1 if arity >= 0 # Make sure the object gets passed
208
+ arity += 1 if arity == 1 && type == :around # Make sure the block gets passed
209
209
 
210
210
  method = if RUBY_VERSION >= '1.9'
211
211
  lambda do |object, *args|
@@ -1,6 +1,4 @@
1
1
  class StateMachine::Railtie < Rails::Railtie
2
- railtie_name :state_machine
3
-
4
2
  rake_tasks do
5
3
  load 'tasks/state_machine.rb'
6
4
  end
@@ -397,14 +397,14 @@ module StateMachine
397
397
  ["#{type}_#{event}", "#{type}_transition_#{name}"].each do |event_segment|
398
398
  ["_from_#{from}", nil].each do |from_segment|
399
399
  ["_to_#{to}", nil].each do |to_segment|
400
- object.class.changed
400
+ object.class.changed if object.class.respond_to?(:changed)
401
401
  object.class.notify_observers([event_segment, from_segment, to_segment].join, object, transition)
402
402
  end
403
403
  end
404
404
  end
405
405
 
406
406
  # Generic updates
407
- object.class.changed
407
+ object.class.changed if object.class.respond_to?(:changed)
408
408
  object.class.notify_observers("#{type}_transition", object, transition)
409
409
 
410
410
  true
@@ -323,6 +323,7 @@ module StateMachine
323
323
  end
324
324
 
325
325
  def self.extended(base) #:nodoc:
326
+ require 'active_record/version'
326
327
  require 'state_machine/integrations/active_model/observer'
327
328
 
328
329
  ::ActiveRecord::Observer.class_eval do
@@ -261,18 +261,25 @@ module StateMachine
261
261
  # Forces the change in state to be recognized regardless of whether the
262
262
  # state value actually changed
263
263
  def write(object, attribute, value)
264
- result = super
265
- if attribute == :state && owner_class.properties.detect {|property| property.name == self.attribute}
266
- if ::DataMapper::VERSION =~ /^0\.\d\./ # Match anything < 0.10
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
+ result = super
271
+
272
+ # Change original attributes in 0.9.4 - 0.10.2
273
+ if ::DataMapper::VERSION =~ /^0\.9\./
267
274
  object.original_values[self.attribute] = "#{value}-ignored" if object.original_values[self.attribute] == value
268
- else
269
- # Force the resource's state to Dirty for 0.10.13+
270
- object.persisted_state = ::DataMapper::Resource::State::Dirty.new(object) unless ::DataMapper::VERSION =~ /^0\.10\.[0-2]$/ || object.persisted_state.respond_to?(:original_attributes)
271
-
275
+ elsif ::DataMapper::VERSION =~ /^0\.10\.[0-2]$/
272
276
  property = owner_class.properties[self.attribute]
273
277
  object.original_attributes[property] = "#{value}-ignored" unless object.original_attributes.include?(property)
274
278
  end
279
+ else
280
+ result = super
275
281
  end
282
+
276
283
  result
277
284
  end
278
285
 
@@ -167,23 +167,12 @@ module StateMachine
167
167
  options = {:after => true}.merge(options)
168
168
  @success = false
169
169
 
170
- # Run before callbacks. :halt is caught here so that it rolls up through
171
- # any around callbacks.
172
- begin
173
- halted = !catch(:halt) { before(options[:after], &block); true }
174
- rescue Exception => error
175
- raise unless @after_block
176
- end
170
+ halted = pausable { before(options[:after], &block) }
177
171
 
178
172
  # After callbacks are only run if:
179
- # * There isn't an after block already running
180
173
  # * An around callback didn't halt after yielding
181
174
  # * They're enabled or the run didn't succeed
182
- if @after_block
183
- @after_block.call(halted, error)
184
- elsif !(@before_run && halted) && (options[:after] || !@success)
185
- after
186
- end
175
+ after if !(@before_run && halted) && (options[:after] || !@success)
187
176
 
188
177
  @before_run
189
178
  end
@@ -247,7 +236,7 @@ module StateMachine
247
236
  # the state has already been persisted
248
237
  def reset
249
238
  @before_run = @persisted = @after_run = false
250
- @around_block = nil
239
+ @paused_block = nil
251
240
  end
252
241
 
253
242
  # Generates a nicely formatted description of this transitions's contents.
@@ -261,6 +250,57 @@ module StateMachine
261
250
  end
262
251
 
263
252
  private
253
+ # Runs a block that may get paused. If the block doesn't pause, then
254
+ # execution will continue as normal. If the block gets paused, then it
255
+ # will take care of switching the execution context when it's resumed.
256
+ #
257
+ # This will return true if the given block halts for a reason other than
258
+ # getting paused.
259
+ def pausable
260
+ begin
261
+ halted = !catch(:halt) { yield; true }
262
+ rescue Exception => error
263
+ raise unless @resume_block
264
+ end
265
+
266
+ if @resume_block
267
+ @resume_block.call(halted, error)
268
+ else
269
+ halted
270
+ end
271
+ end
272
+
273
+ # Pauses the current callback execution. This should only occur within
274
+ # around callbacks when the remainder of the callback will be executed at
275
+ # a later point in time.
276
+ def pause
277
+ unless @resume_block
278
+ require 'continuation' unless defined?(callcc)
279
+ callcc do |block|
280
+ @paused_block = block
281
+ throw :halt, true
282
+ end
283
+ end
284
+ end
285
+
286
+ # Resumes the execution of a previously paused callback execution. Once
287
+ # the paused callbacks complete, the current execution will continue.
288
+ def resume
289
+ if @paused_block
290
+ halted, error = callcc do |block|
291
+ @resume_block = block
292
+ @paused_block.call
293
+ end
294
+
295
+ @resume_block = @paused_block = nil
296
+
297
+ raise error if error
298
+ !halted
299
+ else
300
+ true
301
+ end
302
+ end
303
+
264
304
  # Runs the machine's +before+ callbacks for this transition. Only
265
305
  # callbacks that are configured to match the event, from state, and to
266
306
  # state will be invoked.
@@ -278,16 +318,12 @@ module StateMachine
278
318
  # * The block fails and the callback doesn't run on failures OR
279
319
  # * The block succeeds, but after callbacks are disabled (in which
280
320
  # case a continuation is stored for later execution)
281
- return if catch(:pause) do
321
+ return if catch(:cancel) do
282
322
  callback.call(object, context, self) do
283
323
  before(complete, index, &block)
284
324
 
285
- if @success && !complete && !@around_block && !@after_block
286
- require 'continuation' unless defined?(callcc)
287
- callcc {|block| @around_block = block}
288
- end
289
-
290
- throw :pause, true if @around_block && !@after_block || !callback.matches_success?(@success)
325
+ pause if @success && !complete
326
+ throw :cancel, true unless callback.matches_success?(@success)
291
327
  end
292
328
  end
293
329
  else
@@ -318,22 +354,12 @@ module StateMachine
318
354
  # should never halt the execution of a +perform+.
319
355
  def after
320
356
  unless @after_run
321
- catch(:halt) do
322
- # First call any yielded around blocks
323
- if @around_block
324
- halted, error = callcc do |block|
325
- @after_block = block
326
- @around_block.call
327
- end
328
-
329
- @after_block = @around_block = nil
330
- raise error if error
331
- throw :halt if halted
357
+ # First resume previously paused callbacks
358
+ if resume
359
+ catch(:halt) do
360
+ after_context = context.merge(:success => @success)
361
+ machine.callbacks[:after].each {|callback| callback.call(object, after_context, self)}
332
362
  end
333
-
334
- # Call normal after callbacks in order
335
- after_context = context.merge(:success => @success)
336
- machine.callbacks[:after].each {|callback| callback.call(object, after_context, self)}
337
363
  end
338
364
 
339
365
  @after_run = true
@@ -12,10 +12,9 @@ FIXTURES_ROOT = File.dirname(__FILE__) + '/../../fixtures/'
12
12
  require 'active_support/test_case'
13
13
  require 'active_record/fixtures'
14
14
 
15
- require 'active_record/version'
16
- if ActiveRecord::VERSION::STRING >= '2.1.0'
15
+ begin
17
16
  require 'active_record/test_case'
18
- else
17
+ rescue LoadError
19
18
  class ActiveRecord::TestCase < ActiveSupport::TestCase
20
19
  self.fixture_path = FIXTURES_ROOT
21
20
  self.use_instantiated_fixtures = false
@@ -512,7 +512,9 @@ module DataMapperTest
512
512
  end
513
513
 
514
514
  def test_should_track_attribute_change
515
- if Gem::Version.new(::DataMapper::VERSION) >= Gem::Version.new('0.10.0')
515
+ if Gem::Version.new(::DataMapper::VERSION) >= Gem::Version.new('0.10.3')
516
+ assert_equal e = {@resource.properties[:state] => 'parked'}, @record.original_attributes
517
+ elsif Gem::Version.new(::DataMapper::VERSION) >= Gem::Version.new('0.10.0')
516
518
  assert_equal e = {@resource.properties[:state] => 'parked-ignored'}, @record.original_attributes
517
519
  else
518
520
  assert_equal e = {:state => 'parked-ignored'}, @record.original_values
@@ -580,7 +582,9 @@ module DataMapperTest
580
582
  end
581
583
 
582
584
  def test_should_track_attribute_changes
583
- if Gem::Version.new(::DataMapper::VERSION) >= Gem::Version.new('0.10.0')
585
+ if Gem::Version.new(::DataMapper::VERSION) >= Gem::Version.new('0.10.3')
586
+ assert_equal e = {@resource.properties[:status] => 'parked'}, @record.original_attributes
587
+ elsif Gem::Version.new(::DataMapper::VERSION) >= Gem::Version.new('0.10.0')
584
588
  assert_equal e = {@resource.properties[:status] => 'parked-ignored'}, @record.original_attributes
585
589
  else
586
590
  assert_equal e = {:status => 'parked-ignored'}, @record.original_values
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.0
4
+ version: 0.9.1
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-04-12 00:00:00 -04:00
12
+ date: 2010-05-02 00:00:00 -04:00
13
13
  default_executable:
14
14
  dependencies: []
15
15