lou 0.2.0 → 0.2.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/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
|