deterministic 0.8.1 → 0.10.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/HISTORY.md +17 -0
- data/README.md +121 -153
- data/lib/deterministic/core_ext/object/result.rb +6 -0
- data/lib/deterministic/core_ext/{either.rb → result.rb} +2 -6
- data/lib/deterministic/monad.rb +3 -3
- data/lib/deterministic/result/chain.rb +27 -0
- data/lib/deterministic/result/failure.rb +5 -0
- data/lib/deterministic/{either → result}/match.rb +5 -5
- data/lib/deterministic/result/success.rb +5 -0
- data/lib/deterministic/{either.rb → result.rb} +29 -6
- data/lib/deterministic/version.rb +1 -1
- data/lib/deterministic.rb +5 -6
- data/spec/examples/bookings_spec.rb +3 -5
- data/spec/lib/deterministic/core_ext/object/either_spec.rb +3 -20
- data/spec/lib/deterministic/core_ext/result_spec.rb +22 -0
- data/spec/lib/deterministic/maybe_spec.rb +2 -0
- data/spec/lib/deterministic/monad_spec.rb +3 -3
- data/spec/lib/deterministic/result/chain_spec.rb +150 -0
- data/spec/lib/deterministic/{either → result}/failure_spec.rb +9 -6
- data/spec/lib/deterministic/{either → result}/match_spec.rb +5 -5
- data/spec/lib/deterministic/result/result_shared.rb +23 -0
- data/spec/lib/deterministic/{either → result}/success_spec.rb +10 -6
- data/spec/lib/deterministic/{either_spec.rb → result_spec.rb} +3 -3
- metadata +24 -27
- data/either.rb +0 -97
- data/lib/deterministic/core_ext/object/either.rb +0 -6
- data/lib/deterministic/either/attempt_all.rb +0 -50
- data/lib/deterministic/either/chain.rb +0 -22
- data/lib/deterministic/either/failure.rb +0 -22
- data/lib/deterministic/either/success.rb +0 -22
- data/spec/lib/deterministic/attempt_all_spec.rb +0 -115
- data/spec/lib/deterministic/core_ext/either_spec.rb +0 -50
- data/spec/lib/deterministic/either/chain_spec.rb +0 -80
- data/spec/lib/deterministic/either/either_shared.rb +0 -23
@@ -0,0 +1,22 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "deterministic"
|
3
|
+
require "deterministic/core_ext/result"
|
4
|
+
|
5
|
+
describe Deterministic::CoreExt::Result do
|
6
|
+
it "does something" do
|
7
|
+
h = {}
|
8
|
+
h.extend(Deterministic::CoreExt::Result)
|
9
|
+
expect(h.success?).to be_falsey
|
10
|
+
expect(h.failure?).to be_falsey
|
11
|
+
expect(h.result?).to be_falsey
|
12
|
+
end
|
13
|
+
|
14
|
+
it "enables #success?, #failure?, #result? on all Objects" do
|
15
|
+
ary = [Deterministic::Success(true), Deterministic::Success(1)]
|
16
|
+
expect(ary.all?(&:success?)).to be_truthy
|
17
|
+
|
18
|
+
ary = [Deterministic::Success(true), Deterministic::Failure(1)]
|
19
|
+
expect(ary.all?(&:success?)).to be_falsey
|
20
|
+
expect(ary.any?(&:failure?)).to be_truthy
|
21
|
+
end
|
22
|
+
end
|
@@ -13,9 +13,9 @@ describe Deterministic::Monad do
|
|
13
13
|
|
14
14
|
specify { expect(Identity.new(1).to_s).to eq 'Identity(1)' }
|
15
15
|
specify { expect(Identity.new(nil).to_s).to eq 'Identity(nil)' }
|
16
|
-
specify { expect(Identity.new([1, 2]).
|
17
|
-
specify { expect(Identity.new(1).
|
18
|
-
specify { expect(Identity.new('foo').
|
16
|
+
specify { expect(Identity.new([1, 2]).fmap(&:to_s)).to eq Identity.new("[1, 2]") }
|
17
|
+
specify { expect(Identity.new(1).fmap {|v| v + 2}).to eq Identity.new(3) }
|
18
|
+
specify { expect(Identity.new('foo').fmap(&:upcase)).to eq Identity.new('FOO')}
|
19
19
|
|
20
20
|
context '#bind' do
|
21
21
|
it "raises an error if the passed function does not return a monad of the same class" do
|
@@ -0,0 +1,150 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
include Deterministic
|
4
|
+
|
5
|
+
describe Deterministic::Result do
|
6
|
+
context ">> (map)" do
|
7
|
+
specify { expect(Success(0).map { |n| Success(n + 1) }).to eq Success(1) }
|
8
|
+
specify { expect(Failure(0).map { |n| Success(n + 1) }).to eq Failure(0) }
|
9
|
+
|
10
|
+
it "Failure stops execution" do
|
11
|
+
class ChainUnderTest
|
12
|
+
alias :m :method
|
13
|
+
|
14
|
+
def call
|
15
|
+
init >>
|
16
|
+
m(:validate) >>
|
17
|
+
m(:send) >>
|
18
|
+
m(:parse)
|
19
|
+
end
|
20
|
+
|
21
|
+
def init
|
22
|
+
Success({step: 1})
|
23
|
+
end
|
24
|
+
|
25
|
+
def validate(i)
|
26
|
+
i[:step] = i[:step] + 1
|
27
|
+
Success(i)
|
28
|
+
end
|
29
|
+
|
30
|
+
def send(i)
|
31
|
+
i[:step] = i[:step] + 1
|
32
|
+
Failure("Error @ #{i.fetch(:step)}")
|
33
|
+
end
|
34
|
+
|
35
|
+
def parse(i)
|
36
|
+
i[:step] = i[:step] + 1
|
37
|
+
Success(i)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
test = ChainUnderTest.new
|
42
|
+
|
43
|
+
expect(test.call).to eq Failure("Error @ 3")
|
44
|
+
end
|
45
|
+
|
46
|
+
it "expects an Result" do
|
47
|
+
def returns_non_result(i)
|
48
|
+
2
|
49
|
+
end
|
50
|
+
|
51
|
+
expect { Success(1) >> method(:returns_non_result) }.to raise_error(Deterministic::Monad::NotMonadError)
|
52
|
+
end
|
53
|
+
|
54
|
+
it "works with a block" do
|
55
|
+
expect(
|
56
|
+
Success(1).map { |i| Success(i + 1) }
|
57
|
+
).to eq Success(2)
|
58
|
+
end
|
59
|
+
|
60
|
+
it "works with a lambda" do
|
61
|
+
expect(
|
62
|
+
Success(1) >> ->(i) { Success(i + 1) }
|
63
|
+
).to eq Success(2)
|
64
|
+
end
|
65
|
+
|
66
|
+
it "does not catch exceptions" do
|
67
|
+
expect {
|
68
|
+
Success(1) >> ->(i) { raise "error" }
|
69
|
+
}.to raise_error(RuntimeError)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
context "using self as the context for success" do
|
74
|
+
class SelfContextUnderTest
|
75
|
+
def call
|
76
|
+
@step = 0
|
77
|
+
Success(self).
|
78
|
+
map(&:validate).
|
79
|
+
map(&:build).
|
80
|
+
map(&:send)
|
81
|
+
end
|
82
|
+
|
83
|
+
def validate
|
84
|
+
@step = 1
|
85
|
+
Success(self)
|
86
|
+
end
|
87
|
+
|
88
|
+
def build
|
89
|
+
@step = 2
|
90
|
+
Success(self)
|
91
|
+
end
|
92
|
+
|
93
|
+
def send
|
94
|
+
@step = 3
|
95
|
+
Success(self)
|
96
|
+
end
|
97
|
+
|
98
|
+
def to_s
|
99
|
+
"Step #{@step}"
|
100
|
+
end
|
101
|
+
|
102
|
+
# # def self.procify(*meths)
|
103
|
+
# # meths.each do |m|
|
104
|
+
# # new_m = "__#{m}__procified".to_sym
|
105
|
+
# # alias new_m m
|
106
|
+
# # define_method new_m do |ctx|
|
107
|
+
# # method(m)
|
108
|
+
# # end
|
109
|
+
# # end
|
110
|
+
# # end
|
111
|
+
|
112
|
+
# procify :send
|
113
|
+
end
|
114
|
+
|
115
|
+
it "works" do
|
116
|
+
test = SelfContextUnderTest.new.call
|
117
|
+
expect(test).to be_a Success
|
118
|
+
expect(test.inspect).to eq "Success(Step 3)"
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
context "** (pipe)" do
|
123
|
+
it "ignores the output of pipe" do
|
124
|
+
acc = "ctx: "
|
125
|
+
log = ->(ctx) { acc += ctx.inspect }
|
126
|
+
|
127
|
+
actual = Success(1).pipe(log).map { Success(2) }
|
128
|
+
expect(actual).to eq Success(2)
|
129
|
+
expect(acc).to eq "ctx: Success(1)"
|
130
|
+
end
|
131
|
+
|
132
|
+
it "works with **" do
|
133
|
+
log = ->(n) { n.value + 1 }
|
134
|
+
foo = ->(n) { Success(n + 1) }
|
135
|
+
|
136
|
+
actual = Success(1) ** log >> foo
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
context ">= (try)" do
|
141
|
+
it "try (>=) catches errors and wraps them as Failure" do
|
142
|
+
def error(ctx)
|
143
|
+
raise "error #{ctx}"
|
144
|
+
end
|
145
|
+
|
146
|
+
actual = Success(1) >= method(:error)
|
147
|
+
expect(actual.inspect).to eq "Failure(error 1)"
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
require_relative '../monad_axioms'
|
3
|
-
require_relative '
|
3
|
+
require_relative 'result_shared'
|
4
4
|
|
5
5
|
include Deterministic
|
6
6
|
|
@@ -18,18 +18,21 @@ describe Deterministic::Failure do
|
|
18
18
|
|
19
19
|
specify { expect(subject).to be_an_instance_of described_class }
|
20
20
|
specify { expect(subject).to eq(described_class.new(1)) }
|
21
|
-
specify { expect(subject
|
22
|
-
specify { expect(subject
|
23
|
-
specify { expect(subject.
|
21
|
+
specify { expect(subject.fmap { |v| v + 1} ).to eq Failure(2) }
|
22
|
+
specify { expect(subject.map { |v| Success(v + 1)} ).to eq Failure(1) }
|
23
|
+
specify { expect(subject.map_err { |v| Success(v + 1)} ).to eq Success(2) }
|
24
|
+
specify { expect(subject.pipe { |v| raise RuntimeError unless v == Failure(1) } ).to eq Failure(1) }
|
24
25
|
|
25
26
|
specify { expect(subject.or(Success(2))).to eq Success(2)}
|
27
|
+
specify { expect(subject.or(Failure(2))).to eq Failure(2)}
|
26
28
|
specify { expect(subject.or_else { Success(2) }).to eq Success(2)}
|
29
|
+
specify { expect(subject.or_else { Failure(2) }).to eq Failure(2)}
|
27
30
|
|
28
31
|
specify { expect(subject.and(Success(2))).to eq Failure(1)}
|
29
32
|
specify { expect(subject.and_then { Success(2) }).to eq Failure(1)}
|
30
33
|
|
31
|
-
it_behaves_like '
|
32
|
-
let(:
|
34
|
+
it_behaves_like 'Result' do
|
35
|
+
let(:result) { described_class }
|
33
36
|
end
|
34
37
|
end
|
35
38
|
|
@@ -2,7 +2,7 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
include Deterministic
|
4
4
|
|
5
|
-
describe Deterministic::
|
5
|
+
describe Deterministic::Result::Match do
|
6
6
|
it "can match Success" do
|
7
7
|
expect(
|
8
8
|
Success(1).match do
|
@@ -55,14 +55,14 @@ describe Deterministic::Either::Match do
|
|
55
55
|
).to eq "catch-all"
|
56
56
|
end
|
57
57
|
|
58
|
-
it "can match
|
58
|
+
it "can match result" do
|
59
59
|
expect(
|
60
60
|
Failure(2).match do
|
61
61
|
success { |v| "not matched s" }
|
62
|
-
|
62
|
+
result(2) { |v| "result #{v}" }
|
63
63
|
failure(3) { |v| "not matched f3" }
|
64
64
|
end
|
65
|
-
).to eq "
|
65
|
+
).to eq "result 2"
|
66
66
|
end
|
67
67
|
|
68
68
|
it "can match with lambdas" do
|
@@ -93,7 +93,7 @@ describe Deterministic::Either::Match do
|
|
93
93
|
).to eq "it works"
|
94
94
|
end
|
95
95
|
|
96
|
-
it "allows for
|
96
|
+
it "allows for Result values to play with pattern matching comparisons" do
|
97
97
|
class MyErrorHash < Hash
|
98
98
|
def ==(error_type_symbol)
|
99
99
|
self[:type] == error_type_symbol
|
@@ -0,0 +1,23 @@
|
|
1
|
+
shared_examples 'Result' do
|
2
|
+
let(:result_name) { described_class.name.split("::")[-1]}
|
3
|
+
specify { expect(subject.value).to eq 1 }
|
4
|
+
specify { expect(result.new(subject)).to eq result.new(1) }
|
5
|
+
|
6
|
+
it "#fmap" do
|
7
|
+
expect(result.new(1).fmap { |e| e + 1 }).to eq result.new(2)
|
8
|
+
end
|
9
|
+
|
10
|
+
it "#bind" do
|
11
|
+
expect(result.new(1).bind { |v| result.new(v + 1)}).to eq result.new(2)
|
12
|
+
end
|
13
|
+
|
14
|
+
it "#to_s" do
|
15
|
+
expect(result.new(1).to_s).to eq "1"
|
16
|
+
expect(result.new({a: 1}).to_s).to eq "{:a=>1}"
|
17
|
+
end
|
18
|
+
|
19
|
+
it "#inspect" do
|
20
|
+
expect(result.new(1).inspect).to eq "#{result_name}(1)"
|
21
|
+
expect(result.new(:a=>1).inspect).to eq "#{result_name}({:a=>1})"
|
22
|
+
end
|
23
|
+
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
require_relative '../monad_axioms'
|
3
|
-
require_relative '
|
3
|
+
require_relative 'result_shared'
|
4
4
|
|
5
5
|
include Deterministic
|
6
6
|
|
@@ -18,17 +18,21 @@ describe Deterministic::Success do
|
|
18
18
|
|
19
19
|
specify { expect(subject).to be_an_instance_of described_class }
|
20
20
|
specify { expect(subject).to eq(described_class.new(1)) }
|
21
|
-
specify { expect(subject
|
22
|
-
specify { expect(subject
|
23
|
-
specify { expect(subject.
|
21
|
+
specify { expect(subject.fmap { |v| v + 1} ).to eq Success(2) }
|
22
|
+
specify { expect(subject.map { |v| Failure(v + 1) } ).to eq Failure(2) }
|
23
|
+
specify { expect(subject.map_err { |v| Failure(v + 1) } ).to eq Success(1) }
|
24
|
+
|
25
|
+
specify { expect(subject.pipe{ |r| raise RuntimeError unless r == Success(1) } ).to eq Success(1) }
|
24
26
|
|
25
27
|
specify { expect(subject.or(Success(2))).to eq Success(1)}
|
26
28
|
specify { expect(subject.or_else { Success(2) }).to eq Success(1)}
|
27
29
|
|
28
30
|
specify { expect(subject.and(Success(2))).to eq Success(2)}
|
31
|
+
specify { expect(subject.and(Failure(2))).to eq Failure(2)}
|
29
32
|
specify { expect(subject.and_then { Success(2) }).to eq Success(2)}
|
33
|
+
specify { expect(subject.and_then { Failure(2) }).to eq Failure(2)}
|
30
34
|
|
31
|
-
it_behaves_like '
|
32
|
-
let(:
|
35
|
+
it_behaves_like 'Result' do
|
36
|
+
let(:result) { described_class }
|
33
37
|
end
|
34
38
|
end
|
@@ -1,8 +1,8 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
describe Deterministic::
|
4
|
-
it "can't call
|
3
|
+
describe Deterministic::Result do
|
4
|
+
it "can't call Result#new directly" do
|
5
5
|
expect { described_class.new(1)}
|
6
|
-
.to raise_error(NoMethodError, "protected method `new' called for Deterministic::
|
6
|
+
.to raise_error(NoMethodError, "protected method `new' called for Deterministic::Result:Class")
|
7
7
|
end
|
8
8
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: deterministic
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.10.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Piotr Zolnierek
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-08-
|
11
|
+
date: 2014-08-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -119,39 +119,37 @@ files:
|
|
119
119
|
- .rspec
|
120
120
|
- Gemfile
|
121
121
|
- Guardfile
|
122
|
+
- HISTORY.md
|
122
123
|
- LICENSE.txt
|
123
124
|
- README.md
|
124
125
|
- Rakefile
|
125
126
|
- deterministic.gemspec
|
126
|
-
- either.rb
|
127
127
|
- lib/deterministic.rb
|
128
|
-
- lib/deterministic/core_ext/
|
129
|
-
- lib/deterministic/core_ext/
|
130
|
-
- lib/deterministic/either.rb
|
131
|
-
- lib/deterministic/either/attempt_all.rb
|
132
|
-
- lib/deterministic/either/chain.rb
|
133
|
-
- lib/deterministic/either/failure.rb
|
134
|
-
- lib/deterministic/either/match.rb
|
135
|
-
- lib/deterministic/either/success.rb
|
128
|
+
- lib/deterministic/core_ext/object/result.rb
|
129
|
+
- lib/deterministic/core_ext/result.rb
|
136
130
|
- lib/deterministic/maybe.rb
|
137
131
|
- lib/deterministic/monad.rb
|
138
132
|
- lib/deterministic/none.rb
|
133
|
+
- lib/deterministic/result.rb
|
134
|
+
- lib/deterministic/result/chain.rb
|
135
|
+
- lib/deterministic/result/failure.rb
|
136
|
+
- lib/deterministic/result/match.rb
|
137
|
+
- lib/deterministic/result/success.rb
|
139
138
|
- lib/deterministic/version.rb
|
140
139
|
- spec/examples/bookings_spec.rb
|
141
140
|
- spec/examples/validate_address_spec.rb
|
142
|
-
- spec/lib/deterministic/attempt_all_spec.rb
|
143
|
-
- spec/lib/deterministic/core_ext/either_spec.rb
|
144
141
|
- spec/lib/deterministic/core_ext/object/either_spec.rb
|
145
|
-
- spec/lib/deterministic/
|
146
|
-
- spec/lib/deterministic/either/either_shared.rb
|
147
|
-
- spec/lib/deterministic/either/failure_spec.rb
|
148
|
-
- spec/lib/deterministic/either/match_spec.rb
|
149
|
-
- spec/lib/deterministic/either/success_spec.rb
|
150
|
-
- spec/lib/deterministic/either_spec.rb
|
142
|
+
- spec/lib/deterministic/core_ext/result_spec.rb
|
151
143
|
- spec/lib/deterministic/maybe_spec.rb
|
152
144
|
- spec/lib/deterministic/monad_axioms.rb
|
153
145
|
- spec/lib/deterministic/monad_spec.rb
|
154
146
|
- spec/lib/deterministic/none_spec.rb
|
147
|
+
- spec/lib/deterministic/result/chain_spec.rb
|
148
|
+
- spec/lib/deterministic/result/failure_spec.rb
|
149
|
+
- spec/lib/deterministic/result/match_spec.rb
|
150
|
+
- spec/lib/deterministic/result/result_shared.rb
|
151
|
+
- spec/lib/deterministic/result/success_spec.rb
|
152
|
+
- spec/lib/deterministic/result_spec.rb
|
155
153
|
- spec/spec_helper.rb
|
156
154
|
homepage: http://github.com/pzol/deterministic
|
157
155
|
licenses:
|
@@ -180,17 +178,16 @@ summary: see above
|
|
180
178
|
test_files:
|
181
179
|
- spec/examples/bookings_spec.rb
|
182
180
|
- spec/examples/validate_address_spec.rb
|
183
|
-
- spec/lib/deterministic/attempt_all_spec.rb
|
184
|
-
- spec/lib/deterministic/core_ext/either_spec.rb
|
185
181
|
- spec/lib/deterministic/core_ext/object/either_spec.rb
|
186
|
-
- spec/lib/deterministic/
|
187
|
-
- spec/lib/deterministic/either/either_shared.rb
|
188
|
-
- spec/lib/deterministic/either/failure_spec.rb
|
189
|
-
- spec/lib/deterministic/either/match_spec.rb
|
190
|
-
- spec/lib/deterministic/either/success_spec.rb
|
191
|
-
- spec/lib/deterministic/either_spec.rb
|
182
|
+
- spec/lib/deterministic/core_ext/result_spec.rb
|
192
183
|
- spec/lib/deterministic/maybe_spec.rb
|
193
184
|
- spec/lib/deterministic/monad_axioms.rb
|
194
185
|
- spec/lib/deterministic/monad_spec.rb
|
195
186
|
- spec/lib/deterministic/none_spec.rb
|
187
|
+
- spec/lib/deterministic/result/chain_spec.rb
|
188
|
+
- spec/lib/deterministic/result/failure_spec.rb
|
189
|
+
- spec/lib/deterministic/result/match_spec.rb
|
190
|
+
- spec/lib/deterministic/result/result_shared.rb
|
191
|
+
- spec/lib/deterministic/result/success_spec.rb
|
192
|
+
- spec/lib/deterministic/result_spec.rb
|
196
193
|
- spec/spec_helper.rb
|
data/either.rb
DELETED
@@ -1,97 +0,0 @@
|
|
1
|
-
class Either
|
2
|
-
def chain(&callee)
|
3
|
-
return self if @value.failure?
|
4
|
-
value = callee.call
|
5
|
-
raise "value must be either Success or Failure" unless Either::Abstract === value
|
6
|
-
@value = value
|
7
|
-
return self
|
8
|
-
end
|
9
|
-
|
10
|
-
def self.success(value)
|
11
|
-
Success.new(value)
|
12
|
-
end
|
13
|
-
|
14
|
-
def self.failure(value)
|
15
|
-
Failure.new(value)
|
16
|
-
end
|
17
|
-
|
18
|
-
class Abstract
|
19
|
-
def initialize(value)
|
20
|
-
@value = value
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
class Success < Abstract
|
25
|
-
def <<(value)
|
26
|
-
@value = value
|
27
|
-
end
|
28
|
-
|
29
|
-
def or(*args)
|
30
|
-
self
|
31
|
-
end
|
32
|
-
|
33
|
-
def success?
|
34
|
-
true
|
35
|
-
end
|
36
|
-
|
37
|
-
def failure?
|
38
|
-
false
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
class Failure < Abstract
|
43
|
-
def <<(value)
|
44
|
-
@value = value
|
45
|
-
end
|
46
|
-
|
47
|
-
def or(value)
|
48
|
-
value
|
49
|
-
end
|
50
|
-
|
51
|
-
def success?
|
52
|
-
false
|
53
|
-
end
|
54
|
-
|
55
|
-
def failure?
|
56
|
-
true
|
57
|
-
end
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
|
-
# a container for storing intermediate state
|
62
|
-
class Builder
|
63
|
-
def initialize(deps)
|
64
|
-
@settings_adapter = deps.fetch(:settings)
|
65
|
-
end
|
66
|
-
|
67
|
-
def build
|
68
|
-
Either.new do
|
69
|
-
on_failure do |result|
|
70
|
-
p result
|
71
|
-
end
|
72
|
-
|
73
|
-
chain { @settings = @settings_adapter.call(a, b) }
|
74
|
-
end
|
75
|
-
end
|
76
|
-
|
77
|
-
end
|
78
|
-
|
79
|
-
module SettingsAdapter
|
80
|
-
def self.call(contract, facility)
|
81
|
-
begin
|
82
|
-
client = ResfinitySettingsClient::Client.new
|
83
|
-
auth = self.auth
|
84
|
-
Either.success(client.settings(auth))
|
85
|
-
rescue => ex
|
86
|
-
Either.failure(["Could not get settings: #{ex.message}", ex])
|
87
|
-
end
|
88
|
-
end
|
89
|
-
|
90
|
-
def self.auth
|
91
|
-
{
|
92
|
-
# config to external
|
93
|
-
api_user: ENV['SETTINGS_USER'],
|
94
|
-
api_token: ENV['SETTINGS_TOKEN']
|
95
|
-
}
|
96
|
-
end
|
97
|
-
end
|
@@ -1,50 +0,0 @@
|
|
1
|
-
require 'ostruct'
|
2
|
-
|
3
|
-
class Deterministic::Either
|
4
|
-
def self.attempt_all(context=OpenStruct.new, &block)
|
5
|
-
AttemptAll.new(context, &block).call
|
6
|
-
end
|
7
|
-
|
8
|
-
class AttemptAll
|
9
|
-
class EitherExpectedError < StandardError; end
|
10
|
-
def initialize(context, &block)
|
11
|
-
@context = context || self
|
12
|
-
@tries = []
|
13
|
-
instance_eval(&block)
|
14
|
-
end
|
15
|
-
|
16
|
-
def call(initial=nil)
|
17
|
-
result = @tries.inject(Deterministic::Success(initial)) do |acc, try|
|
18
|
-
acc.success? ? acc << try.call(acc) : acc
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
# This is a functor
|
23
|
-
def try(&block)
|
24
|
-
try_p = ->(acc) {
|
25
|
-
begin
|
26
|
-
value = @context.instance_exec(acc.value, &block)
|
27
|
-
case value
|
28
|
-
when Deterministic::Success, Deterministic::Failure
|
29
|
-
value
|
30
|
-
else
|
31
|
-
Deterministic::Success(value)
|
32
|
-
end
|
33
|
-
rescue => ex
|
34
|
-
Deterministic::Failure(ex)
|
35
|
-
end
|
36
|
-
}
|
37
|
-
|
38
|
-
@tries << try_p
|
39
|
-
end
|
40
|
-
|
41
|
-
# Basicly a monad
|
42
|
-
def let(sym=nil, &block)
|
43
|
-
@tries << ->(acc) {
|
44
|
-
@context.instance_exec(acc.value, &block).tap do |value|
|
45
|
-
raise EitherExpectedError, "Expected the result to be either Success or Failure" unless value.is_a? Either
|
46
|
-
end
|
47
|
-
}
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|
@@ -1,22 +0,0 @@
|
|
1
|
-
module Deterministic
|
2
|
-
class Either
|
3
|
-
module Chain
|
4
|
-
def chain(proc=nil, &block)
|
5
|
-
return self if failure?
|
6
|
-
bind { (proc || block).call(@value) }
|
7
|
-
end
|
8
|
-
|
9
|
-
alias :>> :chain
|
10
|
-
|
11
|
-
def try(proc=nil, &block)
|
12
|
-
return self if failure?
|
13
|
-
bind { (proc || block).call(@value) }
|
14
|
-
rescue => err
|
15
|
-
Failure(err)
|
16
|
-
end
|
17
|
-
|
18
|
-
alias :>= :try
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
@@ -1,22 +0,0 @@
|
|
1
|
-
module Deterministic
|
2
|
-
class Failure < Either
|
3
|
-
class << self; public :new; end
|
4
|
-
|
5
|
-
def and(other)
|
6
|
-
self
|
7
|
-
end
|
8
|
-
|
9
|
-
def and_then(&block)
|
10
|
-
self
|
11
|
-
end
|
12
|
-
|
13
|
-
def or(other)
|
14
|
-
raise NotMonadError, "Expected #{other.inspect} to be an Either" unless other.is_a? Either
|
15
|
-
other
|
16
|
-
end
|
17
|
-
|
18
|
-
def or_else(&block)
|
19
|
-
bind(&block)
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
@@ -1,22 +0,0 @@
|
|
1
|
-
module Deterministic
|
2
|
-
class Success < Either
|
3
|
-
class << self; public :new; end
|
4
|
-
|
5
|
-
def and(other)
|
6
|
-
raise NotMonadError, "Expected #{other.inspect} to be an Either" unless other.is_a? Either
|
7
|
-
other
|
8
|
-
end
|
9
|
-
|
10
|
-
def and_then(&block)
|
11
|
-
bind(&block)
|
12
|
-
end
|
13
|
-
|
14
|
-
def or(other)
|
15
|
-
self
|
16
|
-
end
|
17
|
-
|
18
|
-
def or_else(&block)
|
19
|
-
self
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|