waterfall 1.0.4 → 1.0.5

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2918f5c657d78ab72747847b48ca6024995b8cdc
4
- data.tar.gz: 473b2b1b9cf9512fb13520523cbf4ae358a005b2
3
+ metadata.gz: 152fb9437b8752b16fd77478ec2e12c0d9b6401f
4
+ data.tar.gz: 5e6f25d4bd7c0e23c4a8cd16b921227ed5397a3a
5
5
  SHA512:
6
- metadata.gz: 5ddce902522214cdb5e5cdf939d18a8a1dca0026dd79de3c29ac30c17f3bd7bc6c2abd06c21f8dc67398d3dbf617c3032a67136dd792ffe37b786138a2e1e57f
7
- data.tar.gz: 1d17dee11a63dc85b223e3e70e94bd1b35e09df45ff926d2f3a2da8d6ea2eca07d7c56e4124124aa6b97af651e7ab7fdba0d043baa898ed4fcea365cee1ac0e1
6
+ metadata.gz: 597154dc366df15c6fe84f707c1206e82c624c77b57b818323e67347fd1d3e3f9f990b926d5c389060e2b75c1de71aa807ab7601b9735584cb8c138d40b26c6b
7
+ data.tar.gz: 8004a1da08994b9e668113e348d5312503394d071be2f366fda20dda1650d7648aa19ecb1555a46beab22d6866bd23f1a9bdb10b29184b39bcafc79aad537aa7
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- waterfall (1.0.4)
4
+ waterfall (1.0.5)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
data/lib/waterfall.rb CHANGED
@@ -8,21 +8,21 @@ require 'waterfall/predicates/chain'
8
8
 
9
9
  module Waterfall
10
10
 
11
- attr_reader :error_pool, :outflow, :flowing, :_wf_rolled_back
11
+ attr_reader :error_pool, :outflow
12
12
 
13
13
  class IncorrectDamArgumentError < StandardError; end
14
14
  class IncorrectChainingArgumentError < StandardError; end
15
15
 
16
16
  def when_falsy(&block)
17
- handler = ::Waterfall::WhenFalsy.new(self)
18
- _wf_run { handler.call(&block) }
19
- handler
17
+ ::Waterfall::WhenFalsy.new(self).tap do |handler|
18
+ _wf_run { handler.call(&block) }
19
+ end
20
20
  end
21
21
 
22
22
  def when_truthy(&block)
23
- handler = ::Waterfall::WhenTruthy.new(self)
24
- _wf_run { handler.call(&block) }
25
- handler
23
+ ::Waterfall::WhenTruthy.new(self).tap do |handler|
24
+ _wf_run { handler.call(&block) }
25
+ end
26
26
  end
27
27
 
28
28
  def chain(mapping_or_var_name = nil, &block)
@@ -47,8 +47,7 @@ module Waterfall
47
47
 
48
48
  def dam(obj)
49
49
  raise IncorrectDamArgumentError.new("You cant dam with a falsy object") unless obj
50
- @error_pool = obj
51
- self
50
+ _wf_run { @error_pool = obj }
52
51
  end
53
52
 
54
53
  def undam
@@ -64,8 +63,8 @@ module Waterfall
64
63
  true
65
64
  end
66
65
 
67
- def flowing?
68
- !! @flowing
66
+ def has_flown?
67
+ !! @has_flown
69
68
  end
70
69
 
71
70
  def update_outflow(key, value)
@@ -74,17 +73,16 @@ module Waterfall
74
73
  end
75
74
 
76
75
  def _wf_run
77
- @flowing = true
76
+ @has_flown = true
78
77
  @outflow ||= OpenStruct.new({})
79
78
  yield unless dammed?
80
79
  self
81
80
  end
82
-
83
81
  end
84
82
 
85
83
  class Wf
86
84
  include Waterfall
87
85
  def initialize
88
- @outflow = OpenStruct.new({})
86
+ _wf_run {}
89
87
  end
90
88
  end
@@ -16,9 +16,9 @@ module Waterfall
16
16
  end
17
17
 
18
18
  def map_waterfalls(child_waterfall, mapping)
19
- child_waterfall.call unless child_waterfall.flowing?
19
+ child_waterfall.call unless child_waterfall.has_flown?
20
20
 
21
- raise IncorrectChainingArgumentError.new(mapping_error_message) unless mapping.is_a?(Hash)
21
+ raise IncorrectChainingArgumentError.new(MAPPING_ERROR_MESSAGE) unless mapping.is_a?(Hash)
22
22
 
23
23
  mapping.each do |k, v|
24
24
  @root.update_outflow(k, child_waterfall.outflow[v])
@@ -31,8 +31,6 @@ module Waterfall
31
31
  self
32
32
  end
33
33
 
34
- def mapping_error_message
35
- "When chaining waterfalls, you must pass a mapping hash to pass data from one to the other"
36
- end
34
+ MAPPING_ERROR_MESSAGE = "When chaining waterfalls, you must pass a mapping hash to pass data from one to the other"
37
35
  end
38
36
  end
@@ -1,3 +1,3 @@
1
1
  module Waterfall
2
- VERSION = "1.0.4"
2
+ VERSION = "1.0.5"
3
3
  end
@@ -0,0 +1,92 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Chaining services' do
4
+
5
+ let(:service_class) do
6
+ Class.new do
7
+ include Waterfall
8
+ def initialize(options = {})
9
+ @options = {
10
+ falsy_check: true,
11
+ truthy_check: false
12
+ }.merge options
13
+ end
14
+
15
+ def call
16
+ when_falsy { @options[:falsy_check] }
17
+ .dam { 'errr1' }
18
+ chain(:foo) { 'foo_value' }
19
+ when_truthy { @options[:truthy_check] }
20
+ .dam { 'errr2' }
21
+ chain(:bar) { 'bar_value' }
22
+ self
23
+ end
24
+ end
25
+ end
26
+
27
+ let(:wf) { Wf.new }
28
+ let(:listener) { spy 'listener', is_waterfall?: false }
29
+
30
+ it 'you dont need to call child waterfalls, just pass the instance' do
31
+ service = service_class.new
32
+ expect(service.has_flown?).to be false
33
+ wf.chain { service }
34
+ expect(service.has_flown?).to be true
35
+ end
36
+
37
+ context 'child executed without damming' do
38
+ it 'passes data from one outflow to the other' do
39
+ wf
40
+ .chain(local_foo: :foo, local_bar: :bar) { service_class.new }
41
+ .chain { listener.success }
42
+ .on_dam { listener.failure }
43
+
44
+ expect(wf.outflow.local_foo).to eq 'foo_value'
45
+ expect(wf.outflow.local_bar).to eq 'bar_value'
46
+ expect(wf.dammed?).to be false
47
+ expect(wf.error_pool).to eq nil
48
+ expect(listener).to have_received :success
49
+ end
50
+
51
+ it 'passes only required data from one outflow to the other' do
52
+ wf
53
+ .chain(local_foo: :foo) { service_class.new }
54
+ .chain { listener.success }
55
+ .on_dam { listener.failure }
56
+
57
+ expect(wf.outflow.local_foo).to eq 'foo_value'
58
+ expect(wf.outflow.local_bar).to eq nil
59
+ expect(listener).to have_received :success
60
+ end
61
+ end
62
+
63
+ context 'child dams on when_falsy' do
64
+ it 'stops on dam yet passes existing data' do
65
+ wf
66
+ .chain(local_foo: :foo, local_bar: :bar) { service_class.new(falsy_check: false) }
67
+ .chain { listener.success }
68
+ .on_dam { listener.failure }
69
+
70
+ expect(wf.outflow.local_foo).to eq nil
71
+ expect(wf.outflow.local_bar).to eq nil
72
+ expect(wf.dammed?).to be true
73
+ expect(wf.error_pool).to eq 'errr1'
74
+ expect(listener).to have_received :failure
75
+ end
76
+ end
77
+
78
+ context 'dammed on when_truthy statement' do
79
+ it 'stops on dam yet passes existing data' do
80
+ wf
81
+ .chain(local_foo: :foo, local_bar: :bar) { service_class.new(truthy_check: true) }
82
+ .chain { listener.success }
83
+ .on_dam { listener.failure }
84
+
85
+ expect(wf.outflow.local_foo).to eq 'foo_value'
86
+ expect(wf.outflow.local_bar).to eq nil
87
+ expect(wf.dammed?).to be true
88
+ expect(wf.error_pool).to eq 'errr2'
89
+ expect(listener).to have_received :failure
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,98 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Service' do
4
+
5
+ let(:service_class) do
6
+ Class.new do
7
+ include Waterfall
8
+ attr_reader :error
9
+
10
+ def initialize(options)
11
+ @options = {
12
+ falsy_check: true,
13
+ truthy_check: false
14
+ }.merge options
15
+ end
16
+
17
+ def call
18
+ when_falsy { @options[:falsy_check] }
19
+ .dam { 'errr1' }
20
+ chain(:foo) { 'foo_value' }
21
+ when_truthy { @options[:truthy_check] }
22
+ .dam { 'errr2' }
23
+ chain(:bar) { 'bar_value' }
24
+ end
25
+ end
26
+ end
27
+
28
+ let(:service) { service_class.new(options).tap(&:call) }
29
+
30
+ it 'a waterfall doesnt flow until one chain is executed' do
31
+ expect(service_class.new({}).has_flown?).to be false
32
+ end
33
+
34
+ context 'default options' do
35
+ let(:options) {{}}
36
+
37
+ it 'has flown whenever one chain has been executed' do
38
+ expect(service.has_flown?).to be true
39
+ end
40
+
41
+ it 'executes without damming' do
42
+ expect(service.outflow.foo).to eq 'foo_value'
43
+ expect(service.outflow.bar).to eq 'bar_value'
44
+ expect(service.dammed?).to be false
45
+ expect(service.error_pool).to eq nil
46
+ end
47
+ end
48
+
49
+ context 'dammed on when_falsy statement' do
50
+ let(:options) {{ falsy_check: false }}
51
+ it 'stops on dam' do
52
+ expect(service.outflow.foo).to eq nil
53
+ expect(service.outflow.bar).to eq nil
54
+ expect(service.dammed?).to be true
55
+ expect(service.error_pool).to eq 'errr1'
56
+ end
57
+ end
58
+
59
+ context 'dammed on when_truthy statement' do
60
+ let(:options) {{ truthy_check: true }}
61
+ it 'stops on dam' do
62
+ expect(service.outflow.foo).to eq 'foo_value'
63
+ expect(service.outflow.bar).to eq nil
64
+ expect(service.dammed?).to be true
65
+ expect(service.error_pool).to eq 'errr2'
66
+ end
67
+ end
68
+
69
+ let(:service_class2) do
70
+ Class.new do
71
+ include Waterfall
72
+
73
+ def initialize(listener, options)
74
+ @to_dam, @listener = options[:to_dam], listener
75
+ end
76
+
77
+ def call
78
+ dam('error') if @to_dam
79
+ chain { @listener.success }
80
+ on_dam { @listener.failure }
81
+ end
82
+ end
83
+ end
84
+
85
+ let(:listener) { spy 'listener', is_waterfall?: false }
86
+
87
+ it 'sends success message to listener' do
88
+ service_class2.new(listener, to_dam: false).call
89
+
90
+ expect(listener).to have_received(:success)
91
+ end
92
+
93
+ it 'sends failure message to listener' do
94
+ service_class2.new(listener, to_dam: true).call
95
+
96
+ expect(listener).to have_received(:failure)
97
+ end
98
+ end
@@ -0,0 +1,101 @@
1
+ require 'spec_helper'
2
+
3
+ describe Wf do
4
+ let(:wf) { Wf.new }
5
+
6
+ it 'is a waterfall' do
7
+ expect(wf.is_waterfall?).to be true
8
+ end
9
+
10
+ it 'and a waterfall flows when called' do
11
+ expect(wf.has_flown?).to be true
12
+ end
13
+
14
+ it 'executes code in chain block' do
15
+ listener = double 'listener'
16
+ expect(listener).to receive :success
17
+
18
+ wf.chain { listener.success }
19
+ end
20
+
21
+ it 'executes code in chain block and store it in outflow upon request' do
22
+ wf.chain(:foo) { 1 }
23
+ expect(wf.outflow.foo).to eq 1
24
+ end
25
+
26
+ it 'chain yields outflow and waterfall itself' do
27
+ wf.chain do |outflow, waterfall|
28
+ expect(outflow).to eq wf.outflow
29
+ expect(waterfall).to eq wf
30
+ end
31
+ end
32
+
33
+ it 'isnt dammed by default' do
34
+ expect(wf.dammed?).to be false
35
+ expect(wf.error_pool).to eq nil
36
+ end
37
+
38
+ it 'is dammed if you dam it!' do
39
+ wf.dam('error')
40
+ expect(wf.dammed?).to be true
41
+ expect(wf.error_pool).to eq 'error'
42
+ end
43
+
44
+ it 'dam raises if falsy argument sent' do
45
+ expect { wf.dam(nil) }.to raise_error(Waterfall::IncorrectDamArgumentError)
46
+ end
47
+
48
+ it 'can be undammed' do
49
+ wf.dam('error').undam
50
+ expect(wf.dammed?).to be false
51
+ expect(wf.error_pool).to eq nil
52
+ end
53
+
54
+ it 'can be dammed conditionnaly (falsy)' do
55
+ wf.when_falsy { false }.dam { 'error' }
56
+ expect(wf.dammed?).to be true
57
+ expect(wf.error_pool).to eq 'error'
58
+ end
59
+
60
+ it 'can be dammed conditionnaly (truthy)' do
61
+ wf.when_truthy { true }.dam { 'error' }
62
+ expect(wf.dammed?).to be true
63
+ expect(wf.error_pool).to eq 'error'
64
+ end
65
+
66
+ it 'doesnt execute chain blocks once dammed' do
67
+ expect do
68
+ wf.when_falsy { false }.dam { 'error' }.chain { raise 'I should not be executed because of damming before me' }
69
+ end.to_not raise_error
70
+ end
71
+
72
+ it 'doesnt execute on_dam blocks when not dammed' do
73
+ expect do
74
+ wf.on_dam { raise 'I should not be executed because of damming before me' }
75
+ end.to_not raise_error
76
+ end
77
+
78
+ it 'executes on_dam blocks once dammed' do
79
+ listener = spy 'listener'
80
+ wf.dam('errr').on_dam { listener.failure }
81
+
82
+ expect(listener).to have_received :failure
83
+ end
84
+
85
+ it 'on_dam blocks yield error pool, outflow and waterfall' do
86
+ wf.dam('errr').on_dam do |error_pool, outflow, waterfall|
87
+ expect(error_pool).to eq wf.error_pool
88
+ expect(outflow).to eq wf.outflow
89
+ expect(waterfall).to eq wf
90
+ end
91
+ end
92
+
93
+ it 'raises if chain waterfall without hash mapping' do
94
+ expect { wf.chain(:foo) { Wf.new } }.to raise_error(Waterfall::IncorrectChainingArgumentError, Waterfall::Chain::MAPPING_ERROR_MESSAGE)
95
+ end
96
+
97
+ it 'warns against chain_wf' do
98
+ expect(wf).to receive :warn
99
+ wf.chain_wf { Wf.new }
100
+ end
101
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: waterfall
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.4
4
+ version: 1.0.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Benjamin Roth
@@ -104,8 +104,10 @@ files:
104
104
  - lib/waterfall/predicates/when_falsy.rb
105
105
  - lib/waterfall/predicates/when_truthy.rb
106
106
  - lib/waterfall/version.rb
107
- - spec/integration_spec.rb
107
+ - spec/chaining_services_spec.rb
108
+ - spec/service_spec.rb
108
109
  - spec/spec_helper.rb
110
+ - spec/wf_object_spec.rb
109
111
  - waterfall.gemspec
110
112
  homepage: https://github.com/apneadiving/waterfall
111
113
  licenses:
@@ -133,5 +135,7 @@ specification_version: 4
133
135
  summary: A slice of functional programming to chain ruby services and blocks. Make
134
136
  them flow!
135
137
  test_files:
136
- - spec/integration_spec.rb
138
+ - spec/chaining_services_spec.rb
139
+ - spec/service_spec.rb
137
140
  - spec/spec_helper.rb
141
+ - spec/wf_object_spec.rb
@@ -1,240 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe 'Wf' do
4
- let(:wf) { Wf.new }
5
- let(:error_string) { 'error' }
6
-
7
- describe "chain" do
8
-
9
- it "yields wf outflow" do
10
- wf
11
- .chain {|outflow| outflow.bar = 'bar' }
12
- .chain {|outflow| @bar = outflow.bar }
13
-
14
- expect(wf.outflow.bar).to eq 'bar'
15
- expect(@bar).to eq 'bar'
16
- end
17
-
18
- it "assigns outflow's key the value of the block" do
19
- wf
20
- .chain(:bar) { 'bar' }
21
- expect(wf.outflow.bar).to eq 'bar'
22
- end
23
-
24
- context "wf internals" do
25
- it "dam from within" do
26
- wf
27
- .chain {|outflow, waterfall| waterfall.dam(error_string) }
28
-
29
- expect(wf.dammed?).to be true
30
- expect(wf.error_pool).to eq error_string
31
- end
32
-
33
- it "expose child waterfall outflow even if dammed (or at least what was computed)" do
34
- wf
35
- .chain(bar: :bar, baz: :baz) do
36
- Wf.new
37
- .chain(:bar) { 'bar' }
38
- .dam('boom')
39
- .chain(:baz) { 'baz' }
40
- end
41
-
42
- expect(wf.dammed?).to be true
43
- expect(wf.error_pool).to eq 'boom'
44
- expect(wf.outflow.bar).to eq 'bar'
45
- expect(wf.outflow.baz).to eq nil
46
- end
47
-
48
- it "outflow from within" do
49
- wf
50
- .chain {|outflow, waterfall| waterfall.outflow.foo = 1 }
51
-
52
- expect(wf.outflow.foo).to eq 1
53
- end
54
- end
55
-
56
- describe "chaining waterfalls" do
57
-
58
- shared_examples "a waterfall chain" do
59
- describe 'chain waterfall' do
60
- it "takes expected vars only and rename them" do
61
- wf
62
- .chain(baz: :foo) { waterfall }
63
-
64
- expect(wf.outflow.foo).to be nil
65
- expect(wf.outflow.bar).to be nil
66
- expect(wf.outflow.baz).to eq waterfall.outflow.foo
67
- end
68
-
69
- it 'raises if chain waterfall without hash mapping' do
70
- expect { wf.chain(:foo) { waterfall } }.to raise_error(Waterfall::IncorrectChainingArgumentError)
71
- end
72
- end
73
- end
74
-
75
- context "from an instance of a custom waterfall class" do
76
- class FakeService
77
- include Waterfall
78
-
79
- def call
80
- self
81
- .chain(:foo) { 1 }
82
- .chain(:bar) { 2 }
83
- end
84
- end
85
-
86
- let(:waterfall) { FakeService.new }
87
-
88
- it_behaves_like "a waterfall chain"
89
-
90
- context "only calls waterfall service if it was never called before" do
91
- it "when passed as an instance responding to call" do
92
- expect(waterfall).to receive(:call).once.and_call_original
93
- wf
94
- .chain { waterfall }
95
- end
96
-
97
- it "already called" do
98
- expect(waterfall).to receive(:call).once.and_call_original
99
- wf
100
- .chain { waterfall.call }
101
- end
102
- end
103
- end
104
-
105
- context "from a mere wf" do
106
- let(:waterfall) do
107
- Wf.new
108
- .chain(:foo) { 1 }
109
- .chain(:bar) { 2 }
110
- end
111
-
112
- it_behaves_like "a waterfall chain"
113
- end
114
- end
115
- end
116
-
117
- describe "when falsy" do
118
- let(:my_proc) { ->(val){ val } }
119
-
120
- def action(bool)
121
- wf
122
- .chain { wf.dam('dammed') if dam? }
123
- .when_falsy { my_proc.call(bool) }
124
- .dam { error_string }
125
- .chain { @foo = 1 }
126
- end
127
-
128
- context "main context not dammed" do
129
- let(:dam?) { false }
130
-
131
- it "when actually falsy" do
132
- action false
133
- expect(wf.error_pool).to eq error_string
134
- expect(@foo).to_not eq 1
135
- end
136
-
137
- it "when actually truthy" do
138
- action true
139
- expect(wf.error_pool).to_not eq error_string
140
- expect(@foo).to eq 1
141
- end
142
- end
143
-
144
- context "main context dammed" do
145
- let(:dam?) { true }
146
-
147
- it "when actually falsy" do
148
- expect(my_proc).to_not receive(:call)
149
- action false
150
- expect(wf.error_pool).to eq 'dammed'
151
- end
152
- end
153
- end
154
-
155
- describe "when truthy" do
156
- let(:my_proc) { ->(val){ val } }
157
-
158
- def action(bool)
159
- wf
160
- .chain { wf.dam('dammed') if dam? }
161
- .when_truthy { my_proc.call(bool) }
162
- .dam { error_string }
163
- .chain { @foo = 1 }
164
- end
165
-
166
- context "main context not dammed" do
167
- let(:dam?) { false }
168
-
169
- it "when actually falsy" do
170
- action false
171
- expect(wf.error_pool).to_not eq error_string
172
- expect(@foo).to eq 1
173
- end
174
-
175
- it "when actually truthy" do
176
- action true
177
- expect(wf.error_pool).to eq error_string
178
- expect(@foo).to_not eq 1
179
- end
180
- end
181
-
182
- context "main context dammed" do
183
- let(:dam?) { true }
184
-
185
- it "when actually truthy" do
186
- expect(my_proc).to_not receive(:call)
187
- action true
188
- expect(wf.error_pool).to eq 'dammed'
189
- end
190
- end
191
- end
192
-
193
- describe "error propagation" do
194
- class FailingChain
195
- include Waterfall
196
-
197
- def call
198
- self
199
- .chain {|error_pool, waterfall| waterfall.dam(self.class.error) }
200
- end
201
-
202
- def self.error
203
- 'error'
204
- end
205
- end
206
-
207
- it "error propagates" do
208
- wf
209
- .chain { FailingChain.new }
210
- .chain { @foo = 1 }
211
-
212
- expect(@foo).to_not eq 1
213
- expect(wf.error_pool).to eq FailingChain.error
214
- end
215
- end
216
-
217
- describe "dam" do
218
- it "raises if falsy argument sent" do
219
- expect { wf.dam(nil) }.to raise_error(Waterfall::IncorrectDamArgumentError)
220
- end
221
-
222
- it "dams with truthy argument" do
223
- wf.dam(error_string)
224
- expect(wf.error_pool).to eq error_string
225
- expect(wf.dammed?).to be true
226
- end
227
- end
228
-
229
- describe "undam" do
230
- it "flow goes back to green path" do
231
- wf
232
- .chain { wf.dam(error_string) }
233
- .on_dam { wf.undam }
234
- .chain { @foo = 1 }
235
- .on_dam { raise('shouldnt happen') }
236
-
237
- expect(@foo).to eq 1
238
- end
239
- end
240
- end