statemachine 1.0.0 → 1.1.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/CHANGES +11 -0
- data/README.rdoc +1 -1
- data/lib/statemachine/generate/dot_graph.rb +1 -0
- data/lib/statemachine/generate/dot_graph/dot_graph_statemachine.rb +127 -0
- data/lib/statemachine/generate/java/java_statemachine.rb +6 -4
- data/lib/statemachine/generate/util.rb +14 -1
- data/lib/statemachine/statemachine.rb +33 -33
- data/lib/statemachine/stub_context.rb +3 -1
- data/lib/statemachine/version.rb +2 -2
- data/spec/generate/dot_graph/dot_graph_stagemachine_spec.rb +27 -0
- data/spec/generate/java/java_statemachine_spec.rb +6 -6
- data/spec/spec_helper.rb +14 -6
- metadata +8 -5
data/CHANGES
CHANGED
@@ -1,5 +1,16 @@
|
|
1
1
|
= Statemachine Changelog
|
2
2
|
|
3
|
+
== Version 1.1.0
|
4
|
+
|
5
|
+
DotGraph
|
6
|
+
* DotGraph generator was added to generate graphs of statemachines using Omnigraffle.
|
7
|
+
* Fixed bug in Java generator where Statenames where not formated correctly.
|
8
|
+
|
9
|
+
== Version 1.0.0
|
10
|
+
|
11
|
+
Generator
|
12
|
+
* Java generator was added. Statemachines defined in the Ruby DSL can generate Java code.
|
13
|
+
|
3
14
|
== Version 0.4.2
|
4
15
|
|
5
16
|
Simple Fixes
|
data/README.rdoc
CHANGED
@@ -21,7 +21,7 @@ at http://blog.8thlight.com/articles/2006/11/17/understanding-statemachines-part
|
|
21
21
|
|
22
22
|
== License
|
23
23
|
|
24
|
-
Copyright (C) 2006 Micah Martin
|
24
|
+
Copyright (C) 2006-2010 Micah Martin
|
25
25
|
|
26
26
|
This library is free software; you can redistribute it and/or
|
27
27
|
modify it under the terms of the GNU Lesser General Public
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'statemachine/generate/dot_graph/dot_graph_statemachine'
|
@@ -0,0 +1,127 @@
|
|
1
|
+
require 'statemachine/generate/util'
|
2
|
+
require 'statemachine/generate/src_builder'
|
3
|
+
|
4
|
+
module Statemachine
|
5
|
+
class Statemachine
|
6
|
+
|
7
|
+
attr_reader :states
|
8
|
+
|
9
|
+
def to_dot(options = {})
|
10
|
+
generator = Generate::DotGraph::DotGraphStatemachine.new(self, options)
|
11
|
+
generator.generate!
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
15
|
+
|
16
|
+
module Generate
|
17
|
+
module DotGraph
|
18
|
+
|
19
|
+
class DotGraphStatemachine
|
20
|
+
|
21
|
+
include Generate::Util
|
22
|
+
|
23
|
+
def initialize(sm, options)
|
24
|
+
@sm = sm
|
25
|
+
@output_dir = options[:output]
|
26
|
+
raise "Please specify an output directory. (:output => 'where/you/want/your/code')" if @output_dir.nil?
|
27
|
+
raise "Output dir '#{@output_dir}' doesn't exist." if !File.exist?(@output_dir)
|
28
|
+
end
|
29
|
+
|
30
|
+
def generate!
|
31
|
+
explore_sm
|
32
|
+
save_output(src_file("main"), build_full_graph)
|
33
|
+
@sm.states.values.each do |state|
|
34
|
+
save_output(src_file("#{state.id}"), build_state_graph(state))
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def explore_sm
|
41
|
+
@nodes = []
|
42
|
+
@transitions = []
|
43
|
+
@sm.states.values.each { |state|
|
44
|
+
state.transitions.values.each { |transition|
|
45
|
+
@nodes << transition.origin_id
|
46
|
+
@nodes << transition.destination_id
|
47
|
+
@transitions << transition
|
48
|
+
}
|
49
|
+
}
|
50
|
+
@nodes = @nodes.uniq
|
51
|
+
end
|
52
|
+
|
53
|
+
def build_full_graph
|
54
|
+
builder = Generate::SrcBuilder.new
|
55
|
+
|
56
|
+
add_graph_header(builder, "main")
|
57
|
+
|
58
|
+
@nodes.each { |node| add_node(builder, node) }
|
59
|
+
builder << endl
|
60
|
+
|
61
|
+
@transitions.each do |transition|
|
62
|
+
add_transition(builder, transition)
|
63
|
+
end
|
64
|
+
|
65
|
+
add_graph_footer(builder)
|
66
|
+
|
67
|
+
return builder.to_s
|
68
|
+
end
|
69
|
+
|
70
|
+
def build_state_graph(state)
|
71
|
+
builder = Generate::SrcBuilder.new
|
72
|
+
|
73
|
+
add_graph_header(builder, state.id)
|
74
|
+
|
75
|
+
state.transitions.values.each do |transition|
|
76
|
+
add_transition(builder, transition)
|
77
|
+
end
|
78
|
+
|
79
|
+
add_graph_footer(builder)
|
80
|
+
|
81
|
+
return builder.to_s
|
82
|
+
end
|
83
|
+
|
84
|
+
def add_graph_header(builder, graph_name)
|
85
|
+
builder << "digraph #{graph_name} {" << endl
|
86
|
+
builder.indent!
|
87
|
+
end
|
88
|
+
|
89
|
+
def add_graph_footer(builder)
|
90
|
+
builder.undent!
|
91
|
+
builder << "}" << endl
|
92
|
+
end
|
93
|
+
|
94
|
+
def add_node(builder, node)
|
95
|
+
builder << node
|
96
|
+
builder << " [ href = \"#{node}.svg\"]"
|
97
|
+
builder << endl
|
98
|
+
end
|
99
|
+
|
100
|
+
def add_transition(builder, transition)
|
101
|
+
builder << transition.origin_id
|
102
|
+
builder << " -> "
|
103
|
+
builder << transition.destination_id
|
104
|
+
builder << " [ "
|
105
|
+
builder << "label = #{transition.event} "
|
106
|
+
builder << "]"
|
107
|
+
builder << endl
|
108
|
+
end
|
109
|
+
|
110
|
+
def src_file(name)
|
111
|
+
return name if @output_dir.nil?
|
112
|
+
path = @output_dir
|
113
|
+
answer = File.join(path, "#{name}.dot")
|
114
|
+
return answer
|
115
|
+
end
|
116
|
+
|
117
|
+
def save_output(filename, content)
|
118
|
+
if @output_dir.nil?
|
119
|
+
say "Writing to file: #{filename}"
|
120
|
+
else
|
121
|
+
create_file(filename, content)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
@@ -37,6 +37,7 @@ module Statemachine
|
|
37
37
|
explore_sm
|
38
38
|
create_file(src_file(@classname), build_statemachine_src)
|
39
39
|
create_file(src_file(@context_classname), build_context_src)
|
40
|
+
say "Statemachine generated."
|
40
41
|
end
|
41
42
|
|
42
43
|
private ###########################################
|
@@ -88,8 +89,8 @@ module Statemachine
|
|
88
89
|
src << "// Instance variables" << endl
|
89
90
|
concrete_states = @sm.states.values.reject { |state| state.id.nil? || !state.concrete? }.sort { |a, b| a.id <=> b.id }
|
90
91
|
concrete_states.each do |state|
|
91
|
-
name = state.id.to_s
|
92
|
-
src << "public final State #{name.upcase} = new #{name}State(this);" << endl
|
92
|
+
name = state.id.to_s
|
93
|
+
src << "public final State #{name.upcase} = new #{name.camalized}State(this);" << endl
|
93
94
|
end
|
94
95
|
superstates = @sm.states.values.reject { |state| state.concrete? }.sort { |a, b| a.id <=> b.id }
|
95
96
|
superstates.each do |superstate|
|
@@ -193,7 +194,7 @@ module Statemachine
|
|
193
194
|
src << "statemachine.getContext().#{transition.action.to_s.camalized(:lower)}();" << endl if transition.action
|
194
195
|
src << "statemachine.setState(statemachine.#{transition.destination_id.to_s.upcase});" << endl
|
195
196
|
entries.each do |entry|
|
196
|
-
src << "statemachine.getContext().#{entry.entry_action.to_s.camalized(:lower)}();" << endl if entry.entry_action
|
197
|
+
src << "statemachine.getContext().#{entry.entry_action.to_s.camalized(:lower)}();" << endl if entry.entry_action
|
197
198
|
end
|
198
199
|
end
|
199
200
|
end
|
@@ -244,6 +245,7 @@ module Statemachine
|
|
244
245
|
|
245
246
|
def create_file(filename, content)
|
246
247
|
establish_directory(File.dirname(filename))
|
248
|
+
say "Writing to file: #{filename}"
|
247
249
|
File.open(filename, 'w') do |file|
|
248
250
|
file.write(content)
|
249
251
|
end
|
@@ -260,4 +262,4 @@ module Statemachine
|
|
260
262
|
end
|
261
263
|
end
|
262
264
|
end
|
263
|
-
end
|
265
|
+
end
|
@@ -4,6 +4,13 @@ module Statemachine
|
|
4
4
|
module Generate
|
5
5
|
module Util
|
6
6
|
|
7
|
+
def create_file(filename, content)
|
8
|
+
establish_directory(File.dirname(filename))
|
9
|
+
File.open(filename, 'w') do |file|
|
10
|
+
file.write(content)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
7
14
|
def establish_directory(path)
|
8
15
|
return if File.exist?(path)
|
9
16
|
establish_directory(File.dirname(path))
|
@@ -18,6 +25,12 @@ module Statemachine
|
|
18
25
|
return :endl
|
19
26
|
end
|
20
27
|
|
28
|
+
def say(message)
|
29
|
+
if !defined?($IS_TEST)
|
30
|
+
puts message
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
21
34
|
end
|
22
35
|
end
|
23
36
|
end
|
@@ -34,4 +47,4 @@ class Symbol
|
|
34
47
|
def <=>(other)
|
35
48
|
return to_s <=> other.to_s
|
36
49
|
end
|
37
|
-
end
|
50
|
+
end
|
@@ -1,52 +1,52 @@
|
|
1
1
|
module Statemachine
|
2
|
-
|
2
|
+
|
3
3
|
class StatemachineException < Exception
|
4
4
|
end
|
5
|
-
|
6
|
-
class TransitionMissingException < Exception
|
5
|
+
|
6
|
+
class TransitionMissingException < Exception
|
7
7
|
end
|
8
|
-
|
8
|
+
|
9
9
|
# Used at runtime to execute the behavior of the statemachine.
|
10
10
|
# Should be created by using the Statemachine.build method.
|
11
|
-
#
|
11
|
+
#
|
12
12
|
# sm = Statemachine.build do
|
13
13
|
# trans :locked, :coin, :unlocked
|
14
14
|
# trans :unlocked, :pass, :locked:
|
15
15
|
# end
|
16
|
-
#
|
16
|
+
#
|
17
17
|
# sm.coin
|
18
18
|
# sm.state
|
19
|
-
#
|
19
|
+
#
|
20
20
|
# This class will accept any method that corresponds to an event. If the
|
21
21
|
# current state respons to the event, the appropriate transtion will be invoked.
|
22
22
|
# Otherwise an exception will be raised.
|
23
23
|
class Statemachine
|
24
24
|
include ActionInvokation
|
25
|
-
|
26
|
-
# The tracer is an IO object. The statemachine will write run time execution
|
25
|
+
|
26
|
+
# The tracer is an IO object. The statemachine will write run time execution
|
27
27
|
# information to the +tracer+. Can be helpful in debugging. Defaults to nil.
|
28
28
|
attr_accessor :tracer
|
29
|
-
|
29
|
+
|
30
30
|
# Provides access to the +context+ of the statemachine. The context is a object
|
31
31
|
# where all actions will be invoked. This provides a way to separate logic from
|
32
32
|
# behavior. The statemachine is responsible for all the logic and the context
|
33
|
-
# is responsible for all the behavior.
|
33
|
+
# is responsible for all the behavior.
|
34
34
|
attr_accessor :context
|
35
|
-
|
35
|
+
|
36
36
|
attr_reader :root #:nodoc:
|
37
|
-
|
37
|
+
|
38
38
|
# Should not be called directly. Instances of Statemachine::Statemachine are created
|
39
39
|
# through the Statemachine.build method.
|
40
40
|
def initialize(root = Superstate.new(:root, nil, self))
|
41
41
|
@root = root
|
42
42
|
@states = {}
|
43
43
|
end
|
44
|
-
|
44
|
+
|
45
45
|
# Returns the id of the startstate of the statemachine.
|
46
46
|
def startstate
|
47
47
|
return @root.startstate_id
|
48
48
|
end
|
49
|
-
|
49
|
+
|
50
50
|
# Resets the statemachine back to its starting state.
|
51
51
|
def reset
|
52
52
|
@state = get_state(@root.startstate_id)
|
@@ -55,15 +55,15 @@ module Statemachine
|
|
55
55
|
end
|
56
56
|
raise StatemachineException.new("The state machine doesn't know where to start. Try setting the startstate.") if @state == nil
|
57
57
|
@state.enter
|
58
|
-
|
58
|
+
|
59
59
|
@states.values.each { |state| state.reset }
|
60
60
|
end
|
61
|
-
|
61
|
+
|
62
62
|
# Return the id of the current state of the statemachine.
|
63
63
|
def state
|
64
64
|
return @state.id
|
65
65
|
end
|
66
|
-
|
66
|
+
|
67
67
|
# You may change the state of the statemachine by using this method. The parameter should be
|
68
68
|
# the id of the desired state.
|
69
69
|
def state= value
|
@@ -75,10 +75,10 @@ module Statemachine
|
|
75
75
|
@state = @states[value.to_sym]
|
76
76
|
end
|
77
77
|
end
|
78
|
-
|
78
|
+
|
79
79
|
# The key method to exercise the statemachine. Any extra arguments supplied will be passed into
|
80
80
|
# any actions associated with the transition.
|
81
|
-
#
|
81
|
+
#
|
82
82
|
# Alternatively to this method, you may invoke methods, names the same as the event, on the statemachine.
|
83
83
|
# The advantage of using +process_event+ is that errors messages are more informative.
|
84
84
|
def process_event(event, *args)
|
@@ -95,11 +95,11 @@ module Statemachine
|
|
95
95
|
raise StatemachineException.new("The state machine isn't in any state while processing the '#{event}' event.")
|
96
96
|
end
|
97
97
|
end
|
98
|
-
|
98
|
+
|
99
99
|
def trace(message) #:nodoc:
|
100
100
|
@tracer.puts message if @tracer
|
101
101
|
end
|
102
|
-
|
102
|
+
|
103
103
|
def get_state(id) #:nodoc:
|
104
104
|
if @states.has_key? id
|
105
105
|
return @states[id]
|
@@ -114,11 +114,11 @@ module Statemachine
|
|
114
114
|
return state
|
115
115
|
end
|
116
116
|
end
|
117
|
-
|
117
|
+
|
118
118
|
def add_state(state) #:nodoc:
|
119
119
|
@states[state.id] = state
|
120
120
|
end
|
121
|
-
|
121
|
+
|
122
122
|
def has_state(id) #:nodoc:
|
123
123
|
if(is_history_state_id?(id))
|
124
124
|
return @states.has_key?(base_id(id))
|
@@ -126,13 +126,13 @@ module Statemachine
|
|
126
126
|
return @states.has_key?(id)
|
127
127
|
end
|
128
128
|
end
|
129
|
-
|
129
|
+
|
130
130
|
def respond_to?(message)
|
131
131
|
return true if super(message)
|
132
132
|
return true if @state and @state.transition_for(message)
|
133
133
|
return false
|
134
134
|
end
|
135
|
-
|
135
|
+
|
136
136
|
def method_missing(message, *args) #:nodoc:
|
137
137
|
if @state and @state.transition_for(message)
|
138
138
|
process_event(message.to_sym, *args)
|
@@ -147,17 +147,17 @@ module Statemachine
|
|
147
147
|
end
|
148
148
|
end
|
149
149
|
end
|
150
|
-
|
151
|
-
private
|
152
|
-
|
150
|
+
|
151
|
+
private
|
152
|
+
|
153
153
|
def is_history_state_id?(id)
|
154
154
|
return id.to_s[-2..-1] == "_H"
|
155
155
|
end
|
156
|
-
|
156
|
+
|
157
157
|
def base_id(history_id)
|
158
158
|
return history_id.to_s[0...-2].to_sym
|
159
159
|
end
|
160
|
-
|
160
|
+
|
161
161
|
def load_history(superstate)
|
162
162
|
100.times do
|
163
163
|
history = superstate.history_id ? get_state(superstate.history_id) : nil
|
@@ -170,6 +170,6 @@ module Statemachine
|
|
170
170
|
end
|
171
171
|
raise StatemachineException.new("No history found within 100 levels of nested superstates.")
|
172
172
|
end
|
173
|
-
|
173
|
+
|
174
174
|
end
|
175
|
-
end
|
175
|
+
end
|
@@ -16,7 +16,9 @@ module Statemachine
|
|
16
16
|
end
|
17
17
|
|
18
18
|
def __generic_method(name, *args)
|
19
|
-
|
19
|
+
if !defined?($IS_TEST)
|
20
|
+
puts "action invoked: #{name}(#{args.join(", ")}) #{block_given? ? "with block" : ""}" if @verbose
|
21
|
+
end
|
20
22
|
end
|
21
23
|
|
22
24
|
end
|
data/lib/statemachine/version.rb
CHANGED
@@ -0,0 +1,27 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../../spec_helper'
|
2
|
+
require 'statemachine/generate/dot_graph/dot_graph_statemachine'
|
3
|
+
|
4
|
+
describe Statemachine::Statemachine, "(Turn Stile)" do
|
5
|
+
include TurnstileStatemachine
|
6
|
+
|
7
|
+
before(:each) do
|
8
|
+
remove_test_dir("dot")
|
9
|
+
@output = test_dir("dot")
|
10
|
+
create_turnstile
|
11
|
+
end
|
12
|
+
|
13
|
+
# it "should output to console when no output dir provided" do
|
14
|
+
# # Note - this test doesn't verify output to the console, but it does
|
15
|
+
# # ensure that the to_dot call does not fail if not output is provided.
|
16
|
+
# @sm.to_dot
|
17
|
+
# end
|
18
|
+
|
19
|
+
it "should generate a basic graph declaration" do
|
20
|
+
@sm.to_dot(:output => @output)
|
21
|
+
|
22
|
+
dot = load_lines(@output, "main.dot")
|
23
|
+
|
24
|
+
dot.should_not equal(nil)
|
25
|
+
dot[0].include?("digraph").should == true
|
26
|
+
end
|
27
|
+
end
|
@@ -48,11 +48,11 @@ describe Statemachine::Statemachine, "(Java)" do
|
|
48
48
|
@sm.to_java(:output => @output, :name => "JavaTurnstile", :package => "test.turnstile")
|
49
49
|
end
|
50
50
|
|
51
|
-
def load_lines(*segs)
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
end
|
51
|
+
# def load_lines(*segs)
|
52
|
+
# filename = File.join(*segs)
|
53
|
+
# File.should exist( filename)
|
54
|
+
# return IO.read(filename).split("\n")
|
55
|
+
# end
|
56
56
|
|
57
57
|
def empty_sm_lines
|
58
58
|
@sm.to_java(:name => "JavaTest", :output => @output, :package => "test.blank")
|
@@ -345,4 +345,4 @@ describe Statemachine::Statemachine, "(Java)" do
|
|
345
345
|
lines.shift.should == " }"
|
346
346
|
end
|
347
347
|
|
348
|
-
end
|
348
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -3,6 +3,8 @@ require 'rubygems'
|
|
3
3
|
require 'spec'
|
4
4
|
require 'statemachine'
|
5
5
|
|
6
|
+
$IS_TEST = true
|
7
|
+
|
6
8
|
def check_transition(transition, origin_id, destination_id, event, action)
|
7
9
|
transition.should_not equal(nil)
|
8
10
|
transition.event.should equal(event)
|
@@ -12,20 +14,20 @@ def check_transition(transition, origin_id, destination_id, event, action)
|
|
12
14
|
end
|
13
15
|
|
14
16
|
module SwitchStatemachine
|
15
|
-
|
17
|
+
|
16
18
|
def create_switch
|
17
19
|
@status = "off"
|
18
20
|
@sm = Statemachine.build do
|
19
|
-
trans :off, :toggle, :on, Proc.new { @status = "on" }
|
21
|
+
trans :off, :toggle, :on, Proc.new { @status = "on" }
|
20
22
|
trans :on, :toggle, :off, Proc.new { @status = "off" }
|
21
23
|
end
|
22
24
|
@sm.context = self
|
23
25
|
end
|
24
|
-
|
26
|
+
|
25
27
|
end
|
26
28
|
|
27
29
|
module TurnstileStatemachine
|
28
|
-
|
30
|
+
|
29
31
|
def create_turnstile
|
30
32
|
@locked = true
|
31
33
|
@alarm_status = false
|
@@ -34,7 +36,7 @@ module TurnstileStatemachine
|
|
34
36
|
@unlock = "@locked = false"
|
35
37
|
@alarm = "@alarm_status = true"
|
36
38
|
@thankyou = "@thankyou_status = true"
|
37
|
-
|
39
|
+
|
38
40
|
@sm = Statemachine.build do
|
39
41
|
trans :locked, :coin, :unlocked, "@locked = false"
|
40
42
|
trans :unlocked, :pass, :locked, "@locked = true"
|
@@ -58,4 +60,10 @@ end
|
|
58
60
|
|
59
61
|
def remove_test_dir(name)
|
60
62
|
system "rm -rf #{test_dir(name)}" if File.exist?(test_dir(name))
|
61
|
-
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def load_lines(*segs)
|
66
|
+
filename = File.join(*segs)
|
67
|
+
File.should exist( filename)
|
68
|
+
return IO.read(filename).split("\n")
|
69
|
+
end
|
metadata
CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
|
|
4
4
|
prerelease: false
|
5
5
|
segments:
|
6
6
|
- 1
|
7
|
-
-
|
8
|
-
-
|
9
|
-
version: 1.
|
7
|
+
- 1
|
8
|
+
- 1
|
9
|
+
version: 1.1.1
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Micah Martin
|
@@ -14,7 +14,7 @@ autorequire: statemachine
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2010-
|
17
|
+
date: 2010-09-29 00:00:00 -05:00
|
18
18
|
default_executable:
|
19
19
|
dependencies: []
|
20
20
|
|
@@ -34,6 +34,8 @@ files:
|
|
34
34
|
- TODO
|
35
35
|
- lib/statemachine/action_invokation.rb
|
36
36
|
- lib/statemachine/builder.rb
|
37
|
+
- lib/statemachine/generate/dot_graph/dot_graph_statemachine.rb
|
38
|
+
- lib/statemachine/generate/dot_graph.rb
|
37
39
|
- lib/statemachine/generate/java/java_statemachine.rb
|
38
40
|
- lib/statemachine/generate/java.rb
|
39
41
|
- lib/statemachine/generate/src_builder.rb
|
@@ -48,6 +50,7 @@ files:
|
|
48
50
|
- spec/action_invokation_spec.rb
|
49
51
|
- spec/builder_spec.rb
|
50
52
|
- spec/default_transition_spec.rb
|
53
|
+
- spec/generate/dot_graph/dot_graph_stagemachine_spec.rb
|
51
54
|
- spec/generate/java/java_statemachine_spec.rb
|
52
55
|
- spec/history_spec.rb
|
53
56
|
- spec/sm_action_parameterization_spec.rb
|
@@ -87,7 +90,7 @@ rubyforge_project: statemachine
|
|
87
90
|
rubygems_version: 1.3.6
|
88
91
|
signing_key:
|
89
92
|
specification_version: 3
|
90
|
-
summary: Statemachine-1.
|
93
|
+
summary: Statemachine-1.1.1 - Statemachine Library for Ruby http://slagyr.github.com/statemachine
|
91
94
|
test_files:
|
92
95
|
- spec/action_invokation_spec.rb
|
93
96
|
- spec/builder_spec.rb
|