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.
@@ -17,7 +17,7 @@ class Logger
17
17
  def validate(item)
18
18
  return Failure(["Item cannot be empty"]) if item.blank?
19
19
  return Failure(["Item must be a Hash"]) unless item.is_a?(Hash)
20
-
20
+
21
21
  validate_required_params(item).match {
22
22
  none { Success(item) }
23
23
  some { |errors| Failure(errors) }
@@ -46,7 +46,11 @@ class Logger
46
46
  class Ensure
47
47
  include Deterministic
48
48
  include Deterministic::Monad
49
- None = Deterministic::Option::None.instance
49
+
50
+ None = Deterministic::Option::None.new
51
+ def Some(value)
52
+ Option::Some.new(value)
53
+ end
50
54
 
51
55
  attr_accessor :value
52
56
 
@@ -81,34 +85,35 @@ class Ensure
81
85
  end
82
86
 
83
87
  class Validator < Ensure
84
-
88
+
85
89
  def date_is_one!
86
90
  value[:date] == 1 ? None : Some({actual: value[:date], expected: 1})
87
91
  end
88
92
 
89
93
  def required_params!
90
94
  params = %w(date tenant contract user facility short data)
91
- params.inject(None) { |errors, param|
95
+ params.inject(None) { |errors, param|
92
96
  errors + (value[:param].nil? || value[:param].empty? ? Some([param]) : None)
93
97
  }
94
98
  end
95
99
 
96
100
  def call
97
- not_empty + is_a(Array) + None + has_key(:tenant) + Some("error").value_to_a + date_is_one + required_params
101
+ not_empty + is_a(Array) + None + has_key(:tenant) + Some(["error"]) #+ date_is_one + required_params
98
102
  end
99
103
 
100
104
  end
101
105
 
102
106
  describe Ensure do
103
- # None = Deterministic::Option::None.instance
104
-
107
+ None = Deterministic::Option::None.new
108
+ Some = Deterministic::Option::Some
109
+
105
110
  it "Ensure" do
106
111
  params = {date: 2}
107
112
 
108
113
  v = Validator.new(params)
109
114
 
110
115
  errors = v.call
111
- expect(errors).to be_a Deterministic::Some
116
+ expect(errors).to be_a Some
112
117
  expect(errors.value).not_to be_empty
113
118
  end
114
119
  end
@@ -1,10 +1,10 @@
1
1
  require 'spec_helper'
2
- require 'deterministic'
3
2
 
4
- include Deterministic
5
3
 
6
4
  # A Unit of Work for validating an address
7
5
  module ValidateAddress
6
+ extend Deterministic::Prelude::Result
7
+
8
8
  def self.call(candidate)
9
9
  errors = {}
10
10
  errors[:street] = "Street cannot be empty" unless candidate.has_key? :street
@@ -16,16 +16,17 @@ module ValidateAddress
16
16
  end
17
17
 
18
18
  describe ValidateAddress do
19
+ include Deterministic
19
20
  subject { ValidateAddress.call(candidate) }
20
21
  context 'sunny day' do
21
22
  let(:candidate) { {title: "Hobbiton", street: "501 Buckland Rd", city: "Matamata", postal: "3472", country: "nz"} }
22
- specify { expect(subject).to be_a Result::Success }
23
+ specify { expect(subject).to be_a Deterministic::Result::Success }
23
24
  specify { expect(subject.value).to eq candidate }
24
25
  end
25
26
 
26
27
  context 'empty data' do
27
28
  let(:candidate) { {} }
28
- specify { expect(subject).to be_a Result::Failure }
29
+ specify { expect(subject).to be_a Deterministic::Result::Failure }
29
30
  specify { expect(subject.value).to include(:street, :city, :postal) }
30
31
  end
31
32
  end
@@ -1,14 +1,13 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe 'Class Mixin' do
4
-
5
4
  describe 'try' do
6
5
  module MyApp
7
6
  class Thing
8
- include Deterministic
7
+ include Deterministic::Prelude::Result
9
8
 
10
9
  def run
11
- Success(11) >= method(:double)
10
+ Success(11) >> method(:double)
12
11
  end
13
12
 
14
13
  def double(num)
@@ -19,7 +18,7 @@ describe 'Class Mixin' do
19
18
 
20
19
  it "cleanly mixes into a class" do
21
20
  result = MyApp::Thing.new.run
22
- expect(result).to eq Deterministic::Success.new(22)
21
+ expect(result).to eq Deterministic::Result::Success.new(22)
23
22
  end
24
23
  end
25
24
  end
@@ -3,6 +3,8 @@ require "deterministic"
3
3
  require "deterministic/core_ext/result"
4
4
 
5
5
  describe Deterministic::CoreExt::Result do
6
+ include Deterministic::Prelude::Result
7
+
6
8
  it "does something" do
7
9
  h = {}
8
10
  h.extend(Deterministic::CoreExt::Result)
@@ -12,10 +14,10 @@ describe Deterministic::CoreExt::Result do
12
14
  end
13
15
 
14
16
  it "enables #success?, #failure?, #result? on all Objects" do
15
- ary = [Deterministic::Success(true), Deterministic::Success(1)]
17
+ ary = [Success(true), Success(1)]
16
18
  expect(ary.all?(&:success?)).to be_truthy
17
19
 
18
- ary = [Deterministic::Success(true), Deterministic::Failure(1)]
20
+ ary = [Success(true), Failure(1)]
19
21
  expect(ary.all?(&:success?)).to be_falsey
20
22
  expect(ary.any?(&:failure?)).to be_truthy
21
23
  end
@@ -0,0 +1,88 @@
1
+ require 'spec_helper'
2
+
3
+ module Deterministic
4
+ module Currify
5
+ module ClassMethods
6
+ def currify(*names)
7
+ names.each { |name|
8
+ unbound_method = instance_method(name)
9
+
10
+ define_method(name) { |*args|
11
+ curried_method = unbound_method.bind(self).to_proc.curry
12
+ curried_method[*args]
13
+ }
14
+ }
15
+ end
16
+ end
17
+
18
+ def self.included(curried)
19
+ curried.extend ClassMethods
20
+ end
21
+
22
+ end
23
+ end
24
+
25
+ class ::Proc
26
+ def self.compose(f, g)
27
+ lambda { |*args| f[g[*args]] }
28
+ end
29
+
30
+ # Compose left to right
31
+ def |(g)
32
+ Proc.compose(g, self)
33
+ end
34
+
35
+ # Compose right to left
36
+ def *(g)
37
+ Proc.compose(self, g)
38
+ end
39
+ end
40
+
41
+ class Booking
42
+ include Deterministic::Currify
43
+ include Deterministic::Prelude::Result
44
+
45
+ def initialize(deps)
46
+ @deps = deps
47
+ end
48
+
49
+ def build(id, format)
50
+ validate(id) | req | find | render(format)
51
+
52
+ validate(id) | rq = request(id) | find()
53
+ end
54
+
55
+ def validate(id)
56
+ p [:validate, id]
57
+ Success(id)
58
+ end
59
+
60
+ def req(a, id)
61
+ p [:req, a, id]
62
+ Success(id: id + a)
63
+ end
64
+
65
+ def find(req)
66
+ Success({ found: req})
67
+ end
68
+
69
+ def render(format, req)
70
+ Success("rendered in #{format}: #{req[:found]}")
71
+ end
72
+
73
+ currify :find, :render, :req
74
+
75
+ end
76
+
77
+ describe "Pref" do
78
+ include Deterministic::Prelude::Result
79
+
80
+ it "does something" do
81
+ b = Booking.new(1)
82
+ actual = b.validate(1) >> b.req(2) >> b.find >> b.render(:html)
83
+
84
+ p [:actual, actual]
85
+ expected = Deterministic::Result::Success.new("rendered in html: {:id=>3}")
86
+ expect(actual).to eq expected
87
+ end
88
+ end
@@ -3,12 +3,12 @@ require_relative 'monad_axioms'
3
3
 
4
4
 
5
5
  describe Deterministic::Monad do
6
- class Identity
6
+ class Identity
7
7
  include Deterministic::Monad
8
8
  end
9
9
 
10
10
  let(:monad) { Identity }
11
- it_behaves_like 'a Monad' do
11
+ it_behaves_like 'a Monad' do
12
12
  # let(:monad) { monad }
13
13
  end
14
14
 
@@ -21,7 +21,7 @@ describe Deterministic::Monad do
21
21
  specify { expect(Identity.new('foo').fmap(&:upcase)).to eq Identity.new('FOO')}
22
22
 
23
23
  context '#bind' do
24
- it "raises an error if the passed function does not return a monad of the same class" do
24
+ it "raises an error if the passed function does not return a monad of the same class" do
25
25
  expect { Identity.new(1).bind {} }.to raise_error(Deterministic::Monad::NotMonadError)
26
26
  end
27
27
  specify { expect(Identity.new(1).bind {|value| Identity.new(value) }).to eq Identity.new(1) }
@@ -1,131 +1,140 @@
1
1
  require 'spec_helper'
2
- require_relative 'monad_axioms'
3
2
 
3
+ include Deterministic
4
4
 
5
5
  describe Deterministic::Option do
6
- include Deterministic
7
- Some = Deterministic::Some
8
- None = Deterministic::None
9
-
10
- # nil?
11
- specify { expect(described_class.some?(nil)).to eq None }
12
- specify { expect(described_class.some?(1)).to be_some }
13
- specify { expect(described_class.some?(1)).to eq Some(1) }
14
-
15
- # any?
16
- specify { expect(described_class.any?(nil)).to be_none }
17
- specify { expect(described_class.any?(None)).to be_none }
18
- specify { expect(described_class.any?("")).to be_none }
19
- specify { expect(described_class.any?([])).to be_none }
20
- specify { expect(described_class.any?({})).to be_none }
21
- specify { expect(described_class.any?([1])).to eq Some([1]) }
22
- specify { expect(described_class.any?({foo: 1})).to eq Some({foo: 1}) }
23
-
24
- # try!
25
- specify { expect(described_class.try! { raise "error" }).to be_none }
26
- end
6
+ include Deterministic::Prelude::Option
7
+ None = Deterministic::Prelude::Option::None
27
8
 
28
- describe Deterministic::Option do
29
- include Deterministic
30
- Option = Deterministic::Option
31
-
32
- # it_behaves_like 'a Monad' do
33
- # let(:monad) { described_class }
34
- # end
35
-
36
- specify { expect(Option::Some.new(0)).to be_a Option::Some }
37
- specify { expect(Option::Some.new(0)).to eq Some(0) }
38
-
39
- specify { expect(Option::None.new).to eq Option::None.new }
40
- specify { expect(Option::None.new).to eq None }
41
-
42
- # some?, none?
43
- specify { expect(None.some?).to be_falsey }
44
- specify { expect(None.none?).to be_truthy }
45
- specify { expect(Some(0).some?).to be_truthy }
46
- specify { expect(Some(0).none?).to be_falsey }
47
-
48
- # value, value_or
49
- specify { expect(Some(0).value).to eq 0 }
50
- specify { expect(Some(1).value_or(2)).to eq 1}
51
- specify { expect { None.value }.to raise_error NoMethodError }
52
- specify { expect(None.value_or(2)).to eq 2}
53
-
54
- # fmap
55
- specify { expect(Some(1).fmap { |n| n + 1}).to eq Some(2) }
56
- specify { expect(None.fmap { |n| n + 1}).to eq None }
57
-
58
- # map
59
- specify { expect(Some(1).map { |n| Some(n + 1)}).to eq Some(2) }
60
- specify { expect(Some(1).map { |n| None }).to eq None }
61
- specify { expect(None.map { |n| nil }).to eq None }
62
-
63
- # to_a
64
- specify { expect(Some(1).value_to_a). to eq Some([1])}
65
- specify { expect(Some([1]).value_to_a). to eq Some([1])}
66
- specify { expect(None.value_to_a). to eq None}
67
-
68
- # +
69
- specify { expect(Some(1) + None).to eq Some(1) }
70
- specify { expect(Some(1) + None + None).to eq Some(1) }
71
- specify { expect(Some(1) + Some(1)).to eq Some(2) }
72
- specify { expect(None + Some(1)).to eq Some(1) }
73
- specify { expect(None + None + Some(1)).to eq Some(1) }
74
- specify { expect(None + None + Some(1) + None).to eq Some(1) }
75
- specify { expect { Some([1]) + Some(1)}.to raise_error TypeError}
76
-
77
- # match
78
- specify {
9
+ specify { expect(described_class::Some.new(0)).to be_a described_class::Some }
10
+ specify { expect(described_class::Some.new(0)).to be_a described_class }
11
+ specify { expect(described_class::Some.new(0)).to eq Some(0) }
12
+
13
+ specify { expect(described_class::None.new).to eq described_class::None.new }
14
+ specify { expect(described_class::None.new).to be_a described_class::None }
15
+ specify { expect(described_class::None.new).to be_a described_class }
16
+ specify { expect(described_class::None.new).to eq None }
17
+
18
+ it "join" do
19
+ expect(Some(Some(1))).to eq Some(1)
20
+ end
21
+
22
+ it "fmap" do
23
+ expect(Some(1).fmap { |n| n + 1}).to eq Some(2)
24
+ expect(None.fmap { |n| n + 1}).to eq None
25
+ end
26
+
27
+ it "map" do
28
+ expect(Some(1).map { |n| Some(n + 1)}).to eq Some(2)
29
+ expect(Some(1).map { |n| None }).to eq None
30
+ expect(None.map { |n| Some(n + 1)}).to eq None
31
+ end
32
+
33
+ it "some?" do
34
+ expect(Some(1).some?).to be_truthy
35
+ expect(None.some?).to be_falsey
36
+ end
37
+
38
+ it "none?" do
39
+ expect(None.none?).to be_truthy
40
+ expect(Some(1).none?).to be_falsey
41
+ end
42
+
43
+ it "value" do
44
+ expect(Some(1).value).to eq 1
45
+ expect{ None.value }.to raise_error NoMethodError
46
+ end
47
+
48
+ it "value_or" do
49
+ expect(Some(1).value_or(2)).to eq 1
50
+ expect(None.value_or(0)).to eq 0
51
+ end
52
+
53
+ it "+" do
54
+ expect(Some([1]) + None).to eq Some([1])
55
+ expect(Some(1) + None + None).to eq Some(1)
56
+ expect(Some(1) + Some(1)).to eq Some(2)
57
+ expect(None + Some(1)).to eq Some(1)
58
+ expect(None + None + Some(1)).to eq Some(1)
59
+ expect(None + None + Some(1) + None).to eq Some(1)
60
+ expect(None + Some({foo: 1})).to eq Some({:foo=>1})
61
+ expect(Some([1]) + Some([1])).to eq Some([1, 1])
62
+ expect { Some([1]) + Some(1)}.to raise_error TypeError
63
+ end
64
+
65
+ it "inspect" do
66
+ expect(Some(1).inspect).to eq "Some(1)"
67
+ expect(described_class::None.new.inspect).to eq "None"
68
+ end
69
+
70
+ it "to_s" do
71
+ expect(Some(1).to_s).to eq "1"
72
+ expect(described_class::None.new.to_s).to eq ""
73
+ end
74
+
75
+ it "match" do
79
76
  expect(
80
77
  Some(0).match {
81
- some(1) { |n| 99 }
82
- some(0) { |n| n + 1 }
83
- none(1) {}
78
+ Some(s, where { s == 1 } ) { |n| 99 }
79
+ Some(s, where { s == 0 }) { |n| s + 1 }
80
+ None() {}
84
81
  }
85
82
  ).to eq 1
86
- }
87
83
 
88
- specify {
89
84
  expect(
90
- Some(nil).match {
91
- none { 0 }
92
- some { 1 }
85
+ Some(1).match {
86
+ None() { 0 }
87
+ Some(s) { 1 }
93
88
  }
94
89
  ).to eq 1
95
- }
96
90
 
97
- specify {
98
91
  expect(
99
92
  Some(1).match {
100
- none { 0 }
101
- some(Fixnum) { 1 }
93
+ None() { 0 }
94
+ Some(s, where { s.is_a? Fixnum }) { 1 }
102
95
  }
103
96
  ).to eq 1
104
- }
105
97
 
106
- specify {
107
98
  expect(
108
99
  None.match {
109
- none { 0 }
110
- some { 1 }
100
+ None() { 0 }
101
+ Some() { 1 }
111
102
  }
112
103
  ).to eq 0
113
- }
104
+ end
114
105
 
115
- end
106
+ it "nil?" do
107
+ expect(described_class.some?(nil)).to eq None
108
+ expect(described_class.some?(1)).to be_some
109
+ expect(described_class.some?(1)).to eq Some(1)
110
+ end
116
111
 
117
- describe Deterministic::Option::Some do
118
- include Deterministic
112
+ it "any?" do
113
+ expect(described_class.any?(nil)).to be_none
114
+ expect(described_class.any?(None)).to be_none
115
+ expect(described_class.any?("")).to be_none
116
+ expect(described_class.any?([])).to be_none
117
+ expect(described_class.any?({})).to be_none
118
+ expect(described_class.any?([1])).to eq Some([1])
119
+ expect(described_class.any?({foo: 1})).to eq Some({foo: 1})
120
+ end
119
121
 
120
- it_behaves_like 'a Monad' do
121
- let(:monad) { described_class }
122
+ it "try!" do
123
+ expect(described_class.try! { raise "error" }).to be_none
122
124
  end
123
125
  end
124
126
 
125
- describe Deterministic::Option::None do
126
- include Deterministic
127
+ require_relative 'monad_axioms'
127
128
 
128
- it_behaves_like 'a Monad' do
129
+ describe Deterministic::Option::Some do
130
+ it_behaves_like 'a Monad' do
129
131
  let(:monad) { described_class }
130
132
  end
131
133
  end
134
+
135
+ # describe Deterministic::Option::None do
136
+ # it_behaves_like 'a Monad' do
137
+
138
+ # let(:monad) { described_class }
139
+ # end
140
+ # end