lou 0.2.0 → 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +6 -1
- data/lib/lou/transformer.rb +27 -6
- data/lib/lou/version.rb +1 -1
- data/spec/lou/transformer_spec.rb +88 -0
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6c875d55f836118c55dd4e3bedc345fb9839dbb6
|
4
|
+
data.tar.gz: 12c8985d3aaf1bf744a980f0135e456e8a04b860
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7eb8dedecc8d4589abcb8f83d7e37c00d32689e2710f1f58a6bbea709f198276d2e30c5ab889c3237a39f88e0e9b5691a640c4d3f859542748bfe618b5f9075d
|
7
|
+
data.tar.gz: 38e5554d87650c7df1f439d387091a6b749265b1941fe71edbaa74987ea74efcd4a593dc7521f37a1af0e76bf381325291b5722dbe8a48759d3a011c412e411a
|
data/README.md
CHANGED
@@ -17,6 +17,9 @@ require 'lou'
|
|
17
17
|
class HashTransformer
|
18
18
|
extend Lou::Transformer
|
19
19
|
|
20
|
+
# optional
|
21
|
+
reverse_on RuntimeError
|
22
|
+
|
20
23
|
step.up do |x|
|
21
24
|
x.merge(a_new_key: 'this is new')
|
22
25
|
end.down do |x|
|
@@ -41,7 +44,9 @@ original = HashTransformer.reverse(result)
|
|
41
44
|
# {:an_old_key=>"this is old"}
|
42
45
|
~~~
|
43
46
|
|
44
|
-
The
|
47
|
+
The steps are applied in the order that they're defined, when the ~apply~ method is called, with each step receiving the result of the previous one. The process can be reversed using the ~reverse~ method. Note that for each step, the input is the result of the previous step.
|
48
|
+
|
49
|
+
If ~reverse_on~ is defined, then any completed steps will be reversed if the exception specified is raised.
|
45
50
|
|
46
51
|
Transformers inherit the steps of their parent class, so it's possible to reuse steps by using inheritance.
|
47
52
|
|
data/lib/lou/transformer.rb
CHANGED
@@ -3,29 +3,50 @@ require 'lou/transformer/step'
|
|
3
3
|
|
4
4
|
module Lou
|
5
5
|
module Transformer
|
6
|
+
# never raise this...
|
7
|
+
class NeverError < StandardError; end
|
8
|
+
|
6
9
|
def self.extended(base)
|
7
10
|
base.class_eval do
|
8
11
|
class_attribute(:steps)
|
9
12
|
self.steps = []
|
13
|
+
class_attribute(:error_class)
|
14
|
+
self.error_class = Lou::Transformer::NeverError
|
10
15
|
end
|
11
16
|
end
|
12
17
|
|
18
|
+
def reverse_on(error)
|
19
|
+
self.error_class = error
|
20
|
+
end
|
21
|
+
|
13
22
|
def step
|
14
23
|
Step.new.tap do |t|
|
15
24
|
steps << t
|
16
25
|
end
|
17
26
|
end
|
18
27
|
|
19
|
-
def apply(input)
|
20
|
-
|
21
|
-
|
28
|
+
def apply(input, total_steps = steps.count)
|
29
|
+
applied_steps = 0
|
30
|
+
begin
|
31
|
+
steps.last(total_steps).each do |t|
|
32
|
+
input = t.apply(input)
|
33
|
+
applied_steps += 1
|
34
|
+
end
|
35
|
+
rescue error_class => e
|
36
|
+
total_steps == steps.count ? reverse(input, applied_steps) : raise(e)
|
22
37
|
end
|
23
38
|
input
|
24
39
|
end
|
25
40
|
|
26
|
-
def reverse(output)
|
27
|
-
|
28
|
-
|
41
|
+
def reverse(output, total_steps = steps.count)
|
42
|
+
reversed_steps = 0
|
43
|
+
begin
|
44
|
+
steps.first(total_steps).reverse_each do |t|
|
45
|
+
output = t.reverse(output)
|
46
|
+
reversed_steps += 1
|
47
|
+
end
|
48
|
+
rescue error_class => e
|
49
|
+
total_steps == steps.count ? apply(output, reversed_steps) : raise(e)
|
29
50
|
end
|
30
51
|
output
|
31
52
|
end
|
data/lib/lou/version.rb
CHANGED
@@ -110,5 +110,93 @@ module Lou
|
|
110
110
|
end
|
111
111
|
end
|
112
112
|
end
|
113
|
+
|
114
|
+
context 'when an error is raised' do
|
115
|
+
let(:klass) do
|
116
|
+
Class.new do
|
117
|
+
extend Lou::Transformer
|
118
|
+
step.up { |_| fail 'error on up' }.down { |_| fail 'error on down' }
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
describe '#apply' do
|
123
|
+
it 'raises the exception' do
|
124
|
+
expect { klass.apply('foo') }.to raise_error('error on up')
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
describe '#reverse' do
|
129
|
+
it 'raises the exception' do
|
130
|
+
expect { klass.reverse('bar') }.to raise_error('error on down')
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
context 'when #reverse_on has been set' do
|
136
|
+
let(:parent) do
|
137
|
+
Class.new do
|
138
|
+
extend Lou::Transformer
|
139
|
+
|
140
|
+
class SpecialError < StandardError; end
|
141
|
+
|
142
|
+
reverse_on SpecialError
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
let(:target) { instance_double('Target') }
|
147
|
+
|
148
|
+
context 'and an error is raised on the first step' do
|
149
|
+
let(:klass) do
|
150
|
+
Class.new(parent) do
|
151
|
+
step.up { |_| fail SpecialError }.down { |x| x.destroy(1); x }
|
152
|
+
step.up { |x| x.create(2); x }.down { |_| fail SpecialError }
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
describe '#apply' do
|
157
|
+
it 'reverses no steps when the specified error is raised' do
|
158
|
+
expect(target).to_not receive(:create)
|
159
|
+
expect(target).to_not receive(:destroy)
|
160
|
+
klass.apply(target)
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
describe '#reverse' do
|
165
|
+
it 'applies no steps when the specified error is raised' do
|
166
|
+
expect(target).to_not receive(:destroy)
|
167
|
+
expect(target).to_not receive(:create)
|
168
|
+
klass.reverse(target)
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
context 'and an error is raised part-way through the transform' do
|
174
|
+
let(:klass) do
|
175
|
+
Class.new(parent) do
|
176
|
+
step.up { |x| x.create(1); x }.down { |x| x.destroy(1); x }
|
177
|
+
step.up { |_| fail SpecialError }.down { |_| fail SpecialError }
|
178
|
+
step.up { |x| x.create(3); x }.down { |x| x.destroy(3); x }
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
let(:target) { instance_double('Target') }
|
183
|
+
|
184
|
+
describe '#apply' do
|
185
|
+
it 'reverses all successfully applied steps when the specified error is raised' do
|
186
|
+
expect(target).to receive(:create).once.with(1).ordered
|
187
|
+
expect(target).to receive(:destroy).once.with(1).ordered
|
188
|
+
klass.apply(target)
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
describe '#reverse' do
|
193
|
+
it 'reapplies all successfully reversed steps when the specified error is raised' do
|
194
|
+
expect(target).to receive(:destroy).once.with(3).ordered
|
195
|
+
expect(target).to receive(:create).once.with(3).ordered
|
196
|
+
klass.reverse(target)
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
200
|
+
end
|
113
201
|
end
|
114
202
|
end
|