micromachine 0.0.11 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md ADDED
@@ -0,0 +1,190 @@
1
+ MicroMachine
2
+ ============
3
+
4
+ Minimal Finite State Machine.
5
+
6
+ Description
7
+ -----------
8
+
9
+ There are many finite state machine implementations for Ruby, and they
10
+ all provide a nice DSL for declaring events, exceptions, callbacks,
11
+ and all kinds of niceties in general.
12
+
13
+ But if all you want is a finite state machine, look no further: this
14
+ is only 22 lines of code and provides everything a finite state
15
+ machine must have, and nothing more.
16
+
17
+ Usage
18
+ -----
19
+
20
+ ``` ruby
21
+ require 'micromachine'
22
+
23
+ machine = MicroMachine.new(:new) # Initial state.
24
+
25
+ machine.transitions_for[:confirm] = { :new => :confirmed }
26
+ machine.transitions_for[:ignore] = { :new => :ignored }
27
+ machine.transitions_for[:reset] = { :confirmed => :new, :ignored => :new }
28
+
29
+ machine.trigger(:confirm) #=> true
30
+ machine.state #=> :confirmed
31
+
32
+ machine.trigger(:ignore) #=> false
33
+ machine.state #=> :confirmed
34
+
35
+ machine.trigger(:reset) #=> true
36
+ machine.state #=> :new
37
+
38
+ machine.trigger(:ignore) #=> true
39
+ machine.state #=> :ignored
40
+ ```
41
+
42
+ You can also ask if an event will trigger a change in state. Following
43
+ the example above:
44
+
45
+ ``` ruby
46
+ machine.state #=> :ignored
47
+
48
+ machine.trigger?(:ignore) #=> false
49
+ machine.trigger?(:reset) #=> true
50
+
51
+ # And the state is preserved, because you were only asking.
52
+ machine.state #=> :ignored
53
+ ```
54
+
55
+ It can also have callbacks when entering some state:
56
+
57
+ ``` ruby
58
+ machine.on(:confirmed) do
59
+ puts "Confirmed"
60
+ end
61
+ ```
62
+
63
+ Or callbacks on any transition:
64
+
65
+ ``` ruby
66
+ machine.on(:any) do
67
+ puts "Transitioned..."
68
+ end
69
+ ```
70
+
71
+ Note that `:any` is a special key. Using it as a state when declaring
72
+ transitions will give you unexpected results.
73
+
74
+ Check the examples directory for more information.
75
+
76
+ Adding MicroMachine to your models
77
+ ----------------------------------
78
+
79
+ The most popular pattern among Ruby libraries that tackle this problem
80
+ is to extend the model and transform it into a finite state machine.
81
+ Instead of working as a mixin, MicroMachine's implementation is by
82
+ composition: you instantiate a finite state machine (or many!) inside
83
+ your model and you are in charge of querying and persisting the state.
84
+ Here's an example of how to use it with an ActiveRecord model:
85
+
86
+ ``` ruby
87
+ class Event < ActiveRecord::Base
88
+ before_save :persist_confirmation
89
+
90
+ def confirm!
91
+ confirmation.trigger(:confirm)
92
+ end
93
+
94
+ def cancel!
95
+ confirmation.trigger(:cancel)
96
+ end
97
+
98
+ def reset!
99
+ confirmation.trigger(:reset)
100
+ end
101
+
102
+ def confirmation
103
+ @confirmation ||= begin
104
+ fsm = MicroMachine.new(confirmation_state || "pending")
105
+
106
+ fsm.transitions_for[:confirm] = { "pending" => "confirmed" }
107
+ fsm.transitions_for[:cancel] = { "confirmed" => "cancelled" }
108
+ fsm.transitions_for[:reset] = { "confirmed" => "pending", "cancelled" => "pending" }
109
+
110
+ fsm
111
+ end
112
+ end
113
+
114
+ private
115
+
116
+ def persist_confirmation
117
+ self.confirmation_state = confirmation.state
118
+ end
119
+ end
120
+ ```
121
+
122
+ This example asumes you have a `:confirmation_state` attribute in your
123
+ model. This may look like a very verbose implementation, but you gain a
124
+ lot in flexibility.
125
+
126
+ An alternative approach, using callbacks:
127
+
128
+ ``` ruby
129
+ class Event < ActiveRecord::Base
130
+ def confirm!
131
+ confirmation.trigger(:confirm)
132
+ end
133
+
134
+ def cancel!
135
+ confirmation.trigger(:cancel)
136
+ end
137
+
138
+ def reset!
139
+ confirmation.trigger(:reset)
140
+ end
141
+
142
+ def confirmation
143
+ @confirmation ||= begin
144
+ fsm = MicroMachine.new(confirmation_state || "pending")
145
+
146
+ fsm.transitions_for[:confirm] = { "pending" => "confirmed" }
147
+ fsm.transitions_for[:cancel] = { "confirmed" => "cancelled" }
148
+ fsm.transitions_for[:reset] = { "confirmed" => "pending", "cancelled" => "pending" }
149
+
150
+ fsm.on(:any) { self.confirmation_state = confirmation.state }
151
+
152
+ fsm
153
+ end
154
+ end
155
+ end
156
+ ```
157
+
158
+ Now, on any transition the `confirmation_state` attribute in the model
159
+ will be updated.
160
+
161
+ Installation
162
+ ------------
163
+
164
+ $ sudo gem install micromachine
165
+
166
+ License
167
+ -------
168
+
169
+ Copyright (c) 2009 Michel Martens
170
+
171
+ Permission is hereby granted, free of charge, to any person
172
+ obtaining a copy of this software and associated documentation
173
+ files (the "Software"), to deal in the Software without
174
+ restriction, including without limitation the rights to use,
175
+ copy, modify, merge, publish, distribute, sublicense, and/or sell
176
+ copies of the Software, and to permit persons to whom the
177
+ Software is furnished to do so, subject to the following
178
+ conditions:
179
+
180
+ The above copyright notice and this permission notice shall be
181
+ included in all copies or substantial portions of the Software.
182
+
183
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
184
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
185
+ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
186
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
187
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
188
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
189
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
190
+ OTHER DEALINGS IN THE SOFTWARE.
data/lib/micromachine.rb CHANGED
@@ -20,11 +20,13 @@ class MicroMachine
20
20
  callbacks = @callbacks[@state] + @callbacks[:any]
21
21
  callbacks.each { |callback| callback.call }
22
22
  true
23
+ else
24
+ false
23
25
  end
24
26
  end
25
27
 
26
28
  def trigger?(event)
27
- transitions_for[event][state]
29
+ transitions_for[event][state] ? true : false
28
30
  rescue NoMethodError
29
31
  raise InvalidEvent
30
32
  end
data/micromachine.gemspec CHANGED
@@ -1,10 +1,10 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'micromachine'
3
- s.version = '0.0.11'
3
+ s.version = '1.0.0'
4
4
  s.summary = %{Minimal Finite State Machine.}
5
5
  s.description = %Q{There are many finite state machine implementations for Ruby, and they all provide a nice DSL for declaring events, exceptions, callbacks, and all kinds of niceties in general.\n\nBut if all you want is a finite state machine, look no further: this is only 22 lines of code and provides everything a finite state machine must have, and nothing more.}
6
6
  s.author = "Michel Martens"
7
7
  s.email = "michel@soveran.com"
8
8
  s.homepage = "http://github.com/soveran/micromachine"
9
- s.files = ["lib/micromachine.rb", "README.markdown", "LICENSE", "Rakefile", "micromachine.gemspec", "example/micromachine_sample.rb", "example/micromachine_sample_gem.rb"]
9
+ s.files = Dir["lib/**/*.rb", "README*", "LICENSE", "Rakefile", "*.gemspec", "example/**/*.*"]
10
10
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: micromachine
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.11
4
+ version: 1.0.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,8 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2011-07-17 00:00:00.000000000 -03:00
13
- default_executable:
12
+ date: 2012-03-28 00:00:00.000000000 Z
14
13
  dependencies: []
15
14
  description: ! 'There are many finite state machine implementations for Ruby, and
16
15
  they all provide a nice DSL for declaring events, exceptions, callbacks, and all
@@ -26,13 +25,10 @@ extensions: []
26
25
  extra_rdoc_files: []
27
26
  files:
28
27
  - lib/micromachine.rb
29
- - README.markdown
28
+ - README.md
30
29
  - LICENSE
31
30
  - Rakefile
32
31
  - micromachine.gemspec
33
- - example/micromachine_sample.rb
34
- - example/micromachine_sample_gem.rb
35
- has_rdoc: true
36
32
  homepage: http://github.com/soveran/micromachine
37
33
  licenses: []
38
34
  post_install_message:
@@ -53,7 +49,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
53
49
  version: '0'
54
50
  requirements: []
55
51
  rubyforge_project:
56
- rubygems_version: 1.6.2
52
+ rubygems_version: 1.8.10
57
53
  signing_key:
58
54
  specification_version: 3
59
55
  summary: Minimal Finite State Machine.
data/README.markdown DELETED
@@ -1,152 +0,0 @@
1
- MicroMachine
2
- ============
3
-
4
- Minimal Finite State Machine.
5
-
6
- Description
7
- -----------
8
-
9
- There are many finite state machine implementations for Ruby, and they
10
- all provide a nice DSL for declaring events, exceptions, callbacks,
11
- and all kinds of niceties in general.
12
-
13
- But if all you want is a finite state machine, look no further: this is only
14
- 22 lines of code and provides everything a finite state machine must have, and
15
- nothing more.
16
-
17
- Usage
18
- -----
19
-
20
- require 'micromachine'
21
-
22
- machine = MicroMachine.new(:new) # Initial state.
23
-
24
- machine.transitions_for[:confirm] = { :new => :confirmed }
25
- machine.transitions_for[:ignore] = { :new => :ignored }
26
- machine.transitions_for[:reset] = { :confirmed => :new, :ignored => :new }
27
-
28
- machine.trigger(:confirm) #=> true
29
- machine.trigger(:ignore) #=> false
30
- machine.trigger(:reset) #=> true
31
- machine.trigger(:ignore) #=> true
32
-
33
- It can also have callbacks when entering some state:
34
-
35
- machine.on(:confirmed) do
36
- puts "Confirmed"
37
- end
38
-
39
- Or callbacks on any transition:
40
-
41
- machine.on(:any) do
42
- puts "Transitioned..."
43
- end
44
-
45
- Note that `:any` is a special key. Using it as a state when declaring
46
- transitions will give you unexpected results.
47
-
48
- Adding MicroMachine to your models
49
- ----------------------------------
50
-
51
- The most popular pattern among Ruby libraries that tackle this problem
52
- is to extend the model and transform it into a finite state machine.
53
- Instead of working as a mixin, MicroMachine's implementation is by
54
- composition: you instantiate a finite state machine (or many!) inside
55
- your model and you are in charge of querying and persisting the state.
56
- Here's an example of how to use it with an ActiveRecord model:
57
-
58
- class Event < ActiveRecord::Base
59
- before_save :persist_confirmation
60
-
61
- def confirm!
62
- confirmation.trigger(:confirm)
63
- end
64
-
65
- def cancel!
66
- confirmation.trigger(:cancel)
67
- end
68
-
69
- def reset!
70
- confirmation.trigger(:reset)
71
- end
72
-
73
- def confirmation
74
- @confirmation ||= begin
75
- @confirmation = MicroMachine.new(confirmation_state || "pending")
76
- @confirmation.transitions_for[:confirm] = { "pending" => "confirmed" }
77
- @confirmation.transitions_for[:cancel] = { "confirmed" => "cancelled" }
78
- @confirmation.transitions_for[:reset] = { "confirmed" => "pending", "cancelled" => "pending" }
79
- @confirmation
80
- end
81
- end
82
-
83
- private
84
-
85
- def persist_confirmation
86
- self.confirmation_state = confirmation.state
87
- end
88
- end
89
-
90
- This example asumes you have a :confirmation_state attribute in your
91
- model. This may look like a very verbose implementation, but you gain a
92
- lot in flexibility.
93
-
94
- An alternative approach, using callbacks:
95
-
96
- class Event < ActiveRecord::Base
97
- def confirm!
98
- confirmation.trigger(:confirm)
99
- end
100
-
101
- def cancel!
102
- confirmation.trigger(:cancel)
103
- end
104
-
105
- def reset!
106
- confirmation.trigger(:reset)
107
- end
108
-
109
- def confirmation
110
- @confirmation ||= begin
111
- confirmation = MicroMachine.new(confirmation_state || "pending")
112
- confirmation.transitions_for[:confirm] = { "pending" => "confirmed" }
113
- confirmation.transitions_for[:cancel] = { "confirmed" => "cancelled" }
114
- confirmation.transitions_for[:reset] = { "confirmed" => "pending", "cancelled" => "pending" }
115
- confirmation.on(:any) { self.confirmation_state = confirmation.state }
116
- confirmation
117
- end
118
- end
119
- end
120
-
121
- Now, on any transition the `confirmation_state` attribute in the model will be updated.
122
-
123
- Installation
124
- ------------
125
-
126
- $ sudo gem install micromachine
127
-
128
- License
129
- -------
130
-
131
- Copyright (c) 2009 Michel Martens for Citrusbyte
132
-
133
- Permission is hereby granted, free of charge, to any person
134
- obtaining a copy of this software and associated documentation
135
- files (the "Software"), to deal in the Software without
136
- restriction, including without limitation the rights to use,
137
- copy, modify, merge, publish, distribute, sublicense, and/or sell
138
- copies of the Software, and to permit persons to whom the
139
- Software is furnished to do so, subject to the following
140
- conditions:
141
-
142
- The above copyright notice and this permission notice shall be
143
- included in all copies or substantial portions of the Software.
144
-
145
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
146
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
147
- OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
148
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
149
- HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
150
- WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
151
- FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
152
- OTHER DEALINGS IN THE SOFTWARE.
@@ -1,24 +0,0 @@
1
- require File.join(File.dirname(__FILE__), '../lib/micromachine')
2
-
3
- fsm = MicroMachine.new(:pending)
4
- fsm.transitions_for[:confirm] = { :pending => :confirmed }
5
- fsm.transitions_for[:ignore] = { :pending => :ignored }
6
- fsm.transitions_for[:reset] = { :confirmed => :pending, :ignored => :pending }
7
-
8
- puts "Should print Confirmed, Reset and Ignored."
9
-
10
- if fsm.trigger(:confirm)
11
- puts "Confirmed"
12
- end
13
-
14
- if fsm.trigger(:ignore)
15
- puts "Ignored"
16
- end
17
-
18
- if fsm.trigger(:reset)
19
- puts "Reset"
20
- end
21
-
22
- if fsm.trigger(:ignore)
23
- puts "Ignored"
24
- end
@@ -1,25 +0,0 @@
1
- require 'rubygems'
2
- require 'micromachine'
3
-
4
- fsm = MicroMachine.new(:pending)
5
- fsm.transitions_for[:confirm] = { :pending => :confirmed }
6
- fsm.transitions_for[:ignore] = { :pending => :ignored }
7
- fsm.transitions_for[:reset] = { :confirmed => :pending, :ignored => :pending }
8
-
9
- puts "Should print Confirmed, Reset and Ignored."
10
-
11
- if fsm.trigger(:confirm)
12
- puts "Confirmed"
13
- end
14
-
15
- if fsm.trigger(:ignore)
16
- puts "Ignored"
17
- end
18
-
19
- if fsm.trigger(:reset)
20
- puts "Reset"
21
- end
22
-
23
- if fsm.trigger(:ignore)
24
- puts "Ignored"
25
- end