state_machine 1.0.0 → 1.0.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 +8 -0
- data/Rakefile +1 -1
- data/lib/state_machine/initializers/rails.rb +5 -1
- data/lib/state_machine/integrations/active_record.rb +2 -2
- data/lib/state_machine/integrations/mongo_mapper.rb +2 -2
- data/lib/state_machine/integrations/mongoid.rb +2 -2
- data/lib/state_machine/integrations/sequel/versions.rb +4 -0
- data/lib/state_machine/integrations/sequel.rb +28 -2
- data/lib/state_machine/machine.rb +60 -15
- data/lib/state_machine/state.rb +4 -12
- data/test/unit/event_test.rb +77 -14
- data/test/unit/integrations/sequel_test.rb +15 -3
- data/test/unit/machine_test.rb +398 -29
- data/test/unit/state_test.rb +36 -7
- data/test/unit/transition_test.rb +1 -1
- metadata +20 -39
data/CHANGELOG.rdoc
CHANGED
@@ -1,5 +1,13 @@
|
|
1
1
|
== master
|
2
2
|
|
3
|
+
== 1.0.1 / 2011-05-30
|
4
|
+
|
5
|
+
* Add the ability to ignore method conflicts for helpers
|
6
|
+
* Generate warnings for any helper, not just state helpers, that has a conflicting method defined in the class
|
7
|
+
* Fix scopes in Sequel not working if the table name contains double underscores or is not a string/symbol
|
8
|
+
* Add full support for chaining state scopes within Sequel integrations
|
9
|
+
* Fix Rails 3.1 deprecation warnings for configuring engine locales [Stefan Penner]
|
10
|
+
|
3
11
|
== 1.0.0 / 2011-05-12
|
4
12
|
|
5
13
|
* Celebrate
|
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 = '1.0.
|
9
|
+
s.version = '1.0.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
|
@@ -13,7 +13,11 @@ if defined?(Rails)
|
|
13
13
|
end
|
14
14
|
end
|
15
15
|
|
16
|
-
|
16
|
+
if Rails::VERSION::MAJOR == 3 && Rails::VERSION::MINOR == 0
|
17
|
+
StateMachine::RailsEngine.paths.config.locales = locale_paths
|
18
|
+
else
|
19
|
+
StateMachine::RailsEngine.paths['config/locales'] = locale_paths
|
20
|
+
end
|
17
21
|
elsif defined?(I18n)
|
18
22
|
# Rails 2.x
|
19
23
|
I18n.load_path.unshift(*locale_paths)
|
@@ -416,8 +416,8 @@ module StateMachine
|
|
416
416
|
# ActiveModel's use of method_missing / respond_to for attribute methods
|
417
417
|
# breaks both ancestor lookups and defined?(super). Need to special-case
|
418
418
|
# the existence of query attribute methods.
|
419
|
-
def owner_class_ancestor_has_method?(method)
|
420
|
-
method == "#{name}?" || super
|
419
|
+
def owner_class_ancestor_has_method?(scope, method)
|
420
|
+
scope == :instance && method == "#{name}?" || super
|
421
421
|
end
|
422
422
|
end
|
423
423
|
end
|
@@ -264,8 +264,8 @@ module StateMachine
|
|
264
264
|
# ActiveModel's use of method_missing / respond_to for attribute methods
|
265
265
|
# breaks both ancestor lookups and defined?(super). Need to special-case
|
266
266
|
# the existence of query attribute methods.
|
267
|
-
def owner_class_ancestor_has_method?(method)
|
268
|
-
method == "#{name}?" || super
|
267
|
+
def owner_class_ancestor_has_method?(scope, method)
|
268
|
+
scope == :instance && method == "#{name}?" || super
|
269
269
|
end
|
270
270
|
end
|
271
271
|
end
|
@@ -349,8 +349,8 @@ module StateMachine
|
|
349
349
|
# ActiveModel's use of method_missing / respond_to for attribute methods
|
350
350
|
# breaks both ancestor lookups and defined?(super). Need to special-case
|
351
351
|
# the existence of query attribute methods.
|
352
|
-
def owner_class_ancestor_has_method?(method)
|
353
|
-
method == "#{name}?" || super
|
352
|
+
def owner_class_ancestor_has_method?(scope, method)
|
353
|
+
scope == :instance && method == "#{name}?" || super
|
354
354
|
end
|
355
355
|
end
|
356
356
|
end
|
@@ -374,13 +374,39 @@ module StateMachine
|
|
374
374
|
# Creates a scope for finding records *with* a particular state or
|
375
375
|
# states for the attribute
|
376
376
|
def create_with_scope(name)
|
377
|
-
lambda {|
|
377
|
+
create_scope(name, lambda {|dataset, values| dataset.filter(attribute_column => values)})
|
378
378
|
end
|
379
379
|
|
380
380
|
# Creates a scope for finding records *without* a particular state or
|
381
381
|
# states for the attribute
|
382
382
|
def create_without_scope(name)
|
383
|
-
lambda {|
|
383
|
+
create_scope(name, lambda {|dataset, values| dataset.exclude(attribute_column => values)})
|
384
|
+
end
|
385
|
+
|
386
|
+
# Creates a new named scope with the given name
|
387
|
+
def create_scope(name, scope)
|
388
|
+
machine = self
|
389
|
+
owner_class.def_dataset_method(name) do |*states|
|
390
|
+
machine.send(:run_scope, scope, self, states)
|
391
|
+
end
|
392
|
+
|
393
|
+
false
|
394
|
+
end
|
395
|
+
|
396
|
+
# Generates the results for the given scope based on one or more states to
|
397
|
+
# filter by
|
398
|
+
def run_scope(scope, dataset, states)
|
399
|
+
super(scope, model_from_dataset(dataset).state_machine(name), dataset, states)
|
400
|
+
end
|
401
|
+
|
402
|
+
# Determines the model associated with the given dataset
|
403
|
+
def model_from_dataset(dataset)
|
404
|
+
dataset.model
|
405
|
+
end
|
406
|
+
|
407
|
+
# Generates the fully-qualifed column name for this machine's attribute
|
408
|
+
def attribute_column
|
409
|
+
::Sequel::SQL::QualifiedIdentifier.new(owner_class.table_name, attribute)
|
384
410
|
end
|
385
411
|
|
386
412
|
# Runs a new database transaction, rolling back any changes if the
|
@@ -376,6 +376,11 @@ module StateMachine
|
|
376
376
|
:invalid_transition => 'cannot transition via "%s"'
|
377
377
|
}
|
378
378
|
|
379
|
+
# Whether to ignore any conflicts that are detected for helper methods that
|
380
|
+
# get generated for a machine's owner class. Default is false.
|
381
|
+
class << self; attr_accessor :ignore_method_conflicts; end
|
382
|
+
@ignore_method_conflicts = false
|
383
|
+
|
379
384
|
# The class that the machine is defined in
|
380
385
|
attr_accessor :owner_class
|
381
386
|
|
@@ -583,6 +588,11 @@ module StateMachine
|
|
583
588
|
# name. If the method is already defined in the scope, then this will not
|
584
589
|
# override it.
|
585
590
|
#
|
591
|
+
# If passing in a block, there are two side effects to be aware of
|
592
|
+
# 1. The method cannot be chained, meaning that the block cannot call +super+
|
593
|
+
# 2. If the method is already defined in an ancestor, then it will not get
|
594
|
+
# overridden and a warning will be output.
|
595
|
+
#
|
586
596
|
# Example:
|
587
597
|
#
|
588
598
|
# # Instance helper
|
@@ -611,15 +621,22 @@ module StateMachine
|
|
611
621
|
# end
|
612
622
|
# end_eval
|
613
623
|
def define_helper(scope, method, *args, &block)
|
624
|
+
helper_module = @helper_modules.fetch(scope)
|
625
|
+
|
614
626
|
if block_given?
|
615
|
-
|
616
|
-
|
617
|
-
|
618
|
-
|
627
|
+
if !self.class.ignore_method_conflicts && conflicting_ancestor = owner_class_ancestor_has_method?(scope, method)
|
628
|
+
ancestor_name = conflicting_ancestor.name && !conflicting_ancestor.name.empty? ? conflicting_ancestor.name : conflicting_ancestor.to_s
|
629
|
+
warn "#{scope == :class ? 'Class' : 'Instance'} method \"#{method}\" is already defined in #{ancestor_name}, use generic helper instead."
|
630
|
+
else
|
631
|
+
name = self.name
|
632
|
+
helper_module.class_eval do
|
633
|
+
define_method(method) do |*args|
|
634
|
+
block.call((scope == :instance ? self.class : self).state_machine(name), self, *args)
|
635
|
+
end
|
619
636
|
end
|
620
637
|
end
|
621
638
|
else
|
622
|
-
|
639
|
+
helper_module.class_eval(method, *args)
|
623
640
|
end
|
624
641
|
end
|
625
642
|
|
@@ -1585,13 +1602,14 @@ module StateMachine
|
|
1585
1602
|
def define_state_accessor
|
1586
1603
|
attribute = self.attribute
|
1587
1604
|
|
1588
|
-
@helper_modules[:instance].class_eval {
|
1605
|
+
@helper_modules[:instance].class_eval { attr_reader attribute } unless owner_class_ancestor_has_method?(:instance, attribute)
|
1606
|
+
@helper_modules[:instance].class_eval { attr_writer attribute } unless owner_class_ancestor_has_method?(:instance, "#{attribute}=")
|
1589
1607
|
end
|
1590
1608
|
|
1591
1609
|
# Adds predicate method to the owner class for determining the name of the
|
1592
1610
|
# current state
|
1593
1611
|
def define_state_predicate
|
1594
|
-
call_super = owner_class_ancestor_has_method?("#{name}?")
|
1612
|
+
call_super = !!owner_class_ancestor_has_method?(:instance, "#{name}?")
|
1595
1613
|
define_helper :instance, <<-end_eval, __FILE__, __LINE__ + 1
|
1596
1614
|
def #{name}?(*args)
|
1597
1615
|
args.empty? && #{call_super} ? super : self.class.state_machine(#{name.inspect}).states.matches?(self, *args)
|
@@ -1686,14 +1704,35 @@ module StateMachine
|
|
1686
1704
|
# action must be defined in an ancestor of the owner classs in order for
|
1687
1705
|
# it to be the action hook.
|
1688
1706
|
def action_hook
|
1689
|
-
action && owner_class_ancestor_has_method?(action) ? action : nil
|
1707
|
+
action && owner_class_ancestor_has_method?(:instance, action) ? action : nil
|
1690
1708
|
end
|
1691
1709
|
|
1692
|
-
# Determines whether
|
1693
|
-
#
|
1694
|
-
|
1695
|
-
|
1696
|
-
|
1710
|
+
# Determines whether there's already a helper method defined within the
|
1711
|
+
# given scope. This is true only if one of the owner's ancestors defines
|
1712
|
+
# the method and is further along in the ancestor chain than this
|
1713
|
+
# machine's helper module.
|
1714
|
+
def owner_class_ancestor_has_method?(scope, method)
|
1715
|
+
superclasses = owner_class.ancestors[1..-1].select {|ancestor| ancestor.is_a?(Class)}
|
1716
|
+
|
1717
|
+
if scope == :class
|
1718
|
+
# Use singleton classes
|
1719
|
+
current = (class << owner_class; self; end)
|
1720
|
+
superclass = superclasses.first
|
1721
|
+
else
|
1722
|
+
current = owner_class
|
1723
|
+
superclass = owner_class.superclass
|
1724
|
+
end
|
1725
|
+
|
1726
|
+
# Generate the list of modules that *only* occur in the owner class, but
|
1727
|
+
# were included *prior* to the helper modules, in addition to the
|
1728
|
+
# superclasses
|
1729
|
+
ancestors = current.ancestors - superclass.ancestors + superclasses
|
1730
|
+
ancestors = ancestors[ancestors.index(@helper_modules[scope]) + 1..-1].reverse
|
1731
|
+
|
1732
|
+
# Search for for the first ancestor that defined this method
|
1733
|
+
ancestors.detect do |ancestor|
|
1734
|
+
ancestor = (class << ancestor; self; end) if scope == :class && ancestor.is_a?(Class)
|
1735
|
+
ancestor.method_defined?(method) || ancestor.private_method_defined?(method)
|
1697
1736
|
end
|
1698
1737
|
end
|
1699
1738
|
|
@@ -1737,14 +1776,20 @@ module StateMachine
|
|
1737
1776
|
# Converts state names to their corresponding values so that they
|
1738
1777
|
# can be looked up properly
|
1739
1778
|
define_helper(:class, method) do |machine, klass, *states|
|
1740
|
-
|
1741
|
-
scope.call(klass, values)
|
1779
|
+
run_scope(scope, machine, klass, states)
|
1742
1780
|
end
|
1743
1781
|
end
|
1744
1782
|
end
|
1745
1783
|
end
|
1746
1784
|
end
|
1747
1785
|
|
1786
|
+
# Generates the results for the given scope based on one or more states to
|
1787
|
+
# filter by
|
1788
|
+
def run_scope(scope, machine, klass, states)
|
1789
|
+
values = states.flatten.map {|state| machine.states.fetch(state).value}
|
1790
|
+
scope.call(klass, values)
|
1791
|
+
end
|
1792
|
+
|
1748
1793
|
# Pluralizes the given word using #pluralize (if available) or simply
|
1749
1794
|
# adding an "s" to the end of the word
|
1750
1795
|
def pluralize(word)
|
data/lib/state_machine/state.rb
CHANGED
@@ -260,19 +260,11 @@ module StateMachine
|
|
260
260
|
end
|
261
261
|
|
262
262
|
# Adds a predicate method to the owner class so long as a name has
|
263
|
-
# actually been configured for the state
|
264
|
-
# defined in the owner class.
|
263
|
+
# actually been configured for the state
|
265
264
|
def add_predicate
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
# Checks whether the current value matches this state
|
270
|
-
machine.define_helper(:instance, predicate) do |machine, object|
|
271
|
-
machine.states.matches?(object, name)
|
272
|
-
end
|
273
|
-
else
|
274
|
-
# Only output a warning since we can't defined the predicate
|
275
|
-
warn "#{owner_class.name}##{predicate} is already defined, use #{owner_class.name}##{machine.name}?(:#{name}) instead."
|
265
|
+
# Checks whether the current value matches this state
|
266
|
+
machine.define_helper(:instance, "#{qualified_name}?") do |machine, object|
|
267
|
+
machine.states.matches?(object, name)
|
276
268
|
end
|
277
269
|
end
|
278
270
|
end
|
data/test/unit/event_test.rb
CHANGED
@@ -127,8 +127,68 @@ class EventWithDynamicHumanNameTest < Test::Unit::TestCase
|
|
127
127
|
end
|
128
128
|
end
|
129
129
|
|
130
|
-
class
|
130
|
+
class EventWithConflictingHelpersBeforeDefinitionTest < Test::Unit::TestCase
|
131
131
|
def setup
|
132
|
+
require 'stringio'
|
133
|
+
@original_stderr, $stderr = $stderr, StringIO.new
|
134
|
+
|
135
|
+
@superclass = Class.new do
|
136
|
+
def can_ignite?
|
137
|
+
0
|
138
|
+
end
|
139
|
+
|
140
|
+
def ignite_transition
|
141
|
+
0
|
142
|
+
end
|
143
|
+
|
144
|
+
def ignite
|
145
|
+
0
|
146
|
+
end
|
147
|
+
|
148
|
+
def ignite!
|
149
|
+
0
|
150
|
+
end
|
151
|
+
end
|
152
|
+
@klass = Class.new(@superclass)
|
153
|
+
@machine = StateMachine::Machine.new(@klass)
|
154
|
+
@machine.events << @event = StateMachine::Event.new(@machine, :ignite)
|
155
|
+
@object = @klass.new
|
156
|
+
end
|
157
|
+
|
158
|
+
def test_should_not_redefine_predicate
|
159
|
+
assert_equal 0, @object.can_ignite?
|
160
|
+
end
|
161
|
+
|
162
|
+
def test_should_not_redefine_transition_accessor
|
163
|
+
assert_equal 0, @object.ignite_transition
|
164
|
+
end
|
165
|
+
|
166
|
+
def test_should_not_redefine_action
|
167
|
+
assert_equal 0, @object.ignite
|
168
|
+
end
|
169
|
+
|
170
|
+
def test_should_not_redefine_bang_action
|
171
|
+
assert_equal 0, @object.ignite!
|
172
|
+
end
|
173
|
+
|
174
|
+
def test_should_output_warning
|
175
|
+
expected = %w(can_ignite? ignite_transition ignite ignite!).map do |method|
|
176
|
+
"Instance method \"#{method}\" is already defined in #{@superclass.to_s}, use generic helper instead.\n"
|
177
|
+
end.join
|
178
|
+
|
179
|
+
assert_equal expected, $stderr.string
|
180
|
+
end
|
181
|
+
|
182
|
+
def teardown
|
183
|
+
$stderr = @original_stderr
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
class EventWithConflictingHelpersAfterDefinitionTest < Test::Unit::TestCase
|
188
|
+
def setup
|
189
|
+
require 'stringio'
|
190
|
+
@original_stderr, $stderr = $stderr, StringIO.new
|
191
|
+
|
132
192
|
@klass = Class.new do
|
133
193
|
def can_ignite?
|
134
194
|
0
|
@@ -170,31 +230,34 @@ class EventWithConflictingHelpersTest < Test::Unit::TestCase
|
|
170
230
|
def test_should_allow_super_chaining
|
171
231
|
@klass.class_eval do
|
172
232
|
def can_ignite?
|
173
|
-
super
|
233
|
+
super
|
174
234
|
end
|
175
235
|
|
176
236
|
def ignite_transition
|
177
|
-
super
|
237
|
+
super
|
178
238
|
end
|
179
239
|
|
180
240
|
def ignite
|
181
|
-
super
|
241
|
+
super
|
182
242
|
end
|
183
243
|
|
184
244
|
def ignite!
|
185
|
-
|
186
|
-
super
|
187
|
-
1
|
188
|
-
rescue Exception => ex
|
189
|
-
0
|
190
|
-
end
|
245
|
+
super
|
191
246
|
end
|
192
247
|
end
|
193
248
|
|
194
|
-
assert_equal
|
195
|
-
assert_equal
|
196
|
-
assert_equal
|
197
|
-
|
249
|
+
assert_equal false, @object.can_ignite?
|
250
|
+
assert_equal nil, @object.ignite_transition
|
251
|
+
assert_equal false, @object.ignite
|
252
|
+
assert_raise(StateMachine::InvalidTransition) { @object.ignite! }
|
253
|
+
end
|
254
|
+
|
255
|
+
def test_should_not_output_warning
|
256
|
+
assert_equal '', $stderr.string
|
257
|
+
end
|
258
|
+
|
259
|
+
def teardown
|
260
|
+
$stderr = @original_stderr
|
198
261
|
end
|
199
262
|
end
|
200
263
|
|
@@ -20,11 +20,11 @@ module SequelTest
|
|
20
20
|
def new_model(create_table = :foo, &block)
|
21
21
|
table_name = create_table || :foo
|
22
22
|
|
23
|
-
DB.create_table!(table_name) do
|
23
|
+
DB.create_table!(::Sequel::SQL::Identifier.new(table_name)) do
|
24
24
|
primary_key :id
|
25
25
|
column :state, :string
|
26
26
|
end if create_table
|
27
|
-
model = Class.new(Sequel::Model(table_name)) do
|
27
|
+
model = Class.new(Sequel::Model(DB[::Sequel::SQL::Identifier.new(table_name)])) do
|
28
28
|
self.raise_on_save_failure = false
|
29
29
|
(class << self; self; end).class_eval do
|
30
30
|
define_method(:name) { "SequelTest::#{table_name.to_s.capitalize}" }
|
@@ -1426,7 +1426,19 @@ module SequelTest
|
|
1426
1426
|
parked = @model.create :state => 'parked'
|
1427
1427
|
idling = @model.create :state => 'idling'
|
1428
1428
|
|
1429
|
-
assert_equal [idling], @model.without_state(:parked).
|
1429
|
+
assert_equal [idling], @model.without_state(:parked).with_state(:idling).all
|
1430
|
+
end
|
1431
|
+
|
1432
|
+
def test_should_run_on_tables_with_double_underscores
|
1433
|
+
@model = new_model(:foo__bar)
|
1434
|
+
@machine = StateMachine::Machine.new(@model)
|
1435
|
+
@machine.state :parked, :first_gear
|
1436
|
+
@machine.state :idling, :value => lambda {'idling'}
|
1437
|
+
|
1438
|
+
parked = @model.create :state => 'parked'
|
1439
|
+
idling = @model.create :state => 'idling'
|
1440
|
+
|
1441
|
+
assert_equal [parked], @model.with_state(:parked).all
|
1430
1442
|
end
|
1431
1443
|
end
|
1432
1444
|
|
data/test/unit/machine_test.rb
CHANGED
@@ -1114,6 +1114,104 @@ class MachineWithInstanceHelpersTest < Test::Unit::TestCase
|
|
1114
1114
|
assert_equal 'parked', @object.send(:state)
|
1115
1115
|
end
|
1116
1116
|
|
1117
|
+
def test_should_warn_if_defined_in_superclass
|
1118
|
+
require 'stringio'
|
1119
|
+
@original_stderr, $stderr = $stderr, StringIO.new
|
1120
|
+
|
1121
|
+
superclass = Class.new do
|
1122
|
+
def park
|
1123
|
+
end
|
1124
|
+
end
|
1125
|
+
klass = Class.new(superclass)
|
1126
|
+
machine = StateMachine::Machine.new(klass)
|
1127
|
+
|
1128
|
+
machine.define_helper(:instance, :park) {}
|
1129
|
+
assert_equal "Instance method \"park\" is already defined in #{superclass.to_s}, use generic helper instead.\n", $stderr.string
|
1130
|
+
ensure
|
1131
|
+
$stderr = @original_stderr
|
1132
|
+
end
|
1133
|
+
|
1134
|
+
def test_should_warn_if_defined_in_multiple_superclasses
|
1135
|
+
require 'stringio'
|
1136
|
+
@original_stderr, $stderr = $stderr, StringIO.new
|
1137
|
+
|
1138
|
+
superclass1 = Class.new do
|
1139
|
+
def park
|
1140
|
+
end
|
1141
|
+
end
|
1142
|
+
superclass2 = Class.new(superclass1) do
|
1143
|
+
def park
|
1144
|
+
end
|
1145
|
+
end
|
1146
|
+
klass = Class.new(superclass2)
|
1147
|
+
machine = StateMachine::Machine.new(klass)
|
1148
|
+
|
1149
|
+
machine.define_helper(:instance, :park) {}
|
1150
|
+
assert_equal "Instance method \"park\" is already defined in #{superclass1.to_s}, use generic helper instead.\n", $stderr.string
|
1151
|
+
ensure
|
1152
|
+
$stderr = @original_stderr
|
1153
|
+
end
|
1154
|
+
|
1155
|
+
def test_should_warn_if_defined_in_module_prior_to_helper_module
|
1156
|
+
require 'stringio'
|
1157
|
+
@original_stderr, $stderr = $stderr, StringIO.new
|
1158
|
+
|
1159
|
+
mod = Module.new do
|
1160
|
+
def park
|
1161
|
+
end
|
1162
|
+
end
|
1163
|
+
klass = Class.new do
|
1164
|
+
include mod
|
1165
|
+
end
|
1166
|
+
machine = StateMachine::Machine.new(klass)
|
1167
|
+
|
1168
|
+
machine.define_helper(:instance, :park) {}
|
1169
|
+
assert_equal "Instance method \"park\" is already defined in #{mod.to_s}, use generic helper instead.\n", $stderr.string
|
1170
|
+
ensure
|
1171
|
+
$stderr = @original_stderr
|
1172
|
+
end
|
1173
|
+
|
1174
|
+
def test_should_not_warn_if_defined_in_module_after_helper_module
|
1175
|
+
require 'stringio'
|
1176
|
+
@original_stderr, $stderr = $stderr, StringIO.new
|
1177
|
+
|
1178
|
+
klass = Class.new
|
1179
|
+
machine = StateMachine::Machine.new(klass)
|
1180
|
+
|
1181
|
+
mod = Module.new do
|
1182
|
+
def park
|
1183
|
+
end
|
1184
|
+
end
|
1185
|
+
klass.class_eval do
|
1186
|
+
include mod
|
1187
|
+
end
|
1188
|
+
|
1189
|
+
machine.define_helper(:instance, :park) {}
|
1190
|
+
assert_equal '', $stderr.string
|
1191
|
+
ensure
|
1192
|
+
$stderr = @original_stderr
|
1193
|
+
end
|
1194
|
+
|
1195
|
+
def test_should_define_if_ignoring_method_conflicts_and_defined_in_superclass
|
1196
|
+
require 'stringio'
|
1197
|
+
@original_stderr, $stderr = $stderr, StringIO.new
|
1198
|
+
StateMachine::Machine.ignore_method_conflicts = true
|
1199
|
+
|
1200
|
+
superclass = Class.new do
|
1201
|
+
def park
|
1202
|
+
end
|
1203
|
+
end
|
1204
|
+
klass = Class.new(superclass)
|
1205
|
+
machine = StateMachine::Machine.new(klass)
|
1206
|
+
|
1207
|
+
machine.define_helper(:instance, :park) {true}
|
1208
|
+
assert_equal '', $stderr.string
|
1209
|
+
assert_equal true, klass.new.park
|
1210
|
+
ensure
|
1211
|
+
StateMachine::Machine.ignore_method_conflicts = false
|
1212
|
+
$stderr = @original_stderr
|
1213
|
+
end
|
1214
|
+
|
1117
1215
|
def test_should_define_nonexistent_methods
|
1118
1216
|
@machine.define_helper(:instance, :state) {'parked'}
|
1119
1217
|
assert_equal 'parked', @object.state
|
@@ -1186,6 +1284,104 @@ class MachineWithClassHelpersTest < Test::Unit::TestCase
|
|
1186
1284
|
assert_equal [], @klass.send(:states)
|
1187
1285
|
end
|
1188
1286
|
|
1287
|
+
def test_should_warn_if_defined_in_superclass
|
1288
|
+
require 'stringio'
|
1289
|
+
@original_stderr, $stderr = $stderr, StringIO.new
|
1290
|
+
|
1291
|
+
superclass = Class.new do
|
1292
|
+
def self.park
|
1293
|
+
end
|
1294
|
+
end
|
1295
|
+
klass = Class.new(superclass)
|
1296
|
+
machine = StateMachine::Machine.new(klass)
|
1297
|
+
|
1298
|
+
machine.define_helper(:class, :park) {}
|
1299
|
+
assert_equal "Class method \"park\" is already defined in #{superclass.to_s}, use generic helper instead.\n", $stderr.string
|
1300
|
+
ensure
|
1301
|
+
$stderr = @original_stderr
|
1302
|
+
end
|
1303
|
+
|
1304
|
+
def test_should_warn_if_defined_in_multiple_superclasses
|
1305
|
+
require 'stringio'
|
1306
|
+
@original_stderr, $stderr = $stderr, StringIO.new
|
1307
|
+
|
1308
|
+
superclass1 = Class.new do
|
1309
|
+
def self.park
|
1310
|
+
end
|
1311
|
+
end
|
1312
|
+
superclass2 = Class.new(superclass1) do
|
1313
|
+
def self.park
|
1314
|
+
end
|
1315
|
+
end
|
1316
|
+
klass = Class.new(superclass2)
|
1317
|
+
machine = StateMachine::Machine.new(klass)
|
1318
|
+
|
1319
|
+
machine.define_helper(:class, :park) {}
|
1320
|
+
assert_equal "Class method \"park\" is already defined in #{superclass1.to_s}, use generic helper instead.\n", $stderr.string
|
1321
|
+
ensure
|
1322
|
+
$stderr = @original_stderr
|
1323
|
+
end
|
1324
|
+
|
1325
|
+
def test_should_warn_if_defined_in_module_prior_to_helper_module
|
1326
|
+
require 'stringio'
|
1327
|
+
@original_stderr, $stderr = $stderr, StringIO.new
|
1328
|
+
|
1329
|
+
mod = Module.new do
|
1330
|
+
def park
|
1331
|
+
end
|
1332
|
+
end
|
1333
|
+
klass = Class.new do
|
1334
|
+
extend mod
|
1335
|
+
end
|
1336
|
+
machine = StateMachine::Machine.new(klass)
|
1337
|
+
|
1338
|
+
machine.define_helper(:class, :park) {}
|
1339
|
+
assert_equal "Class method \"park\" is already defined in #{mod.to_s}, use generic helper instead.\n", $stderr.string
|
1340
|
+
ensure
|
1341
|
+
$stderr = @original_stderr
|
1342
|
+
end
|
1343
|
+
|
1344
|
+
def test_should_not_warn_if_defined_in_module_after_helper_module
|
1345
|
+
require 'stringio'
|
1346
|
+
@original_stderr, $stderr = $stderr, StringIO.new
|
1347
|
+
|
1348
|
+
klass = Class.new
|
1349
|
+
machine = StateMachine::Machine.new(klass)
|
1350
|
+
|
1351
|
+
mod = Module.new do
|
1352
|
+
def park
|
1353
|
+
end
|
1354
|
+
end
|
1355
|
+
klass.class_eval do
|
1356
|
+
extend mod
|
1357
|
+
end
|
1358
|
+
|
1359
|
+
machine.define_helper(:class, :park) {}
|
1360
|
+
assert_equal '', $stderr.string
|
1361
|
+
ensure
|
1362
|
+
$stderr = @original_stderr
|
1363
|
+
end
|
1364
|
+
|
1365
|
+
def test_should_define_if_ignoring_method_conflicts_and_defined_in_superclass
|
1366
|
+
require 'stringio'
|
1367
|
+
@original_stderr, $stderr = $stderr, StringIO.new
|
1368
|
+
StateMachine::Machine.ignore_method_conflicts = true
|
1369
|
+
|
1370
|
+
superclass = Class.new do
|
1371
|
+
def self.park
|
1372
|
+
end
|
1373
|
+
end
|
1374
|
+
klass = Class.new(superclass)
|
1375
|
+
machine = StateMachine::Machine.new(klass)
|
1376
|
+
|
1377
|
+
machine.define_helper(:class, :park) {true}
|
1378
|
+
assert_equal '', $stderr.string
|
1379
|
+
assert_equal true, klass.park
|
1380
|
+
ensure
|
1381
|
+
StateMachine::Machine.ignore_method_conflicts = false
|
1382
|
+
$stderr = @original_stderr
|
1383
|
+
end
|
1384
|
+
|
1189
1385
|
def test_should_define_nonexistent_methods
|
1190
1386
|
@machine.define_helper(:class, :states) {[]}
|
1191
1387
|
assert_equal [], @klass.states
|
@@ -1217,8 +1413,176 @@ class MachineWithClassHelpersTest < Test::Unit::TestCase
|
|
1217
1413
|
end
|
1218
1414
|
end
|
1219
1415
|
|
1220
|
-
class
|
1416
|
+
class MachineWithConflictingHelpersBeforeDefinitionTest < Test::Unit::TestCase
|
1417
|
+
def setup
|
1418
|
+
require 'stringio'
|
1419
|
+
@original_stderr, $stderr = $stderr, StringIO.new
|
1420
|
+
|
1421
|
+
@superclass = Class.new do
|
1422
|
+
def self.with_state
|
1423
|
+
:with_state
|
1424
|
+
end
|
1425
|
+
|
1426
|
+
def self.with_states
|
1427
|
+
:with_states
|
1428
|
+
end
|
1429
|
+
|
1430
|
+
def self.without_state
|
1431
|
+
:without_state
|
1432
|
+
end
|
1433
|
+
|
1434
|
+
def self.without_states
|
1435
|
+
:without_states
|
1436
|
+
end
|
1437
|
+
|
1438
|
+
def self.human_state_name
|
1439
|
+
:human_state_name
|
1440
|
+
end
|
1441
|
+
|
1442
|
+
def self.human_state_event_name
|
1443
|
+
:human_state_event_name
|
1444
|
+
end
|
1445
|
+
|
1446
|
+
attr_accessor :status
|
1447
|
+
|
1448
|
+
def state
|
1449
|
+
'parked'
|
1450
|
+
end
|
1451
|
+
|
1452
|
+
def state=(value)
|
1453
|
+
self.status = value
|
1454
|
+
end
|
1455
|
+
|
1456
|
+
def state?
|
1457
|
+
true
|
1458
|
+
end
|
1459
|
+
|
1460
|
+
def state_name
|
1461
|
+
:parked
|
1462
|
+
end
|
1463
|
+
|
1464
|
+
def human_state_name
|
1465
|
+
'parked'
|
1466
|
+
end
|
1467
|
+
|
1468
|
+
def state_events
|
1469
|
+
[:ignite]
|
1470
|
+
end
|
1471
|
+
|
1472
|
+
def state_transitions
|
1473
|
+
[{:parked => :idling}]
|
1474
|
+
end
|
1475
|
+
|
1476
|
+
def state_paths
|
1477
|
+
[[{:parked => :idling}]]
|
1478
|
+
end
|
1479
|
+
end
|
1480
|
+
@klass = Class.new(@superclass)
|
1481
|
+
|
1482
|
+
StateMachine::Integrations.const_set('Custom', Module.new do
|
1483
|
+
include StateMachine::Integrations::Base
|
1484
|
+
|
1485
|
+
def create_with_scope(name)
|
1486
|
+
lambda {|klass, values| []}
|
1487
|
+
end
|
1488
|
+
|
1489
|
+
def create_without_scope(name)
|
1490
|
+
lambda {|klass, values| []}
|
1491
|
+
end
|
1492
|
+
end)
|
1493
|
+
|
1494
|
+
@machine = StateMachine::Machine.new(@klass, :integration => :custom)
|
1495
|
+
@machine.state :parked, :idling
|
1496
|
+
@machine.event :ignite
|
1497
|
+
@object = @klass.new
|
1498
|
+
end
|
1499
|
+
|
1500
|
+
def test_should_not_redefine_singular_with_scope
|
1501
|
+
assert_equal :with_state, @klass.with_state
|
1502
|
+
end
|
1503
|
+
|
1504
|
+
def test_should_not_redefine_plural_with_scope
|
1505
|
+
assert_equal :with_states, @klass.with_states
|
1506
|
+
end
|
1507
|
+
|
1508
|
+
def test_should_not_redefine_singular_without_scope
|
1509
|
+
assert_equal :without_state, @klass.without_state
|
1510
|
+
end
|
1511
|
+
|
1512
|
+
def test_should_not_redefine_plural_without_scope
|
1513
|
+
assert_equal :without_states, @klass.without_states
|
1514
|
+
end
|
1515
|
+
|
1516
|
+
def test_should_not_redefine_human_attribute_name_reader
|
1517
|
+
assert_equal :human_state_name, @klass.human_state_name
|
1518
|
+
end
|
1519
|
+
|
1520
|
+
def test_should_not_redefine_human_event_name_reader
|
1521
|
+
assert_equal :human_state_event_name, @klass.human_state_event_name
|
1522
|
+
end
|
1523
|
+
|
1524
|
+
def test_should_not_redefine_attribute_writer
|
1525
|
+
assert_equal 'parked', @object.state
|
1526
|
+
end
|
1527
|
+
|
1528
|
+
def test_should_not_redefine_attribute_writer
|
1529
|
+
@object.state = 'parked'
|
1530
|
+
assert_equal 'parked', @object.status
|
1531
|
+
end
|
1532
|
+
|
1533
|
+
def test_should_not_define_attribute_predicate
|
1534
|
+
assert @object.state?
|
1535
|
+
end
|
1536
|
+
|
1537
|
+
def test_should_not_redefine_attribute_name_reader
|
1538
|
+
assert_equal :parked, @object.state_name
|
1539
|
+
end
|
1540
|
+
|
1541
|
+
def test_should_not_redefine_attribute_human_name_reader
|
1542
|
+
assert_equal 'parked', @object.human_state_name
|
1543
|
+
end
|
1544
|
+
|
1545
|
+
def test_should_not_redefine_attribute_events_reader
|
1546
|
+
assert_equal [:ignite], @object.state_events
|
1547
|
+
end
|
1548
|
+
|
1549
|
+
def test_should_not_redefine_attribute_transitions_reader
|
1550
|
+
assert_equal [{:parked => :idling}], @object.state_transitions
|
1551
|
+
end
|
1552
|
+
|
1553
|
+
def test_should_not_redefine_attribute_paths_reader
|
1554
|
+
assert_equal [[{:parked => :idling}]], @object.state_paths
|
1555
|
+
end
|
1556
|
+
|
1557
|
+
def test_should_output_warning
|
1558
|
+
expected = [
|
1559
|
+
'Instance method "state_events"',
|
1560
|
+
'Instance method "state_transitions"',
|
1561
|
+
'Instance method "state_paths"',
|
1562
|
+
'Class method "human_state_name"',
|
1563
|
+
'Class method "human_state_event_name"',
|
1564
|
+
'Instance method "state_name"',
|
1565
|
+
'Instance method "human_state_name"',
|
1566
|
+
'Class method "with_state"',
|
1567
|
+
'Class method "without_state"',
|
1568
|
+
'Class method "with_states"',
|
1569
|
+
'Class method "without_states"'
|
1570
|
+
].map {|method| "#{method} is already defined in #{@superclass.to_s}, use generic helper instead.\n"}.join
|
1571
|
+
|
1572
|
+
assert_equal expected, $stderr.string
|
1573
|
+
end
|
1574
|
+
|
1575
|
+
def teardown
|
1576
|
+
$stderr = @original_stderr
|
1577
|
+
StateMachine::Integrations.send(:remove_const, 'Custom')
|
1578
|
+
end
|
1579
|
+
end
|
1580
|
+
|
1581
|
+
class MachineWithConflictingHelpersAfterDefinitionTest < Test::Unit::TestCase
|
1221
1582
|
def setup
|
1583
|
+
require 'stringio'
|
1584
|
+
@original_stderr, $stderr = $stderr, StringIO.new
|
1585
|
+
|
1222
1586
|
@klass = Class.new do
|
1223
1587
|
def self.with_state
|
1224
1588
|
:with_state
|
@@ -1357,84 +1721,89 @@ class MachineWithConflictingHelpersTest < Test::Unit::TestCase
|
|
1357
1721
|
def test_should_allow_super_chaining
|
1358
1722
|
@klass.class_eval do
|
1359
1723
|
def self.with_state(*states)
|
1360
|
-
super
|
1724
|
+
super
|
1361
1725
|
end
|
1362
1726
|
|
1363
1727
|
def self.with_states(*states)
|
1364
|
-
super
|
1728
|
+
super
|
1365
1729
|
end
|
1366
1730
|
|
1367
1731
|
def self.without_state(*states)
|
1368
|
-
super
|
1732
|
+
super
|
1369
1733
|
end
|
1370
1734
|
|
1371
1735
|
def self.without_states(*states)
|
1372
|
-
super
|
1736
|
+
super
|
1373
1737
|
end
|
1374
1738
|
|
1375
1739
|
def self.human_state_name(state)
|
1376
|
-
super
|
1740
|
+
super
|
1377
1741
|
end
|
1378
1742
|
|
1379
1743
|
def self.human_state_event_name(event)
|
1380
|
-
super
|
1744
|
+
super
|
1381
1745
|
end
|
1382
1746
|
|
1383
1747
|
attr_accessor :status
|
1384
1748
|
|
1385
1749
|
def state
|
1386
|
-
super
|
1750
|
+
super
|
1387
1751
|
end
|
1388
1752
|
|
1389
1753
|
def state=(value)
|
1390
1754
|
super
|
1391
|
-
self.status = value
|
1392
1755
|
end
|
1393
1756
|
|
1394
1757
|
def state?(state)
|
1395
|
-
super
|
1758
|
+
super
|
1396
1759
|
end
|
1397
1760
|
|
1398
1761
|
def state_name
|
1399
|
-
super
|
1762
|
+
super
|
1400
1763
|
end
|
1401
1764
|
|
1402
1765
|
def human_state_name
|
1403
|
-
super
|
1766
|
+
super
|
1404
1767
|
end
|
1405
1768
|
|
1406
1769
|
def state_events
|
1407
|
-
super
|
1770
|
+
super
|
1408
1771
|
end
|
1409
1772
|
|
1410
1773
|
def state_transitions
|
1411
|
-
super
|
1774
|
+
super
|
1412
1775
|
end
|
1413
1776
|
|
1414
1777
|
def state_paths
|
1415
|
-
super
|
1778
|
+
super
|
1416
1779
|
end
|
1417
1780
|
end
|
1418
1781
|
|
1419
|
-
assert_equal
|
1420
|
-
assert_equal
|
1421
|
-
assert_equal
|
1422
|
-
assert_equal
|
1423
|
-
assert_equal
|
1424
|
-
assert_equal
|
1782
|
+
assert_equal [], @klass.with_state
|
1783
|
+
assert_equal [], @klass.with_states
|
1784
|
+
assert_equal [], @klass.without_state
|
1785
|
+
assert_equal [], @klass.without_states
|
1786
|
+
assert_equal 'parked', @klass.human_state_name(:parked)
|
1787
|
+
assert_equal 'ignite', @klass.human_state_event_name(:ignite)
|
1425
1788
|
|
1426
|
-
assert_equal
|
1789
|
+
assert_equal nil, @object.state
|
1427
1790
|
@object.state = 'idling'
|
1428
|
-
assert_equal 'idling', @object.
|
1429
|
-
assert_equal
|
1430
|
-
assert_equal
|
1431
|
-
assert_equal
|
1432
|
-
assert_equal
|
1433
|
-
assert_equal
|
1434
|
-
assert_equal
|
1791
|
+
assert_equal 'idling', @object.state
|
1792
|
+
assert_equal nil, @object.status
|
1793
|
+
assert_equal false, @object.state?(:parked)
|
1794
|
+
assert_equal :idling, @object.state_name
|
1795
|
+
assert_equal 'idling', @object.human_state_name
|
1796
|
+
assert_equal [], @object.state_events
|
1797
|
+
assert_equal [], @object.state_transitions
|
1798
|
+
assert_equal [], @object.state_paths
|
1799
|
+
end
|
1800
|
+
|
1801
|
+
def test_should_not_output_warning
|
1802
|
+
assert_equal '', $stderr.string
|
1435
1803
|
end
|
1436
1804
|
|
1437
1805
|
def teardown
|
1806
|
+
$stderr = @original_stderr
|
1438
1807
|
StateMachine::Integrations.send(:remove_const, 'Custom')
|
1439
1808
|
end
|
1440
1809
|
end
|
data/test/unit/state_test.rb
CHANGED
@@ -458,7 +458,36 @@ class StateNotFinalTest < Test::Unit::TestCase
|
|
458
458
|
end
|
459
459
|
end
|
460
460
|
|
461
|
-
class
|
461
|
+
class StateWithConflictingHelpersBeforeDefinitionTest < Test::Unit::TestCase
|
462
|
+
def setup
|
463
|
+
require 'stringio'
|
464
|
+
@original_stderr, $stderr = $stderr, StringIO.new
|
465
|
+
|
466
|
+
@superclass = Class.new do
|
467
|
+
def parked?
|
468
|
+
0
|
469
|
+
end
|
470
|
+
end
|
471
|
+
@klass = Class.new(@superclass)
|
472
|
+
@machine = StateMachine::Machine.new(@klass)
|
473
|
+
@machine.state :parked
|
474
|
+
@object = @klass.new
|
475
|
+
end
|
476
|
+
|
477
|
+
def test_should_not_override_state_predicate
|
478
|
+
assert_equal 0, @object.parked?
|
479
|
+
end
|
480
|
+
|
481
|
+
def test_should_output_warning
|
482
|
+
assert_equal "Instance method \"parked?\" is already defined in #{@superclass.to_s}, use generic helper instead.\n", $stderr.string
|
483
|
+
end
|
484
|
+
|
485
|
+
def teardown
|
486
|
+
$stderr = @original_stderr
|
487
|
+
end
|
488
|
+
end
|
489
|
+
|
490
|
+
class StateWithConflictingHelpersAfterDefinitionTest < Test::Unit::TestCase
|
462
491
|
def setup
|
463
492
|
require 'stringio'
|
464
493
|
@original_stderr, $stderr = $stderr, StringIO.new
|
@@ -477,18 +506,18 @@ class StateWithConflictingHelpersTest < Test::Unit::TestCase
|
|
477
506
|
assert_equal 0, @object.parked?
|
478
507
|
end
|
479
508
|
|
480
|
-
def
|
509
|
+
def test_should_still_allow_super_chaining
|
481
510
|
@klass.class_eval do
|
482
511
|
def parked?
|
483
|
-
super
|
512
|
+
super
|
484
513
|
end
|
485
514
|
end
|
486
515
|
|
487
|
-
|
516
|
+
assert_equal false, @object.parked?
|
488
517
|
end
|
489
518
|
|
490
|
-
def
|
491
|
-
assert_equal
|
519
|
+
def test_should_not_output_warning
|
520
|
+
assert_equal '', $stderr.string
|
492
521
|
end
|
493
522
|
|
494
523
|
def teardown
|
@@ -496,7 +525,7 @@ class StateWithConflictingHelpersTest < Test::Unit::TestCase
|
|
496
525
|
end
|
497
526
|
end
|
498
527
|
|
499
|
-
class
|
528
|
+
class StateWithConflictingMachineTest < Test::Unit::TestCase
|
500
529
|
def setup
|
501
530
|
require 'stringio'
|
502
531
|
@original_stderr, $stderr = $stderr, StringIO.new
|
@@ -1508,7 +1508,7 @@ class TransitionEqualityTest < Test::Unit::TestCase
|
|
1508
1508
|
end
|
1509
1509
|
|
1510
1510
|
def test_should_not_be_equal_with_different_machines
|
1511
|
-
machine = StateMachine::Machine.new(@klass, :namespace => :other)
|
1511
|
+
machine = StateMachine::Machine.new(@klass, :status, :namespace => :other)
|
1512
1512
|
machine.state :parked, :idling
|
1513
1513
|
machine.event :ignite
|
1514
1514
|
transition = StateMachine::Transition.new(@object, machine, :ignite, :parked, :idling)
|
metadata
CHANGED
@@ -1,33 +1,23 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: state_machine
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
5
|
-
prerelease:
|
6
|
-
segments:
|
7
|
-
- 1
|
8
|
-
- 0
|
9
|
-
- 0
|
10
|
-
version: 1.0.0
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.1
|
5
|
+
prerelease:
|
11
6
|
platform: ruby
|
12
|
-
authors:
|
7
|
+
authors:
|
13
8
|
- Aaron Pfeifer
|
14
9
|
autorequire:
|
15
10
|
bindir: bin
|
16
11
|
cert_chain: []
|
17
|
-
|
18
|
-
date: 2011-05-12 00:00:00 -04:00
|
12
|
+
date: 2011-05-30 00:00:00.000000000 -04:00
|
19
13
|
default_executable:
|
20
14
|
dependencies: []
|
21
|
-
|
22
15
|
description: Adds support for creating state machines for attributes on any Ruby class
|
23
16
|
email: aaron@pluginaweek.org
|
24
17
|
executables: []
|
25
|
-
|
26
18
|
extensions: []
|
27
|
-
|
28
19
|
extra_rdoc_files: []
|
29
|
-
|
30
|
-
files:
|
20
|
+
files:
|
31
21
|
- examples/car.rb
|
32
22
|
- examples/TrafficLight_state.png
|
33
23
|
- examples/vehicle.rb
|
@@ -138,38 +128,29 @@ files:
|
|
138
128
|
has_rdoc: true
|
139
129
|
homepage: http://www.pluginaweek.org
|
140
130
|
licenses: []
|
141
|
-
|
142
131
|
post_install_message:
|
143
132
|
rdoc_options: []
|
144
|
-
|
145
|
-
require_paths:
|
133
|
+
require_paths:
|
146
134
|
- lib
|
147
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
135
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
148
136
|
none: false
|
149
|
-
requirements:
|
150
|
-
- -
|
151
|
-
- !ruby/object:Gem::Version
|
152
|
-
|
153
|
-
|
154
|
-
- 0
|
155
|
-
version: "0"
|
156
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
137
|
+
requirements:
|
138
|
+
- - ! '>='
|
139
|
+
- !ruby/object:Gem::Version
|
140
|
+
version: '0'
|
141
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
157
142
|
none: false
|
158
|
-
requirements:
|
159
|
-
- -
|
160
|
-
- !ruby/object:Gem::Version
|
161
|
-
|
162
|
-
segments:
|
163
|
-
- 0
|
164
|
-
version: "0"
|
143
|
+
requirements:
|
144
|
+
- - ! '>='
|
145
|
+
- !ruby/object:Gem::Version
|
146
|
+
version: '0'
|
165
147
|
requirements: []
|
166
|
-
|
167
148
|
rubyforge_project: pluginaweek
|
168
|
-
rubygems_version: 1.
|
149
|
+
rubygems_version: 1.6.2
|
169
150
|
signing_key:
|
170
151
|
specification_version: 3
|
171
152
|
summary: Adds support for creating state machines for attributes on any Ruby class
|
172
|
-
test_files:
|
153
|
+
test_files:
|
173
154
|
- test/unit/path_test.rb
|
174
155
|
- test/unit/condition_proxy_test.rb
|
175
156
|
- test/unit/state_machine_test.rb
|