deterministic 0.15.3 → 0.16.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: 70b4013b20820efd41949d10c8bcb0706b514d12
4
- data.tar.gz: cdb7071c05a8001af91c10212a67eceede5106cb
3
+ metadata.gz: 7120823c22300ba01fd44a7a3d18aae96f7357ba
4
+ data.tar.gz: 8cd374ad1eed4bba6aae559d96730954d76b15bd
5
5
  SHA512:
6
- metadata.gz: 30b231a3e818e90d9f49fc5b9932adafe969ccfe8e645cabda707f2e5a13b50efd0e2f07916accb82c53f64e5dd592d85aa2075d21b1859a598c56a7ed9ba91b
7
- data.tar.gz: b81e77b351c2fb48c5debfc979db451e5f021bd7cf3d240d101e867e0ae6e9c65ceeb3dd285f88f7332fce58c68db8d0c906dd1734c16c229ba80964c6336de2
6
+ metadata.gz: 0a15bd39adfa6dd90d2a9f5f395aba58881bab0380b743770a5dc6d09bf87d4681b7ae7493f344a66ae771a4f084e898d853c3f9745c9b165df27d9a7b928c49
7
+ data.tar.gz: d0df2e74a8a941216a1a58b836916dd55e5ed15d90c3e93dcd22d611e20a3b041dbf7ed4c767ad47c08c38eab7e2ccc60c76c10a9290c7125bb32c5321a1dd71
data/README.md CHANGED
@@ -5,7 +5,7 @@
5
5
 
6
6
  Deterministic is to help your code to be more confident, by utilizing functional programming patterns.
7
7
 
8
- This is a spiritual successor of the [Monadic gem](http://github.com/pzol/monadic). The goal of the rewrite is to get away from a bit to forceful aproach I took in Monadic, especially when it comes to coercing monads, but also a more practical but at the same time more strict adherence to monad laws.
8
+ This is a spiritual successor of the [Monadic gem](http://github.com/pzol/monadic). The goal of the rewrite is to get away from a bit too forceful aproach I took in Monadic, especially when it comes to coercing monads, but also a more practical but at the same time more strict adherence to monad laws.
9
9
 
10
10
  ## Patterns
11
11
 
@@ -213,29 +213,35 @@ Now that you have some result, you want to control flow by providing patterns.
213
213
 
214
214
  ```ruby
215
215
  Success(1).match do
216
- Success(s) { |v| "success #{s}"}
217
- Failure(f) { |v| "failure #{f}"}
216
+ Success() { |s| "success #{s}"}
217
+ Failure() { |f| "failure #{f}"}
218
218
  end # => "success 1"
219
219
  ```
220
- Note1: the inner value has been unwrapped!
220
+ Note1: the variant's inner value(s) have been unwrapped, and passed to the block.
221
221
 
222
222
  Note2: only the __first__ matching pattern block will be executed, so order __can__ be important.
223
223
 
224
+ Note3: you can omit block parameters if you don't use them, or you can use `_` to signify that you don't care about their values. If you specify parameters, their number must match the number of values in the variant.
225
+
224
226
  The result returned will be the result of the __first__ `#try` or `#let`. As a side note, `#try` is a monad, `#let` is a functor.
225
227
 
226
228
  Guards
227
229
 
228
230
  ```ruby
229
231
  Success(1).match do
230
- Success(s, where { s == 1 }) { "Success #{s}" }
232
+ Success(where { s == 1 }) { |s| "Success #{s}" }
231
233
  end # => "Success 1"
232
234
  ```
233
235
 
236
+ Note1: the guard has access to variable names defined by the block arguments.
237
+
238
+ Note2: the guard is not evaluated using the enclosing context's `self`; if you need to call methods on the enclosing scope, you must specify a receiver.
239
+
234
240
  Also you can match the result class
235
241
 
236
242
  ```ruby
237
243
  Success([1, 2, 3]).match do
238
- Success(s, where { s.is_a?(Array)} ) { s.first }
244
+ Success(where { s.is_a?(Array) }) { |s| s.first }
239
245
  end # => 1
240
246
  ```
241
247
 
@@ -243,7 +249,7 @@ If no match was found a `NoMatchError` is raised, so make sure you always cover
243
249
 
244
250
  ```ruby
245
251
  Success(1).match do
246
- Failure(f) { "you'll never get me" }
252
+ Failure() { |f| "you'll never get me" }
247
253
  end # => NoMatchError
248
254
  ```
249
255
 
@@ -323,9 +329,9 @@ Option.try! { raise "error"} # => None
323
329
  ### Pattern Matching
324
330
  ```ruby
325
331
  Some(1).match {
326
- Some(s, where { s == 1 }) { s + 1 }
327
- Some(s) { 1 }
328
- None() { 0 }
332
+ Some(where { s == 1 }) { |s| s + 1 }
333
+ Some() { |s| 1 }
334
+ None() { 0 }
329
335
  } # => 2
330
336
  ```
331
337
 
@@ -361,28 +367,28 @@ Pattern matching
361
367
 
362
368
  ```ruby
363
369
  Threenum::Unary(5).match {
364
- Nullary() { 0 }
365
- Unary(u) { u }
366
- Binary(a, b) { a + b }
370
+ Nullary() { 0 }
371
+ Unary() { |u| u }
372
+ Binary() { |a, b| a + b }
367
373
  } # => 5
368
374
 
369
375
  # or
370
376
  t = Threenum::Unary(5)
371
377
  Threenum.match(t) {
372
- Nullary() { 0 }
373
- Unary(u) { u }
374
- Binary(a, b) { a + b }
378
+ Nullary() { 0 }
379
+ Unary() { |u| u }
380
+ Binary() { |a, b| a + b }
375
381
  } # => 5
376
382
  ```
377
383
 
378
- If you want the whole thing use the arg passed to the block (second case)
384
+ If you want to return the whole matched object, you'll need to pass a reference to the object (second case). Note that `self` refers to the scope enclosing the `match` call.
379
385
 
380
386
  ```ruby
381
387
  def drop(n)
382
388
  match {
383
- Cons(h, t, where { n > 0 }) { t.drop(n - 1) }
384
- Cons(_, _) { |c| c }
385
- Nil() { raise EmptyListError}
389
+ Cons(where { n > 0 }) { |h, t| t.drop(n - 1) }
390
+ Cons() { |_, _| self }
391
+ Nil() { raise EmptyListError }
386
392
  }
387
393
  end
388
394
  ```
@@ -393,10 +399,10 @@ With guard clauses
393
399
 
394
400
  ```ruby
395
401
  Threenum::Unary(5).match {
396
- Nullary() { 0 }
397
- Unary(u) { u }
398
- Binary(a, b, where { a.is_a?(Fixnum) && b.is_a?(Fixnum)}) { a + b }
399
- Binary(a, b) { raise "Expected a, b to be numbers" }
402
+ Nullary() { 0 }
403
+ Unary() { |u| u }
404
+ Binary(where { a.is_a?(Fixnum) && b.is_a?(Fixnum) }) { |a, b| a + b }
405
+ Binary() { |a, b| raise "Expected a, b to be numbers" }
400
406
  } # => 5
401
407
  ```
402
408
 
@@ -406,17 +412,17 @@ Implementing methods for enums
406
412
  Deterministic::impl(Threenum) {
407
413
  def sum
408
414
  match {
409
- Nullary() { 0 }
410
- Unary(u) { u }
411
- Binary(a, b) { a + b }
415
+ Nullary() { 0 }
416
+ Unary() { |u| u }
417
+ Binary() { |a, b| a + b }
412
418
  }
413
419
  end
414
420
 
415
421
  def +(other)
416
422
  match {
417
- Nullary() { other.sum }
418
- Unary(a) { |this| this.sum + other.sum }
419
- Binary(a, b) { |this| this.sum + other.sum }
423
+ Nullary() { other.sum }
424
+ Unary() { |a| self.sum + other.sum }
425
+ Binary() { |a, b| self.sum + other.sum }
420
426
  }
421
427
  end
422
428
  }
@@ -23,6 +23,16 @@ module Deterministic
23
23
  def name
24
24
  self.class.name.split("::")[-1]
25
25
  end
26
+
27
+ # Returns array. Will fail on Nullary objects.
28
+ # TODO: define a Unary module so we can define this method differently on Unary vs Binary
29
+ def wrapped_values
30
+ if self.is_a?(Deterministic::EnumBuilder::DataType::Binary)
31
+ value.values
32
+ else
33
+ [value]
34
+ end
35
+ end
26
36
  end
27
37
 
28
38
  module Nullary
@@ -35,6 +45,7 @@ module Deterministic
35
45
  end
36
46
  end
37
47
 
48
+ # TODO: this should probably be named Multary
38
49
  module Binary
39
50
  def initialize(*init)
40
51
  raise ArgumentError, "Expected arguments for #{args}, got #{init}" unless (init.count == 1 && init[0].is_a?(Hash)) || init.count == args.count
@@ -103,6 +114,8 @@ module_function
103
114
  class << self; private :new; end
104
115
 
105
116
  def self.match(obj, &block)
117
+ caller_ctx = block.binding.eval 'self'
118
+
106
119
  matcher = self::Matcher.new(obj)
107
120
  matcher.instance_eval(&block)
108
121
 
@@ -116,17 +129,19 @@ module_function
116
129
  obj, type, block, args, guard = match
117
130
 
118
131
  if args.count == 0
119
- return instance_exec(obj, &block)
132
+ return caller_ctx.instance_eval(&block)
120
133
  else
121
- raise Enum::MatchError, "Pattern (#{args.join(', ')}) must match (#{obj.args.join(', ')})" if args.count != obj.args.count
122
- context = exec_context(obj, args)
134
+ if args.count != obj.args.count
135
+ raise Enum::MatchError, "Pattern (#{args.join(', ')}) must match (#{obj.args.join(', ')})"
136
+ end
137
+ guard_ctx = guard_context(obj, args)
123
138
 
124
139
  if guard
125
- if context.instance_exec(obj, &guard)
126
- return context.instance_exec(obj, &block)
140
+ if guard_ctx.instance_exec(obj, &guard)
141
+ return caller_ctx.instance_exec(* obj.wrapped_values, &block)
127
142
  end
128
143
  else
129
- return context.instance_exec(obj, &block)
144
+ return caller_ctx.instance_exec(* obj.wrapped_values, &block)
130
145
  end
131
146
  end
132
147
  }
@@ -137,7 +152,7 @@ module_function
137
152
  def self.variants; constants - [:Matcher, :MatchError]; end
138
153
 
139
154
  private
140
- def self.exec_context(obj, args)
155
+ def self.guard_context(obj, args)
141
156
  if obj.is_a?(Deterministic::EnumBuilder::DataType::Binary)
142
157
  Struct.new(*(args)).new(*(obj.value.values))
143
158
  else
@@ -163,17 +178,22 @@ module_function
163
178
  guard
164
179
  end
165
180
 
166
- def method_missing(m)
167
- m
168
- end
169
-
170
181
  type_variants.each { |m|
171
- define_method(m) { |*args, &block|
182
+ define_method(m) { |guard = nil, &block|
172
183
  raise ArgumentError, "No block given to `#{m}`" if block.nil?
184
+ params_spec = block.parameters
185
+ if params_spec.any? {|spec| spec.size < 2 }
186
+ raise ArgumentError, "Unnamed param found in block parameters: #{params_spec.inspect}"
187
+ end
188
+ if params_spec.any? {|spec| spec[0] != :req && spec[0] != :opt }
189
+ raise ArgumentError, "Only :req & :opt params allowed; parameters=#{params_spec.inspect}"
190
+ end
191
+ args = params_spec.map {|spec| spec[1] }
192
+
173
193
  type = Kernel.eval("#{mod.name}::#{m}")
174
194
 
175
- if args.count > 0 && args[-1].is_a?(Proc)
176
- guard = args.delete_at(-1)
195
+ if guard && !guard.is_a?(Proc)
196
+ guard = nil
177
197
  end
178
198
 
179
199
  @matches << [@obj, type, block, args, guard]
@@ -1,3 +1,4 @@
1
+ # TODO: remove dead code
1
2
  module Deterministic
2
3
  module PatternMatching
3
4
 
@@ -29,15 +29,15 @@ module Deterministic
29
29
 
30
30
  def fmap(&fn)
31
31
  match {
32
- Some(s) { |m| m.class.new(fn.(s)) }
33
- None() { |n| n }
32
+ Some() {|s| self.class.new(fn.(s)) }
33
+ None() { self }
34
34
  }
35
35
  end
36
36
 
37
37
  def map(&fn)
38
38
  match {
39
- Some(s) { |m| m.bind(&fn) }
40
- None() { |n| n }
39
+ Some() {|s| self.bind(&fn) }
40
+ None() { self }
41
41
  }
42
42
  end
43
43
 
@@ -53,8 +53,8 @@ module Deterministic
53
53
 
54
54
  def value_or(n)
55
55
  match {
56
- Some(s) { s }
57
- None() { n }
56
+ Some() {|s| s }
57
+ None() { n }
58
58
  }
59
59
  end
60
60
 
@@ -65,9 +65,9 @@ module Deterministic
65
65
  def +(other)
66
66
  match {
67
67
  None() { other }
68
- Some(_, where { !other.is_a?(Option)}) { raise TypeError, "Other must be an #{Option}"}
69
- Some(s, where { other.some? }) { Option::Some.new(s + other.value) }
70
- Some(_) { |s| s }
68
+ Some(where { !other.is_a?(Option) }) {|_| raise TypeError, "Other must be an #{Option}"}
69
+ Some(where { other.some? }) {|s| Option::Some.new(s + other.value) }
70
+ Some() {|_| self }
71
71
  }
72
72
  end
73
73
  }
@@ -19,8 +19,8 @@ module Deterministic
19
19
  Deterministic::impl(Result) {
20
20
  def map(proc=nil, &block)
21
21
  match {
22
- Success(_) { |s| s.bind(proc || block) }
23
- Failure(_) { |f| f }
22
+ Success() {|_| self.bind(proc || block) }
23
+ Failure() {|_| self }
24
24
  }
25
25
  end
26
26
 
@@ -29,8 +29,8 @@ module Deterministic
29
29
 
30
30
  def map_err(proc=nil, &block)
31
31
  match {
32
- Success(_) { |s| s }
33
- Failure(_) { |f| f.bind(proc|| block) }
32
+ Success() {|_| self }
33
+ Failure() {|_| self.bind(proc|| block) }
34
34
  }
35
35
  end
36
36
 
@@ -54,26 +54,26 @@ module Deterministic
54
54
  def or(other)
55
55
  raise Deterministic::Monad::NotMonadError, "Expected #{other.inspect} to be a Result" unless other.is_a? Result
56
56
  match {
57
- Success(_) { |s| s }
58
- Failure(_) { other}
57
+ Success() {|_| self }
58
+ Failure() {|_| other }
59
59
  }
60
60
  end
61
61
 
62
62
  def and(other)
63
63
  raise Deterministic::Monad::NotMonadError, "Expected #{other.inspect} to be a Result" unless other.is_a? Result
64
64
  match {
65
- Success(_) { other }
66
- Failure(_) { |f| f }
65
+ Success() {|_| other }
66
+ Failure() {|_| self }
67
67
  }
68
68
  end
69
69
 
70
70
  def +(other)
71
71
  raise Deterministic::Monad::NotMonadError, "Expected #{other.inspect} to be a Result" unless other.is_a? Result
72
72
  match {
73
- Success(s, where { other.success?} ) { Result::Success.new(s + other.value) }
74
- Failure(f, where { other.failure?} ) { Result::Failure.new(f + other.value) }
75
- Success(_) { other } # implied other.failure?
76
- Failure(_) { |f| f } # implied other.success?
73
+ Success(where { other.success? } ) {|s| Result::Success.new(s + other.value) }
74
+ Failure(where { other.failure? } ) {|f| Result::Failure.new(f + other.value) }
75
+ Success() {|_| other } # implied other.failure?
76
+ Failure() {|_| self } # implied other.success?
77
77
  }
78
78
  end
79
79
 
@@ -1,3 +1,3 @@
1
1
  module Deterministic
2
- VERSION = "0.15.3"
2
+ VERSION = "0.16.0"
3
3
  end
@@ -16,17 +16,17 @@ end
16
16
  Deterministic::impl(Amount) {
17
17
  def to_s
18
18
  match {
19
- Due(a) { "%0.2f" % [a] }
20
- Paid(a) { "-%0.2f" % [a] }
21
- Info(a) { "(%0.2f)" % [a] }
19
+ Due() {|a| "%0.2f" % [a] }
20
+ Paid() {|a| "-%0.2f" % [a] }
21
+ Info() {|a| "(%0.2f)" % [a] }
22
22
  }
23
23
  end
24
24
 
25
25
  def to_f
26
26
  match {
27
- Info(a) { 0 }
28
- Due(a) { a }
29
- Paid(a) { -1 * a }
27
+ Info() {|a| 0 }
28
+ Due() {|a| a }
29
+ Paid() {|a| -1 * a }
30
30
  }
31
31
  end
32
32
 
@@ -11,8 +11,8 @@ class ElasticSearchConfig
11
11
 
12
12
  def hosts
13
13
  Option.any?(proc_env["RESFINITY_LOG_CLIENT_ES_HOST"]).match {
14
- Some(s) { { hosts: s.split(/, */) } }
15
- None() { default_hosts }
14
+ Some() {|s| { hosts: s.split(/, */) } }
15
+ None() { default_hosts } # calls ElasticSearchConfig instance's method
16
16
  }
17
17
  end
18
18
 
@@ -31,7 +31,7 @@ private
31
31
  end
32
32
 
33
33
  describe ElasticSearchConfig do
34
- pending("match exec context must have access to parents block binding context") {
34
+ # NOTE: the "empty" cases also verify that the variant matchers use the enclosing context as self
35
35
 
36
36
  let(:cfg) { ElasticSearchConfig.new(environment, env) }
37
37
  context "test" do
@@ -72,5 +72,4 @@ describe ElasticSearchConfig do
72
72
  specify { expect(cfg.hosts).to eq({ hosts: ["acc.resfinity.net:9200"] }) }
73
73
  end
74
74
  end
75
- }
76
75
  end
@@ -28,46 +28,46 @@ Deterministic::impl(List) {
28
28
 
29
29
  def first
30
30
  match {
31
- Cons(_, _) { |c| c }
32
- Nil() { |n| n }
31
+ Cons() {|_, _| self }
32
+ Nil() { self }
33
33
  }
34
34
  end
35
35
 
36
36
  def last
37
37
  match {
38
- Cons(h, t, where { t.null? }) { |c| return c }
39
- Cons(_, t) { t.last }
40
- Nil() { |n| n }
38
+ Cons(where { t.null? }) {|h, t| return self }
39
+ Cons() {|_, t| t.last }
40
+ Nil() { self }
41
41
  }
42
42
  end
43
43
 
44
44
  def head
45
45
  match {
46
- Cons(h, _) { h }
47
- Nil() { |n| n }
46
+ Cons() {|h, _| h }
47
+ Nil() { self }
48
48
  }
49
49
  end
50
50
 
51
51
  def tail
52
52
  match {
53
- Cons(_, t) { t }
54
- Nil() { |n| raise EmptyListError }
53
+ Cons() { |_, t| t }
54
+ Nil() { raise EmptyListError }
55
55
  }
56
56
  end
57
57
 
58
58
  def init
59
59
  match {
60
- Cons(h, t, where { |c| t.tail.null? } ) { |c| Cons.new(h, Nil.new) }
61
- Cons(h, t) { |c| Cons.new(h, t.init) }
60
+ Cons(where { t.tail.null? } ) {|h, t| Cons.new(h, Nil.new) }
61
+ Cons() {|h, t| Cons.new(h, t.init) }
62
62
  Nil() { raise EmptyListError }
63
63
  }
64
64
  end
65
65
 
66
66
  def filter(&pred)
67
67
  match {
68
- Cons(h, t, where { pred.(h) }) { |c| Cons.new(h, t.filter(&pred)) }
69
- Cons(_, t) { t.filter(&pred) }
70
- Nil() { |n| n }
68
+ Cons(where { pred.(h) }) {|h, t| Cons.new(h, t.filter(&pred)) }
69
+ Cons() {|_, t| t.filter(&pred) }
70
+ Nil() { self }
71
71
  }
72
72
  end
73
73
 
@@ -76,21 +76,21 @@ Deterministic::impl(List) {
76
76
  def find(&pred)
77
77
  match {
78
78
  Nil() { Deterministic::Option::None.new }
79
- Cons(h, t) { if pred.(h) then Deterministic::Option::Some.new(h) else t.find(&pred) end }
79
+ Cons() {|h, t| pred.(h) ? Deterministic::Option::Some.new(h) : t.find(&pred) }
80
80
  }
81
81
  end
82
82
 
83
83
  def length
84
84
  match {
85
- Cons(h, t) { 1 + t.length }
85
+ Cons() {|h, t| 1 + t.length }
86
86
  Nil() { 0 }
87
87
  }
88
88
  end
89
89
 
90
90
  def map(&fn)
91
91
  match {
92
- Cons(h, t) { Cons.new(fn.(h), t.map(&fn)) }
93
- Nil() { |n| n }
92
+ Cons() {|h, t| Cons.new(fn.(h), t.map(&fn)) }
93
+ Nil() { self }
94
94
  }
95
95
  end
96
96
 
@@ -102,14 +102,14 @@ Deterministic::impl(List) {
102
102
  match {
103
103
  Nil() { start }
104
104
  # foldl f z (x:xs) = foldl f (f z x) xs
105
- Cons(h, t) { t.foldl(fn.(start, h), &fn) }
105
+ Cons() {|h, t| t.foldl(fn.(start, h), &fn) }
106
106
  }
107
107
  end
108
108
 
109
109
  def foldl1(&fn)
110
110
  match {
111
111
  Nil() { raise EmptyListError }
112
- Cons(h, t) { t.foldl(h, &fn)}
112
+ Cons() {|h, t| t.foldl(h, &fn)}
113
113
  }
114
114
  end
115
115
 
@@ -117,32 +117,32 @@ Deterministic::impl(List) {
117
117
  match {
118
118
  Nil() { start }
119
119
  # foldr f z (x:xs) = f x (foldr f z xs)
120
- Cons(h, t) { fn.(h, t.foldr(start, &fn)) }
120
+ Cons() {|h, t| fn.(h, t.foldr(start, &fn)) }
121
121
  }
122
122
  end
123
123
 
124
124
  def foldr1(&fn)
125
125
  match {
126
126
  Nil() { raise EmptyListError }
127
- Cons(h, t, where { t.null? }) { h }
127
+ Cons(where { t.null? }) {|h, t| h }
128
128
  # foldr1 f (x:xs) = f x (foldr1 f xs)
129
- Cons(h, t) { fn.(h, t.foldr1(&fn)) }
129
+ Cons() {|h, t| fn.(h, t.foldr1(&fn)) }
130
130
  }
131
131
  end
132
132
 
133
133
  def take(n)
134
134
  match {
135
- Cons(h, t, where { n > 0 }) { Cons.new(h, t.take(n - 1))}
136
- Cons(_, _) { Nil.new }
137
- Nil() { raise EmptyListError}
135
+ Cons(where { n > 0 }) {|h, t| Cons.new(h, t.take(n - 1)) }
136
+ Cons() {|_, _| Nil.new }
137
+ Nil() { raise EmptyListError }
138
138
  }
139
139
  end
140
140
 
141
141
  def drop(n)
142
142
  match {
143
- Cons(h, t, where { n > 0 }) { t.drop(n - 1) }
144
- Cons(_, _) { |c| c }
145
- Nil() { raise EmptyListError}
143
+ Cons(where { n > 0 }) {|h, t| t.drop(n - 1) }
144
+ Cons() {|_, _| self }
145
+ Nil() { raise EmptyListError }
146
146
  }
147
147
  end
148
148
 
@@ -153,31 +153,31 @@ Deterministic::impl(List) {
153
153
  def any?(&pred)
154
154
  match {
155
155
  Nil() { false }
156
- Cons(h, t, where { t.null? }) { pred.(h) }
157
- Cons(h, t) { pred.(h) || t.any?(&pred) }
156
+ Cons(where { t.null? }) {|h, t| pred.(h) }
157
+ Cons() {|h, t| pred.(h) || t.any?(&pred) }
158
158
  }
159
159
  end
160
160
 
161
161
  def all?(&pred)
162
162
  match {
163
163
  Nil() { false }
164
- Cons(h, t, where { t.null? }) { pred.(h) }
165
- Cons(h, t) { pred.(h) && t.all?(&pred) }
164
+ Cons(where { t.null? }) {|h, t| pred.(h) }
165
+ Cons() {|h, t| pred.(h) && t.all?(&pred) }
166
166
  }
167
167
  end
168
168
 
169
169
  def reverse
170
170
  match {
171
- Nil() { |n| n }
172
- Cons(_, t, where { t.null? }) { |c| c }
173
- Cons(h, t) { |c| Cons.new(c.last.head, c.init.reverse) }
171
+ Nil() { self }
172
+ Cons(where { t.null? }) {|_, t| self }
173
+ Cons() {|h, t| Cons.new(self.last.head, self.init.reverse) }
174
174
  }
175
175
  end
176
176
 
177
177
  def to_s(joiner = ", ")
178
178
  match {
179
179
  Nil() { "Nil" }
180
- Cons(head, tail) { head.to_s + joiner + tail.to_s }
180
+ Cons() {|head, tail| head.to_s + joiner + tail.to_s }
181
181
  }
182
182
  end
183
183
  }
@@ -13,9 +13,9 @@ describe List do
13
13
  it "catches ignores guards with non-matching clauses" do
14
14
  expect(
15
15
  list.match {
16
- Nil() { self }
17
- Cons(h, t, where { h == 0 }) { h }
18
- Cons(h, t) { h }
16
+ Nil() { list }
17
+ Cons(where { h == 0 }) {|h,t| h }
18
+ Cons() {|h, t| h }
19
19
  }).to eq 1
20
20
  end
21
21
 
@@ -23,15 +23,15 @@ describe List do
23
23
  expect( # guard catched
24
24
  list.match {
25
25
  Nil() { raise "unreachable" }
26
- Cons(h, t, where { h == 1 }) { h + 1 }
27
- Cons(h, t) { h }
26
+ Cons(where { h == 1 }) {|h,t| h + 1 }
27
+ Cons() {|h| h }
28
28
  }).to eq 2
29
29
  end
30
30
 
31
31
  it "raises an error when no match was made" do
32
32
  expect {
33
33
  list.match {
34
- Cons(_, _, where { true == false }) { 1 }
34
+ Cons(where { true == false }) {|_, _| 1 }
35
35
  Nil(where { true == false }) { 0 }
36
36
  }
37
37
  }.to raise_error(Deterministic::Enum::MatchError)
@@ -40,7 +40,7 @@ describe List do
40
40
  it "raises an error when the match is not exhaustive" do
41
41
  expect {
42
42
  list.match {
43
- Cons(_, _) {}
43
+ Cons() {|_, _| }
44
44
  }
45
45
  }.to raise_error(Deterministic::Enum::MatchError)
46
46
  end
@@ -1,5 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
+ # TODO: dead code?
3
4
  class Logger
4
5
  alias :m :method
5
6
 
@@ -14,6 +15,7 @@ class Logger
14
15
  private
15
16
  attr_reader :repository
16
17
 
18
+ # TODO: this is never called; the matcher syntax is old
17
19
  def validate(item)
18
20
  return Failure(["Item cannot be empty"]) if item.blank?
19
21
  return Failure(["Item must be a Hash"]) unless item.is_a?(Hash)
@@ -75,8 +75,8 @@ describe Deterministic::Option do
75
75
  it "match" do
76
76
  expect(
77
77
  Some(0).match {
78
- Some(s, where { s == 1 } ) { |n| 99 }
79
- Some(s, where { s == 0 }) { |n| s + 1 }
78
+ Some(where { s == 1 }) {|s| 99 }
79
+ Some(where { s == 0 }) {|s| s + 1 }
80
80
  None() {}
81
81
  }
82
82
  ).to eq 1
@@ -84,14 +84,14 @@ describe Deterministic::Option do
84
84
  expect(
85
85
  Some(1).match {
86
86
  None() { 0 }
87
- Some(s) { 1 }
87
+ Some() {|s| 1 }
88
88
  }
89
89
  ).to eq 1
90
90
 
91
91
  expect(
92
92
  Some(1).match {
93
93
  None() { 0 }
94
- Some(s, where { s.is_a? Fixnum }) { 1 }
94
+ Some(where { s.is_a? Fixnum }) {|s| 1 }
95
95
  }
96
96
  ).to eq 1
97
97
 
@@ -27,7 +27,7 @@ describe Deterministic::Enum do
27
27
  expect(n).to be_a MyEnym
28
28
  expect(n).to be_a MyEnym::Nullary
29
29
  expect(n.name).to eq "Nullary"
30
- expect { n.value }.to raise_error
30
+ expect { n.value }.to raise_error NoMethodError
31
31
  expect(n.inspect).to eq "Nullary"
32
32
  expect(n.to_s).to eq ""
33
33
  expect(n.fmap { }).to eq n
@@ -77,8 +77,8 @@ describe Deterministic::Enum do
77
77
  res =
78
78
  MyEnym.match(b) {
79
79
  Nullary() { 0 }
80
- Unary(a) { [a, b] }
81
- Binary(x, y) { [x, y]}
80
+ Unary() {|a| a }
81
+ Binary() {|x,y| [x, y] }
82
82
  }
83
83
 
84
84
  expect(res).to eq [1, 2]
@@ -86,8 +86,8 @@ describe Deterministic::Enum do
86
86
  res =
87
87
  b.match {
88
88
  Nullary() { 0 }
89
- Unary(a) { [a, b] }
90
- Binary(x, y) { [x, y]}
89
+ Unary() {|a| a }
90
+ Binary() {|x,y| [x, y] }
91
91
  }
92
92
 
93
93
  expect(res).to eq [1, 2]
@@ -98,10 +98,10 @@ describe Deterministic::Enum do
98
98
  }.to raise_error(NameError)
99
99
 
100
100
  expect { b.match {
101
- Nullary()
102
- Unary()
103
- Binary()
104
- }
101
+ Nullary()
102
+ Unary()
103
+ Binary()
104
+ }
105
105
  }.to raise_error ArgumentError, "No block given to `Nullary`"
106
106
  end
107
107
  end
@@ -20,19 +20,18 @@ Threenum = Deterministic::enum {
20
20
 
21
21
  Deterministic::impl(Threenum) {
22
22
  def sum
23
-
24
23
  match {
25
- Nullary() { 0 }
26
- Unary(u) { u }
27
- Binary(a, b) { a + b }
24
+ Nullary() { 0 }
25
+ Unary() { |u| u }
26
+ Binary() { |a, b| a + b }
28
27
  }
29
28
  end
30
29
 
31
30
  def +(other)
32
31
  match {
33
- Nullary() { other.sum }
34
- Unary(a) { |this| this.sum + other.sum }
35
- Binary(a, b) { |this| this.sum + other.sum }
32
+ Nullary() { other.sum }
33
+ Unary() { |a| self.sum + other.sum }
34
+ Binary() { |a, b| self.sum + other.sum }
36
35
  }
37
36
  end
38
37
  }
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.15.3
4
+ version: 0.16.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: 2015-07-28 00:00:00.000000000 Z
11
+ date: 2016-03-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler