consequence 0.2.2 → 0.2.3
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 +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
|
+
[](https://travis-ci.org/mushishi78/consequence)
|
3
4
|
[](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
|