yawl 0.0.3 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --colour
2
+ --format progress
3
+ --order random
data/README.md CHANGED
@@ -1,6 +1,8 @@
1
1
  # Yawl
2
2
 
3
- TODO: Write a gem description
3
+ Yawl is **Y**et **a**nother **w**orkflow **l**ibrary.
4
+
5
+ The target audience is for those who have workflows that are mostly sequential and don't need to create complex branching logic.
4
6
 
5
7
  ## Installation
6
8
 
@@ -18,16 +20,45 @@ Or install it yourself as:
18
20
 
19
21
  ## Usage
20
22
 
21
- TODO: Write usage instructions here
23
+ The way you go about using it is:
24
+
25
+ 1. You define a set of steps where most of your logic will go
26
+
27
+ ```ruby
28
+ Yawl::Steps.set :morning_routine do
29
+ step :first_thing do
30
+ def run
31
+ puts "brush teeth"
32
+ end
33
+ end
34
+ end
35
+ ```
36
+ 2. You define a process which references set(s) of steps, this will be the name you call when you want to run the process.
37
+
38
+ ```ruby
39
+ Yawl::ProcessDefinitions.add(:wake_up) do |process|
40
+ Yawl::Steps.realize_set_on(:morning_routine)
41
+ end
42
+ ```
43
+ 3. You call the process with the name you defined in step 2, and add any variables that you need to the `Yawl::Process#config` json field.
22
44
 
23
- ## Example
45
+ ```ruby
46
+ p = Yawl::Process.create(:desired_state => "wake_up", :config => {})
47
+ p.start
48
+ ```
49
+
50
+ ## Running the Example
24
51
 
25
52
  ```
26
53
  bundle exec sequel -m migrations/ postgres://localhost/yawl_examples
54
+ bundle exec ruby examples/cook_worker.rb &
27
55
  bundle exec ruby examples/cook.rb
28
- bundle exec ruby examples/cook_worker.rb
29
56
  ```
30
57
 
58
+ ## Credit
59
+
60
+ Originally written by @dpiddy, extracted by @ricardochimal from a larger project into its own gem.
61
+
31
62
  ## Contributing
32
63
 
33
64
  1. Fork it
data/Rakefile CHANGED
@@ -1 +1,7 @@
1
1
  require "bundler/gem_tasks"
2
+
3
+ require 'rspec/core/rake_task'
4
+
5
+ RSpec::Core::RakeTask.new('spec')
6
+
7
+ task :default => :spec
data/examples/cook.rb CHANGED
@@ -1,8 +1,6 @@
1
1
  $:.unshift(File.expand_path(File.join(File.dirname($0), "../lib")))
2
2
 
3
- require "sequel"
4
-
5
- Sequel.connect(ENV["DATABASE_URL"] || "postgres://localhost/yawl_examples")
3
+ ENV["DATABASE_URL"] ||= "postgres://localhost/yawl_examples"
6
4
 
7
5
  require "yawl"
8
6
  require File.dirname(File.expand_path(__FILE__)) + "/steps/scrambled_eggs"
@@ -2,8 +2,7 @@
2
2
 
3
3
  $:.unshift(File.expand_path(File.join(File.dirname($0), "../lib")))
4
4
 
5
- require "sequel"
6
- Sequel.connect(ENV["DATABASE_URL"] || "postgres://localhost/yawl_examples")
5
+ ENV["DATABASE_URL"] ||= "postgres://localhost/yawl_examples"
7
6
 
8
7
  require "yawl"
9
8
  require "yawl/worker"
data/lib/yawl.rb CHANGED
@@ -7,6 +7,8 @@ end
7
7
  require "yawl/config"
8
8
  require "yawl/log"
9
9
 
10
+ require "yawl/db"
11
+
10
12
  require "yawl/process"
11
13
  require "yawl/process_definitions"
12
14
  require "yawl/step"
data/lib/yawl/config.rb CHANGED
@@ -2,13 +2,9 @@ module Yawl
2
2
  module Config
3
3
  extend self
4
4
 
5
- attr_writer :app
5
+ attr_accessor :app
6
6
  attr_accessor :deploy
7
7
 
8
- def app
9
- @app || "yawl"
10
- end
11
-
12
8
  def log_quiet?
13
9
  env("LOG_QUIET") == "1"
14
10
  end
data/lib/yawl/db.rb ADDED
@@ -0,0 +1,13 @@
1
+ require 'sequel'
2
+ require 'yawl/config'
3
+
4
+ module Yawl
5
+ DB = Sequel.connect(ENV["DATABASE_URL"].gsub('postgresql://', 'postgres://'))
6
+ DB.extension :pg_json
7
+ DB.execute("SET bytea_output TO 'escape'")
8
+
9
+ if Config.log_sequel?
10
+ require 'logger'
11
+ DB.loggers << Logger.new($stdout)
12
+ end
13
+ end
data/lib/yawl/log.rb CHANGED
@@ -10,7 +10,12 @@ module Yawl
10
10
  end
11
11
 
12
12
  def log_measure(data)
13
- measure_base = "#{Config.app}.#{data[:ns]}.#{data[:fn]}"
13
+ if Config.app
14
+ measure_base = "#{Config.app}.#{data[:ns]}.#{data[:fn]}"
15
+ else
16
+ measure_base = "#{data[:ns]}.#{data[:fn]}"
17
+ end
18
+
14
19
  begin
15
20
  t0 = Time.now
16
21
  log(data.merge(at: "start"))
@@ -28,7 +33,8 @@ module Yawl
28
33
  if Config.log_quiet?
29
34
  block.call if block
30
35
  else
31
- params = { app: Config.app }
36
+ params = { }
37
+ params[:app] = Config.app if Config.app
32
38
  params[:source] = Config.deploy if Config.deploy
33
39
  Scrolls.log(params.merge(data), &block)
34
40
  end
data/lib/yawl/process.rb CHANGED
@@ -15,7 +15,7 @@ module Yawl
15
15
  class RequestIdAttributeMismatch < RuntimeError; end
16
16
 
17
17
  def self.log(data, &block)
18
- Log.log({ ns: "process" }.merge(data), &block)
18
+ Log.log({ ns: "yawl-process" }.merge(data), &block)
19
19
  end
20
20
 
21
21
  def log(data, &block)
data/lib/yawl/setup.rb CHANGED
@@ -1,5 +1,7 @@
1
1
  require 'sequel'
2
2
 
3
+ require 'yawl/db'
4
+
3
5
  Sequel.extension :migration
4
6
 
5
7
  module Yawl
@@ -41,17 +43,27 @@ module Yawl
41
43
  end
42
44
  end
43
45
 
44
-
45
46
  def create!
46
- MIGRATION.apply(db, :up)
47
+ MIGRATION.apply(DB, :up)
47
48
  end
48
49
 
49
50
  def destroy!
50
- MIGRATION.apply(db, :down)
51
+ MIGRATION.apply(DB, :down)
51
52
  end
52
53
 
53
- def db
54
- Sequel.connect(ENV["DATABASE_URL"])
54
+ def create_for_test!
55
+ if DB.tables.include?(:processes)
56
+ destroy!
57
+ end
58
+ create!
59
+
60
+ require "queue_classic"
61
+ QC::Setup.drop
62
+ QC::Setup.create
63
+
64
+ require "queue_classic/later"
65
+ QC::Later::Setup.drop
66
+ QC::Later::Setup.create
55
67
  end
56
68
  end
57
69
  end
data/lib/yawl/step.rb CHANGED
@@ -22,7 +22,7 @@ module Yawl
22
22
  end
23
23
 
24
24
  def self.log(data, &block)
25
- Log.log({ ns: "step" }.merge(data), &block)
25
+ Log.log({ ns: "yawl-step" }.merge(data), &block)
26
26
  end
27
27
 
28
28
  def log(data, &block)
@@ -115,7 +115,7 @@ module Yawl
115
115
  end
116
116
 
117
117
  def log(data, &block)
118
- Log.log({ ns: "step_#{name}" }.merge(data), &block)
118
+ Log.log({ ns: "yawl-step_#{name}" }.merge(data), &block)
119
119
  end
120
120
  end
121
121
 
data/lib/yawl/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Yawl
2
- VERSION = "0.0.3"
2
+ VERSION = "0.1.0"
3
3
  end
@@ -0,0 +1,368 @@
1
+ require "spec_helper"
2
+
3
+ describe Yawl::Step do
4
+ let(:process) {
5
+ p = Yawl::Process.create(:desired_state => "tested")
6
+ p.start
7
+ p
8
+ }
9
+ let(:step) { process.unfinished_steps.first }
10
+
11
+ before do
12
+ Yawl::ProcessDefinitions.add :tested do |process|
13
+ process.add_step(:name => "testing")
14
+ end
15
+ end
16
+
17
+ def define_successful_step
18
+ Yawl::Steps.step :testing do
19
+ def run
20
+ puts "I worked"
21
+ end
22
+ end
23
+ end
24
+
25
+ def define_failing_step
26
+ Yawl::Steps.step :testing do
27
+ def run
28
+ puts "I started"
29
+ raise "I failed"
30
+ end
31
+ end
32
+ end
33
+
34
+ def define_sigterm_step
35
+ Yawl::Steps.step :testing do
36
+ def run
37
+ puts "I started"
38
+ raise SignalException.new("SIGTERM")
39
+ end
40
+ end
41
+ end
42
+
43
+ def define_one_shot_failing_step
44
+ Yawl::Steps.step :testing do
45
+ def run
46
+ puts "I started"
47
+ raise "I failed"
48
+ end
49
+
50
+ def attempts
51
+ 1
52
+ end
53
+ end
54
+ end
55
+
56
+ def define_fatal_step
57
+ Yawl::Steps.step :testing do
58
+ def run
59
+ puts "I started"
60
+ raise Yawl::Step::Fatal
61
+ end
62
+ end
63
+ end
64
+
65
+ def define_sleepy_step
66
+ Yawl::Steps.step :testing do
67
+ def run
68
+ puts "I started"
69
+ sleep
70
+ end
71
+ end
72
+ end
73
+
74
+ def define_one_shot_sleepy_step
75
+ Yawl::Steps.step :testing do
76
+ def run
77
+ puts "I started"
78
+ sleep
79
+ end
80
+
81
+ def attempts
82
+ 1
83
+ end
84
+ end
85
+ end
86
+
87
+ describe ".execute" do
88
+ before do
89
+ define_successful_step
90
+ end
91
+
92
+ it "executes a single step by id" do
93
+ Yawl::Step.execute(step.id)
94
+
95
+ step.reload.state.should == "completed"
96
+ end
97
+ end
98
+
99
+ describe ".restart_interrupted" do
100
+ before do
101
+ define_successful_step
102
+ end
103
+
104
+ it "starts steps in the interrupted state" do
105
+ step.update(:state => "interrupted")
106
+
107
+ Yawl::Step.restart_interrupted
108
+
109
+ step.should be_queued_for_now
110
+ end
111
+ end
112
+
113
+ describe "#start" do
114
+ before do
115
+ define_successful_step
116
+ end
117
+
118
+ it "enqueues the step for immediate execution" do
119
+ step.start
120
+
121
+ step.should be_queued_for_now
122
+ end
123
+
124
+ it "resets state to pending" do
125
+ step.update(:state => "failed")
126
+
127
+ step.start
128
+
129
+ step.state.should == "pending"
130
+ end
131
+ end
132
+
133
+ context "running a successful step" do
134
+ before do
135
+ define_successful_step
136
+ end
137
+
138
+ it "sets state to completed" do
139
+ step.execute
140
+
141
+ step.state.should == "completed"
142
+ end
143
+
144
+ it "notifies the process of completion" do
145
+ step.process.should_receive(:step_finished)
146
+
147
+ step.execute
148
+ end
149
+
150
+ it "captures output" do
151
+ step.execute
152
+
153
+ step.attempts.first.output.should == "I worked\n"
154
+ end
155
+ end
156
+
157
+ context "running a failing step" do
158
+ context "that has attempts remaining" do
159
+ before do
160
+ define_failing_step
161
+ end
162
+
163
+ it "sets state to pending" do
164
+ step.execute
165
+
166
+ step.state.should == "pending"
167
+ end
168
+
169
+ it "does not notify the process of failure" do
170
+ step.process.should_not_receive(:step_failed)
171
+
172
+ step.execute
173
+ end
174
+
175
+ it "is queued for retry" do
176
+ step.execute
177
+
178
+ step.should be_queued_for_later
179
+ end
180
+
181
+ it "captures output" do
182
+ step.execute
183
+
184
+ step.attempts.first.output.should =~ /\AI started\n\n\n---\nCAUGHT ERROR: I failed\n.*:in `.*'/ # backtrace
185
+ end
186
+ end
187
+
188
+ context "running a fatal step" do
189
+ context "that has attempts remaining" do
190
+ before do
191
+ define_fatal_step
192
+ end
193
+
194
+ it "sets state to pending" do
195
+ expect {
196
+ step.execute
197
+ }.to raise_error(Yawl::Step::Fatal)
198
+
199
+ step.state.should == "failed"
200
+ end
201
+
202
+ it "does not notify the process of failure" do
203
+ step.process.should_receive(:step_failed)
204
+
205
+ expect {
206
+ step.execute
207
+ }.to raise_error(Yawl::Step::Fatal)
208
+ end
209
+
210
+ it "is not queued for retry" do
211
+ expect {
212
+ step.execute
213
+ }.to raise_error(Yawl::Step::Fatal)
214
+
215
+ step.should_not be_queued_for_later
216
+ end
217
+
218
+ it "captures output" do
219
+ expect {
220
+ step.execute
221
+ }.to raise_error(Yawl::Step::Fatal)
222
+
223
+ step.attempts.first.output.should =~ /\AI started\n\n\n---\nCAUGHT ERROR: Fatal error in step\n.*:in `.*'/ # backtrace
224
+ end
225
+ end
226
+ end
227
+
228
+ context "that has no attempts remaining" do
229
+ before do
230
+ define_one_shot_failing_step
231
+ end
232
+
233
+ it "passes the error through" do
234
+ expect {
235
+ step.execute
236
+ }.to raise_error("I failed")
237
+ end
238
+
239
+ it "sets state to failed" do
240
+ expect { step.execute }.to raise_error
241
+
242
+ step.state.should == "failed"
243
+ end
244
+
245
+ it "notifies the process of failure" do
246
+ step.process.should_receive(:step_failed)
247
+
248
+ expect { step.execute }.to raise_error
249
+ end
250
+
251
+ it "is not queued for retry" do
252
+ expect { step.execute }.to raise_error
253
+
254
+ step.should_not be_queued_for_later
255
+ end
256
+
257
+ it "captures output" do
258
+ expect { step.execute }.to raise_error
259
+
260
+ step.attempts.first.output.should =~ /\AI started\n\n\n---\nCAUGHT ERROR: I failed\n.*:in `.*'/
261
+ end
262
+ end
263
+
264
+ context "that fails due to SIGTERM" do
265
+ before do
266
+ define_sigterm_step
267
+ end
268
+
269
+ it "passes the error through" do
270
+ expect {
271
+ step.execute
272
+ }.to raise_error("SIGTERM")
273
+ end
274
+
275
+ it "sets state to interrupted" do
276
+ expect { step.execute }.to raise_error
277
+
278
+ step.state.should == "interrupted"
279
+ end
280
+
281
+ it "does not notify the process of failure" do
282
+ step.process.should_not_receive(:step_failed)
283
+
284
+ expect { step.execute }.to raise_error
285
+ end
286
+
287
+ it "is not queued for retry" do
288
+ expect { step.execute }.to raise_error
289
+
290
+ step.should_not be_queued_for_later
291
+ end
292
+
293
+ it "captures output" do
294
+ expect { step.execute }.to raise_error
295
+
296
+ step.attempts.first.output.should =~ /\AI started\n\n\n---\nCAUGHT ERROR: SIGTERM\n.*:in `.*'/ # backtrace
297
+ end
298
+ end
299
+ end
300
+
301
+ context "running a sleepy process" do
302
+ context "that has attempts remaining" do
303
+ before do
304
+ define_sleepy_step
305
+ end
306
+
307
+ it "sets state to pending" do
308
+ step.execute
309
+
310
+ step.state.should == "pending"
311
+ end
312
+
313
+ it "does not notify the process of failure" do
314
+ step.process.should_not_receive(:step_failed)
315
+
316
+ step.execute
317
+ end
318
+
319
+ it "is queued for retry" do
320
+ step.execute
321
+
322
+ step.should be_queued_for_later
323
+ end
324
+
325
+ it "captures output" do
326
+ step.execute
327
+
328
+ step.attempts.first.output.should =~ /\AI started\n\n\n---\nCAUGHT ERROR: Step slept\n.*:in `.*'/ # backtrace
329
+ end
330
+ end
331
+
332
+ context "that has no attempts remaining" do
333
+ before do
334
+ define_one_shot_sleepy_step
335
+ end
336
+
337
+ it "passes the error through" do
338
+ expect {
339
+ step.execute
340
+ }.to raise_error(Yawl::Step::Tired)
341
+ end
342
+
343
+ it "sets state to failed" do
344
+ expect { step.execute }.to raise_error
345
+
346
+ step.state.should == "failed"
347
+ end
348
+
349
+ it "notifies the process of failure" do
350
+ step.process.should_receive(:step_failed)
351
+
352
+ expect { step.execute }.to raise_error
353
+ end
354
+
355
+ it "is not queued for retry" do
356
+ expect { step.execute }.to raise_error
357
+
358
+ step.should_not be_queued_for_later
359
+ end
360
+
361
+ it "captures output" do
362
+ expect { step.execute }.to raise_error
363
+
364
+ step.attempts.first.output.should =~ /\AI started\n\n\n---\nCAUGHT ERROR: Step slept\n.*:in `.*'/ # backtrace
365
+ end
366
+ end
367
+ end
368
+ end
@@ -0,0 +1,70 @@
1
+ if ENV["CI"]
2
+ raise "ENV[DATABASE_URL] not set" unless ENV["DATABASE_URL"]
3
+ else
4
+ ENV["DATABASE_URL"] = "postgres://localhost/yawl-test"
5
+ end
6
+ ENV["LOG_QUIET"] ||= "1"
7
+
8
+ require "rspec"
9
+ require "yawl"
10
+
11
+ require "yawl/setup"
12
+
13
+ Yawl::Setup.create_for_test!
14
+
15
+ def QC.jobs
16
+ s = "SELECT * FROM queue_classic_jobs"
17
+ [QC::Conn.execute(s)].compact.flatten.
18
+ map {|j| j.reject {|k, v| !%w[q_name method args].include?(k) } }.
19
+ map {|j| j.merge("args" => JSON.parse(j["args"])) }.
20
+ map {|j| j.reject {|k, v| k == "args" && v.empty? } }
21
+ end
22
+
23
+ def QC.later_jobs
24
+ s = "SELECT * FROM queue_classic_later_jobs"
25
+ [QC::Conn.execute(s)].compact.flatten.
26
+ map {|j| j.reject {|k, v| !%w[q_name method args].include?(k) } }.
27
+ map {|j| j.merge("args" => JSON.parse(j["args"])) }.
28
+ map {|j| j.reject {|k, v| k == "args" && v.empty? } }
29
+ end
30
+
31
+ RSpec.configure do |c|
32
+ c.around(:each) do |example|
33
+ Yawl::DB.transaction(:rollback => :always) do
34
+ begin
35
+ QC::Conn.execute("BEGIN")
36
+ example.run
37
+ ensure
38
+ QC::Conn.execute("ROLLBACK")
39
+ end
40
+ end
41
+ end
42
+ end
43
+
44
+ RSpec::Matchers.define :be_queued_for_later do
45
+ match do |step|
46
+ QC.later_jobs.include?("q_name" => "default", "method" => "Yawl::Step.execute", "args" => [step.id])
47
+ end
48
+
49
+ failure_message_for_should do |step|
50
+ "expected #{step.inspect} to be queued for later in later jobs #{QC.later_jobs}"
51
+ end
52
+
53
+ failure_message_for_should_not do |step|
54
+ "expected #{step.inspect} to not be queued for later in later jobs #{QC.later_jobs}"
55
+ end
56
+ end
57
+
58
+ RSpec::Matchers.define :be_queued_for_now do
59
+ match do |step|
60
+ QC.jobs.include?("q_name" => "default", "method" => "Yawl::Step.execute", "args" => [step.id])
61
+ end
62
+
63
+ failure_message_for_should do |step|
64
+ "expected #{step.inspect} to be queued for now in jobs #{QC.jobs}"
65
+ end
66
+
67
+ failure_message_for_should_not do |step|
68
+ "expected #{step.inspect} to not be queued for now in jobs #{QC.jobs}"
69
+ end
70
+ end
data/yawl.gemspec CHANGED
@@ -21,8 +21,9 @@ Gem::Specification.new do |spec|
21
21
  spec.add_dependency "sequel"
22
22
  spec.add_dependency "scrolls"
23
23
  spec.add_dependency "queue_classic"
24
- spec.add_dependency "queue_classic-later"
24
+ spec.add_dependency "queue_classic-later", ">= 0.3.0"
25
25
 
26
26
  spec.add_development_dependency "bundler", "~> 1.3"
27
27
  spec.add_development_dependency "rake"
28
+ spec.add_development_dependency "rspec"
28
29
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: yawl
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.1.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2014-01-29 00:00:00.000000000 Z
12
+ date: 2014-01-30 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: sequel
@@ -66,7 +66,7 @@ dependencies:
66
66
  requirements:
67
67
  - - ! '>='
68
68
  - !ruby/object:Gem::Version
69
- version: '0'
69
+ version: 0.3.0
70
70
  type: :runtime
71
71
  prerelease: false
72
72
  version_requirements: !ruby/object:Gem::Requirement
@@ -74,7 +74,7 @@ dependencies:
74
74
  requirements:
75
75
  - - ! '>='
76
76
  - !ruby/object:Gem::Version
77
- version: '0'
77
+ version: 0.3.0
78
78
  - !ruby/object:Gem::Dependency
79
79
  name: bundler
80
80
  requirement: !ruby/object:Gem::Requirement
@@ -107,6 +107,22 @@ dependencies:
107
107
  - - ! '>='
108
108
  - !ruby/object:Gem::Version
109
109
  version: '0'
110
+ - !ruby/object:Gem::Dependency
111
+ name: rspec
112
+ requirement: !ruby/object:Gem::Requirement
113
+ none: false
114
+ requirements:
115
+ - - ! '>='
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ none: false
122
+ requirements:
123
+ - - ! '>='
124
+ - !ruby/object:Gem::Version
125
+ version: '0'
110
126
  description: Yet Another Workflow Library for Ruby
111
127
  email:
112
128
  - kiwi@null.cx
@@ -115,6 +131,7 @@ extensions: []
115
131
  extra_rdoc_files: []
116
132
  files:
117
133
  - .gitignore
134
+ - .rspec
118
135
  - Gemfile
119
136
  - LICENSE.txt
120
137
  - README.md
@@ -124,6 +141,7 @@ files:
124
141
  - examples/steps/scrambled_eggs.rb
125
142
  - lib/yawl.rb
126
143
  - lib/yawl/config.rb
144
+ - lib/yawl/db.rb
127
145
  - lib/yawl/log.rb
128
146
  - lib/yawl/process.rb
129
147
  - lib/yawl/process_definitions.rb
@@ -135,6 +153,8 @@ files:
135
153
  - lib/yawl/worker.rb
136
154
  - migrations/01_setup_tables.rb
137
155
  - migrations/02_setup_queue_classic.rb
156
+ - spec/lib/step_spec.rb
157
+ - spec/spec_helper.rb
138
158
  - yawl.gemspec
139
159
  homepage: https://github.com/ricardochimal/yawl
140
160
  licenses:
@@ -151,7 +171,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
151
171
  version: '0'
152
172
  segments:
153
173
  - 0
154
- hash: -1266345301425141028
174
+ hash: -3718802543540648108
155
175
  required_rubygems_version: !ruby/object:Gem::Requirement
156
176
  none: false
157
177
  requirements:
@@ -160,11 +180,13 @@ required_rubygems_version: !ruby/object:Gem::Requirement
160
180
  version: '0'
161
181
  segments:
162
182
  - 0
163
- hash: -1266345301425141028
183
+ hash: -3718802543540648108
164
184
  requirements: []
165
185
  rubyforge_project:
166
186
  rubygems_version: 1.8.23
167
187
  signing_key:
168
188
  specification_version: 3
169
189
  summary: Yet Another Workflow Library for Ruby
170
- test_files: []
190
+ test_files:
191
+ - spec/lib/step_spec.rb
192
+ - spec/spec_helper.rb