step_machine 0.0.3

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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: bef3877ea59535b62e02fe0bf0abfb5fb04a3ed1
4
+ data.tar.gz: 4d5489faf7ff54e3939dc6b061f43cf94b179b6c
5
+ SHA512:
6
+ metadata.gz: 5e87e732a0d7dfa89573a2d972bf47f62a8b1ea91e5449473f715415189e04fd7f9dff48b73425dc25e0801dd109d7c655420d25d59eed611b40beb1904f21dd
7
+ data.tar.gz: 0b31754b61675dc2646b4c2dc4656686007f0a8a2988b7ac1f772fd7267d00d3fc958278ab82021a082e442d2082a6513ba9f0f1031aaa7ffda990646c268b77
data/.gitignore ADDED
@@ -0,0 +1,19 @@
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
18
+ *.sublime-project
19
+ *.sublime-workspace
data/Gemfile ADDED
@@ -0,0 +1,12 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # ruby '1.9.3'
4
+ # Specify your gem's dependencies in step_machine.gemspec
5
+ gemspec
6
+
7
+ group :development, :test do
8
+ gem 'rspec'
9
+ gem 'guard-rspec'
10
+ gem 'pry'
11
+ gem 'simplecov'
12
+ end
data/Guardfile ADDED
@@ -0,0 +1,24 @@
1
+ # A sample Guardfile
2
+ # More info at https://github.com/guard/guard#readme
3
+
4
+ guard :rspec do
5
+ watch(%r{^spec/.+_spec\.rb$})
6
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
7
+ watch('spec/spec_helper.rb') { "spec" }
8
+
9
+ # Rails example
10
+ watch(%r{^app/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
11
+ watch(%r{^app/(.*)(\.erb|\.haml)$}) { |m| "spec/#{m[1]}#{m[2]}_spec.rb" }
12
+ watch(%r{^app/controllers/(.+)_(controller)\.rb$}) { |m| ["spec/routing/#{m[1]}_routing_spec.rb", "spec/#{m[2]}s/#{m[1]}_#{m[2]}_spec.rb", "spec/acceptance/#{m[1]}_spec.rb"] }
13
+ watch(%r{^spec/support/(.+)\.rb$}) { "spec" }
14
+ watch('config/routes.rb') { "spec/routing" }
15
+ watch('app/controllers/application_controller.rb') { "spec/controllers" }
16
+
17
+ # Capybara features specs
18
+ watch(%r{^app/views/(.+)/.*\.(erb|haml)$}) { |m| "spec/features/#{m[1]}_spec.rb" }
19
+
20
+ # Turnip features and steps
21
+ watch(%r{^spec/acceptance/(.+)\.feature$})
22
+ watch(%r{^spec/acceptance/steps/(.+)_steps\.rb$}) { |m| Dir[File.join("**/#{m[1]}.feature")][0] || 'spec/acceptance' }
23
+ end
24
+
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Rafael Vettori and Geison Biazus
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,163 @@
1
+ # StepMachine
2
+
3
+ step_machine is a simple gem for executing code based in steps. Each step can be validated and if a step fails, the execution is aborted.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'step_machine'
10
+
11
+ or
12
+
13
+ gem 'step_machine', git: git@bitbucket.org:geisonbiazus/step_machine.git
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ ## Usage
20
+
21
+ ## Creating and running steps:
22
+ include StepMachine
23
+
24
+ step(:step_1) do
25
+ # code for step 1
26
+ end
27
+
28
+ step(:step_2) do
29
+ # code for step 2
30
+ end
31
+
32
+ run_steps
33
+
34
+ This code will run the steps in the created order
35
+
36
+ ## Changing the execution order
37
+
38
+ step(:step_1).next_step = step(:step_2)
39
+
40
+ or:
41
+
42
+ step(:step_1).next_step do
43
+ step(:step_2)
44
+ end
45
+
46
+ ## Validating steps
47
+
48
+ step(:step_1).validate do |step|
49
+ step.result == "OK"
50
+ end
51
+
52
+ step(step_1).validate(/^OK/)
53
+
54
+ step(step_1).validate('OK')
55
+
56
+ ## Validating steps error message
57
+
58
+ step(:step_1).validate do |step|
59
+ step.result == "OK"
60
+ step.errors << 'This is a array error message forced to false validate'
61
+ end
62
+
63
+ step(step_1).errors({}) << 'This is a hash error message forced to false validate'
64
+
65
+ step(step_1).errors('') << 'This is a string error message forced to false validate'
66
+
67
+ ## Callbacks
68
+
69
+ on_step_failure do |f|
70
+ f.go_to :step_2
71
+ end
72
+
73
+ on_step_failure :only => [:step_2] do |f|
74
+ f.restart
75
+ end
76
+
77
+ on_step_failure :except => [:step_1] do |f|
78
+ if contition
79
+ f.repeat
80
+ else
81
+ f.continue
82
+ end
83
+ end
84
+
85
+ before_each_step do |step|
86
+ # code
87
+ end
88
+
89
+ after_each_step do |step|
90
+ # code
91
+ end
92
+
93
+ ## Executing code if a step runs successful
94
+
95
+ step(:step_1).success do |step|
96
+ # code
97
+ end
98
+
99
+ ## Conditional Steps
100
+
101
+ step(:step_1).condition do
102
+ true
103
+ end
104
+
105
+ ## Executing a step depending on other step condition
106
+
107
+ step(:step_2) do
108
+ # code
109
+ end.condition do
110
+ step(:step_1).performed?
111
+ end
112
+
113
+ ## Grouping steps
114
+
115
+ group :group_1 do
116
+
117
+ step :step_1 do
118
+ #code
119
+ end
120
+
121
+ step :step_2 do
122
+ #code
123
+ end
124
+
125
+ end
126
+
127
+ step :step_3 do
128
+ #code
129
+ end
130
+
131
+ run_steps( {:group => :group_1} ) # only the steps 1 and 2 will be performed
132
+
133
+ ## Group with condition
134
+
135
+ group(:group_1)
136
+
137
+ step(:step_2) do
138
+ # code
139
+ end
140
+
141
+ end.condition do
142
+ step(:step_1).performed?
143
+ end
144
+
145
+ run_steps # only if was performed
146
+
147
+ ## Execute from and/or upto defined step
148
+
149
+ step :step_1 { ... }
150
+ step :step_2 { ... }
151
+ step :step_3 { ... }
152
+ step :step_4 { ... }
153
+ run_steps :upto => :step_2 # should execute :step_1 end :step_2
154
+ run_steps :from => :step_3 # should execute :step_3 end :step_4
155
+ run_steps :from => :step2, :upto => :step_3 # should execute :step_2 end :step_3
156
+
157
+ ## Contributing
158
+
159
+ 1. Fork it
160
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
161
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
162
+ 4. Push to the branch (`git push origin my-new-feature`)
163
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,59 @@
1
+ # encoding: utf-8
2
+
3
+ require "step_machine/version"
4
+ require "step_machine/group"
5
+ require "step_machine/step"
6
+ require "step_machine/runner"
7
+
8
+ module StepMachine
9
+
10
+ module ClassMethods
11
+ end
12
+
13
+ module InstanceMethods
14
+
15
+ def group(name, &block)
16
+ @step_machine_runner ||= Runner.new
17
+ @step_machine_runner.group(name, &block)
18
+ end
19
+
20
+ def step(name, &block)
21
+ @step_machine_runner ||= Runner.new
22
+ @step_machine_runner.step(name, &block)
23
+ end
24
+
25
+ def on_step_failure(options = {}, &block)
26
+ @step_machine_runner.on_step_failure(options, &block)
27
+ end
28
+
29
+ def before_each_step(options = {}, &block)
30
+ @step_machine_runner.before_each_step(options, &block)
31
+ end
32
+
33
+ def after_each_step(options = {}, &block)
34
+ @step_machine_runner.after_each_step(options, &block)
35
+ end
36
+
37
+ def run_steps(options = {})
38
+ @step_machine_runner.run(options)
39
+ end
40
+
41
+ def first_step(step)
42
+ @step_machine_runner.first_step = step
43
+ end
44
+
45
+ def run_status
46
+ @step_machine_runner.status
47
+ end
48
+
49
+ def failed_step
50
+ @step_machine_runner.failed_step
51
+ end
52
+
53
+ end
54
+
55
+ def self.included(receiver)
56
+ receiver.extend ClassMethods
57
+ receiver.send :include, InstanceMethods
58
+ end
59
+ end
@@ -0,0 +1,17 @@
1
+ module StepMachine
2
+
3
+ class Group
4
+ attr_accessor :name, :first_step
5
+ attr_reader :condition_block
6
+
7
+ def initialize(name)
8
+ @name = name
9
+ end
10
+
11
+ def condition(&block)
12
+ @condition_block = block if block
13
+ self
14
+ end
15
+
16
+ end
17
+ end
@@ -0,0 +1,201 @@
1
+ module StepMachine
2
+ class Runner
3
+
4
+ attr_accessor :first_step, :continue, :next_step, :times_to_repeat, :repeat_what
5
+ attr_reader :status, :failed_step
6
+
7
+ def initialize
8
+ @steps = []
9
+ @groups = []
10
+ @failure_treatments = []
11
+ @before_each_step = []
12
+ @after_each_step = []
13
+ @times_to_repeat = -1
14
+ end
15
+
16
+ def step(name, &block)
17
+ step = get_step(name) || create_step(name)
18
+ step.block = block if block
19
+ @first_step ||= step
20
+ @next_step ||= @first_step
21
+
22
+ step
23
+ end
24
+
25
+ def group(name)
26
+ return nil if name.nil?
27
+ @current_group = group = @groups.detect {|g| g.name == name} || create_group(name)
28
+ yield if block_given?
29
+ @current_group = nil
30
+ group
31
+ end
32
+
33
+ def on_step_failure(options = {}, &block)
34
+ @failure_treatments << FailureTreatment.new(self, block, options)
35
+ end
36
+
37
+ def before_each_step(options = {}, &block)
38
+ @before_each_step << options.merge(:block => block)
39
+ end
40
+
41
+ def after_each_step(options = {}, &block)
42
+ @after_each_step << options.merge(:block => block)
43
+ end
44
+
45
+ def first_step=(step)
46
+ @next_step = @first_step = step
47
+ end
48
+
49
+ def run(options = {})
50
+ if group = group(options[:group])
51
+ assign_group_first_step(group)
52
+ return if @next_step.group != group
53
+ end
54
+
55
+ assign_from_step(options[:from]) unless options[:from].nil?
56
+
57
+ @continue = nil
58
+ step = @next_step
59
+
60
+ @status ||= :success
61
+
62
+ execute_before_each_step(step)
63
+
64
+ unless step.perform
65
+ @failed_step = step
66
+
67
+ return repeat if repeat?
68
+
69
+ execute_step_failures(step)
70
+
71
+ return run if @continue
72
+ @status = :failure
73
+ return
74
+ end
75
+ execute_after_each_step(step)
76
+
77
+ return if step.name == options[:upto]
78
+
79
+ run(options) if @next_step = step.next
80
+ end
81
+
82
+ private
83
+
84
+ def assign_from_step(step)
85
+ if !@from_first_step
86
+ @next_step = get_step(step)
87
+ @from_first_step = true
88
+ end
89
+ end
90
+
91
+ def assign_group_first_step(group)
92
+ if !@group_first_step
93
+ @next_step = group.first_step
94
+ @group_first_step = true
95
+ end
96
+ end
97
+
98
+ def execute_before_each_step(step)
99
+ @before_each_step.each do |before|
100
+ next if before.has_key?(:only) && !before[:only].include?(step.name)
101
+ next if before.has_key?(:except) && before[:except].include?(step.name)
102
+ before[:block].call(step)
103
+ end
104
+ end
105
+
106
+ def execute_after_each_step(step)
107
+ @after_each_step.each do |after|
108
+ next if after.has_key?(:only) && !after[:only].include?(step.name)
109
+ next if after.has_key?(:except) && after[:except].include?(step.name)
110
+ after[:block].call(step)
111
+ end
112
+ end
113
+
114
+ def execute_step_failures(step)
115
+ @failure_treatments.each do |failure_treatment|
116
+ failure_treatment.treat(step)
117
+ end
118
+ end
119
+
120
+ def get_step(name)
121
+ @steps.find { |step| step.name == name }
122
+ end
123
+
124
+ def create_step(name)
125
+ step = Step.new(name)
126
+ step.group = @current_group
127
+ @current_group.first_step ||= step if @current_group
128
+ @steps << step
129
+ @steps[-2].next_step = step if @steps.length > 1
130
+ step
131
+ end
132
+
133
+ def create_group(name)
134
+ group = Group.new(name)
135
+ @groups << group
136
+ group
137
+ end
138
+
139
+ def repeat?
140
+ @times_to_repeat >= 0
141
+ end
142
+
143
+ def repeat
144
+ @times_to_repeat -= 1
145
+
146
+ if @times_to_repeat == -1
147
+ @status = :failure
148
+ return
149
+ end
150
+
151
+ @next_step = @repeat_what == :process ? @first_step : @failed_step
152
+ return run
153
+ end
154
+
155
+
156
+ class FailureTreatment
157
+ attr_accessor :step
158
+
159
+ def initialize(runner, block, options)
160
+ @runner = runner
161
+ @block = block
162
+ @options = options
163
+ end
164
+
165
+ def treat(step)
166
+ return if @options.has_key?(:only) && !@options[:only].include?(step.name)
167
+ return if @options.has_key?(:except) && @options[:except].include?(step.name)
168
+ @step = step
169
+
170
+ @block.call(self)
171
+ end
172
+
173
+ def go_to(step_name)
174
+ @runner.next_step = @runner.step(step_name)
175
+ @runner.continue = true
176
+ end
177
+
178
+ def repeat
179
+ go_to(@step.name)
180
+ @runner.repeat_what = :step
181
+ self
182
+ end
183
+
184
+ def continue
185
+ go_to(@step.next.name)
186
+ end
187
+
188
+ def restart
189
+ go_to(@runner.first_step.name)
190
+ @runner.repeat_what = :process
191
+ self
192
+ end
193
+
194
+ def times(number)
195
+ @runner.times_to_repeat = number - 1
196
+ end
197
+
198
+ end
199
+
200
+ end
201
+ end