deterministic 0.14.1 → 0.15.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.
@@ -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