nanomachine 1.0.0

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.
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ -Ilib
2
+ --require ./spec/spec_helper
@@ -0,0 +1,8 @@
1
+ rvm:
2
+ - "1.9.3"
3
+ - "1.9.2"
4
+ - "jruby-19mode"
5
+ - "rbx-19mode"
6
+ - "1.8.7"
7
+ - "jruby-18mode"
8
+ - "rbx-18mode"
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec
4
+
5
+ gem "yard"
@@ -0,0 +1,76 @@
1
+ # Nanomachine
2
+
3
+ A really tiny state machine for ruby. No events, only accepted transitions and transition callbacks.
4
+
5
+ The difference between Nanomachine, and otherwise known Micromachine (https://rubygems.org/gems/micromachine) is that
6
+ Micromachine transitions to new states in response to events; multiple events can transition between the two same states.
7
+ Nanomachine, on the other hand, does not care about events, and only needs the state you want to be in after successful
8
+ transition.
9
+
10
+ Nanomachine can be used in any ruby project, and have no runtime dependencies.
11
+
12
+ ## Installation
13
+
14
+ Install the gem:
15
+
16
+ ```shell
17
+ gem install nanomachine
18
+ ```
19
+
20
+ or add it to your Gemfile, if you are using [Bundler][]:
21
+
22
+ ```ruby
23
+ gem "nanomachine", "~> 1.0"
24
+ ```
25
+
26
+ [Bundler]: http://gembundler.com/
27
+
28
+ ## Example
29
+
30
+ ```ruby
31
+ state_machine = Nanomachine.new("unpublished") do |fsm|
32
+ fsm.transition("published", %w[unpublished processing removed])
33
+ fsm.transition("unpublished", %w[published processing removed])
34
+ fsm.transition("processing", %w[published unpublished])
35
+ fsm.transition("removed", []) # defined for being explicit
36
+
37
+ fsm.on_transition(:to => "processing") do |(previous_state, _), id|
38
+ Worker.schedule(id, previous_state)
39
+ end
40
+
41
+ fsm.on_transition do |(from_state, to_state)|
42
+ update_column(:state, to_state)
43
+ end
44
+ end
45
+
46
+ if state_machine.transition_to("published")
47
+ puts "Publish success!"
48
+ else
49
+ puts "Publish failure! We’re in #{state_machine.state}."
50
+ end
51
+ ```
52
+
53
+ ## License
54
+
55
+ Copyright (c) 2012 Ivan Navarrete and Kim Burgestrand
56
+
57
+ MIT License
58
+
59
+ Permission is hereby granted, free of charge, to any person obtaining
60
+ a copy of this software and associated documentation files (the
61
+ "Software"), to deal in the Software without restriction, including
62
+ without limitation the rights to use, copy, modify, merge, publish,
63
+ distribute, sublicense, and/or sell copies of the Software, and to
64
+ permit persons to whom the Software is furnished to do so, subject to
65
+ the following conditions:
66
+
67
+ The above copyright notice and this permission notice shall be
68
+ included in all copies or substantial portions of the Software.
69
+
70
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
71
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
72
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
73
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
74
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
75
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
76
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,34 @@
1
+ begin
2
+ require "bundler/gem_tasks"
3
+ rescue LoadError
4
+ # bundler not required
5
+ end
6
+
7
+ begin
8
+ require "yard"
9
+ YARD::Rake::YardocTask.new("yard:doc") do |task|
10
+ task.options = ["--no-stats"]
11
+ end
12
+
13
+ desc "List undocumented methods and constants"
14
+ task "yard:stats" do
15
+ YARD::CLI::Stats.run("--list-undoc")
16
+ end
17
+
18
+ desc "Generate documentation and show documentation stats"
19
+ task :yard => ["yard:doc", "yard:stats"]
20
+ rescue LoadError
21
+ puts "WARN: YARD not available. You may install documentation dependencies via bundler."
22
+ end
23
+
24
+ desc "Start an IRB session with Nanomachine loaded"
25
+ task :console do
26
+ exec "irb", "-Ilib", "-rnanomachine"
27
+ end
28
+
29
+ require "rspec/core/rake_task"
30
+ RSpec::Core::RakeTask.new do |spec|
31
+ spec.ruby_opts = ["-W"]
32
+ end
33
+
34
+ task :default => :spec
@@ -0,0 +1,183 @@
1
+ require "nanomachine/version"
2
+ require "set"
3
+
4
+ # A minimal state machine where you transition between states, instead
5
+ # of transition by input symbols or events.
6
+ #
7
+ # @example
8
+ # state_machine = Nanomachine.new("unpublished") do |fsm|
9
+ # fsm.transition("published", %w[unpublished processing removed])
10
+ # fsm.transition("unpublished", %w[published processing removed])
11
+ # fsm.transition("processing", %w[published unpublished])
12
+ # fsm.transition("removed", []) # defined for being explicit
13
+ #
14
+ # fsm.on_transition do |(from_state, to_state)|
15
+ # update_column(:state, to_state)
16
+ # end
17
+ # end
18
+ #
19
+ # if state_machine.transition_to("published")
20
+ # puts "Publish success!"
21
+ # else
22
+ # puts "Publish failure! We’re in #{state_machine.state}."
23
+ # end
24
+ #
25
+ #
26
+ class Nanomachine
27
+ # Raised when a transition cannot be performed.
28
+ InvalidTransitionError = Class.new(StandardError)
29
+
30
+ # Raised when a given state cannot be accepted.
31
+ InvalidStateError = Class.new(StandardError)
32
+
33
+ # Construct a Nanomachine with an initial state.
34
+ #
35
+ # @example initialization with a block
36
+ # machine = Nanomachine.new("initial") do |fsm|
37
+ # fsm.transition("initial", %w[green orange])
38
+ # fsm.transition("green", %w[orange error])
39
+ # fsm.transition("orange", %w[green error])
40
+ # # error is a dead state, no transition out of it
41
+ # # so not necessary to define the transitions for it
42
+ #
43
+ # fsm.on_transition(to: "error") do |(from_state, to_state), message|
44
+ # notifier.notify_error(message)
45
+ # end
46
+ #
47
+ # fsm.on_transition do |(from_state, to_state)|
48
+ # object.update_state(to_state)
49
+ # end
50
+ # end
51
+ #
52
+ # @param [#to_s] initial_state state the machine is in after initialization
53
+ # @raise [InvalidStateError] if initial state is nil
54
+ # @yield [self] yields the machine for easy definition of states
55
+ # @yieldparam [Nanomachine] self
56
+ def initialize(initial_state)
57
+ if initial_state.nil?
58
+ raise InvalidStateError, "initial state cannot be nil"
59
+ end
60
+
61
+ @state = initial_state.to_s
62
+ @transitions = Hash.new(Set.new)
63
+ @callbacks = Hash.new { |h, k| h[k] = [] }
64
+ yield self if block_given?
65
+ end
66
+
67
+ # @return [String] current state of the state machine.
68
+ attr_reader :state
69
+
70
+ # @example
71
+ # {"initial"=>#<Set: {"green", "orange"}>,
72
+ # "green"=>#<Set: {"orange", "error"}>,
73
+ # "orange"=>#<Set: {"green", "error"}>}
74
+ #
75
+ # @return [Hash<String, Set>] mapping of state to possible transition targets
76
+ attr_reader :transitions
77
+
78
+ # Define possible state transitions from the source state.
79
+ #
80
+ # @example
81
+ # fsm.transition("green", %w[orange red])
82
+ # fsm.transition("orange", %w[red])
83
+ # fsm.transition(:error, [:nowhere])
84
+ #
85
+ # @param [#to_s] from
86
+ # @param [#each] to each target state must respond to #to_s
87
+ def transition(from, to)
88
+ transitions[from.to_s] = Set.new(to).map!(&:to_s)
89
+ end
90
+
91
+ # Define a callback to be executed on transition.
92
+ #
93
+ # @example callback executed on any transition
94
+ # fsm.on_transition do |(from_state, to_state), *args, &block|
95
+ # # executed on any transition
96
+ # end
97
+ #
98
+ # @example callback executed on transition from a given state only
99
+ # fsm.on_transition(from: "green") do |(from_state, to_state), *args, &block|
100
+ # # executed only on transitions *from* green state
101
+ # end
102
+ #
103
+ # @example callback executed on transition to a given state only
104
+ # fsm.on_transition(to: "green") do |(from_state, to_state), *args, &block|
105
+ # # executed only on transitions *to* green state
106
+ # end
107
+ #
108
+ # @example callback executed on transition between two states only
109
+ # fsm.on_transition(from: "green", to: "red") do |(from_state, to_state), *args, &block|
110
+ # # executed only on transitions between green and red
111
+ # end
112
+ #
113
+ # @param [Hash] options constraint on when callback is to be executed
114
+ # @option options [#to_s, nil] :from (nil) only match when transitioning from the given state, nil for any
115
+ # @option options [#to_s, nil] :to (nil) only match when transitioning to the given state, nil for any
116
+ # @yield [transition, *args, &block] transition states (from, to), and parameters given to {#transition_to} on transition
117
+ # @yieldparam [Array<from_state, to_state>] transition
118
+ # @yieldparam *args arguments passed to {#transition_to}
119
+ # @yieldparam &block block passed to {#transition_to}
120
+ # @raise [ArgumentError] when given unknown options
121
+ # @raise [LocalJumpError] when no callback block is supplied
122
+ def on_transition(options = {}, &block)
123
+ unless block_given?
124
+ raise LocalJumpError, "no block given"
125
+ end
126
+
127
+ from = options.delete(:from)
128
+ from &&= from.to_s
129
+
130
+ to = options.delete(:to)
131
+ to &&= to.to_s
132
+
133
+ unless options.empty?
134
+ raise ArgumentError, "unknown options: #{options.keys.join(", ")}"
135
+ end
136
+
137
+ @callbacks[[from, to]] << block
138
+ end
139
+
140
+ # Transition the state machine from the current state to a target state.
141
+ #
142
+ # @example transition to error state with a message given to any callbacks
143
+ # if previous_state = fsm.transition_to("error", "something went really wrong")
144
+ # puts "Transition from #{previous_state} to #{fsm.state} successful!"
145
+ # else
146
+ # puts "Transition failed."
147
+ # end
148
+ #
149
+ # @param [#to_s] other_state new state to transition to
150
+ # @param args any number of arguments, passed to callbacks defined with {#on_transition}
151
+ # @param block passed to callbacks defined with {#on_transition}
152
+ # @return [String, false] state the machine was in before transition, or false if transition is not allowed
153
+ def transition_to(other_state, *args, &block)
154
+ other_state &&= other_state.to_s
155
+ if transitions[state].include?(other_state)
156
+ previous_state, @state = @state, other_state
157
+ [[nil, nil], [previous_state, nil], [nil, @state], [previous_state, @state]].each do |combo|
158
+ @callbacks[combo].each do |callback|
159
+ callback.call([previous_state, @state], *args, &block)
160
+ end
161
+ end
162
+ previous_state
163
+ else
164
+ false
165
+ end
166
+ end
167
+
168
+ # Same as {#transition_to}, but raises an error if the transition is not allowed.
169
+ #
170
+ # @example
171
+ # fsm.transition_to!("bogus state") # => InvalidTransitionError
172
+ #
173
+ # @param (see #transition_to)
174
+ # @return [String] the state the state machine was in before transition
175
+ # @raise [InvalidTransitionError] if the state machine cannot transition from current state to target state
176
+ def transition_to!(other_state)
177
+ if previous_state = transition_to(other_state)
178
+ previous_state
179
+ else
180
+ raise InvalidTransitionError, "cannot transition from #{state.inspect} to #{other_state.inspect}"
181
+ end
182
+ end
183
+ end
@@ -0,0 +1,4 @@
1
+ class Nanomachine
2
+ # @see http://semver.org/
3
+ VERSION = "1.0.0"
4
+ end
@@ -0,0 +1,52 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path("../lib", __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require "nanomachine/version"
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "nanomachine"
8
+ gem.summary = "A really tiny state machine for ruby. No events, only acceptable transitions and transition callbacks."
9
+ gem.description = <<-DESCRIPTION.gsub(/^ */, "")
10
+ A really tiny state machine for ruby. No events, only accepted transitions and transition callbacks.
11
+
12
+ The difference between Nanomachine, and otherwise known Micromachine (https://rubygems.org/gems/micromachine) is that
13
+ Micromachine transitions to new states in response to events; multiple events can transition between the two same states.
14
+ Nanomachine, on the other hand, does not care about events, and only needs the state you want to be in after successful
15
+ transition.
16
+
17
+ Nanomachine can be used in any ruby project, and have no runtime dependencies.
18
+
19
+ Example:
20
+ state_machine = Nanomachine.new("unpublished") do |fsm|
21
+ fsm.transition("published", %w[unpublished processing removed])
22
+ fsm.transition("unpublished", %w[published processing removed])
23
+ fsm.transition("processing", %w[published unpublished])
24
+ fsm.transition("removed", []) # defined for being explicit
25
+
26
+ fsm.on_transition do |(from_state, to_state)|
27
+ update_column(:state, to_state)
28
+ end
29
+ end
30
+
31
+ if state_machine.transition_to("published")
32
+ puts "Publish success!"
33
+ else
34
+ puts "Publish failure! We’re in \#{state_machine.state}."
35
+ end
36
+ DESCRIPTION
37
+
38
+ gem.version = Nanomachine::VERSION
39
+
40
+ gem.homepage = "https://github.com/elabs/nanomachine"
41
+ gem.authors = ["Ivan Navarrete", "Kim Burgestrand"]
42
+ gem.email = ["crzivn@gmail.com", "kim@burgestrand.se"]
43
+ gem.license = "MIT License"
44
+
45
+ gem.files = `git ls-files`.split($/)
46
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
47
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
48
+ gem.require_paths = ["lib"]
49
+
50
+ gem.add_development_dependency "rake"
51
+ gem.add_development_dependency "rspec", "~> 2.0"
52
+ end
@@ -0,0 +1,163 @@
1
+ describe "Nanomachine state machine" do
2
+ before do
3
+ @callbacks = []
4
+ end
5
+
6
+ let(:fsm) do
7
+ Nanomachine.new("A") do |m|
8
+ m.transition("A", %w[B C E X])
9
+ m.transition("B", %w[A])
10
+ m.transition(:C, [:A, :D])
11
+ m.transition("D", %w[])
12
+ m.transition("E", %w[B C])
13
+
14
+ m.on_transition(:to => "B") do |*args, &block|
15
+ @callbacks << [:to, args, block]
16
+ end
17
+
18
+ m.on_transition(:from => "A") do |*args, &block|
19
+ @callbacks << [:from, args, block]
20
+ end
21
+
22
+ m.on_transition(:from => "A", :to => "B") do |*args, &block|
23
+ @callbacks << [:from_to, args, block]
24
+ end
25
+
26
+ m.on_transition(:from => "E", :to => "C") do |*args, &block|
27
+ @callbacks << [:from_to_e, args, block]
28
+ end
29
+
30
+ m.on_transition do |*args, &block|
31
+ @callbacks << [:any, args, block]
32
+ end
33
+ end
34
+ end
35
+
36
+ describe "VERSION" do
37
+ specify { Nanomachine::VERSION.should be_a String }
38
+ end
39
+
40
+ describe "#initialize" do
41
+ it "raises an error if given an invalid initial state" do
42
+ expect { Nanomachine.new(nil) }.to raise_error(Nanomachine::InvalidStateError, /initial state/)
43
+ end
44
+ end
45
+
46
+ describe "#state" do
47
+ it "returns the current state" do
48
+ fsm.state.should eq("A")
49
+ end
50
+ end
51
+
52
+ describe "#transitions" do
53
+ it "returns the available transitions" do
54
+ fsm.transitions.should eq({"A" => Set.new(%w[B C E X]),
55
+ "B" => Set.new(%w[A]),
56
+ "C" => Set.new(%w[A D]),
57
+ "D" => Set.new(),
58
+ "E" => Set.new(%w[B C])})
59
+ end
60
+ end
61
+
62
+ describe "#on_transition" do
63
+ it "raises an error when given unknown options" do
64
+ expect { fsm.on_transition(:bad_option => "foo") { } }.to raise_error(ArgumentError, /bad_option/)
65
+ end
66
+
67
+ it "raises an error when given no block" do
68
+ expect { fsm.on_transition }.to raise_error(LocalJumpError, /no block given/)
69
+ end
70
+ end
71
+
72
+ describe "#transition_to" do
73
+ it "transitions to the new state" do
74
+ expect { fsm.transition_to("B") }.to change { fsm.state }.from("A").to("B")
75
+ end
76
+
77
+ it "does not transition when the transition is undefined" do
78
+ fsm.transition_to("X")
79
+ expect { fsm.transition_to("A").should be_false }.to_not change { fsm.state }
80
+ end
81
+
82
+ it "returns the previous state" do
83
+ fsm.transition_to("B").should eq("A")
84
+ end
85
+
86
+ it "returns false if transition failed" do
87
+ fsm.transition_to("D").should be_false
88
+ end
89
+
90
+ context "callbacks" do
91
+ it "executes all callbacks in the correct order, most generic first" do
92
+ block = proc {}
93
+ args = [1, [3, 4]]
94
+
95
+ fsm.transition_to("B", *args, &block)
96
+
97
+ @callbacks.should eq([
98
+ [:any, [["A", "B"], 1, [3, 4]], block],
99
+ [:from, [["A", "B"], 1, [3, 4]], block],
100
+ [:to, [["A", "B"], 1, [3, 4]], block],
101
+ [:from_to, [["A", "B"], 1, [3, 4]], block]
102
+ ])
103
+ end
104
+
105
+ it "executes callbacks reacting to any transition" do
106
+ fsm.transition_to("C")
107
+ @callbacks.clear
108
+ fsm.transition_to("D")
109
+
110
+ @callbacks.should eq([
111
+ [:any, [["C", "D"]], nil],
112
+ ])
113
+ end
114
+
115
+ it "executes callbacks for the from-transition" do
116
+ fsm.transition_to("C")
117
+
118
+ @callbacks.should eq([
119
+ [:any, [["A", "C"]], nil],
120
+ [:from, [["A", "C"]], nil],
121
+ ])
122
+ end
123
+
124
+ it "executes callbacks for the to-transition" do
125
+ fsm.transition_to("E")
126
+ @callbacks.clear
127
+ fsm.transition_to("B")
128
+
129
+ @callbacks.should eq([
130
+ [:any, [["E", "B"]], nil],
131
+ [:to, [["E", "B"]], nil],
132
+ ])
133
+ end
134
+
135
+ it "executes callbacks for the from-to-transition" do
136
+ fsm.transition_to("E")
137
+ @callbacks.clear
138
+ fsm.transition_to("C")
139
+
140
+ @callbacks.should eq([
141
+ [:any, [["E", "C"]], nil],
142
+ [:from_to_e, [["E", "C"]], nil],
143
+ ])
144
+ end
145
+
146
+ it "executes no callbacks on failed transitions" do
147
+ fsm.transition_to("D").should be_false
148
+ @callbacks.should be_empty
149
+ end
150
+ end
151
+ end
152
+
153
+ describe "#transition_to!" do
154
+ it "raises an error on an invalid transition" do
155
+ fsm.should_receive(:transition_to).and_return(false)
156
+ expect { fsm.transition_to!("D") }.to raise_error(Nanomachine::InvalidTransitionError, /cannot transition/)
157
+ end
158
+
159
+ it "returns the previous state on success" do
160
+ fsm.transition_to!("B").should eq "A"
161
+ end
162
+ end
163
+ end
@@ -0,0 +1,2 @@
1
+ require "rspec"
2
+ require "nanomachine"
metadata ADDED
@@ -0,0 +1,136 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: nanomachine
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Ivan Navarrete
9
+ - Kim Burgestrand
10
+ autorequire:
11
+ bindir: bin
12
+ cert_chain: []
13
+ date: 2012-11-15 00:00:00.000000000 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: rake
17
+ requirement: &2170833800 !ruby/object:Gem::Requirement
18
+ none: false
19
+ requirements:
20
+ - - ! '>='
21
+ - !ruby/object:Gem::Version
22
+ version: '0'
23
+ type: :development
24
+ prerelease: false
25
+ version_requirements: *2170833800
26
+ - !ruby/object:Gem::Dependency
27
+ name: rspec
28
+ requirement: &2170833240 !ruby/object:Gem::Requirement
29
+ none: false
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: '2.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: *2170833240
37
+ description: ! 'A really tiny state machine for ruby. No events, only accepted transitions
38
+ and transition callbacks.
39
+
40
+
41
+ The difference between Nanomachine, and otherwise known Micromachine (https://rubygems.org/gems/micromachine)
42
+ is that
43
+
44
+ Micromachine transitions to new states in response to events; multiple events can
45
+ transition between the two same states.
46
+
47
+ Nanomachine, on the other hand, does not care about events, and only needs the state
48
+ you want to be in after successful
49
+
50
+ transition.
51
+
52
+
53
+ Nanomachine can be used in any ruby project, and have no runtime dependencies.
54
+
55
+
56
+ Example:
57
+
58
+ state_machine = Nanomachine.new("unpublished") do |fsm|
59
+
60
+ fsm.transition("published", %w[unpublished processing removed])
61
+
62
+ fsm.transition("unpublished", %w[published processing removed])
63
+
64
+ fsm.transition("processing", %w[published unpublished])
65
+
66
+ fsm.transition("removed", []) # defined for being explicit
67
+
68
+
69
+ fsm.on_transition do |(from_state, to_state)|
70
+
71
+ update_column(:state, to_state)
72
+
73
+ end
74
+
75
+ end
76
+
77
+
78
+ if state_machine.transition_to("published")
79
+
80
+ puts "Publish success!"
81
+
82
+ else
83
+
84
+ puts "Publish failure! We’re in #{state_machine.state}."
85
+
86
+ end
87
+
88
+ '
89
+ email:
90
+ - crzivn@gmail.com
91
+ - kim@burgestrand.se
92
+ executables: []
93
+ extensions: []
94
+ extra_rdoc_files: []
95
+ files:
96
+ - .gitignore
97
+ - .rspec
98
+ - .travis.yml
99
+ - Gemfile
100
+ - README.md
101
+ - Rakefile
102
+ - lib/nanomachine.rb
103
+ - lib/nanomachine/version.rb
104
+ - nanomachine.gemspec
105
+ - spec/nano_machine_spec.rb
106
+ - spec/spec_helper.rb
107
+ homepage: https://github.com/elabs/nanomachine
108
+ licenses:
109
+ - MIT License
110
+ post_install_message:
111
+ rdoc_options: []
112
+ require_paths:
113
+ - lib
114
+ required_ruby_version: !ruby/object:Gem::Requirement
115
+ none: false
116
+ requirements:
117
+ - - ! '>='
118
+ - !ruby/object:Gem::Version
119
+ version: '0'
120
+ required_rubygems_version: !ruby/object:Gem::Requirement
121
+ none: false
122
+ requirements:
123
+ - - ! '>='
124
+ - !ruby/object:Gem::Version
125
+ version: '0'
126
+ requirements: []
127
+ rubyforge_project:
128
+ rubygems_version: 1.8.10
129
+ signing_key:
130
+ specification_version: 3
131
+ summary: A really tiny state machine for ruby. No events, only acceptable transitions
132
+ and transition callbacks.
133
+ test_files:
134
+ - spec/nano_machine_spec.rb
135
+ - spec/spec_helper.rb
136
+ has_rdoc: