consequence 0.2.2 → 0.2.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +18 -30
- data/lib/consequence/eventually.rb +10 -10
- data/lib/consequence/monad.rb +14 -8
- data/lib/consequence/something.rb +3 -3
- data/lib/consequence/success.rb +2 -2
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1d9f0c8c6460d68c6920b23b9d54b164d5e89d6e
|
4
|
+
data.tar.gz: 9b94446f09dbf982fb67043adc34dff1646b5043
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 52332a52917ef7cc1359d80e9a667cdaff60593a393d035d0f2091f03eb4ec01ec914ac68923bee4f687412349122aff6c7b6af02bc6fad5dde886fc29889dc6
|
7
|
+
data.tar.gz: 879ea1c9cdebb84d14e8f95e303f7f76bfcd6188fc820a6355092e5a396cddaa7da6dbd1761191d76b78f9f70293cb3b5e3b1329de346ac45ceac199ff8fae8e
|
data/README.md
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
# Consequence
|
2
2
|
|
3
|
+
[![Build Status](https://travis-ci.org/mushishi78/consequence.svg?branch=master)](https://travis-ci.org/mushishi78/consequence)
|
3
4
|
[![Gem Version](https://badge.fury.io/rb/consequence.svg)](http://badge.fury.io/rb/consequence)
|
4
5
|
|
5
6
|
Simple monad implementation with clear and consistent syntax.
|
@@ -41,7 +42,7 @@ Foo[0] == Foo[0] # true
|
|
41
42
|
|
42
43
|
Monads have two main operations `>>` and `<<`.
|
43
44
|
|
44
|
-
Both take a proc for their only argument. The
|
45
|
+
Both take an object with a `#call` method, such as a proc, for their only argument. The `#call` method can take 0-2 arguments and the monad will match them, even if it's a lamda or method object with arity checking.
|
45
46
|
|
46
47
|
It's first argument will be passed the monads value:
|
47
48
|
|
@@ -61,13 +62,13 @@ Foo[0] << ->(v, m) { puts v if m.is_a?(Foo) }
|
|
61
62
|
|
62
63
|
The `>>` operation may be variously thought of as the 'map', 'bind' or 'join' operations, but has been left unnamed to avoid any specific connotations.
|
63
64
|
|
64
|
-
It takes the result of the
|
65
|
+
It takes the result of the argument's `#call` method and passes it on:
|
65
66
|
|
66
67
|
``` ruby
|
67
68
|
Foo[0] >> ->(v) { Bar[v] } # Bar[0]
|
68
69
|
```
|
69
70
|
|
70
|
-
If
|
71
|
+
If the returned result that is not a monad, it is wrapped up in one so the chain can continue:
|
71
72
|
|
72
73
|
``` ruby
|
73
74
|
Foo[0] >> ->(v) { v + 1 } # Foo[1]
|
@@ -77,7 +78,7 @@ Foo[0] >> ->(v) { v + 1 } # Foo[1]
|
|
77
78
|
|
78
79
|
The `<<` operation may be thought of as the 'pipe' operation.
|
79
80
|
|
80
|
-
It calls the
|
81
|
+
It calls the argument's `#call` method, but ignores the return value:
|
81
82
|
|
82
83
|
``` ruby
|
83
84
|
Foo[0] << ->(v) { v + 1 } # Foo[0]
|
@@ -91,28 +92,6 @@ puts @side_effect
|
|
91
92
|
# $ 1
|
92
93
|
```
|
93
94
|
|
94
|
-
### `#to_proc`
|
95
|
-
|
96
|
-
Before either operation calls a proc, the `#to_proc` method is called on it. This can be useful if the operation is given an object that is no a proc, but has a `#to_proc` method that returns one.
|
97
|
-
|
98
|
-
A good example of this is the Symbol object, whose `#to_proc` method supplies a proc that sends the symbol as a message to its first argument. In this case this means calling that method on the value:
|
99
|
-
|
100
|
-
``` ruby
|
101
|
-
Foo[[1, 4, 7]] >> :pop # Foo[7]
|
102
|
-
```
|
103
|
-
|
104
|
-
This also can be used to make a composition syntax, by writing a `#to_proc` method for a monad:
|
105
|
-
|
106
|
-
``` ruby
|
107
|
-
class Add < Monad
|
108
|
-
def to_proc
|
109
|
-
->(v) { v + value }
|
110
|
-
end
|
111
|
-
end
|
112
|
-
|
113
|
-
Add[1] >> Add[4] >> Add[6] # Add[11]
|
114
|
-
```
|
115
|
-
|
116
95
|
## Built-In Types
|
117
96
|
|
118
97
|
### NullMonad
|
@@ -123,7 +102,7 @@ The `NullMonad` is a monad whose `>>` and `<<` operations have been overriden to
|
|
123
102
|
NullMonad[0] >> ->(v) { v + 1 } # Consequence::NullMonad[0]
|
124
103
|
```
|
125
104
|
|
126
|
-
This is different from the `<<` operation, because the
|
105
|
+
This is different from the `<<` operation, because the argument's `#call` method isn't even run, so can cause no side effects:
|
127
106
|
|
128
107
|
``` ruby
|
129
108
|
NullMonad[0] << ->(v) { @side_effect = v + 1 }
|
@@ -155,7 +134,7 @@ Success[0] >> ->(v) { 5 / v }
|
|
155
134
|
# Consequence::Failure[#<ZeroDivisionError: divided by 0>]
|
156
135
|
```
|
157
136
|
|
158
|
-
A `Failure` monad is a subclass of the `NullMonad` so all successive chained
|
137
|
+
A `Failure` monad is a subclass of the `NullMonad` so all successive chained operations are ignored.
|
159
138
|
|
160
139
|
Both `Success` and `Failure` respond to the `#succeeded?` and `#failed?` query methods in the way you'd expect:
|
161
140
|
|
@@ -176,7 +155,7 @@ A `Something` monad wraps up a nil result in a `Nothing` monad:
|
|
176
155
|
Something[[1, 3, 5]] >> ->(v) { v[4] } # Consequence::Nothing[nil]
|
177
156
|
```
|
178
157
|
|
179
|
-
A `Nothing` monad is also a subclass of the `NullMonad` so all successive chained
|
158
|
+
A `Nothing` monad is also a subclass of the `NullMonad` so all successive chained operations are ignored. This prevents `MissingMethod` errors from trying to call a method on a `nil`.
|
180
159
|
|
181
160
|
A `Nothing` responds positively to the `#nil?` method:
|
182
161
|
|
@@ -208,6 +187,16 @@ Something[dangrous_hash][:user][:orders][1][:price] # Consequence::Something[3.9
|
|
208
187
|
Something[dangrous_hash][:user][:orders][2][:price] # Consequence::Nothing[nil]
|
209
188
|
```
|
210
189
|
|
190
|
+
## `#to_proc`
|
191
|
+
|
192
|
+
Before either operation calls the argument's `#call` method, the `#to_proc` method is called on it if it has one. This can be useful if the operation is given an object that has no `#call` method, but has a `#to_proc`.
|
193
|
+
|
194
|
+
A good example of this is the Symbol object, whose `#to_proc` method supplies a proc that sends the symbol as a message to its first argument. In this case this means calling that method on the value:
|
195
|
+
|
196
|
+
``` ruby
|
197
|
+
Foo[[1, 4, 7]] >> :pop # Foo[7]
|
198
|
+
```
|
199
|
+
|
211
200
|
## Wiki
|
212
201
|
|
213
202
|
To find some examples and information about utils, [check out the wiki](https://github.com/mushishi78/consequence/wiki) and feel free to contribute to it.
|
@@ -215,7 +204,6 @@ To find some examples and information about utils, [check out the wiki](https://
|
|
215
204
|
## Inspirations
|
216
205
|
|
217
206
|
* [Deterministic](https://github.com/pzol/deterministic)
|
218
|
-
* [Kleisli](https://github.com/txus/kleisli)
|
219
207
|
* [Refactoring Ruby with Monads](https://www.youtube.com/watch?v=J1jYlPtkrqQ&feature=youtu.be&a)
|
220
208
|
|
221
209
|
## Installation
|
@@ -1,17 +1,17 @@
|
|
1
1
|
require 'consequence/monad'
|
2
2
|
|
3
3
|
module Consequence
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
4
|
+
class Eventually < Monad
|
5
|
+
def execute(proc)
|
6
|
+
value.(proc)
|
7
|
+
end
|
8
8
|
|
9
|
-
|
9
|
+
def <<(_); self end
|
10
10
|
|
11
|
-
|
11
|
+
private
|
12
12
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
13
|
+
def bind(proc)
|
14
|
+
->(callback) { execute(proc.(callback)) }
|
15
|
+
end
|
16
|
+
end
|
17
17
|
end
|
data/lib/consequence/monad.rb
CHANGED
@@ -10,12 +10,13 @@ module Consequence
|
|
10
10
|
|
11
11
|
attr_reader :value
|
12
12
|
|
13
|
-
def >>(
|
14
|
-
|
13
|
+
def >>(obj)
|
14
|
+
obj = obj.to_proc if obj.respond_to?(:to_proc)
|
15
|
+
wrap(bind(obj))
|
15
16
|
end
|
16
17
|
|
17
|
-
def <<(
|
18
|
-
bind(
|
18
|
+
def <<(obj)
|
19
|
+
bind(obj.to_proc)
|
19
20
|
self
|
20
21
|
end
|
21
22
|
|
@@ -33,12 +34,17 @@ module Consequence
|
|
33
34
|
|
34
35
|
private
|
35
36
|
|
36
|
-
def bind(
|
37
|
-
|
37
|
+
def bind(obj)
|
38
|
+
obj.call(*args_for(obj))
|
38
39
|
end
|
39
40
|
|
40
|
-
def args_for(
|
41
|
-
[value, self][0,
|
41
|
+
def args_for(obj)
|
42
|
+
[value, self][0, arity(obj)]
|
43
|
+
end
|
44
|
+
|
45
|
+
def arity(obj)
|
46
|
+
method = obj.respond_to?(:arity) ? obj : obj.method(:call)
|
47
|
+
method.arity.abs
|
42
48
|
end
|
43
49
|
|
44
50
|
def wrap(value)
|
@@ -3,16 +3,16 @@ require 'consequence/delegates_to_value'
|
|
3
3
|
|
4
4
|
module Consequence
|
5
5
|
class Something < Monad
|
6
|
-
|
6
|
+
include DelegatesToValue
|
7
7
|
|
8
|
-
def >>(
|
8
|
+
def >>(obj)
|
9
9
|
result = super
|
10
10
|
result.value.nil? ? Nothing[nil] : result
|
11
11
|
end
|
12
12
|
end
|
13
13
|
|
14
14
|
class Nothing < NullMonad
|
15
|
-
|
15
|
+
include DelegatesToValue
|
16
16
|
|
17
17
|
def nil?; true end
|
18
18
|
end
|
data/lib/consequence/success.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: consequence
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Max White
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-01-
|
11
|
+
date: 2015-01-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rspec
|