waterfall 1.0.4 → 1.0.5

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 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