deterministic 0.14.1 → 0.15.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,43 @@
1
+ require 'spec_helper'
2
+ require 'deterministic/protocol'
3
+
4
+
5
+ module Monoid
6
+ extend Deterministic::Protocol
7
+
8
+ Deterministic::protocol(M) {
9
+ fn empty() => M
10
+ fn(append(a => M, b => M) => M) { |a, b|
11
+ a + b
12
+ }
13
+ }
14
+
15
+ Int = Deterministic::instance(Monoid, M => Fixnum) {
16
+ def empty()
17
+ 0
18
+ end
19
+
20
+ def append(a, b)
21
+ a + b + 1
22
+ end
23
+ }
24
+
25
+ String = Deterministic::instance(Monoid, M => String) {
26
+ def empty()
27
+ ""
28
+ end
29
+ }
30
+ end
31
+
32
+ describe Monoid do
33
+ it "does something" do
34
+ expect(described_class.constants).to eq [:Protocol, :Int, :String]
35
+ int = described_class::Int.new
36
+ expect(int.empty).to eq 0
37
+ expect(int.append(1, 2)).to eq 4
38
+
39
+ str = described_class::String.new
40
+ expect(str.empty).to eq ""
41
+ expect(str.append("a", "b")).to eq "ab"
42
+ end
43
+ end
@@ -2,9 +2,8 @@ require 'spec_helper'
2
2
  require_relative '../monad_axioms'
3
3
  require_relative 'result_shared'
4
4
 
5
-
6
5
  describe Deterministic::Result::Failure do
7
- include Deterministic
6
+ include Deterministic::Prelude::Result
8
7
 
9
8
  it_behaves_like 'a Monad' do
10
9
  let(:monad) { described_class }
@@ -36,11 +35,6 @@ describe Deterministic::Result::Failure do
36
35
  it_behaves_like 'Result' do
37
36
  let(:result) { described_class }
38
37
  end
39
- end
40
-
41
-
42
- describe "Chaining" do
43
- include Deterministic
44
38
 
45
39
  it "#or" do
46
40
  expect(Success(1).or(Failure(2))).to eq Success(1)
@@ -2,7 +2,7 @@ require 'spec_helper'
2
2
 
3
3
 
4
4
  describe Deterministic::Result do
5
- include Deterministic
5
+ include Deterministic::Prelude::Result
6
6
 
7
7
  context ">> (map)" do
8
8
  specify { expect(Success(0).map { |n| Success(n + 1) }).to eq Success(1) }
@@ -10,14 +10,13 @@ describe Deterministic::Result do
10
10
 
11
11
  it "Failure stops execution" do
12
12
  class ChainUnderTest
13
- include Deterministic
14
-
13
+ include Deterministic::Prelude::Result
15
14
  alias :m :method
16
15
 
17
16
  def call
18
17
  init >>
19
- m(:validate) >>
20
- m(:send) >>
18
+ m(:validate) >>
19
+ m(:send) >>
21
20
  m(:parse)
22
21
  end
23
22
 
@@ -75,7 +74,7 @@ describe Deterministic::Result do
75
74
 
76
75
  context "using self as the context for success" do
77
76
  class SelfContextUnderTest
78
- include Deterministic
77
+ include Deterministic::Prelude::Result
79
78
 
80
79
  def call
81
80
  @step = 0
@@ -124,7 +123,7 @@ describe Deterministic::Result do
124
123
  end
125
124
  end
126
125
 
127
- context "** (pipe)" do
126
+ context "<< (pipe)" do
128
127
  it "ignores the output of pipe" do
129
128
  acc = "ctx: "
130
129
  log = ->(ctx) { acc += ctx.inspect }
@@ -134,16 +133,17 @@ describe Deterministic::Result do
134
133
  expect(acc).to eq "ctx: Success(1)"
135
134
  end
136
135
 
137
- it "works with **" do
136
+ it "works with <<" do
138
137
  log = ->(n) { n.value + 1 }
139
138
  foo = ->(n) { Success(n + 1) }
140
139
 
141
- actual = Success(1) ** log >> foo
140
+ actual = Success(1) << log >> foo
142
141
  end
143
142
  end
144
143
 
145
144
  context ">= (try)" do
146
145
  it "try (>=) catches errors and wraps them as Failure" do
146
+ pending "not implemented"
147
147
  def error(ctx)
148
148
  raise "error #{ctx}"
149
149
  end
@@ -2,9 +2,8 @@ require 'spec_helper'
2
2
  require_relative '../monad_axioms'
3
3
  require_relative 'result_shared'
4
4
 
5
-
6
5
  describe Deterministic::Result::Success do
7
- include Deterministic
6
+ include Deterministic::Prelude::Result
8
7
 
9
8
  it_behaves_like 'a Monad' do
10
9
  let(:monad) { described_class }
@@ -1,23 +1,52 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Deterministic::Result do
4
+ include Deterministic::Prelude::Result
5
+
4
6
  it "can't call Result#new directly" do
5
- expect { described_class.new(1)}
6
- .to raise_error(NoMethodError, "protected method `new' called for Deterministic::Result:Class")
7
+ expect { described_class.new(1)}
8
+ .to raise_error(NoMethodError, "private method `new' called for Deterministic::Result:Class")
7
9
  end
8
- end
9
10
 
10
- describe Deterministic::Result do
11
- include Deterministic
12
- describe "+" do
13
- specify { expect(Success(1) + Success(1)).to eq Success(2) }
14
- specify { expect(Failure(1) + Failure(1)).to eq Failure(2) }
15
- specify { expect { Success([1]) + Success(1)}.to raise_error TypeError}
16
- specify { expect { Failure([1]) + Failure(1)}.to raise_error TypeError}
17
- specify { expect(Success(1) + Failure(2)).to eq Failure(2) }
18
- specify { expect(Failure(1) + Success(2)).to eq Failure(1) }
19
- specify { expect(Success(1) + Failure(2) + Failure(3)).to eq Failure(5) }
20
- specify { expect(Failure([2]) + Failure([3]) + Success(1)).to eq Failure([2, 3]) }
21
- specify { expect(Success([1]) + Success([1])).to eq Success([1, 1]) }
11
+ it "fmap" do
12
+ expect(Success(1).fmap { |n| n + 1}).to eq Success(2)
13
+ expect(Failure(0).fmap { |n| n + 1}).to eq Failure(1)
14
+ end
15
+
16
+ it "map" do
17
+ expect(Success(1).map { |n| Success(n + 1)}).to eq Success(2)
18
+ expect(Failure(0).map { |n| Success(n + 1)}).to eq Failure(0)
19
+ end
20
+
21
+ it "+" do
22
+ expect(Success([1]) + Failure([2])).to eq Failure([2])
23
+ expect(Success(1) + Success(1)).to eq Success(2)
24
+ expect(Failure(2) + Success(1)).to eq Failure(2)
25
+ expect(Failure([2]) + Failure([3]) + Success(1)).to eq Failure([2, 3])
26
+ expect(Success([1]) + Success([1])).to eq Success([1, 1])
27
+ expect { Success([1]) + Success(1)}.to raise_error TypeError
22
28
  end
29
+
30
+ subject { Success(1) }
31
+ # specify { expect(subject).to be_an_instance_of described_class }
32
+ specify { expect(subject).to be_success }
33
+ specify { expect(subject).not_to be_failure }
34
+ specify { expect(subject.success?).to be_truthy }
35
+ specify { expect(subject.failure?).to be_falsey }
36
+
37
+ specify { expect(subject).to be_a described_class }
38
+ # specify { expect(subject).to eq(described_class.new(1)) }
39
+ specify { expect(subject.fmap { |v| v + 1} ).to eq Success(2) }
40
+ specify { expect(subject.map { |v| Failure(v + 1) } ).to eq Failure(2) }
41
+ specify { expect(subject.map_err { |v| Failure(v + 1) } ).to eq Success(1) }
42
+
43
+ specify { expect(subject.pipe{ |r| raise RuntimeError unless r == Success(1) } ).to eq Success(1) }
44
+
45
+ specify { expect(subject.or(Success(2))).to eq Success(1)}
46
+ specify { expect(subject.or_else { Success(2) }).to eq Success(1)}
47
+
48
+ specify { expect(subject.and(Success(2))).to eq Success(2)}
49
+ specify { expect(subject.and(Failure(2))).to eq Failure(2)}
50
+ specify { expect(subject.and_then { Success(2) }).to eq Success(2)}
51
+ specify { expect(subject.and_then { Failure(2) }).to eq Failure(2)}
23
52
  end
@@ -0,0 +1,108 @@
1
+ require 'spec_helper'
2
+ require 'deterministic/enum'
3
+
4
+ describe Deterministic::Enum do
5
+ include Deterministic
6
+
7
+ it "can't use value" do
8
+ expect { InvalidEnum = Deterministic::enum {
9
+ Unary(:value)
10
+ }}.to raise_error ArgumentError
11
+ end
12
+
13
+ context "Nullary, Unary, Binary" do
14
+ MyEnym = Deterministic::enum {
15
+ Nullary()
16
+ Unary(:a)
17
+ Binary(:a, :b)
18
+ }
19
+
20
+ it "can't instantiate parent" do
21
+ expect { MyEnym.new }.to raise_error NoMethodError, "private method `new' called for MyEnym:Class"
22
+ end
23
+
24
+ it "Nullary" do
25
+ n = MyEnym.Nullary
26
+
27
+ expect(n).to be_a MyEnym
28
+ expect(n).to be_a MyEnym::Nullary
29
+ expect(n.name).to eq "Nullary"
30
+ expect { n.value }.to raise_error
31
+ expect(n.inspect).to eq "Nullary"
32
+ expect(n.to_s).to eq ""
33
+ expect(n.fmap { }).to eq n
34
+ end
35
+
36
+ it "Unary" do
37
+ u = MyEnym::Unary(1)
38
+
39
+ expect(u).to be_a MyEnym
40
+ expect(u).to be_a MyEnym::Unary
41
+ expect(u.name).to eq "Unary"
42
+ expect(u.a).to eq 1
43
+ expect(u.value).to eq 1
44
+ expect(u.inspect).to eq "Unary(1)"
45
+ expect(u.to_s).to eq "1"
46
+ end
47
+
48
+ it "Binary" do
49
+ # hash
50
+ b = MyEnym::Binary(a: 1, b: 2)
51
+ expect(b).to be_a MyEnym
52
+ expect(b).to be_a MyEnym::Binary
53
+ expect(b.name).to eq "Binary"
54
+ expect(b.inspect).to eq "Binary(a: 1, b: 2)"
55
+
56
+ expect(b.a).to eq 1
57
+ expect(b.b).to eq 2
58
+ expect(b.value).to eq({a: 1, b: 2})
59
+
60
+ # values only
61
+ b = MyEnym::Binary(1, 2)
62
+ expect(b.value).to eq({a: 1, b: 2})
63
+
64
+ # other names are ok
65
+ b = MyEnym::Binary(c: 1, d: 2)
66
+ expect(b.value).to eq({a: 1, b: 2})
67
+
68
+ expect { MyEnym::Binary(1) }.to raise_error ArgumentError
69
+ end
70
+
71
+ it "generated enum" do
72
+ expect(MyEnym.variants).to eq [:Nullary, :Unary, :Binary]
73
+ expect(MyEnym.constants.inspect).to eq "[:Nullary, :Unary, :Binary, :Matcher]"
74
+
75
+ b = MyEnym::Binary(a: 1, b: 2)
76
+
77
+ res =
78
+ MyEnym.match(b) {
79
+ Nullary() { 0 }
80
+ Unary(a) { [a, b] }
81
+ Binary(x, y) { [x, y]}
82
+ }
83
+
84
+ expect(res).to eq [1, 2]
85
+
86
+ res =
87
+ b.match {
88
+ Nullary() { 0 }
89
+ Unary(a) { [a, b] }
90
+ Binary(x, y) { [x, y]}
91
+ }
92
+
93
+ expect(res).to eq [1, 2]
94
+
95
+ expect { b.match {
96
+ Nullary # Nullary is treated as a constant
97
+ }
98
+ }.to raise_error(NameError)
99
+
100
+ expect { b.match {
101
+ Nullary()
102
+ Unary()
103
+ Binary()
104
+ }
105
+ }.to raise_error ArgumentError, "No block given to `Nullary`"
106
+ end
107
+ end
108
+ end
data/spec/spec_helper.rb CHANGED
@@ -1,6 +1,8 @@
1
1
  require 'simplecov'
2
2
  SimpleCov.start
3
3
 
4
+ require 'deterministic'
5
+
4
6
  RSpec.configure do |config|
5
7
  # Limit the spec run to only specs with the focus metadata. If no specs have
6
8
  # the filtering metadata and `run_all_when_everything_filtered = true` then
@@ -23,4 +25,3 @@ RSpec.configure do |config|
23
25
 
24
26
  config.filter_run_excluding isolate: true
25
27
  end
26
- require 'deterministic'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: deterministic
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.14.1
4
+ version: 0.15.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Piotr Zolnierek
@@ -116,7 +116,6 @@ extensions: []
116
116
  extra_rdoc_files: []
117
117
  files:
118
118
  - ".gitignore"
119
- - ".rspec"
120
119
  - Gemfile
121
120
  - Guardfile
122
121
  - HISTORY.md
@@ -128,33 +127,39 @@ files:
128
127
  - lib/deterministic/core_ext/object/result.rb
129
128
  - lib/deterministic/core_ext/result.rb
130
129
  - lib/deterministic/either.rb
130
+ - lib/deterministic/enum.rb
131
131
  - lib/deterministic/match.rb
132
132
  - lib/deterministic/maybe.rb
133
133
  - lib/deterministic/monad.rb
134
134
  - lib/deterministic/null.rb
135
135
  - lib/deterministic/option.rb
136
+ - lib/deterministic/protocol.rb
136
137
  - lib/deterministic/result.rb
137
138
  - lib/deterministic/version.rb
138
- - spec/examples/bookings_spec.rb
139
+ - spec/examples/amount_spec.rb
139
140
  - spec/examples/config_spec.rb
140
141
  - spec/examples/controller_spec.rb
142
+ - spec/examples/list.rb
143
+ - spec/examples/list_spec.rb
141
144
  - spec/examples/logger_spec.rb
142
145
  - spec/examples/validate_address_spec.rb
143
146
  - spec/lib/deterministic/class_mixin_spec.rb
144
147
  - spec/lib/deterministic/core_ext/object/either_spec.rb
145
148
  - spec/lib/deterministic/core_ext/result_spec.rb
149
+ - spec/lib/deterministic/currify_spec.rb
146
150
  - spec/lib/deterministic/either_spec.rb
147
151
  - spec/lib/deterministic/maybe_spec.rb
148
152
  - spec/lib/deterministic/monad_axioms.rb
149
153
  - spec/lib/deterministic/monad_spec.rb
150
154
  - spec/lib/deterministic/null_spec.rb
151
155
  - spec/lib/deterministic/option_spec.rb
156
+ - spec/lib/deterministic/protocol_spec.rb
152
157
  - spec/lib/deterministic/result/failure_spec.rb
153
- - spec/lib/deterministic/result/match_spec.rb
154
- - spec/lib/deterministic/result/result_map.rb
158
+ - spec/lib/deterministic/result/result_map_spec.rb
155
159
  - spec/lib/deterministic/result/result_shared.rb
156
160
  - spec/lib/deterministic/result/success_spec.rb
157
161
  - spec/lib/deterministic/result_spec.rb
162
+ - spec/lib/enum_spec.rb
158
163
  - spec/spec_helper.rb
159
164
  homepage: http://github.com/pzol/deterministic
160
165
  licenses:
@@ -181,24 +186,28 @@ signing_key:
181
186
  specification_version: 4
182
187
  summary: see above
183
188
  test_files:
184
- - spec/examples/bookings_spec.rb
189
+ - spec/examples/amount_spec.rb
185
190
  - spec/examples/config_spec.rb
186
191
  - spec/examples/controller_spec.rb
192
+ - spec/examples/list.rb
193
+ - spec/examples/list_spec.rb
187
194
  - spec/examples/logger_spec.rb
188
195
  - spec/examples/validate_address_spec.rb
189
196
  - spec/lib/deterministic/class_mixin_spec.rb
190
197
  - spec/lib/deterministic/core_ext/object/either_spec.rb
191
198
  - spec/lib/deterministic/core_ext/result_spec.rb
199
+ - spec/lib/deterministic/currify_spec.rb
192
200
  - spec/lib/deterministic/either_spec.rb
193
201
  - spec/lib/deterministic/maybe_spec.rb
194
202
  - spec/lib/deterministic/monad_axioms.rb
195
203
  - spec/lib/deterministic/monad_spec.rb
196
204
  - spec/lib/deterministic/null_spec.rb
197
205
  - spec/lib/deterministic/option_spec.rb
206
+ - spec/lib/deterministic/protocol_spec.rb
198
207
  - spec/lib/deterministic/result/failure_spec.rb
199
- - spec/lib/deterministic/result/match_spec.rb
200
- - spec/lib/deterministic/result/result_map.rb
208
+ - spec/lib/deterministic/result/result_map_spec.rb
201
209
  - spec/lib/deterministic/result/result_shared.rb
202
210
  - spec/lib/deterministic/result/success_spec.rb
203
211
  - spec/lib/deterministic/result_spec.rb
212
+ - spec/lib/enum_spec.rb
204
213
  - spec/spec_helper.rb
data/.rspec DELETED
@@ -1,2 +0,0 @@
1
- --color
2
- --format progress
@@ -1,72 +0,0 @@
1
- require 'spec_helper'
2
- require 'deterministic'
3
-
4
- include Deterministic
5
-
6
- module Examples
7
- module Bookings
8
-
9
- module Adapters
10
- class BookingsRepo
11
- def find(params)
12
- end
13
- end
14
- end
15
-
16
- class FakeWebUi
17
- def method_missing(m, *args)
18
- { m => args }
19
- end
20
- end
21
-
22
- class Dependencies
23
- include Adapters
24
- def bookings_repo
25
- BookingsRepo.new
26
- end
27
- end
28
-
29
- class ShowBookings
30
- def initialize(world=FakeWebUi.new, deps=Dependencies.new)
31
- @world = world
32
- @world.booking_list([])
33
- end
34
-
35
- def call(dirty_params)
36
-
37
- ( parse_params(dirty_params) >> method(:read_bookings) ).match(world) do
38
- success(Array) { |bookings| booking_list(bookings) }
39
- success { |booking| booking(booking) }
40
- failure(:no_bookings) { empty_booking_list }
41
- failure(StandardError) { |ex| raise ex }
42
- any { |result| raise "Something went terribly wrong `#{result.class}`" }
43
- end
44
- end
45
-
46
- # private
47
- attr_reader :bookings_repo, :world
48
-
49
- def parse_params(dirty_params)
50
- Success(dirty_params)
51
- end
52
-
53
- def read_bookings(params)
54
- bookings = [params]
55
- case bookings
56
- when nil; Failure(:no_bookings)
57
- when bookings.count == 1;
58
- else Success(bookings)
59
- end
60
- end
61
- end
62
- end
63
- end
64
-
65
- describe Examples::Bookings::ShowBookings do
66
- subject { described_class.new }
67
- it "works" do
68
- expect(
69
- subject.call({status: 'confirmed'})
70
- ).to eq({:booking_list=>[[{:status=>"confirmed"}]]})
71
- end
72
- end