lou 0.2.3 → 0.3.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/.travis.yml +0 -6
- data/README.md +7 -7
- data/lib/lou/transformer.rb +28 -19
- data/lib/lou/transformer/step.rb +9 -5
- data/lib/lou/version.rb +1 -1
- data/lou.gemspec +1 -3
- data/spec/lou/transformer_spec.rb +63 -68
- metadata +6 -25
- data/.gemfiles/activesupport3_0.gemfile +0 -5
- data/.gemfiles/activesupport3_1.gemfile +0 -5
- data/.gemfiles/activesupport3_2.gemfile +0 -5
- data/.gemfiles/activesupport4_0.gemfile +0 -5
- data/.gemfiles/activesupport4_1.gemfile +0 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d4e9da0024d50ac97f6475a747331b461913f9af
|
4
|
+
data.tar.gz: 22ed73a5d3655e207b34ef4f3b5464de39c8a3eb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8996c9b19efda37c3045f5a31ede025978ccc868f7dd6de4fb1a14b5aa87697d7707dffd52e1df6ba8d56a5f352ac5b7a1c5b21902f104c24bd19f02d03e62cd
|
7
|
+
data.tar.gz: a8e59536b841561dd694e08456b91d53671e503302765a6cfee64852a5eb429081bc2128b15533653654705088d52a1e1efe833ec51bb5643971e6549db6cf36
|
data/.travis.yml
CHANGED
data/README.md
CHANGED
@@ -18,16 +18,16 @@ class HashTransformer
|
|
18
18
|
extend Lou::Transformer
|
19
19
|
|
20
20
|
# optional
|
21
|
-
|
21
|
+
revert_on RuntimeError
|
22
22
|
|
23
|
-
step
|
23
|
+
step up do |x|
|
24
24
|
x.merge(a_new_key: 'this is new')
|
25
25
|
end.down do |x|
|
26
26
|
x.delete(:a_new_key)
|
27
27
|
x
|
28
28
|
end
|
29
29
|
|
30
|
-
step
|
30
|
+
step up do |x|
|
31
31
|
x.flatten
|
32
32
|
end.down do |x|
|
33
33
|
Hash[*x]
|
@@ -40,15 +40,15 @@ Then you can use it like this:
|
|
40
40
|
~~~ruby
|
41
41
|
result = HashTransformer.apply(an_old_key: 'this is old')
|
42
42
|
# [:an_old_key, "this is old", :a_new_key, "this is new"]
|
43
|
-
original = HashTransformer.
|
43
|
+
original = HashTransformer.revert(result)
|
44
44
|
# {:an_old_key=>"this is old"}
|
45
45
|
~~~
|
46
46
|
|
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 `
|
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 `revert` method. Note that for each step, the input is the result of the previous step.
|
48
48
|
|
49
|
-
If `
|
49
|
+
If `revert_on` is defined, then any completed steps will be reversed if the exception specified is raised.
|
50
50
|
|
51
|
-
Transformers
|
51
|
+
Transformers can reuse other transformers as steps. In fact, any object that defines an `apply` method and a `revert` method can be used as a step.
|
52
52
|
|
53
53
|
Credits
|
54
54
|
-------
|
data/lib/lou/transformer.rb
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
require 'active_support/core_ext/class/attribute'
|
2
1
|
require 'lou/transformer/step'
|
3
2
|
|
4
3
|
module Lou
|
@@ -8,49 +7,59 @@ module Lou
|
|
8
7
|
|
9
8
|
def self.extended(base)
|
10
9
|
base.class_eval do
|
11
|
-
|
12
|
-
self.
|
13
|
-
class_attribute :error_class
|
14
|
-
self.error_class = Lou::Transformer::NeverError
|
10
|
+
self.transformer_steps = []
|
11
|
+
self.transformer_error_class = Lou::Transformer::NeverError
|
15
12
|
end
|
16
13
|
end
|
17
14
|
|
18
|
-
def
|
19
|
-
self.
|
15
|
+
def revert_on(error)
|
16
|
+
self.transformer_error_class = error
|
20
17
|
end
|
21
18
|
|
22
|
-
def step
|
23
|
-
|
24
|
-
self.
|
19
|
+
def step(transformer)
|
20
|
+
transformer.tap do |t|
|
21
|
+
self.transformer_steps += [t]
|
25
22
|
end
|
26
23
|
end
|
27
24
|
|
28
|
-
def
|
25
|
+
def up(&block)
|
26
|
+
Transformer::Step.new.up(&block)
|
27
|
+
end
|
28
|
+
|
29
|
+
def down(&block)
|
30
|
+
Transformer::Step.new.down(&block)
|
31
|
+
end
|
32
|
+
|
33
|
+
def apply(input, total_steps = transformer_steps.count)
|
29
34
|
applied_steps = 0
|
30
35
|
begin
|
31
|
-
|
36
|
+
transformer_steps.last(total_steps).each do |t|
|
32
37
|
input = t.apply(input)
|
33
38
|
applied_steps += 1
|
34
39
|
end
|
35
|
-
rescue
|
36
|
-
|
40
|
+
rescue transformer_error_class => e
|
41
|
+
revert(input, applied_steps) if total_steps == transformer_steps.count
|
37
42
|
raise e
|
38
43
|
end
|
39
44
|
input
|
40
45
|
end
|
41
46
|
|
42
|
-
def
|
47
|
+
def revert(output, total_steps = transformer_steps.count)
|
43
48
|
reversed_steps = 0
|
44
49
|
begin
|
45
|
-
|
46
|
-
output = t.
|
50
|
+
transformer_steps.first(total_steps).reverse_each do |t|
|
51
|
+
output = t.revert(output)
|
47
52
|
reversed_steps += 1
|
48
53
|
end
|
49
|
-
rescue
|
50
|
-
apply(output, reversed_steps) if total_steps ==
|
54
|
+
rescue transformer_error_class => e
|
55
|
+
apply(output, reversed_steps) if total_steps == transformer_steps.count
|
51
56
|
raise e
|
52
57
|
end
|
53
58
|
output
|
54
59
|
end
|
60
|
+
|
61
|
+
protected
|
62
|
+
|
63
|
+
attr_accessor :transformer_steps, :transformer_error_class
|
55
64
|
end
|
56
65
|
end
|
data/lib/lou/transformer/step.rb
CHANGED
@@ -2,22 +2,26 @@ module Lou
|
|
2
2
|
module Transformer
|
3
3
|
class Step
|
4
4
|
def up(&block)
|
5
|
-
|
5
|
+
self.up_blk = block
|
6
6
|
self
|
7
7
|
end
|
8
8
|
|
9
9
|
def down(&block)
|
10
|
-
|
10
|
+
self.down_blk = block
|
11
11
|
self
|
12
12
|
end
|
13
13
|
|
14
14
|
def apply(input)
|
15
|
-
|
15
|
+
up_blk.nil? ? input : up_blk.call(input)
|
16
16
|
end
|
17
17
|
|
18
|
-
def
|
19
|
-
|
18
|
+
def revert(output)
|
19
|
+
down_blk.nil? ? output : down_blk.call(output)
|
20
20
|
end
|
21
|
+
|
22
|
+
protected
|
23
|
+
|
24
|
+
attr_accessor :up_blk, :down_blk
|
21
25
|
end
|
22
26
|
end
|
23
27
|
end
|
data/lib/lou/version.rb
CHANGED
data/lou.gemspec
CHANGED
@@ -21,7 +21,5 @@ Gem::Specification.new do |spec|
|
|
21
21
|
|
22
22
|
spec.add_development_dependency "bundler", "~> 1.6"
|
23
23
|
spec.add_development_dependency "rake"
|
24
|
-
spec.add_development_dependency "rspec", "
|
25
|
-
|
26
|
-
spec.add_dependency "activesupport", ">= 3.0"
|
24
|
+
spec.add_development_dependency "rspec", "~> 3.1"
|
27
25
|
end
|
@@ -16,9 +16,9 @@ module Lou
|
|
16
16
|
end
|
17
17
|
end
|
18
18
|
|
19
|
-
describe '#
|
19
|
+
describe '#revert' do
|
20
20
|
it 'returns the input' do
|
21
|
-
expect(klass.
|
21
|
+
expect(klass.revert('this is the input')).to eq('this is the input')
|
22
22
|
end
|
23
23
|
end
|
24
24
|
end
|
@@ -27,7 +27,7 @@ module Lou
|
|
27
27
|
let!(:klass) do
|
28
28
|
Class.new do
|
29
29
|
extend Lou::Transformer
|
30
|
-
step
|
30
|
+
step up { |x| x.push 'world' }.down { |x| x.delete_if { |y| y == 'world' } }
|
31
31
|
end
|
32
32
|
end
|
33
33
|
|
@@ -37,9 +37,9 @@ module Lou
|
|
37
37
|
end
|
38
38
|
end
|
39
39
|
|
40
|
-
describe '#
|
40
|
+
describe '#revert' do
|
41
41
|
it 'applies the down step' do
|
42
|
-
expect(klass.
|
42
|
+
expect(klass.revert(%w(hello world))).to eq(%w(hello))
|
43
43
|
end
|
44
44
|
end
|
45
45
|
end
|
@@ -48,8 +48,8 @@ module Lou
|
|
48
48
|
let!(:klass) do
|
49
49
|
Class.new do
|
50
50
|
extend Lou::Transformer
|
51
|
-
step
|
52
|
-
step
|
51
|
+
step up { |x| x + ', or not to be' }.down { |x| x.gsub(/, or not to be$/, '') }
|
52
|
+
step up { |x| x + ', that is the question.' }.down { |x| x.gsub(/, that is the question\.$/, '') }
|
53
53
|
end
|
54
54
|
end
|
55
55
|
|
@@ -59,28 +59,34 @@ module Lou
|
|
59
59
|
end
|
60
60
|
end
|
61
61
|
|
62
|
-
describe '#
|
63
|
-
it 'applies all of the down steps in
|
64
|
-
expect(klass.
|
62
|
+
describe '#revert' do
|
63
|
+
it 'applies all of the down steps in revert order' do
|
64
|
+
expect(klass.revert('To be, or not to be, that is the question.')).to eq('To be')
|
65
65
|
end
|
66
66
|
end
|
67
67
|
end
|
68
68
|
|
69
|
-
context 'when
|
70
|
-
let!(:
|
71
|
-
Class.new do
|
69
|
+
context 'when one of the steps is another transformer' do
|
70
|
+
let!(:grandchild) do
|
71
|
+
parent = Class.new do
|
72
72
|
extend Lou::Transformer
|
73
|
-
step
|
73
|
+
step up { |x| x.create; x }.down { |x| x.destroy; x }
|
74
74
|
end
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
75
|
+
|
76
|
+
child = Class.new do
|
77
|
+
extend Lou::Transformer
|
78
|
+
|
79
|
+
step(parent)
|
80
|
+
|
81
|
+
step up { |x| x.create; x }.down { |x| x.destroy; x }
|
79
82
|
end
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
83
|
+
|
84
|
+
Class.new do
|
85
|
+
extend Lou::Transformer
|
86
|
+
|
87
|
+
step(child)
|
88
|
+
|
89
|
+
step up { |x| x.create; x }.down { |x| x.destroy; x }
|
84
90
|
end
|
85
91
|
end
|
86
92
|
|
@@ -91,22 +97,12 @@ module Lou
|
|
91
97
|
expect(target).to receive(:create).exactly(3).times
|
92
98
|
grandchild.apply(target)
|
93
99
|
end
|
94
|
-
|
95
|
-
it 'does not alter the up steps of the parent' do
|
96
|
-
expect(target).to receive(:create).exactly(1).times
|
97
|
-
parent.apply(target)
|
98
|
-
end
|
99
100
|
end
|
100
101
|
|
101
|
-
describe '#
|
102
|
-
it '
|
102
|
+
describe '#revert' do
|
103
|
+
it 'reverts the steps of the child first, then the parent' do
|
103
104
|
expect(target).to receive(:destroy).exactly(3).times
|
104
|
-
grandchild.
|
105
|
-
end
|
106
|
-
|
107
|
-
it 'does not alter the down steps of the parent' do
|
108
|
-
expect(target).to receive(:destroy).exactly(1).times
|
109
|
-
parent.reverse(target)
|
105
|
+
grandchild.revert(target)
|
110
106
|
end
|
111
107
|
end
|
112
108
|
end
|
@@ -115,7 +111,7 @@ module Lou
|
|
115
111
|
let!(:klass) do
|
116
112
|
Class.new do
|
117
113
|
extend Lou::Transformer
|
118
|
-
step
|
114
|
+
step up { |_| fail 'error on up' }.down { |_| fail 'error on down' }
|
119
115
|
end
|
120
116
|
end
|
121
117
|
|
@@ -125,86 +121,85 @@ module Lou
|
|
125
121
|
end
|
126
122
|
end
|
127
123
|
|
128
|
-
describe '#
|
124
|
+
describe '#revert' do
|
129
125
|
it 'raises the exception' do
|
130
|
-
expect { klass.
|
126
|
+
expect { klass.revert('bar') }.to raise_error('error on down')
|
131
127
|
end
|
132
128
|
end
|
133
129
|
end
|
134
130
|
|
135
|
-
context 'when #
|
131
|
+
context 'when #revert_on has been set' do
|
136
132
|
let!(:error_class) do
|
137
133
|
class SpecialError < StandardError; end
|
138
134
|
end
|
139
135
|
|
140
|
-
let!(:parent) do
|
141
|
-
Class.new do
|
142
|
-
extend Lou::Transformer
|
143
|
-
|
144
|
-
reverse_on SpecialError
|
145
|
-
end
|
146
|
-
end
|
147
|
-
|
148
136
|
let(:target) { instance_double('Target') }
|
149
137
|
|
150
138
|
context 'and an error is raised on the first step' do
|
151
139
|
let!(:klass) do
|
152
|
-
Class.new
|
153
|
-
|
154
|
-
|
140
|
+
Class.new do
|
141
|
+
extend Lou::Transformer
|
142
|
+
revert_on(SpecialError)
|
143
|
+
|
144
|
+
step up { |_| fail SpecialError }.down { |x| x.destroy(1); x }
|
145
|
+
step up { |x| x.create(2); x }.down { |_| fail SpecialError }
|
155
146
|
end
|
156
147
|
end
|
157
148
|
|
158
149
|
describe '#apply' do
|
159
|
-
it '
|
150
|
+
it 'reverts no steps when the specified error is raised' do
|
160
151
|
expect(target).to_not receive(:create)
|
161
152
|
expect(target).to_not receive(:destroy)
|
162
153
|
expect { klass.apply(target) }.to raise_error(SpecialError)
|
163
154
|
end
|
164
155
|
end
|
165
156
|
|
166
|
-
describe '#
|
157
|
+
describe '#revert' do
|
167
158
|
it 'applies no steps when the specified error is raised' do
|
168
159
|
expect(target).to_not receive(:destroy)
|
169
160
|
expect(target).to_not receive(:create)
|
170
|
-
expect { klass.
|
161
|
+
expect { klass.revert(target) }.to raise_error(SpecialError)
|
171
162
|
end
|
172
163
|
end
|
173
164
|
end
|
174
165
|
|
175
166
|
context 'and an error is raised part-way through the transform' do
|
176
167
|
let!(:klass) do
|
177
|
-
Class.new
|
178
|
-
|
179
|
-
|
180
|
-
|
168
|
+
Class.new do
|
169
|
+
extend Lou::Transformer
|
170
|
+
revert_on(SpecialError)
|
171
|
+
|
172
|
+
step up { |x| x.create(1); x }.down { |x| x.destroy(1); x }
|
173
|
+
step up { |_| fail SpecialError }.down { |_| fail SpecialError }
|
174
|
+
step up { |x| x.create(3); x }.down { |x| x.destroy(3); x }
|
181
175
|
end
|
182
176
|
end
|
183
177
|
|
184
|
-
let(:target) { instance_double('Target') }
|
185
|
-
|
186
178
|
describe '#apply' do
|
187
|
-
it '
|
179
|
+
it 'reverts all successfully applied steps before raising the error when the specified error is raised' do
|
188
180
|
expect(target).to receive(:create).once.with(1).ordered
|
189
181
|
expect(target).to receive(:destroy).once.with(1).ordered
|
190
182
|
expect { klass.apply(target) }.to raise_error(SpecialError)
|
191
183
|
end
|
192
184
|
end
|
193
185
|
|
194
|
-
describe '#
|
195
|
-
it 'reapplies all successfully
|
186
|
+
describe '#revert' do
|
187
|
+
it 'reapplies all successfully revertd steps before raising the error when the specified error is raised' do
|
196
188
|
expect(target).to receive(:destroy).once.with(3).ordered
|
197
189
|
expect(target).to receive(:create).once.with(3).ordered
|
198
|
-
expect { klass.
|
190
|
+
expect { klass.revert(target) }.to raise_error(SpecialError)
|
199
191
|
end
|
200
192
|
end
|
201
193
|
end
|
202
194
|
|
203
195
|
context 'and the up and down steps should lead to an infinite loop' do
|
204
196
|
let!(:klass) do
|
205
|
-
Class.new
|
206
|
-
|
207
|
-
|
197
|
+
Class.new do
|
198
|
+
extend Lou::Transformer
|
199
|
+
revert_on(SpecialError)
|
200
|
+
|
201
|
+
step up { |x| x.create(1); x }.down { |_| fail SpecialError, 'fail on down' }
|
202
|
+
step up { |_| fail SpecialError, 'fail on up' }.down { |x| x.destroy(2); x }
|
208
203
|
end
|
209
204
|
end
|
210
205
|
|
@@ -215,10 +210,10 @@ module Lou
|
|
215
210
|
end
|
216
211
|
end
|
217
212
|
|
218
|
-
describe '#
|
213
|
+
describe '#revert' do
|
219
214
|
it 'raises the error from the up step' do
|
220
215
|
expect(target).to receive(:destroy).once.with(2)
|
221
|
-
expect { klass.
|
216
|
+
expect { klass.revert(target) }.to raise_error(SpecialError, 'fail on up')
|
222
217
|
end
|
223
218
|
end
|
224
219
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: lou
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Iain Beeston
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-09-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -42,30 +42,16 @@ dependencies:
|
|
42
42
|
name: rspec
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- -
|
45
|
+
- - ~>
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: '3.
|
47
|
+
version: '3.1'
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- -
|
53
|
-
- !ruby/object:Gem::Version
|
54
|
-
version: '3.0'
|
55
|
-
- !ruby/object:Gem::Dependency
|
56
|
-
name: activesupport
|
57
|
-
requirement: !ruby/object:Gem::Requirement
|
58
|
-
requirements:
|
59
|
-
- - '>='
|
60
|
-
- !ruby/object:Gem::Version
|
61
|
-
version: '3.0'
|
62
|
-
type: :runtime
|
63
|
-
prerelease: false
|
64
|
-
version_requirements: !ruby/object:Gem::Requirement
|
65
|
-
requirements:
|
66
|
-
- - '>='
|
52
|
+
- - ~>
|
67
53
|
- !ruby/object:Gem::Version
|
68
|
-
version: '3.
|
54
|
+
version: '3.1'
|
69
55
|
description:
|
70
56
|
email:
|
71
57
|
- iain.beeston@gmail.com
|
@@ -73,11 +59,6 @@ executables: []
|
|
73
59
|
extensions: []
|
74
60
|
extra_rdoc_files: []
|
75
61
|
files:
|
76
|
-
- .gemfiles/activesupport3_0.gemfile
|
77
|
-
- .gemfiles/activesupport3_1.gemfile
|
78
|
-
- .gemfiles/activesupport3_2.gemfile
|
79
|
-
- .gemfiles/activesupport4_0.gemfile
|
80
|
-
- .gemfiles/activesupport4_1.gemfile
|
81
62
|
- .gitignore
|
82
63
|
- .rspec
|
83
64
|
- .travis.yml
|