deterministic 0.1.2 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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