possibly 0.2.0 → 1.0.1
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/lib/possibly.rb +145 -12
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 96dcbb348677eea89d2b1b9f600015c2cfbf7cb5
|
4
|
+
data.tar.gz: 5ce3bd31351c85b455f91163e069df325dd199bd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b5b7b56a8bd3a74fcbb24b655e93460ae38590c208c7a6eaf25cbf0837eafc74e1c5da0d55c80d391a8cbd558c5dbef4c48ed3ed09b1ae565dde7d6c21982e7a
|
7
|
+
data.tar.gz: fed125cd006f48f4a73083f4128cd03ae3abdf309754c8f22bebf6c152bc6fe1c665e248ad41158747a385c14ed1cb6fc478255f172c7e0d20947fdb7f54b7f5
|
data/lib/possibly.rb
CHANGED
@@ -1,8 +1,10 @@
|
|
1
|
+
# coding: utf-8
|
1
2
|
class Maybe
|
2
3
|
([:each] + Enumerable.instance_methods).each do |enumerable_method|
|
3
4
|
define_method(enumerable_method) do |*args, &block|
|
5
|
+
@invocation ||= [enumerable_method, args, block]
|
4
6
|
res = __enumerable_value.send(enumerable_method, *args, &block)
|
5
|
-
res.respond_to?(:each) ? Maybe(res.first) : res
|
7
|
+
res.respond_to?(:each) ? Maybe(res.first, self.stack, @invocation) : res
|
6
8
|
end
|
7
9
|
end
|
8
10
|
|
@@ -15,12 +17,74 @@ class Maybe
|
|
15
17
|
other.class == self.class
|
16
18
|
end
|
17
19
|
alias_method :eql?, :==
|
20
|
+
|
21
|
+
def inspect
|
22
|
+
to_s
|
23
|
+
end
|
24
|
+
|
25
|
+
protected
|
26
|
+
|
27
|
+
def print_error(msg)
|
28
|
+
message =
|
29
|
+
if msg
|
30
|
+
msg + "\n\n"
|
31
|
+
else
|
32
|
+
"\n"
|
33
|
+
end
|
34
|
+
|
35
|
+
message + print_stack + "\n"
|
36
|
+
end
|
37
|
+
|
38
|
+
def print_stack
|
39
|
+
longest_method = stack.drop(1).map { |inv| inv.first }.map(&:length).max || 0
|
40
|
+
stack.map { |(method, value)|
|
41
|
+
method ||= ""
|
42
|
+
"#{method.ljust(longest_method)} => #{value}"
|
43
|
+
}.join("\n")
|
44
|
+
end
|
45
|
+
|
46
|
+
def stack
|
47
|
+
@parent_stack + [self_stack]
|
48
|
+
end
|
49
|
+
|
50
|
+
def self_stack
|
51
|
+
[inst_method, self.inspect]
|
52
|
+
end
|
53
|
+
|
54
|
+
|
55
|
+
def inst_method
|
56
|
+
"#{print_method(@inst_method)}"
|
57
|
+
end
|
58
|
+
|
59
|
+
def print_method(invocation)
|
60
|
+
method, args, block = invocation
|
61
|
+
|
62
|
+
print_method =
|
63
|
+
if method == :[]
|
64
|
+
args.to_s
|
65
|
+
else
|
66
|
+
method.to_s
|
67
|
+
end
|
68
|
+
|
69
|
+
print_args =
|
70
|
+
if method == :[]
|
71
|
+
nil
|
72
|
+
elsif args.empty?
|
73
|
+
nil
|
74
|
+
else
|
75
|
+
"(#{args.join(', ')})"
|
76
|
+
end
|
77
|
+
|
78
|
+
[print_method, print_args].compact.join("")
|
79
|
+
end
|
18
80
|
end
|
19
81
|
|
20
82
|
# Represents a non-empty value
|
21
83
|
class Some < Maybe
|
22
|
-
def initialize(value)
|
84
|
+
def initialize(value, inst_method = nil, parent_stack = [])
|
23
85
|
@value = value
|
86
|
+
@inst_method = inst_method || ["Some.new", []]
|
87
|
+
@parent_stack = parent_stack
|
24
88
|
end
|
25
89
|
|
26
90
|
def get
|
@@ -31,6 +95,14 @@ class Some < Maybe
|
|
31
95
|
@value
|
32
96
|
end
|
33
97
|
|
98
|
+
def or_raise(*)
|
99
|
+
@value
|
100
|
+
end
|
101
|
+
|
102
|
+
def or_nil
|
103
|
+
@value
|
104
|
+
end
|
105
|
+
|
34
106
|
# rubocop:disable PredicateName
|
35
107
|
def is_some?
|
36
108
|
true
|
@@ -51,9 +123,14 @@ class Some < Maybe
|
|
51
123
|
end
|
52
124
|
|
53
125
|
def method_missing(method_sym, *args, &block)
|
126
|
+
@invocation ||= [method_sym, args, block]
|
54
127
|
map { |value| value.send(method_sym, *args, &block) }
|
55
128
|
end
|
56
129
|
|
130
|
+
def to_s
|
131
|
+
"Some(#{@value})"
|
132
|
+
end
|
133
|
+
|
57
134
|
private
|
58
135
|
|
59
136
|
def __enumerable_value
|
@@ -63,14 +140,53 @@ end
|
|
63
140
|
|
64
141
|
# Represents an empty value
|
65
142
|
class None < Maybe
|
143
|
+
|
144
|
+
class ValueExpectedException < Exception; end
|
145
|
+
|
146
|
+
def initialize(inst_method = nil, parent_stack = [])
|
147
|
+
@inst_method = inst_method || ["None.new", []]
|
148
|
+
@parent_stack = parent_stack
|
149
|
+
end
|
150
|
+
|
66
151
|
def get
|
67
|
-
|
152
|
+
msg ||= "`get` called to None. A value was expected."
|
153
|
+
raise ValueExpectedException.new(print_error(msg))
|
68
154
|
end
|
69
155
|
|
70
156
|
def or_else(els = nil)
|
71
157
|
block_given? ? yield : els
|
72
158
|
end
|
73
159
|
|
160
|
+
def or_raise(*args)
|
161
|
+
opts, args = extract_opts(args)
|
162
|
+
msg_or_exception, msg = args
|
163
|
+
default_message = "`or_raise` called to None. A value was expected."
|
164
|
+
|
165
|
+
exception_object =
|
166
|
+
if msg_or_exception.respond_to? :exception
|
167
|
+
if msg
|
168
|
+
msg_or_exception.exception(msg)
|
169
|
+
else
|
170
|
+
msg_or_exception.exception
|
171
|
+
end
|
172
|
+
else
|
173
|
+
ValueExpectedException.new(msg_or_exception || default_message)
|
174
|
+
end
|
175
|
+
|
176
|
+
exception_and_stack =
|
177
|
+
if opts[:print_stack] == false
|
178
|
+
exception_object
|
179
|
+
else
|
180
|
+
exception_object.exception(print_error(exception_object.message))
|
181
|
+
end
|
182
|
+
|
183
|
+
raise exception_and_stack
|
184
|
+
end
|
185
|
+
|
186
|
+
def or_nil
|
187
|
+
nil
|
188
|
+
end
|
189
|
+
|
74
190
|
# rubocop:disable PredicateName
|
75
191
|
def is_some?
|
76
192
|
false
|
@@ -81,8 +197,12 @@ class None < Maybe
|
|
81
197
|
end
|
82
198
|
# rubocop:enable PredicateName
|
83
199
|
|
84
|
-
def method_missing(*)
|
85
|
-
self
|
200
|
+
def method_missing(method_sym, *args, &block)
|
201
|
+
None([method_sym, args, block], self.stack)
|
202
|
+
end
|
203
|
+
|
204
|
+
def to_s
|
205
|
+
"None"
|
86
206
|
end
|
87
207
|
|
88
208
|
private
|
@@ -90,22 +210,35 @@ class None < Maybe
|
|
90
210
|
def __enumerable_value
|
91
211
|
[]
|
92
212
|
end
|
213
|
+
|
214
|
+
def extract_opts(args)
|
215
|
+
*initial, last = *args
|
216
|
+
|
217
|
+
if last.is_a?(::Hash)
|
218
|
+
[last, initial]
|
219
|
+
else
|
220
|
+
[{}, args]
|
221
|
+
end
|
222
|
+
end
|
93
223
|
end
|
94
224
|
|
95
225
|
# rubocop:disable MethodName
|
96
|
-
def Maybe(value)
|
226
|
+
def Maybe(value, parent_stack = [], inst_method = nil)
|
227
|
+
inst_method ||= ["Maybe", []]
|
97
228
|
if value.nil? || (value.respond_to?(:length) && value.length == 0)
|
98
|
-
None()
|
229
|
+
None(inst_method, parent_stack)
|
99
230
|
else
|
100
|
-
Some(value)
|
231
|
+
Some(value, inst_method, parent_stack)
|
101
232
|
end
|
102
233
|
end
|
103
234
|
|
104
|
-
def Some(value)
|
105
|
-
Some
|
235
|
+
def Some(value, inst_method = nil, parent_stack = [])
|
236
|
+
inst_method ||= ["Some", []]
|
237
|
+
Some.new(value, inst_method, parent_stack)
|
106
238
|
end
|
107
239
|
|
108
|
-
def None
|
109
|
-
None
|
240
|
+
def None(inst_method = nil, parent_stack = [])
|
241
|
+
inst_method ||= ["None", []]
|
242
|
+
None.new(inst_method, parent_stack)
|
110
243
|
end
|
111
244
|
# rubocop:enable MethodName
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: possibly
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mikko Koski
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2016-07-24 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: Maybe monad implementation for Ruby (some might call it Option pattern
|
14
14
|
or Null pattern)
|
@@ -38,7 +38,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
38
38
|
version: '0'
|
39
39
|
requirements: []
|
40
40
|
rubyforge_project:
|
41
|
-
rubygems_version: 2.
|
41
|
+
rubygems_version: 2.5.1
|
42
42
|
signing_key:
|
43
43
|
specification_version: 4
|
44
44
|
summary: Maybe monad
|