composable_operations 0.7.0 → 0.8.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.
- checksums.yaml +4 -4
- data/lib/composable_operations/composed_operation.rb +1 -1
- data/lib/composable_operations/operation.rb +28 -3
- data/lib/composable_operations/version.rb +1 -1
- data/spec/composable_operations/exception_handling_spec.rb +146 -0
- data/spec/composable_operations/operation_input_forwarding_spec.rb +29 -0
- data/spec/composable_operations/operation_spec.rb +0 -75
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: af1c4603f14d42656d794709d5db02bc69014f7b
|
4
|
+
data.tar.gz: c3b7bcd54b0747b0173f1e01050cb0f1a307247c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7cd11e937b6183a4b628d02d9b9ade6400a6dd9c831410a6905ab21e06d88db3b17117e8a06261e6064119f092b760f66053db87d8d2c8294eb5e6af31915e64
|
7
|
+
data.tar.gz: 6647e6ba14819d2d6fe07d339ac5290d449038ed2096f33f8c1ea64903202379adb1acd707586332b6c2c809c2d8bdbfe05cff3bbf9f33cbdde232dba05027a8
|
@@ -15,7 +15,7 @@ module ComposableOperations
|
|
15
15
|
operation = new(*args)
|
16
16
|
operation.perform
|
17
17
|
|
18
|
-
raise
|
18
|
+
raise operation.exception if operation.failed?
|
19
19
|
|
20
20
|
operation.result
|
21
21
|
end
|
@@ -86,6 +86,7 @@ module ComposableOperations
|
|
86
86
|
attr_reader :result
|
87
87
|
attr_reader :message
|
88
88
|
attr_reader :backtrace
|
89
|
+
attr_reader :exception
|
89
90
|
|
90
91
|
def initialize(*args)
|
91
92
|
named_input_parameters = args.shift(self.class.arity)
|
@@ -136,18 +137,42 @@ module ComposableOperations
|
|
136
137
|
attr_writer :message
|
137
138
|
attr_writer :result
|
138
139
|
attr_writer :backtrace
|
140
|
+
attr_writer :exception
|
139
141
|
|
140
142
|
def execute
|
141
143
|
raise NotImplementedError, "#{name}#execute not implemented"
|
142
144
|
end
|
143
145
|
|
144
|
-
def fail(
|
146
|
+
def fail(*args)
|
145
147
|
raise "Operation execution has already been aborted" if halted? or failed?
|
148
|
+
exception, message, backtrace = nil, nil, nil
|
149
|
+
|
150
|
+
case args.length
|
151
|
+
when 1
|
152
|
+
value = args[0]
|
153
|
+
if Exception === value
|
154
|
+
exception = value
|
155
|
+
elsif Class === value && Exception > value
|
156
|
+
exception = value
|
157
|
+
message = value.message
|
158
|
+
backtrace = value.backtrace
|
159
|
+
else
|
160
|
+
message = value
|
161
|
+
end
|
162
|
+
when 2, 3
|
163
|
+
exception, message, backtrace = args[0], args[1], args[2]
|
164
|
+
end
|
165
|
+
|
166
|
+
backtrace ||= caller
|
167
|
+
exception ||= self.class.exception
|
168
|
+
exception = Class === exception ? exception.new(message) : exception
|
169
|
+
exception.set_backtrace(backtrace)
|
146
170
|
|
147
171
|
self.state = :failed
|
148
172
|
self.backtrace = backtrace
|
149
173
|
self.message = message
|
150
|
-
|
174
|
+
self.exception = exception
|
175
|
+
throw :halt, nil
|
151
176
|
end
|
152
177
|
|
153
178
|
def halt(message = nil, return_value = nil)
|
@@ -0,0 +1,146 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe ComposableOperations::Operation, "that always fails:" do
|
4
|
+
let(:failing_operation) do
|
5
|
+
Class.new(described_class) do
|
6
|
+
def execute
|
7
|
+
fail "Operation failed"
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
context "When no default exception has been specified" do
|
13
|
+
it "should raise an error when executed" do
|
14
|
+
expect { failing_operation.perform }.to raise_error(ComposableOperations::OperationError, "Operation failed")
|
15
|
+
end
|
16
|
+
|
17
|
+
context "when manually instantiated and executed" do
|
18
|
+
subject(:failing_operation_instance) do
|
19
|
+
operation = failing_operation.new
|
20
|
+
operation.perform
|
21
|
+
operation
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should have nil as result" do
|
25
|
+
failing_operation_instance.result.should be_nil
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should have failed" do
|
29
|
+
failing_operation_instance.should be_failed
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should have a message" do
|
33
|
+
failing_operation_instance.message.should_not be_nil
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should have an exception of type OperationError whose message is 'Operation failed'" do
|
37
|
+
failing_operation_instance.exception.should be_kind_of(ComposableOperations::OperationError)
|
38
|
+
failing_operation_instance.exception.message.should be == 'Operation failed'
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
context "when extended with a finalizer" do
|
43
|
+
let(:supervisor) { mock("Supervisor") }
|
44
|
+
|
45
|
+
let(:failing_operation_with_finalizer) do
|
46
|
+
supervisor = supervisor()
|
47
|
+
Class.new(failing_operation) do
|
48
|
+
after { supervisor.notify }
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
subject(:failing_operation_with_finalizer_instance) do
|
53
|
+
failing_operation_with_finalizer.new
|
54
|
+
end
|
55
|
+
|
56
|
+
it "should execute the finalizers" do
|
57
|
+
supervisor.should_receive(:notify)
|
58
|
+
failing_operation_with_finalizer_instance.perform
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
context "When a default exception has been specified" do
|
64
|
+
let(:custom_exception) { Class.new(RuntimeError) }
|
65
|
+
|
66
|
+
subject(:failing_operation_with_custom_default_exception) do
|
67
|
+
custom_exception = custom_exception()
|
68
|
+
Class.new(failing_operation) do
|
69
|
+
raises custom_exception
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
it "should raise the custom exeception when executed" do
|
74
|
+
expect { failing_operation_with_custom_default_exception.perform }.
|
75
|
+
to raise_error(custom_exception, "Operation failed")
|
76
|
+
end
|
77
|
+
|
78
|
+
context "when manually instantiated and executed" do
|
79
|
+
subject(:failing_operation_with_custom_default_exception_instance) do
|
80
|
+
operation = failing_operation_with_custom_default_exception.new
|
81
|
+
operation.perform
|
82
|
+
operation
|
83
|
+
end
|
84
|
+
|
85
|
+
it "should have an exception of the custom exception type whose message is 'Operation failed'" do
|
86
|
+
failing_operation_with_custom_default_exception_instance.exception.should be_kind_of(custom_exception)
|
87
|
+
failing_operation_with_custom_default_exception_instance.exception.message.should be == 'Operation failed'
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
context "When a custom exception has been specified" do
|
93
|
+
let(:custom_exception) { Class.new(RuntimeError) }
|
94
|
+
subject(:failing_operation_with_custom_exception) do
|
95
|
+
custom_exception = self.custom_exception
|
96
|
+
Class.new(described_class) do
|
97
|
+
define_method(:execute) do
|
98
|
+
fail custom_exception, "Operation failed"
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
it "should raise the custom exeception when executed" do
|
104
|
+
expect { failing_operation_with_custom_exception.perform }.
|
105
|
+
to raise_error(custom_exception, "Operation failed")
|
106
|
+
end
|
107
|
+
|
108
|
+
context "when manually instantiated and executed" do
|
109
|
+
subject(:failing_operation_with_custom_exception_instance) do
|
110
|
+
operation = failing_operation_with_custom_exception.new
|
111
|
+
operation.perform
|
112
|
+
operation
|
113
|
+
end
|
114
|
+
|
115
|
+
it "should have an exception of the custom exception type whose message is 'Operation failed'" do
|
116
|
+
failing_operation_with_custom_exception_instance.exception.should be_kind_of(custom_exception)
|
117
|
+
failing_operation_with_custom_exception_instance.exception.message.should be == 'Operation failed'
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
context "when used in a composed operation" do
|
122
|
+
let(:failing_composed_operation) do
|
123
|
+
ComposableOperations::ComposedOperation.compose(failing_operation_with_custom_exception)
|
124
|
+
end
|
125
|
+
|
126
|
+
it "should raise the custom exception that is thrown by the inner operation when executed" do
|
127
|
+
expect { failing_composed_operation.perform }.
|
128
|
+
to raise_error(custom_exception, "Operation failed")
|
129
|
+
end
|
130
|
+
|
131
|
+
context "when this composed operation is manually instantiated and executed" do
|
132
|
+
subject(:failing_composed_operation_instance) do
|
133
|
+
operation = failing_composed_operation.new
|
134
|
+
operation.perform
|
135
|
+
operation
|
136
|
+
end
|
137
|
+
|
138
|
+
it "should have an exception of the custom exception type whose message is 'Operation failed'" do
|
139
|
+
failing_composed_operation_instance.exception.should be_kind_of(custom_exception)
|
140
|
+
failing_composed_operation_instance.exception.message.should be == 'Operation failed'
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
@@ -2,6 +2,35 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
describe ComposableOperations::ComposedOperation, "input forwarding:" do
|
4
4
|
|
5
|
+
describe "An operation pipeline that first constructs an array with two elements and then passes it to an operation that accepts two input parameters and returns the second one" do
|
6
|
+
|
7
|
+
let(:array_generator) do
|
8
|
+
Class.new(ComposableOperations::Operation) do
|
9
|
+
def execute
|
10
|
+
[:first_element, :second_element]
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
let(:extractor) do
|
16
|
+
Class.new(ComposableOperations::Operation) do
|
17
|
+
processes :first_parameter, :second_parameter
|
18
|
+
def execute
|
19
|
+
second_parameter
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
subject(:pipeline) do
|
25
|
+
ComposableOperations::ComposedOperation.compose(array_generator, extractor)
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should return the correct element" do
|
29
|
+
result = pipeline.perform
|
30
|
+
result.should == :second_element
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
5
34
|
describe "An operation pipeline that first constructs an enumerator, then passes it from operation to operation and finally returns it as the result" do
|
6
35
|
|
7
36
|
let(:enum_generator) do
|
@@ -46,81 +46,6 @@ describe ComposableOperations::Operation do
|
|
46
46
|
|
47
47
|
end
|
48
48
|
|
49
|
-
context "that always fails" do
|
50
|
-
|
51
|
-
let(:failing_operation) do
|
52
|
-
Class.new(described_class) do
|
53
|
-
def execute
|
54
|
-
fail "Operation failed"
|
55
|
-
end
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
subject(:failing_operation_instance) do
|
60
|
-
failing_operation.new
|
61
|
-
end
|
62
|
-
|
63
|
-
before(:each) do
|
64
|
-
failing_operation_instance.perform
|
65
|
-
end
|
66
|
-
|
67
|
-
it "should have nil as result" do
|
68
|
-
failing_operation_instance.result.should be_nil
|
69
|
-
end
|
70
|
-
|
71
|
-
it "should have failed" do
|
72
|
-
failing_operation_instance.should be_failed
|
73
|
-
end
|
74
|
-
|
75
|
-
it "should have a message" do
|
76
|
-
failing_operation_instance.message.should_not be_nil
|
77
|
-
end
|
78
|
-
|
79
|
-
it "should raise an error when executed using the class method perform" do
|
80
|
-
expect { failing_operation.perform }.to raise_error("Operation failed")
|
81
|
-
end
|
82
|
-
|
83
|
-
context "when extended with a finalizer" do
|
84
|
-
|
85
|
-
let(:supervisor) { mock("Supervisor") }
|
86
|
-
|
87
|
-
let(:failing_operation_instance_with_finalizer) do
|
88
|
-
supervisor = supervisor()
|
89
|
-
Class.new(failing_operation) do
|
90
|
-
after { supervisor.notify }
|
91
|
-
end
|
92
|
-
end
|
93
|
-
|
94
|
-
subject(:failing_operation_instance_with_finalizer_instance) do
|
95
|
-
failing_operation_instance_with_finalizer.new
|
96
|
-
end
|
97
|
-
|
98
|
-
it "should execute the finalizers" do
|
99
|
-
supervisor.should_receive(:notify)
|
100
|
-
failing_operation_instance_with_finalizer_instance.perform
|
101
|
-
end
|
102
|
-
|
103
|
-
end
|
104
|
-
|
105
|
-
context "when configured to raise a custom exception" do
|
106
|
-
|
107
|
-
let(:custom_exception) { Class.new(RuntimeError) }
|
108
|
-
|
109
|
-
subject(:failing_operation_with_custom_exception) do
|
110
|
-
custom_exception = custom_exception()
|
111
|
-
Class.new(failing_operation) do
|
112
|
-
raises custom_exception
|
113
|
-
end
|
114
|
-
end
|
115
|
-
|
116
|
-
it "should raise the custom exeception when executed using the class method perform" do
|
117
|
-
expect { failing_operation_with_custom_exception.perform }.to raise_error(custom_exception, "Operation failed")
|
118
|
-
end
|
119
|
-
|
120
|
-
end
|
121
|
-
|
122
|
-
end
|
123
|
-
|
124
49
|
context "that always returns something when executed" do
|
125
50
|
|
126
51
|
let(:simple_operation) do
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: composable_operations
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.8.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Konstantin Tennhard
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-
|
11
|
+
date: 2013-10-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: smart_properties
|
@@ -105,6 +105,7 @@ files:
|
|
105
105
|
- lib/composable_operations/version.rb
|
106
106
|
- spec/composable_operations/composed_operation_spec.rb
|
107
107
|
- spec/composable_operations/control_flow_spec.rb
|
108
|
+
- spec/composable_operations/exception_handling_spec.rb
|
108
109
|
- spec/composable_operations/operation_input_forwarding_spec.rb
|
109
110
|
- spec/composable_operations/operation_input_processing_spec.rb
|
110
111
|
- spec/composable_operations/operation_spec.rb
|
@@ -136,6 +137,7 @@ summary: Tool set for operation pipelines.
|
|
136
137
|
test_files:
|
137
138
|
- spec/composable_operations/composed_operation_spec.rb
|
138
139
|
- spec/composable_operations/control_flow_spec.rb
|
140
|
+
- spec/composable_operations/exception_handling_spec.rb
|
139
141
|
- spec/composable_operations/operation_input_forwarding_spec.rb
|
140
142
|
- spec/composable_operations/operation_input_processing_spec.rb
|
141
143
|
- spec/composable_operations/operation_spec.rb
|