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.
Files changed (3) hide show
  1. checksums.yaml +4 -4
  2. data/lib/possibly.rb +145 -12
  3. metadata +3 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 88d90724eacd2027f146e147fe9b3b44d70e11d9
4
- data.tar.gz: 69d10e194d938c8c27ec131a69296d7dca8d597a
3
+ metadata.gz: 96dcbb348677eea89d2b1b9f600015c2cfbf7cb5
4
+ data.tar.gz: 5ce3bd31351c85b455f91163e069df325dd199bd
5
5
  SHA512:
6
- metadata.gz: a8e95af1c6849dc749e809df67539585abacb495d74f3100a7ad08dd825dc4a645615bffa98c40f0ab7e3561368c268c84262e683bb44df9242ee23dd7c9202d
7
- data.tar.gz: 638e0c13f133d4d1f03d655e2efa24da79a623fb798e0ea6cb0b2f5323bfc8768ff2b16a3377082399b0a9e9941e3f3af02c94e3aef11900c6540328e9ab494a
6
+ metadata.gz: b5b7b56a8bd3a74fcbb24b655e93460ae38590c208c7a6eaf25cbf0837eafc74e1c5da0d55c80d391a8cbd558c5dbef4c48ed3ed09b1ae565dde7d6c21982e7a
7
+ data.tar.gz: fed125cd006f48f4a73083f4128cd03ae3abdf309754c8f22bebf6c152bc6fe1c665e248ad41158747a385c14ed1cb6fc478255f172c7e0d20947fdb7f54b7f5
@@ -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
- fail 'No such element'
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.new(value)
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.new
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.2.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: 2014-04-25 00:00:00.000000000 Z
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.2.2
41
+ rubygems_version: 2.5.1
42
42
  signing_key:
43
43
  specification_version: 4
44
44
  summary: Maybe monad