deterministic 0.1.2 → 0.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 24278b8af8e996a30226c448b0677f8669e14606
4
- data.tar.gz: 6a67ad79ac2e6ff81e0530b547c658f0cfb4633a
3
+ metadata.gz: a99a96ae91c0ed68fd47e14ba991e03c1302349c
4
+ data.tar.gz: c9de7570b1ef16aab2b10ee4aa97f927d7661048
5
5
  SHA512:
6
- metadata.gz: 0fd77c14af51a1814426d1c33bffccda8b97a58c5266638503dca676e1cbd78ac8a159becabfb3e4fe262016b5a2d0bf1663111f76d0fcbe92e7d105fa296f52
7
- data.tar.gz: 6181518d77416ec8cf02712cd738f56b842deaf212a4ac368b8babcc141c01bf718fb7b9b10f2d11d6109cf36a35db0b3306fce8629cdafca940d239d9a2c675
6
+ metadata.gz: c15b124c022ae997e29be36a63237cb50963268c6642d6f55c6f3a5e79f5de047b76182d3eb3d69b57b3a4e6ef207e9ace98b3579613154788fb706429cd750f
7
+ data.tar.gz: efe04519bfbca769720df381304134c72b4e21ebea770aabb1f0dff73dadca7bb98e0735f90ae0f569e7182fdba7ffd6d4f736ba5c238053a589e5cd55e42324
data/README.md CHANGED
@@ -72,7 +72,7 @@ Success(1).match do
72
72
  success { |v| "success #{v}"}
73
73
  failure { |v| "failure #{v}"}
74
74
  either { |v| "either #{v}"}
75
- end # => "either 1"
75
+ end # => "success 1"
76
76
  ```
77
77
  Note1: the inner value has been unwrapped!
78
78
 
@@ -84,7 +84,7 @@ Values for patterns are good, too:
84
84
 
85
85
  ```ruby
86
86
  Success(1).match do
87
- success(1) { "Success #{v}" }
87
+ success(1) {|v| "Success #{v}" }
88
88
  end # => "Success 1"
89
89
  ```
90
90
 
@@ -92,7 +92,7 @@ You can and should also use procs for patterns:
92
92
 
93
93
  ```ruby
94
94
  Success(1).match do
95
- success ->(v) { v == 1} { "Success #{v}" }
95
+ success ->(v) { v == 1 } {|v| "Success #{v}" }
96
96
  end # => "Success 1"
97
97
  ```
98
98
 
@@ -132,6 +132,59 @@ Success(1).match do
132
132
  end # => "catch-all"
133
133
  ```
134
134
 
135
+ ## core_ext
136
+ You can use a core extension, to include Either in your own class or in Object, i.e. in all classes.
137
+
138
+ In a class, as a mixin
139
+
140
+ ```ruby
141
+ require "deterministic/core_ext/either" # this includes Deterministic in the global namespace!
142
+ class UnderTest
143
+ include Deterministic::CoreExt::Either
144
+ def test
145
+ attempt_all do
146
+ try { foo }
147
+ end
148
+ end
149
+
150
+ def foo
151
+ 1
152
+ end
153
+ end
154
+
155
+ ut = UnderTest.new
156
+ ```
157
+
158
+ To add it to all classes
159
+
160
+ ```ruby
161
+ require "deterministic/core_ext/object/either" # this includes Deterministic to Object
162
+
163
+ class UnderTest
164
+ def test
165
+ attempt_all do
166
+ try { foo }
167
+ end
168
+ end
169
+
170
+ def foo
171
+ 1
172
+ end
173
+ end
174
+
175
+ ut = UnderTest.new
176
+ ```
177
+
178
+ or use it on built-in classes
179
+
180
+ ```ruby
181
+ require "deterministic/core_ext/object/either"
182
+ h = {a:1}
183
+ h.attempt_all do
184
+ try { |s| self[:a] + 1}
185
+ end
186
+ ```
187
+
135
188
  ## Inspirations
136
189
  * My [Monadic gem](http://github.com/pzol/monadic) of course
137
190
  * `#attempt_all` was somewhat inspired by [An error monad in Clojure](http://brehaut.net/blog/2011/error_monads)
@@ -20,7 +20,7 @@ Gem::Specification.new do |spec|
20
20
 
21
21
  spec.add_development_dependency "bundler", "~> 1.3"
22
22
  spec.add_development_dependency "rake"
23
- spec.add_development_dependency "rspec"
23
+ spec.add_development_dependency "rspec", "~>3.0.0.beta1"
24
24
  spec.add_development_dependency "guard"
25
25
  spec.add_development_dependency "guard-bundler"
26
26
  spec.add_development_dependency "guard-rspec"
@@ -0,0 +1,23 @@
1
+ include Deterministic
2
+
3
+ module Deterministic
4
+ module CoreExt
5
+ module Either
6
+ def success?
7
+ self.is_a? Success
8
+ end
9
+
10
+ def failure?
11
+ self.is_a? Failure
12
+ end
13
+
14
+ def either?
15
+ success? || failure?
16
+ end
17
+
18
+ def attempt_all(context=self, &block)
19
+ Deterministic::Either::AttemptAll.new(context, &block).call(self)
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,6 @@
1
+ require "deterministic/core_ext/either"
2
+
3
+ include Deterministic
4
+ class Object
5
+ include Deterministic::CoreExt::Either
6
+ end
@@ -14,7 +14,7 @@ class Deterministic::Either
14
14
  end
15
15
 
16
16
  def call(initial=nil)
17
- result = @tries.inject(Success(initial)) do |acc, try|
17
+ result = @tries.inject(Deterministic::Success(initial)) do |acc, try|
18
18
  acc.success? ? acc << try.call(acc) : acc
19
19
  end
20
20
  end
@@ -24,9 +24,9 @@ class Deterministic::Either
24
24
  try_p = ->(acc) {
25
25
  begin
26
26
  value = @context.instance_exec(acc.value, &block)
27
- Success(value)
27
+ Deterministic::Success(value)
28
28
  rescue => ex
29
- Failure(ex)
29
+ Deterministic::Failure(ex)
30
30
  end
31
31
  }
32
32
 
@@ -35,7 +35,7 @@ class Deterministic::Either
35
35
 
36
36
  # Basicly a monad
37
37
  def let(sym=nil, &block)
38
- @tries << ->(acc) {
38
+ @tries << ->(acc) {
39
39
  @context.instance_exec(acc.value, &block).tap do |value|
40
40
  raise EitherExpectedError, "Expected the result to be either Success or Failure" unless value.is_a? Either
41
41
  end
@@ -1,6 +1,7 @@
1
1
  module Deterministic::PatternMatching
2
2
 
3
- def match(context=self, &block)
3
+ def match(context=nil, &block)
4
+ context ||= block.binding.eval('self')
4
5
  match = Match.new(self, context)
5
6
  match.instance_eval &block
6
7
  match.result
@@ -35,7 +36,7 @@ module Deterministic::PatternMatching
35
36
  end
36
37
 
37
38
  private
38
- Matcher = Struct.new(:condition, :block) do
39
+ Matcher = Struct.new(:condition, :block) do
39
40
  def matches?(value)
40
41
  condition.call(value)
41
42
  end
@@ -46,7 +47,7 @@ module Deterministic::PatternMatching
46
47
  when condition.nil?; ->(v) { true }
47
48
  when condition.is_a?(Proc); condition
48
49
  when condition.is_a?(Class); ->(v) { condition === @container.value }
49
- else ->(v) { condition == @container.value }
50
+ else ->(v) { @container.value == condition }
50
51
  end
51
52
 
52
53
  matcher_pred = compose_predicates(type_pred[type], condition_pred)
@@ -1,3 +1,3 @@
1
1
  module Deterministic
2
- VERSION = "0.1.2"
2
+ VERSION = "0.2.0"
3
3
  end
@@ -29,7 +29,7 @@ describe Deterministic::Either::AttemptAll do
29
29
  expect(attempt).to be_a RuntimeError
30
30
  expect(attempt.message).to eq "error"
31
31
  end
32
-
32
+
33
33
  it "don't continue on failure" do
34
34
  fake = double()
35
35
  expect(
@@ -0,0 +1,50 @@
1
+ require "spec_helper"
2
+ require "deterministic"
3
+ require "deterministic/core_ext/either"
4
+
5
+ describe Deterministic::CoreExt::Either do
6
+ it "does something" do
7
+ h = {}
8
+ h.extend(Deterministic::CoreExt::Either)
9
+ expect(h.success?).to be_falsey
10
+ expect(h.failure?).to be_falsey
11
+ expect(h.either?).to be_falsey
12
+ end
13
+
14
+ it "enables #success?, #failure?, #either? 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
+
23
+ it "allows using attempt_all on all Objects" do
24
+ h = {a: 1}
25
+ h.extend(Deterministic::CoreExt::Either)
26
+ res = h.attempt_all do
27
+ try { |s| self[:a] + 1}
28
+ end
29
+
30
+ expect(res).to eq Deterministic::Success(2)
31
+ end
32
+
33
+ it "use attempt_all in an instance" do
34
+ class UnderTest
35
+ include Deterministic::CoreExt::Either
36
+ def test
37
+ attempt_all do
38
+ try { foo }
39
+ end
40
+ end
41
+
42
+ def foo
43
+ 1
44
+ end
45
+ end
46
+
47
+ ut = UnderTest.new
48
+ expect(ut.test).to eq Success(1)
49
+ end
50
+ end
@@ -0,0 +1,28 @@
1
+ require "spec_helper"
2
+ require "deterministic/core_ext/object/either"
3
+
4
+ describe Deterministic::CoreExt::Either, "object", isolate: true do
5
+ it "does something" do
6
+ h = {a: 1}
7
+ expect(h.success?).to be_falsey
8
+ expect(h.failure?).to be_falsey
9
+ expect(h.either?).to be_falsey
10
+ end
11
+
12
+ it "use attempt_all in an instance" do
13
+ class UnderTest
14
+ def test
15
+ attempt_all do
16
+ try { foo }
17
+ end
18
+ end
19
+
20
+ def foo
21
+ 1
22
+ end
23
+ end
24
+
25
+ ut = UnderTest.new
26
+ expect(ut.test).to eq Success(1)
27
+ end
28
+ end
@@ -9,7 +9,7 @@ describe Deterministic::Either::Match do
9
9
  success { |v| "Success #{v}" }
10
10
  failure { |v| "Failure #{v}" }
11
11
  end
12
- ).to eq "Success 1"
12
+ ).to eq "Success 1"
13
13
  end
14
14
 
15
15
  it "can match Failure" do
@@ -18,7 +18,7 @@ describe Deterministic::Either::Match do
18
18
  success { |v| "Success #{v}" }
19
19
  failure { |v| "Failure #{v}" }
20
20
  end
21
- ).to eq "Failure 1"
21
+ ).to eq "Failure 1"
22
22
  end
23
23
 
24
24
  it "can match with values" do
@@ -81,4 +81,35 @@ describe Deterministic::Either::Match do
81
81
  end
82
82
  }.to raise_error Deterministic::PatternMatching::NoMatchError
83
83
  end
84
+
85
+ it "can use methods from the caller's binding scope by default" do
86
+ def my_method
87
+ "it works"
88
+ end
89
+ expect(
90
+ Success(1).match do
91
+ success { my_method }
92
+ end
93
+ ).to eq "it works"
94
+ end
95
+
96
+ it "allows for Either values to play with pattern matching comparisons" do
97
+ class MyErrorHash < Hash
98
+ def ==(error_type_symbol)
99
+ self[:type] == error_type_symbol
100
+ end
101
+ end
102
+
103
+ error_hash = MyErrorHash.new.merge(:type => :needs_more_salt, :arbitrary => 'data')
104
+
105
+ expect(
106
+ Failure(error_hash).match do
107
+ failure(:nothing) {|v| raise "We should not get to this point" }
108
+ failure(:needs_more_salt) do |error|
109
+ "Successfully failed with #{error[:arbitrary]}!"
110
+ end
111
+ failure { raise "We should also not get to this point" }
112
+ end
113
+ ).to eq "Successfully failed with data!"
114
+ end
84
115
  end
@@ -3,7 +3,7 @@ shared_examples 'a Monad' do
3
3
  it '1st monadic law: left-identity' do
4
4
  f = ->(value) { monad.new(value + 1) }
5
5
  expect(
6
- monad::new(1).bind do |value|
6
+ monad.new(1).bind do |value|
7
7
  f.(value)
8
8
  end
9
9
  ).to eq f.(1)
@@ -26,7 +26,6 @@ describe Deterministic::Monad do
26
26
  it "passes the monad class, this is ruby-fu?!" do
27
27
  Identity.new(1)
28
28
  .bind do |_, monad|
29
- p self.class
30
29
  expect(monad).to eq Identity
31
30
  monad.new(_)
32
31
  end
data/spec/spec_helper.rb CHANGED
@@ -20,5 +20,7 @@ RSpec.configure do |config|
20
20
  c.syntax = :expect
21
21
  end
22
22
  config.order = 'random'
23
+
24
+ config.filter_run_excluding isolate: true
23
25
  end
24
26
  require 'deterministic'
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.1.2
4
+ version: 0.2.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-01-06 00:00:00.000000000 Z
11
+ date: 2014-03-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -42,16 +42,16 @@ dependencies:
42
42
  name: rspec
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - '>='
45
+ - - ~>
46
46
  - !ruby/object:Gem::Version
47
- version: '0'
47
+ version: 3.0.0.beta1
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - '>='
52
+ - - ~>
53
53
  - !ruby/object:Gem::Version
54
- version: '0'
54
+ version: 3.0.0.beta1
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: guard
57
57
  requirement: !ruby/object:Gem::Requirement
@@ -125,6 +125,8 @@ files:
125
125
  - deterministic.gemspec
126
126
  - either.rb
127
127
  - lib/deterministic.rb
128
+ - lib/deterministic/core_ext/either.rb
129
+ - lib/deterministic/core_ext/object/either.rb
128
130
  - lib/deterministic/either.rb
129
131
  - lib/deterministic/either/attempt_all.rb
130
132
  - lib/deterministic/either/failure.rb
@@ -135,6 +137,8 @@ files:
135
137
  - spec/examples/bookings_spec.rb
136
138
  - spec/examples/validate_address_spec.rb
137
139
  - spec/lib/deterministic/attempt_all_spec.rb
140
+ - spec/lib/deterministic/core_ext/either_spec.rb
141
+ - spec/lib/deterministic/core_ext/object/either_spec.rb
138
142
  - spec/lib/deterministic/either/match_spec.rb
139
143
  - spec/lib/deterministic/either/success_spec.rb
140
144
  - spec/lib/deterministic/either_spec.rb
@@ -161,7 +165,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
161
165
  version: '0'
162
166
  requirements: []
163
167
  rubyforge_project:
164
- rubygems_version: 2.0.3
168
+ rubygems_version: 2.2.1
165
169
  signing_key:
166
170
  specification_version: 4
167
171
  summary: see above
@@ -169,6 +173,8 @@ test_files:
169
173
  - spec/examples/bookings_spec.rb
170
174
  - spec/examples/validate_address_spec.rb
171
175
  - spec/lib/deterministic/attempt_all_spec.rb
176
+ - spec/lib/deterministic/core_ext/either_spec.rb
177
+ - spec/lib/deterministic/core_ext/object/either_spec.rb
172
178
  - spec/lib/deterministic/either/match_spec.rb
173
179
  - spec/lib/deterministic/either/success_spec.rb
174
180
  - spec/lib/deterministic/either_spec.rb