micromachine 0.0.11 → 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.
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