rung 0.0.1.pre.alpha → 0.1
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 +4 -4
- data/.circleci/config.yml +72 -0
- data/.config/cucumber.yml +1 -0
- data/.gitignore +3 -0
- data/.rspec +0 -1
- data/.rubocop.yml +22 -0
- data/Gemfile +6 -2
- data/Gemfile.lock +23 -1
- data/README.adoc +111 -0
- data/Rakefile +19 -4
- data/features/{steps_definition.feature → 010_operation.feature} +29 -6
- data/features/{state.feature → 020_state.feature} +17 -4
- data/features/{failure.feature → 030_failure.feature} +29 -6
- data/features/040_failure_step.feature +118 -0
- data/features/050_other_steps.feature +135 -0
- data/features/051_fail_fast.feature +66 -0
- data/features/060_step_wrappers.feature +170 -0
- data/features/070_operation_wrappers.feature +41 -0
- data/features/080_exceptions_handling.feature +57 -0
- data/features/090_around_step_wrapper.feature +130 -0
- data/features/200_misc.feature +18 -0
- data/features/step_definitions/output.rb +8 -3
- data/features/step_definitions/temporary_code_scope.rb +8 -7
- data/lib/rung.rb +7 -6
- data/lib/rung/definition/callback.rb +14 -0
- data/lib/rung/definition/nested_step.rb +16 -0
- data/lib/rung/definition/operation_dsl.rb +31 -0
- data/lib/rung/definition/step.rb +43 -0
- data/lib/rung/definition/steps_dsl.rb +33 -18
- data/lib/rung/{base.rb → operation.rb} +3 -2
- data/lib/rung/runner/call_helper.rb +30 -12
- data/lib/rung/runner/run_context.rb +23 -6
- data/lib/rung/runner/runner.rb +34 -14
- data/lib/rung/state.rb +35 -0
- data/lib/rung/value_object.rb +12 -0
- data/lib/rung/version.rb +1 -1
- data/rung.gemspec +15 -16
- data/target/cukedoctor-intro.adoc +1 -0
- data/target/cukedoctor.css +3 -0
- metadata +39 -23
- data/README.md +0 -79
- data/lib/rung/definition/steps/nested_step.rb +0 -20
- data/lib/rung/definition/steps/step.rb +0 -30
- data/lib/rung/definition/steps_definition.rb +0 -13
- data/lib/rung/runner/result.rb +0 -24
- data/lib/rung/runner/run_state.rb +0 -12
@@ -0,0 +1,41 @@
|
|
1
|
+
# order: 70
|
2
|
+
Feature: Operation wrappers
|
3
|
+
:!hardbreaks:
|
4
|
+
It is possible to define global wrappers on the Operation level using `around` call.
|
5
|
+
|
6
|
+
Scenario: Operation can have multiple global wrappers
|
7
|
+
Wrappers are called in the order they are defined.
|
8
|
+
Given definition
|
9
|
+
"""ruby
|
10
|
+
class Operation < Rung::Operation
|
11
|
+
class Wrapper
|
12
|
+
def initialize(name)
|
13
|
+
@name = name
|
14
|
+
end
|
15
|
+
|
16
|
+
def call
|
17
|
+
print_to_output "#{@name} start\n"
|
18
|
+
yield
|
19
|
+
print_to_output "#{@name} done\n"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
around Wrapper.new("1")
|
24
|
+
around Wrapper.new("2")
|
25
|
+
|
26
|
+
step { print_to_output "Hello World!\n" }
|
27
|
+
end
|
28
|
+
"""
|
29
|
+
When I run
|
30
|
+
"""
|
31
|
+
Operation.new.call(variable: true)
|
32
|
+
"""
|
33
|
+
Then I see output
|
34
|
+
"""
|
35
|
+
1 start
|
36
|
+
2 start
|
37
|
+
Hello World!
|
38
|
+
2 done
|
39
|
+
1 done
|
40
|
+
|
41
|
+
"""
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# order: 80
|
2
|
+
Feature: Exceptions handling
|
3
|
+
Rung doesn't provide any built-in exception handling.
|
4
|
+
If you need to catch any exceptions you can implement error catching
|
5
|
+
using a wrapper on a desired execution level.
|
6
|
+
|
7
|
+
Scenario: All exceptions are raised
|
8
|
+
Given definition
|
9
|
+
"""ruby
|
10
|
+
class Operation < Rung::Operation
|
11
|
+
step { raise "Oh no!" }
|
12
|
+
end
|
13
|
+
"""
|
14
|
+
When I run
|
15
|
+
"""
|
16
|
+
begin
|
17
|
+
Operation.new.call(output_text: "Hello ")
|
18
|
+
rescue => e
|
19
|
+
print_to_output e.message
|
20
|
+
end
|
21
|
+
"""
|
22
|
+
Then I see output
|
23
|
+
"""
|
24
|
+
Oh no!
|
25
|
+
"""
|
26
|
+
|
27
|
+
Scenario: Exception can be caught in a wrapper
|
28
|
+
Given definition
|
29
|
+
"""ruby
|
30
|
+
class Operation < Rung::Operation
|
31
|
+
class Wrapper
|
32
|
+
def self.call(state)
|
33
|
+
yield
|
34
|
+
rescue
|
35
|
+
print_to_output "Exception handled"
|
36
|
+
state[:exception_handled] = true
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
around Wrapper
|
41
|
+
|
42
|
+
step { print_to_output "Hello World!\n"; raise "oops!" }
|
43
|
+
end
|
44
|
+
"""
|
45
|
+
When I run
|
46
|
+
"""
|
47
|
+
@result = Operation.new.call
|
48
|
+
"""
|
49
|
+
Then I see output
|
50
|
+
"""
|
51
|
+
Hello World!
|
52
|
+
Exception handled
|
53
|
+
"""
|
54
|
+
And I can assure that
|
55
|
+
"""
|
56
|
+
@result.to_h == { exception_handled: true }
|
57
|
+
"""
|
@@ -0,0 +1,130 @@
|
|
1
|
+
# order: 90
|
2
|
+
Feature: Around step wrapper
|
3
|
+
:!hardbreaks:
|
4
|
+
|
5
|
+
Scenario: Step wrapper is called for every step
|
6
|
+
Given definition
|
7
|
+
"""ruby
|
8
|
+
class Operation < Rung::Operation
|
9
|
+
class Counter
|
10
|
+
def initialize
|
11
|
+
@count = 0
|
12
|
+
end
|
13
|
+
|
14
|
+
def call
|
15
|
+
@count += 1
|
16
|
+
print_to_output "Step #{@count}\n"
|
17
|
+
yield
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
around_each Counter.new
|
22
|
+
|
23
|
+
step do
|
24
|
+
print_to_output "Hello\n"
|
25
|
+
end
|
26
|
+
|
27
|
+
step do
|
28
|
+
print_to_output "World\n"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
"""
|
32
|
+
When I run
|
33
|
+
"""
|
34
|
+
Operation.new.call
|
35
|
+
"""
|
36
|
+
Then I see output
|
37
|
+
"""
|
38
|
+
Step 1
|
39
|
+
Hello
|
40
|
+
Step 2
|
41
|
+
World
|
42
|
+
|
43
|
+
"""
|
44
|
+
|
45
|
+
Scenario: Step wrapper receives state and current step
|
46
|
+
Given definition
|
47
|
+
"""ruby
|
48
|
+
class Operation < Rung::Operation
|
49
|
+
class Logger
|
50
|
+
def self.call(state, step)
|
51
|
+
result = yield
|
52
|
+
|
53
|
+
print_to_output "State: #{state.to_h}, success: #{state.success?}," \
|
54
|
+
"ignores result: #{step.ignore_result?}, nested: #{step.nested?}, result: #{result}\n"
|
55
|
+
|
56
|
+
result
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
noop_wrapper = -> (&block) { block.call }
|
61
|
+
|
62
|
+
around_each Logger
|
63
|
+
|
64
|
+
step do |state|
|
65
|
+
print_to_output "Hello\n"
|
66
|
+
state[:test] = 42
|
67
|
+
end
|
68
|
+
|
69
|
+
step noop_wrapper do
|
70
|
+
tee do |state|
|
71
|
+
state[:test] = 5
|
72
|
+
print_to_output "World\n"
|
73
|
+
true
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
"""
|
78
|
+
When I run
|
79
|
+
"""
|
80
|
+
Operation.new.call
|
81
|
+
"""
|
82
|
+
Then I see output
|
83
|
+
"""
|
84
|
+
Hello
|
85
|
+
State: {:test=>42}, success: true,ignores result: false, nested: false, result: 42
|
86
|
+
World
|
87
|
+
State: {:test=>5}, success: true,ignores result: true, nested: false, result: true
|
88
|
+
State: {:test=>5}, success: true,ignores result: false, nested: true, result: true
|
89
|
+
|
90
|
+
"""
|
91
|
+
|
92
|
+
Scenario: Step wrapper returned result is treated as the step result
|
93
|
+
Given definition
|
94
|
+
"""ruby
|
95
|
+
class Operation < Rung::Operation
|
96
|
+
class Boom
|
97
|
+
def self.call(state)
|
98
|
+
yield
|
99
|
+
print_to_output "Boom!\n"
|
100
|
+
false # always return false
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
around_each Boom
|
105
|
+
|
106
|
+
tee do |state| # tee step ignores result, so Boom doesn't affect it
|
107
|
+
print_to_output "Hello\n"
|
108
|
+
end
|
109
|
+
|
110
|
+
step { print_to_output "Beautiful\n" }
|
111
|
+
step { print_to_output "World\n" }
|
112
|
+
end
|
113
|
+
"""
|
114
|
+
When I run
|
115
|
+
"""
|
116
|
+
@result = Operation.new.call
|
117
|
+
"""
|
118
|
+
Then I see output
|
119
|
+
"""
|
120
|
+
Hello
|
121
|
+
Boom!
|
122
|
+
Beautiful
|
123
|
+
Boom!
|
124
|
+
|
125
|
+
"""
|
126
|
+
And I can assure that
|
127
|
+
"""
|
128
|
+
@result.success? == false
|
129
|
+
"""
|
130
|
+
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# order: 200
|
2
|
+
Feature: Misc
|
3
|
+
Scenario: Operation defines .call shorthand class method
|
4
|
+
Given definition
|
5
|
+
"""ruby
|
6
|
+
class Operation < Rung::Operation
|
7
|
+
step {|state| state[:test] = 42 + state[:input] }
|
8
|
+
end
|
9
|
+
"""
|
10
|
+
When I run
|
11
|
+
"""
|
12
|
+
@result1 = Operation.call(input: 1)
|
13
|
+
@result2 = Operation.new.call(input: 1)
|
14
|
+
"""
|
15
|
+
And I can assure that
|
16
|
+
"""
|
17
|
+
@result1.to_h == @result2.to_h
|
18
|
+
"""
|
@@ -1,10 +1,15 @@
|
|
1
1
|
Before do
|
2
|
-
allow_any_instance_of(Object)
|
3
|
-
|
2
|
+
allow_any_instance_of(Object)
|
3
|
+
.to receive(:print_to_output) do |_receiver, output|
|
4
|
+
@stored_output ||= ''
|
4
5
|
@stored_output << output
|
5
6
|
end
|
6
7
|
end
|
7
8
|
|
8
|
-
Then(
|
9
|
+
Then('I see output') do |string|
|
9
10
|
expect(@stored_output).to eq string
|
10
11
|
end
|
12
|
+
|
13
|
+
Then('I clear output') do
|
14
|
+
@stored_output = ''
|
15
|
+
end
|
@@ -1,16 +1,17 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
Given("definition") do |content|
|
5
|
-
@temporary_scope ||= TemporaryScope.new
|
1
|
+
Given('definition') do |content|
|
2
|
+
@temporary_scope ||= Object.new
|
6
3
|
|
7
4
|
@temporary_scope.instance_eval(content)
|
8
5
|
end
|
9
6
|
|
10
|
-
When(
|
7
|
+
When('I run') do |content|
|
11
8
|
@temporary_scope.instance_eval(content)
|
12
9
|
end
|
13
10
|
|
14
|
-
Then(
|
11
|
+
Then(/^I can assure that/) do |content|
|
15
12
|
expect(@temporary_scope.instance_eval(content)).to eq true
|
16
13
|
end
|
14
|
+
|
15
|
+
Then('I can test that') do |content|
|
16
|
+
@temporary_scope.instance_eval(content)
|
17
|
+
end
|
data/lib/rung.rb
CHANGED
@@ -2,17 +2,18 @@ require 'forwardable'
|
|
2
2
|
|
3
3
|
require 'rung/version'
|
4
4
|
require 'rung/error'
|
5
|
+
require 'rung/value_object'
|
5
6
|
|
6
|
-
require 'rung/definition/
|
7
|
-
require 'rung/definition/
|
7
|
+
require 'rung/definition/step'
|
8
|
+
require 'rung/definition/callback'
|
9
|
+
require 'rung/definition/nested_step'
|
8
10
|
|
9
|
-
require 'rung/definition/
|
11
|
+
require 'rung/definition/operation_dsl'
|
10
12
|
require 'rung/definition/steps_dsl'
|
11
13
|
|
12
|
-
require 'rung/
|
14
|
+
require 'rung/state'
|
13
15
|
require 'rung/runner/run_context'
|
14
|
-
require 'rung/runner/run_state'
|
15
16
|
require 'rung/runner/call_helper'
|
16
17
|
require 'rung/runner/runner'
|
17
18
|
|
18
|
-
require 'rung/
|
19
|
+
require 'rung/operation'
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Rung
|
2
|
+
module Definition
|
3
|
+
class NestedStep < Step
|
4
|
+
def initialize(action, nested_steps, options = {})
|
5
|
+
super(action, options)
|
6
|
+
@nested_steps = nested_steps
|
7
|
+
end
|
8
|
+
|
9
|
+
attr_reader :nested_steps
|
10
|
+
|
11
|
+
def nested?
|
12
|
+
true
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Rung
|
2
|
+
module Definition
|
3
|
+
module OperationDSL
|
4
|
+
def around_callbacks
|
5
|
+
@around_callbacks ||= []
|
6
|
+
end
|
7
|
+
|
8
|
+
def around_each_callbacks
|
9
|
+
@around_each_callbacks ||= []
|
10
|
+
end
|
11
|
+
|
12
|
+
def around(action = nil, &block)
|
13
|
+
around_callbacks.push callback_from_definition(action, &block)
|
14
|
+
end
|
15
|
+
|
16
|
+
def around_each(action = nil, &block)
|
17
|
+
around_each_callbacks.push callback_from_definition(action, &block)
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def callback_from_definition(action, &block)
|
23
|
+
if block
|
24
|
+
Callback.new block, from_block: true
|
25
|
+
else
|
26
|
+
Callback.new action
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Rung
|
2
|
+
module Definition
|
3
|
+
class Step
|
4
|
+
include ValueObject
|
5
|
+
# rubocop:disable Metrics/LineLength
|
6
|
+
def initialize(action, from_block: false, run_on: :success, ignore_result: false, fail_fast: false)
|
7
|
+
# rubocop:enable Metrics/LineLength
|
8
|
+
@action = action
|
9
|
+
@from_block = from_block
|
10
|
+
@run_on = run_on
|
11
|
+
@ignore_result = ignore_result
|
12
|
+
@fail_fast = fail_fast
|
13
|
+
end
|
14
|
+
|
15
|
+
attr_reader :action, :from_block
|
16
|
+
|
17
|
+
def run?(success)
|
18
|
+
case @run_on
|
19
|
+
when :success
|
20
|
+
success
|
21
|
+
when :failure
|
22
|
+
!success
|
23
|
+
when :any
|
24
|
+
true
|
25
|
+
else
|
26
|
+
false
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def nested?
|
31
|
+
false
|
32
|
+
end
|
33
|
+
|
34
|
+
def ignore_result?
|
35
|
+
@ignore_result
|
36
|
+
end
|
37
|
+
|
38
|
+
def fail_fast?
|
39
|
+
@fail_fast
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -2,35 +2,50 @@ module Rung
|
|
2
2
|
module Definition
|
3
3
|
module StepsDSL
|
4
4
|
def steps_definition
|
5
|
-
@steps_definition ||=
|
5
|
+
@steps_definition ||= []
|
6
6
|
end
|
7
7
|
|
8
|
-
def
|
9
|
-
|
8
|
+
def add_generic_step(action, options = {}, &block)
|
9
|
+
step = step_from_definition action, **options, &block
|
10
|
+
steps_definition.push step
|
10
11
|
end
|
11
12
|
|
12
|
-
def
|
13
|
-
|
13
|
+
def step(*args, &block)
|
14
|
+
add_step_from_args args, &block
|
14
15
|
end
|
15
16
|
|
16
|
-
def
|
17
|
-
|
18
|
-
|
17
|
+
def tee(*args, &block)
|
18
|
+
add_step_from_args args, ignore_result: true, &block
|
19
|
+
end
|
20
|
+
|
21
|
+
def failure(*args, &block)
|
22
|
+
add_step_from_args args, run_on: :failure, ignore_result: true, &block
|
23
|
+
end
|
24
|
+
|
25
|
+
def always(*args, &block)
|
26
|
+
add_step_from_args args, run_on: :any, ignore_result: true, &block
|
19
27
|
end
|
20
28
|
|
21
29
|
private
|
22
30
|
|
23
|
-
def
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
31
|
+
def add_step_from_args(args, options = {}, &block)
|
32
|
+
action, action_options = extract_action_and_options!(args)
|
33
|
+
add_generic_step action, **options, **action_options, &block
|
34
|
+
end
|
35
|
+
|
36
|
+
def extract_action_and_options!(args)
|
37
|
+
options = args.last.is_a?(::Hash) ? args.pop : {}
|
38
|
+
[args.first, options]
|
30
39
|
end
|
31
40
|
|
32
|
-
def
|
33
|
-
|
41
|
+
def step_from_definition(action, options, &block)
|
42
|
+
if action && block
|
43
|
+
NestedStep.new(action, calculate_block_nested_steps(&block), options)
|
44
|
+
elsif block
|
45
|
+
Step.new(block, **options, from_block: true)
|
46
|
+
else
|
47
|
+
Step.new(action, options)
|
48
|
+
end
|
34
49
|
end
|
35
50
|
|
36
51
|
def calculate_block_nested_steps(&block)
|
@@ -42,7 +57,7 @@ module Rung
|
|
42
57
|
|
43
58
|
def with_new_steps_definition
|
44
59
|
old_steps_definition = @steps_definition
|
45
|
-
@steps_definition =
|
60
|
+
@steps_definition = []
|
46
61
|
yield
|
47
62
|
ensure
|
48
63
|
@steps_definition = old_steps_definition
|