possibly 0.2.0 → 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
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