anthonyw-simple_state 0.1.1 → 0.1.2
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/Rakefile +58 -0
- data/VERSION.yml +4 -0
- data/lib/simple_state/builder.rb +117 -0
- data/lib/simple_state/mixins.rb +65 -0
- data/lib/simple_state.rb +14 -0
- data/spec/builder_spec.rb +71 -0
- data/spec/event_methods_spec.rb +199 -0
- data/spec/mixins_spec.rb +47 -0
- data/spec/predicate_methods_spec.rb +20 -0
- data/spec/simple_state_spec.rb +10 -0
- data/spec/spec_helper.rb +16 -0
- metadata +14 -2
data/Rakefile
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'spec/rake/spectask'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "simple_state"
|
8
|
+
gem.platform = Gem::Platform::RUBY
|
9
|
+
gem.summary = 'A *very simple* state machine implementation.'
|
10
|
+
gem.description = gem.summary
|
11
|
+
gem.email = "anthony@ninecraft.com"
|
12
|
+
gem.homepage = "http://github.com/anthonyw/simple_state"
|
13
|
+
gem.authors = ["Anthony Williams"]
|
14
|
+
|
15
|
+
gem.extra_rdoc_files = %w(README.markdown LICENSE)
|
16
|
+
|
17
|
+
gem.files = %w(LICENSE README.markdown Rakefile VERSION.yml) +
|
18
|
+
Dir.glob("{lib,spec}/**/*")
|
19
|
+
end
|
20
|
+
rescue LoadError
|
21
|
+
puts "Jeweler not available. Install it with: sudo gem install " \
|
22
|
+
"technicalpickles-jeweler -s http://gems.github.com"
|
23
|
+
end
|
24
|
+
|
25
|
+
# rDoc =======================================================================
|
26
|
+
|
27
|
+
require 'rake/rdoctask'
|
28
|
+
Rake::RDocTask.new do |rdoc|
|
29
|
+
rdoc.rdoc_dir = 'rdoc'
|
30
|
+
rdoc.title = 'simple_state'
|
31
|
+
rdoc.options << '--line-numbers' << '--inline-source'
|
32
|
+
rdoc.rdoc_files.include('README*')
|
33
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
34
|
+
end
|
35
|
+
|
36
|
+
# rSpec & rcov ===============================================================
|
37
|
+
|
38
|
+
desc "Run all examples (or a specific spec with TASK=xxxx)"
|
39
|
+
Spec::Rake::SpecTask.new('spec') do |t|
|
40
|
+
t.spec_opts = ["-c -f s"]
|
41
|
+
t.spec_files = begin
|
42
|
+
if ENV["TASK"]
|
43
|
+
ENV["TASK"].split(',').map { |task| "spec/**/#{task}_spec.rb" }
|
44
|
+
else
|
45
|
+
FileList['spec/**/*_spec.rb']
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
desc "Run all examples with RCov"
|
51
|
+
Spec::Rake::SpecTask.new('spec:rcov') do |t|
|
52
|
+
t.spec_files = FileList['spec/**/*.rb']
|
53
|
+
t.spec_opts = ['-c -f s']
|
54
|
+
t.rcov = true
|
55
|
+
t.rcov_opts = ['--exclude', 'spec']
|
56
|
+
end
|
57
|
+
|
58
|
+
task :default => :spec
|
data/VERSION.yml
ADDED
@@ -0,0 +1,117 @@
|
|
1
|
+
module SimpleState
|
2
|
+
##
|
3
|
+
# Responsible for taking a state machine block and building the methods.
|
4
|
+
#
|
5
|
+
# The builder is run whenever you call +state_machine+ on a class and does
|
6
|
+
# a number of things.
|
7
|
+
#
|
8
|
+
# * Firstly, it adds a :state reader if one is not defined, and a
|
9
|
+
# _private_ :state writer.
|
10
|
+
#
|
11
|
+
# * It adds a +states+ method to the class, used for easily accessing
|
12
|
+
# the list of states for the class, and the events belonging to each
|
13
|
+
# state (and the state that the event transitions to).
|
14
|
+
#
|
15
|
+
# * Four internal methods +initial_state+, +initial_state=+,
|
16
|
+
# +_determine_new_state+ and +_valid_transition+ which are used
|
17
|
+
# internally by SimpleState for aiding the transition from one state to
|
18
|
+
# another.
|
19
|
+
#
|
20
|
+
class Builder
|
21
|
+
def initialize(klass)
|
22
|
+
@klass = klass
|
23
|
+
end
|
24
|
+
|
25
|
+
##
|
26
|
+
# Trigger for building the state machine methods.
|
27
|
+
#
|
28
|
+
def build(&blk)
|
29
|
+
@klass.class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
30
|
+
include ::SimpleState::Mixins
|
31
|
+
RUBY
|
32
|
+
|
33
|
+
instance_eval(&blk)
|
34
|
+
end
|
35
|
+
|
36
|
+
##
|
37
|
+
# Defines a new state.
|
38
|
+
#
|
39
|
+
# @param [Symbol] name
|
40
|
+
# The name of the state.
|
41
|
+
# @param [Block] &blk
|
42
|
+
# An optional block for defining transitions for the state. If no block
|
43
|
+
# is given, the state will be an end-point.
|
44
|
+
#
|
45
|
+
def state(name, &blk)
|
46
|
+
@klass.states[name] = []
|
47
|
+
@klass.initial_state ||= name
|
48
|
+
|
49
|
+
@klass.class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
50
|
+
def #{name}? # def prepared?
|
51
|
+
self.state == :#{name} # self.state == :prepared
|
52
|
+
end # end
|
53
|
+
RUBY
|
54
|
+
|
55
|
+
# Define transitions for this state.
|
56
|
+
StateBuilder.new(@klass, name).build(&blk) if blk
|
57
|
+
end
|
58
|
+
|
59
|
+
##
|
60
|
+
# Responsible for building events for a given state.
|
61
|
+
#
|
62
|
+
class StateBuilder
|
63
|
+
def initialize(klass, state)
|
64
|
+
@klass, @state = klass, state
|
65
|
+
end
|
66
|
+
|
67
|
+
##
|
68
|
+
# Specialises a state by defining events.
|
69
|
+
#
|
70
|
+
# @param [Block] &blk
|
71
|
+
# An block for defining transitions for the state.
|
72
|
+
#
|
73
|
+
def build(&blk)
|
74
|
+
instance_eval(&blk)
|
75
|
+
end
|
76
|
+
|
77
|
+
##
|
78
|
+
# Defines an event and transition.
|
79
|
+
#
|
80
|
+
# @param [Symbol] event_name A name for this event.
|
81
|
+
# @param [Hash] opts An options hash for customising the event.
|
82
|
+
#
|
83
|
+
def event(event, opts = {})
|
84
|
+
unless opts[:transitions_to].kind_of?(Symbol)
|
85
|
+
raise ArgumentError, 'You must declare a :transitions_to state ' \
|
86
|
+
'when defining events'
|
87
|
+
end
|
88
|
+
|
89
|
+
# Keep track of valid transitions for this state.
|
90
|
+
@klass.states[@state].push([event, opts[:transitions_to]])
|
91
|
+
|
92
|
+
unless @klass.method_defined?(:"#{event}!")
|
93
|
+
# Example:
|
94
|
+
#
|
95
|
+
# def process!
|
96
|
+
# if self.class._valid_transition?(self.state, :process)
|
97
|
+
# self.state =
|
98
|
+
# self.class._determine_new_state(self.state, :process)
|
99
|
+
# else
|
100
|
+
# false
|
101
|
+
# end
|
102
|
+
# end
|
103
|
+
@klass.class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
104
|
+
def #{event}!
|
105
|
+
if self.class._valid_transition?(self.state, :#{event})
|
106
|
+
self.state =
|
107
|
+
self.class._determine_new_state(self.state, :#{event})
|
108
|
+
else
|
109
|
+
false
|
110
|
+
end
|
111
|
+
end
|
112
|
+
RUBY
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
module SimpleState
|
2
|
+
module Mixins
|
3
|
+
def self.included(klass)
|
4
|
+
klass.class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
5
|
+
attr_reader :state unless method_defined?(:state)
|
6
|
+
@@states = {}
|
7
|
+
@@initial_state = nil
|
8
|
+
|
9
|
+
unless method_defined?(:state=)
|
10
|
+
attr_writer :state
|
11
|
+
private :state=
|
12
|
+
end
|
13
|
+
|
14
|
+
extend Singleton
|
15
|
+
include Instance
|
16
|
+
RUBY
|
17
|
+
end
|
18
|
+
|
19
|
+
##
|
20
|
+
# Defines singleton methods which are mixed in to a class when
|
21
|
+
# state_machine is called.
|
22
|
+
#
|
23
|
+
module Singleton
|
24
|
+
# @api private
|
25
|
+
def states
|
26
|
+
class_variable_get(:@@states)
|
27
|
+
end
|
28
|
+
|
29
|
+
# @api public
|
30
|
+
def initial_state=(state)
|
31
|
+
class_variable_set(:@@initial_state, state)
|
32
|
+
end
|
33
|
+
|
34
|
+
# @api public
|
35
|
+
def initial_state
|
36
|
+
class_variable_get(:@@initial_state)
|
37
|
+
end
|
38
|
+
|
39
|
+
# @api private
|
40
|
+
def _determine_new_state(current, to)
|
41
|
+
states[current] && (t = states[current].assoc(to)) && t.last
|
42
|
+
end
|
43
|
+
|
44
|
+
# @api private
|
45
|
+
def _valid_transition?(current, to)
|
46
|
+
states[current] and not states[current].assoc(to).nil?
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
##
|
51
|
+
# Defines instance methods which are mixed in to a class when
|
52
|
+
# state_machine is called.
|
53
|
+
#
|
54
|
+
module Instance
|
55
|
+
##
|
56
|
+
# Set the initial value for the state machine after calling the original
|
57
|
+
# initialize method.
|
58
|
+
#
|
59
|
+
def initialize(*args, &blk)
|
60
|
+
super
|
61
|
+
self.state = self.class.initial_state
|
62
|
+
end
|
63
|
+
end # Instance
|
64
|
+
end # Mixins
|
65
|
+
end # SimpleState
|
data/lib/simple_state.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
module SimpleState
|
2
|
+
class Error < StandardError; end
|
3
|
+
class ArgumentError < Error; end
|
4
|
+
|
5
|
+
##
|
6
|
+
# Sets up a state machine on the current class.
|
7
|
+
#
|
8
|
+
def state_machine(&blk)
|
9
|
+
Builder.new(self).build(&blk)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
require 'simple_state/builder'
|
14
|
+
require 'simple_state/mixins'
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'spec_helper.rb')
|
2
|
+
|
3
|
+
# Basic State Machine ========================================================
|
4
|
+
|
5
|
+
describe SimpleState::Builder do
|
6
|
+
before(:each) do
|
7
|
+
@c = state_class do
|
8
|
+
state :prepared
|
9
|
+
state :processed
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'should add a private state writer' do
|
14
|
+
@c.private_methods.map { |m| m.to_sym }.should include(:state=)
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'should add a state reader' do
|
18
|
+
@c.methods.map { |m| m.to_sym }.should include(:state)
|
19
|
+
end
|
20
|
+
|
21
|
+
describe 'when defining states with no events' do
|
22
|
+
it 'should create a predicate' do
|
23
|
+
methods = @c.methods.map { |m| m.to_sym }
|
24
|
+
methods.should include(:prepared?)
|
25
|
+
methods.should include(:processed?)
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'should add the state to register' do
|
29
|
+
@c.class.states.keys.should include(:prepared)
|
30
|
+
@c.class.states.keys.should include(:processed)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# State Machine with Events ==================================================
|
36
|
+
|
37
|
+
describe 'when defining a state with an event' do
|
38
|
+
before(:each) do
|
39
|
+
@evented_state = state_class do
|
40
|
+
state :prepared do
|
41
|
+
event :process, :transitions_to => :processed
|
42
|
+
event :processing_failed, :transitions_to => :failed
|
43
|
+
end
|
44
|
+
|
45
|
+
state :processed
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'should add a bang method for the transition' do
|
50
|
+
@evented_state.methods.map { |m| m.to_sym }.should \
|
51
|
+
include(:process!)
|
52
|
+
@evented_state.methods.map { |m| m.to_sym }.should \
|
53
|
+
include(:processing_failed!)
|
54
|
+
end
|
55
|
+
|
56
|
+
it 'should add the state to register' do
|
57
|
+
@evented_state.class.states.keys.should include(:prepared)
|
58
|
+
@evented_state.class.states.keys.should include(:processed)
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'should raise an argument error if no :transitions_to is provided' do
|
62
|
+
lambda {
|
63
|
+
Class.new do
|
64
|
+
extend SimpleState
|
65
|
+
state_machine do
|
66
|
+
state(:prepared) { event :process }
|
67
|
+
end
|
68
|
+
end
|
69
|
+
}.should raise_error(SimpleState::ArgumentError)
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,199 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'spec_helper.rb')
|
2
|
+
|
3
|
+
# Event Validation ===========================================================
|
4
|
+
|
5
|
+
describe 'Generated event methods when the transition is valid' do
|
6
|
+
before(:each) do
|
7
|
+
@c = state_class do
|
8
|
+
state :begin do
|
9
|
+
event :go, :transitions_to => :state_one
|
10
|
+
end
|
11
|
+
|
12
|
+
state :state_one
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'should return the new state' do
|
17
|
+
@c.go!.should == :state_one
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'should transition the instance to the new state' do
|
21
|
+
@c.go!
|
22
|
+
@c.should be_state_one
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe 'Generated event methods when the transition is not valid' do
|
27
|
+
before(:each) do
|
28
|
+
@c = state_class do
|
29
|
+
state :begin do
|
30
|
+
event :go, :transitions_to => :state_one
|
31
|
+
end
|
32
|
+
|
33
|
+
state :state_one do
|
34
|
+
event :go_again, :transitions_to => :state_two
|
35
|
+
end
|
36
|
+
|
37
|
+
state :state_two
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'should return false' do
|
42
|
+
@c.go_again!.should be_false
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should not change the instance's state" do
|
46
|
+
@c.go_again!
|
47
|
+
@c.should be_begin
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
|
52
|
+
# Multiple Paths Definition ==================================================
|
53
|
+
|
54
|
+
describe 'Generated event methods when mulitple states share the same event' do
|
55
|
+
before(:each) do
|
56
|
+
@path = state_class do
|
57
|
+
state :begin do
|
58
|
+
event :s1, :transitions_to => :state_one
|
59
|
+
event :s2, :transitions_to => :state_two
|
60
|
+
end
|
61
|
+
|
62
|
+
state :state_one do
|
63
|
+
event :go, :transitions_to => :state_three
|
64
|
+
end
|
65
|
+
|
66
|
+
state :state_two do
|
67
|
+
event :go, :transitions_to => :state_four
|
68
|
+
end
|
69
|
+
|
70
|
+
state :state_three
|
71
|
+
state :state_four
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
it 'should transition to state_three if currently in state_one' do
|
76
|
+
@path.s1!
|
77
|
+
@path.go!
|
78
|
+
@path.should be_state_three
|
79
|
+
end
|
80
|
+
|
81
|
+
it 'should transition to state_four if current in state_two' do
|
82
|
+
@path.s2!
|
83
|
+
@path.go!
|
84
|
+
@path.should be_state_four
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
|
89
|
+
# Test full workflow =========================================================
|
90
|
+
# This tests all the possible transition permutations of a state machine.
|
91
|
+
|
92
|
+
describe 'Generated event methods (integration)' do
|
93
|
+
before(:each) do
|
94
|
+
@c = state_class do
|
95
|
+
state :prepared do
|
96
|
+
event :requires_decompress, :transitions_to => :requires_decompress
|
97
|
+
event :invalid_extension, :transitions_to => :halted
|
98
|
+
event :processed, :transitions_to => :processed
|
99
|
+
event :processing_failed, :transitions_to => :halted
|
100
|
+
end
|
101
|
+
|
102
|
+
state :processed do
|
103
|
+
event :stored, :transitions_to => :stored
|
104
|
+
event :store_failed, :transitions_to => :halted
|
105
|
+
end
|
106
|
+
|
107
|
+
state :requires_decompress do
|
108
|
+
event :decompressed, :transitions_to => :complete
|
109
|
+
event :decompress_failed, :transitions_to => :halted
|
110
|
+
end
|
111
|
+
|
112
|
+
state :stored do
|
113
|
+
event :cleaned, :transitions_to => :complete
|
114
|
+
end
|
115
|
+
|
116
|
+
state :halted do
|
117
|
+
event :cleaned, :transitions_to => :failed
|
118
|
+
end
|
119
|
+
|
120
|
+
state :failed
|
121
|
+
state :complete
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
it 'should successfully change the state to complete via the ' \
|
126
|
+
'intermediate states' do
|
127
|
+
|
128
|
+
# begin -> processed -> stored -> complete
|
129
|
+
|
130
|
+
@c.should be_prepared
|
131
|
+
|
132
|
+
@c.processed!.should == :processed
|
133
|
+
@c.should be_processed
|
134
|
+
|
135
|
+
@c.stored!.should == :stored
|
136
|
+
@c.should be_stored
|
137
|
+
|
138
|
+
@c.cleaned!.should == :complete
|
139
|
+
@c.should be_complete
|
140
|
+
end
|
141
|
+
|
142
|
+
it 'should successfully change the state to complete via successful ' \
|
143
|
+
'decompress' do
|
144
|
+
|
145
|
+
# begin -> requires_decompress -> complete
|
146
|
+
|
147
|
+
@c.requires_decompress!.should == :requires_decompress
|
148
|
+
@c.should be_requires_decompress
|
149
|
+
|
150
|
+
@c.decompressed!.should == :complete
|
151
|
+
@c.should be_complete
|
152
|
+
end
|
153
|
+
|
154
|
+
it 'should successfully change the state to failed via failed decompress' do
|
155
|
+
# begins -> requires_decompress -> halted -> failed
|
156
|
+
|
157
|
+
@c.requires_decompress!.should == :requires_decompress
|
158
|
+
@c.should be_requires_decompress
|
159
|
+
|
160
|
+
@c.decompress_failed!.should == :halted
|
161
|
+
@c.should be_halted
|
162
|
+
|
163
|
+
@c.cleaned!.should == :failed
|
164
|
+
@c.should be_failed
|
165
|
+
end
|
166
|
+
|
167
|
+
it 'should successfully change the state to failed via invalid extension' do
|
168
|
+
# begins -> halted -> failed
|
169
|
+
|
170
|
+
@c.invalid_extension!.should == :halted
|
171
|
+
@c.should be_halted
|
172
|
+
|
173
|
+
@c.cleaned!.should == :failed
|
174
|
+
@c.should be_failed
|
175
|
+
end
|
176
|
+
|
177
|
+
it 'should successfully change the state to failed via failed processing' do
|
178
|
+
# begins -> halted -> failed
|
179
|
+
|
180
|
+
@c.processing_failed!.should == :halted
|
181
|
+
@c.should be_halted
|
182
|
+
|
183
|
+
@c.cleaned!.should == :failed
|
184
|
+
@c.should be_failed
|
185
|
+
end
|
186
|
+
|
187
|
+
it 'should successfully change the state to failed via failed storage' do
|
188
|
+
# begins -> processed -> halted -> failed
|
189
|
+
|
190
|
+
@c.processed!.should == :processed
|
191
|
+
@c.should be_processed
|
192
|
+
|
193
|
+
@c.store_failed!.should == :halted
|
194
|
+
@c.should be_halted
|
195
|
+
|
196
|
+
@c.cleaned!.should == :failed
|
197
|
+
@c.should be_failed
|
198
|
+
end
|
199
|
+
end
|
data/spec/mixins_spec.rb
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'spec_helper.rb')
|
2
|
+
|
3
|
+
describe SimpleState::Mixins::Instance do
|
4
|
+
describe '#initialize' do
|
5
|
+
it 'should set the initial state' do
|
6
|
+
c = state_class do
|
7
|
+
state :begin
|
8
|
+
state :finish
|
9
|
+
end
|
10
|
+
|
11
|
+
c.state.should == :begin
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'should call the original #initialize' do
|
15
|
+
parent = Class.new do
|
16
|
+
attr_reader :called
|
17
|
+
|
18
|
+
def initialize
|
19
|
+
@called = true
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
child = Class.new(parent) do
|
24
|
+
extend SimpleState
|
25
|
+
state_machine do
|
26
|
+
state :begin
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
child.new.called.should be_true
|
31
|
+
child.new.state.should == :begin
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'should have separate state machines for each class' do
|
35
|
+
class_one = state_class do
|
36
|
+
state :one
|
37
|
+
end
|
38
|
+
|
39
|
+
class_two = state_class do
|
40
|
+
state :two
|
41
|
+
end
|
42
|
+
|
43
|
+
class_one.class.states.keys.should == [:one]
|
44
|
+
class_two.class.states.keys.should == [:two]
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'spec_helper.rb')
|
2
|
+
|
3
|
+
describe SimpleState, 'generated predicate methods' do
|
4
|
+
before(:each) do
|
5
|
+
@predicate_test = state_class do
|
6
|
+
state :state_one
|
7
|
+
state :state_two
|
8
|
+
state :state_three
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'should return true if the current state matches the predicate' do
|
13
|
+
@predicate_test.should be_state_one
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'should return false if the current state does not match the predicate' do
|
17
|
+
@predicate_test.should_not be_state_two
|
18
|
+
@predicate_test.should_not be_state_three
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'spec_helper.rb')
|
2
|
+
|
3
|
+
describe "SimpleState" do
|
4
|
+
it "should add a state_machine method to the class" do
|
5
|
+
Class.new { extend SimpleState }.methods.map do |m|
|
6
|
+
# Ruby 1.9 compat.
|
7
|
+
m.to_sym
|
8
|
+
end.should include(:state_machine)
|
9
|
+
end
|
10
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'spec'
|
3
|
+
|
4
|
+
# $LOAD_PATH.unshift(File.dirname(__FILE__))
|
5
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
6
|
+
require 'simple_state'
|
7
|
+
|
8
|
+
##
|
9
|
+
# Creates an anonymous class which uses SimpleState.
|
10
|
+
#
|
11
|
+
def state_class(&blk)
|
12
|
+
Class.new do
|
13
|
+
extend SimpleState
|
14
|
+
state_machine(&blk)
|
15
|
+
end.new
|
16
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: anthonyw-simple_state
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Anthony Williams
|
@@ -23,8 +23,20 @@ extra_rdoc_files:
|
|
23
23
|
- README.markdown
|
24
24
|
- LICENSE
|
25
25
|
files:
|
26
|
-
- README.markdown
|
27
26
|
- LICENSE
|
27
|
+
- README.markdown
|
28
|
+
- Rakefile
|
29
|
+
- VERSION.yml
|
30
|
+
- lib/simple_state
|
31
|
+
- lib/simple_state/builder.rb
|
32
|
+
- lib/simple_state/mixins.rb
|
33
|
+
- lib/simple_state.rb
|
34
|
+
- spec/builder_spec.rb
|
35
|
+
- spec/event_methods_spec.rb
|
36
|
+
- spec/mixins_spec.rb
|
37
|
+
- spec/predicate_methods_spec.rb
|
38
|
+
- spec/simple_state_spec.rb
|
39
|
+
- spec/spec_helper.rb
|
28
40
|
has_rdoc: true
|
29
41
|
homepage: http://github.com/anthonyw/simple_state
|
30
42
|
post_install_message:
|