range_extd 1.0 → 2.0

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.
@@ -0,0 +1,160 @@
1
+ require_relative "infinity" if !defined?(RangeExtd::Infinity)
2
+
3
+ #
4
+ # = class Numeric
5
+ #
6
+ # Modify {Numeric#>} and {Numeric#<} and {Numeric#<=>} because +5 < RangeExtd::Infinity::POSITIVE+
7
+ # raises ArgumentError(!). In other words, +Integer#<+ does not respect
8
+ # +Object#<=>+ but rewrites it.
9
+ #
10
+ # I do not know if it has been always the case, or some changes have been made
11
+ # in more recent versions of Ruby.
12
+ #
13
+ # Note that +Float#<+ etc need to be redefined individually, because they seem
14
+ # not to use +Numeric#<+ any more.
15
+ #
16
+ # To activate these features, explicitly do one of the following
17
+ # require "range_extd/numeric"
18
+ # require "range_extd/object"
19
+ # require "range_extd/load_all"
20
+ #
21
+ class Numeric
22
+
23
+ # Backup of the original {Numeric#<=>}
24
+ alias_method :compare_than_numeric_before_infinity?, :<=> if ! self.method_defined?(:compare_than_numeric_before_infinity?)
25
+ # Special case for comparison with a {RangeExtd::Infinity} instance.
26
+ def <=>(c)
27
+ # Default if the special case INFINITY.
28
+ return compare_than_numeric_before_infinity?(c) if ((abs rescue self) == Float::INFINITY)
29
+
30
+ return (-(c.send(__method__, self) || return)) if RangeExtd::Infinity.infinity? c
31
+ compare_than_numeric_before_infinity?(c)
32
+ end
33
+
34
+ # Backup of the original {Numeric#>}
35
+ alias_method :greater_than_numeric_before_infinity?, :> if ! self.method_defined?(:greater_than_numeric_before_infinity?)
36
+ # Special case for comparison with a {RangeExtd::Infinity} instance.
37
+ def >(c)
38
+ # Default if self is Complex or something not Integer, Rational, Float or alike
39
+ # or the special case INFINITY.
40
+ return greater_than_numeric_before_infinity?(c) if !self.class.method_defined?(:>) || ((abs rescue self) == Float::INFINITY)
41
+
42
+ if RangeExtd::Infinity.infinity? c
43
+ c.negative?
44
+ else
45
+ greater_than_numeric_before_infinity?(c)
46
+ end
47
+ end
48
+
49
+ # Backup of the original {Numeric#<}
50
+ alias_method :less_than_numeric_before_infinity?, :< if ! self.method_defined?(:less_than_numeric_before_infinity?) # No overwriting.
51
+ # Special case for comparison with a {RangeExtd::Infinity} instance.
52
+ def <(c)
53
+ # Default if self is Complex or something not Integer, Rational, Float or alike
54
+ # or the special case INFINITY.
55
+ return less_than_numeric_before_infinity?(c) if !self.class.method_defined?(:>) || ((abs rescue self) == Float::INFINITY)
56
+
57
+ if RangeExtd::Infinity.infinity? c
58
+ c.positive?
59
+ else
60
+ less_than_numeric_before_infinity?(c)
61
+ end
62
+ end
63
+ end # class Numeric
64
+
65
+
66
+ #
67
+ # = class Float
68
+ #
69
+ # The same as {Numeric#>} and {Numeric#<}. See them for the background.
70
+ class Float
71
+
72
+ # Backup of the original {Float#<=>}
73
+ alias_method :compare_than_float_before_infinity?, :<=> if ! self.method_defined?(:compare_than_float_before_infinity?) # No overwriting.
74
+ # Special case for comparison with a {RangeExtd::Infinity} instance.
75
+ def <=>(c)
76
+ # Default if the special case INFINITY.
77
+ return compare_than_float_before_infinity?(c) if ((abs rescue self) == Float::INFINITY)
78
+
79
+ return (-(c.send(__method__, self) || return)) if RangeExtd::Infinity.infinity? c
80
+ compare_than_float_before_infinity?(c)
81
+ end
82
+
83
+ # Backup of the original {Float#>}
84
+ alias_method :greater_than_float_before_infinity?, :> if ! self.method_defined?(:greater_than_float_before_infinity?) # No overwriting.
85
+ # Special case for comparison with a {RangeExtd::Infinity} instance.
86
+ def >(c)
87
+ # Default if self is Complex or something not Integer, Rational, Float or alike
88
+ # or the special case INFINITY.
89
+ return greater_than_float_before_infinity?(c) if ((abs rescue self) == Float::INFINITY)
90
+
91
+ if RangeExtd::Infinity.infinity? c
92
+ c.negative?
93
+ else
94
+ greater_than_float_before_infinity?(c)
95
+ end
96
+ end
97
+
98
+ # Backup of the original {Float#<}
99
+ alias_method :less_than_float_before_infinity?, :< if ! self.method_defined?(:less_than_float_before_infinity?) # No overwriting.
100
+ # Special case for comparison with a {RangeExtd::Infinity} instance.
101
+ def <(c)
102
+ # Default if self is Complex or something not Integer, Rational, Float or alike
103
+ # or the special case INFINITY.
104
+ return less_than_float_before_infinity?(c) if ((abs rescue self) == Float::INFINITY)
105
+
106
+ if RangeExtd::Infinity.infinity? c
107
+ c.positive?
108
+ else
109
+ less_than_float_before_infinity?(c)
110
+ end
111
+ end
112
+ end # class Float
113
+
114
+
115
+ #
116
+ # = class Integer
117
+ #
118
+ # The same as {Numeric#>} and {Numeric#<}. See them for the background.
119
+ class Integer
120
+
121
+ # Backup of the original {Integer#<=>}
122
+ alias_method :compare_than_integer_before_infinity?, :<=> if ! self.method_defined?(:compare_than_integer_before_infinity?) # No overwriting.
123
+ # Special case for comparison with a {RangeExtd::Infinity} instance.
124
+ def <=>(c)
125
+ # Default if the special case INFINITY (never happens in Default, but a user may define Integer::INFINITY).
126
+ return compare_than_integer_before_infinity?(c) if ((abs rescue self) == Float::INFINITY)
127
+
128
+ return (-(c.send(__method__, self) || return)) if RangeExtd::Infinity.infinity? c
129
+ compare_than_integer_before_infinity?(c)
130
+ end
131
+
132
+ # Backup of the original {Integer#>}
133
+ alias_method :greater_than_integer_before_infinity?, :> if ! self.method_defined?(:greater_than_integer_before_infinity?) # No overwriting.
134
+ # Special case for comparison with a {RangeExtd::Infinity} instance.
135
+ def >(c)
136
+ # Default if self is not comparable (in case the Integer method is redifined by a user).
137
+ return greater_than_integer_before_infinity?(c) if !self.class.method_defined?(:>)
138
+
139
+ if RangeExtd::Infinity.infinity? c
140
+ c.negative?
141
+ else
142
+ greater_than_integer_before_infinity?(c)
143
+ end
144
+ end
145
+
146
+ # Backup of the original {Integer#<}
147
+ alias_method :less_than_integer_before_infinity?, :< if ! self.method_defined?(:less_than_integer_before_infinity?) # No overwriting.
148
+ # Special case for comparison with a {RangeExtd::Infinity} instance.
149
+ def <(c)
150
+ # Default if self is not comparable (in case the Integer method is redifined by a user).
151
+ return less_than_integer_before_infinity?(c) if !self.class.method_defined?(:>)
152
+
153
+ if RangeExtd::Infinity.infinity? c
154
+ c.positive?
155
+ else
156
+ less_than_integer_before_infinity?(c)
157
+ end
158
+ end
159
+ end # class Integer
160
+
@@ -0,0 +1,53 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ #
4
+ # = class Object
5
+ #
6
+ # Overwrite {Object#<=>}() so all its sub-classes can be
7
+ # aware of {RangeExtd::Infinity} objects (the two constants).
8
+ #
9
+ # To activate these features, explicitly do either of the following
10
+ # require "range_extd/object"
11
+ # require "range_extd/load_all"
12
+ #
13
+ class Object
14
+ # Backup of the original method {Object#<=>}
15
+ alias_method :compare_obj_before_infinity, :<=> if ! self.method_defined?(:compare_obj_before_infinity)
16
+
17
+ # Overwrite {Object#<=>}(). Then, all its sub-classes can be
18
+ # aware of RangeExtd::Infinity objects (the two constants).
19
+ #
20
+ # In this definition of {#<=>}, if self is Comparable
21
+ # (by judging whether it has the method [#<=]),
22
+ # it always returns, unless infinity? and positive? are set
23
+ # accordingly, either -1 or 1, depending which of
24
+ # RangeExtd::Infinity::(NEGATIVE|POSITIVE)
25
+ # is compared. If self is not Comparable, the original [#<=>]
26
+ # is called, which should return nil (unless both the object_id
27
+ # agree, eg., nil and nil, in which case 0 is returned).
28
+ #
29
+ # If you define your own class, which is Comparable, you should
30
+ # define the method "<=>" as follows, as in the standard practice
31
+ # when you redefine a method that exists in a superclass;
32
+ #
33
+ # @example A method definition of user-defined Comparable class
34
+ # class MyComparableClass
35
+ # include Comparable
36
+ # # alias :cmp_orig :<=> if !self.method_defined?(:cmp_orig) # if you want
37
+ # def <=>(c)
38
+ # if c._is_what_i_expect?
39
+ # # Write your definition.
40
+ # else # When self does not know what to do with c.
41
+ # super c # to call Object#<=> or its descendant's
42
+ # end
43
+ # end
44
+ # end
45
+ #
46
+ def <=>(c)
47
+ return (-(c.send(__method__, self) || return)) if RangeExtd::Infinity.infinity? c # Second "return" is essential as c.send() may return nil.
48
+ compare_obj_before_infinity(c)
49
+ end # def <=>(c)
50
+ end # class Object
51
+
52
+ require_relative "infinity" if !defined?(RangeExtd::Infinity)
53
+
@@ -0,0 +1,401 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ #== Summary
4
+ #
5
+ # Modifies {#==} and add methods of
6
+ # {#valid?}, {#empty?}, {#null?}, {#is_none?} and {#is_all?}.
7
+ #
8
+ class Range
9
+
10
+ alias_method :equal_prerangeextd?, :== if ! self.method_defined?(:equal_prerangeextd?) # No overwriting.
11
+
12
+ # It is extended to handle {RangeExtd} objects.
13
+ # For each element, that is, +Range#begin+ and +Range#end+,
14
+ # this uses their method of ==().
15
+ #
16
+ # As long as the comparison is limited within {Range} objects,
17
+ # the returned value of this method has unchanged.
18
+ #
19
+ # A note of caution is, some ranges which the built-in Range accepts,
20
+ # are now regarded as NOT valid, such as, (1...1) and (nil..nil)
21
+ # (the latter was not permitted in Ruby 1.8), though you can still
22
+ # use them;
23
+ # (1...1).valid? # => false
24
+ # On the other hand, {RangeExtd} class does not accept or create
25
+ # any invalid range; for any {RangeExtd} object, RangeExtd#valid?
26
+ # returns true. For example, there is no {RangeExtd} object
27
+ # that is expressed as (1...1) (See {#valid?} for detail).
28
+ #
29
+ # For that reason, when those non-valid Range objects are compared
30
+ # with a {RangeExtd} object, the returned value may not be what
31
+ # you would expect. For example,
32
+ # (1...1) == RangeExtd(1, 1, true, true) # => false.
33
+ # The former is an invalid range, while the latter is
34
+ # a rigidly-defined empty range.
35
+ #
36
+ # Consult {#valid?} and {RangeExtd#==} for more detail.
37
+ def ==(r)
38
+ _equal_core(r, :==, :equal_prerangeextd?)
39
+ end
40
+
41
+
42
+ alias_method :eql_prerangeextd?, :eql? if ! self.method_defined?(:eql_prerangeextd?) # No overwriting.
43
+
44
+ ## Same as {#==}, but the comparison is made with eql?() method.
45
+ #def eql?(r)
46
+ # _equal_core(r, :eql?, :eql_prerangeextd?)
47
+ #end
48
+
49
+ alias_method :size_prerangeextd?, :size if ! self.method_defined?(:size_prerangeextd?) # No overwriting.
50
+
51
+ # {RangeExtd::Infinity} objects are considered
52
+ #
53
+ # Other than those, identical to the original {Range#size}
54
+ #
55
+ # Size is tricky. For example, +(nil..).size+ should be nil according to the specification
56
+ # {https://ruby-doc.org/core-3.1.2/Range.html#method-i-size}
57
+ # but it returns Float::INFINITY (in Ruby-3.1)
58
+ #
59
+ # See {RangeExtd#size} for more in-depth discussion.
60
+ #
61
+ # @return [Integer, NilClass]
62
+ # @raise [FloatDomainError] +(Infinity..Infinity).size+ (as in Ruby-3.1, though it used to be 0 in Ruby-2.1)
63
+ def size(*rest)
64
+ rbeg = self.begin
65
+ rend = self.end
66
+
67
+ # Both sides are (general) Infinity
68
+ if (rbeg.respond_to?(:infinity?) && rbeg.infinity? &&
69
+ rend.respond_to?(:infinity?) && rend.infinity?)
70
+ if rbeg.negative? && rend.positive?
71
+ # should be nil according to the specification
72
+ # https://ruby-doc.org/core-3.1.2/Range.html#method-i-size
73
+ # but this returns Float::INFINITY (in Ruby-3.1)
74
+ return (nil..).size
75
+ elsif rbeg.positive? && rend.negative?
76
+ return (Float::INFINITY..(-Float::INFINITY)).size
77
+ else
78
+ ## NOTE:
79
+ # (Infinity..Infinity) => 0 (as in Ruby 2.1)
80
+ # (Infinity..Infinity) => FloatDomainError (as in Ruby 3.1)
81
+ return (Float::INFINITY..Float::INFINITY).size
82
+ end
83
+ end
84
+
85
+ # Checking Infinities.
86
+ #
87
+ if rbeg.respond_to?(:infinity?) && rbeg.infinity? # but not self.end!
88
+ return (..rend).size
89
+ elsif rend.respond_to?(:infinity?) && rend.infinity? # but not self.begin!
90
+ return (rbeg..).size
91
+ end
92
+
93
+ size_prerangeextd?(*rest)
94
+ end # def size(*rest)
95
+
96
+
97
+ # Returns true if self is valid as a comparable range.
98
+ #
99
+ # See {RangeExtd.valid?} for the definition of what is valid
100
+ # and more examples.
101
+ #
102
+ # See {#empty?} and {#null?}, too.
103
+ #
104
+ # @example
105
+ # (nil..nil).valid? # => false
106
+ # (0..0).valid? # => true
107
+ # (0...0).valid? # => false
108
+ # (2..-1).valid? # => false
109
+ # RangeExtd(0...0, true) # => true
110
+ # (3..Float::INFINITY).valid? # => true
111
+ # RangeExtd::NONE.valid? # => true
112
+ # RangeExtd::ALL.valid? # => true
113
+ #
114
+ # @note By definition, all the {RangeExtd} instances are valid,
115
+ # because {RangeExtd.initialize} (+RangeExtd.new+) checks the validity.
116
+ def valid?
117
+ RangeExtd.valid?(self)
118
+ end # def valid?
119
+
120
+
121
+ # Returns true if self is empty.
122
+ # Returns nil if self is not valid (nb., any RangeExtd instance is valid.)
123
+ # Otherwise false.
124
+ #
125
+ # The definition of what is empty is as follow.
126
+ #
127
+ # 1. the range must be valid: {#valid?} => true
128
+ # 2. if it is either a beginless or endless Range, returns false.
129
+ # 3. if the range id discrete, that is, +#begin+ has
130
+ # +#succ+ method, there must be no member within the range:
131
+ # returns +Range#to_a.empty?+
132
+ # 4. if the range is continuous, that is, +#begin+ does not have
133
+ # +#succ+ method, +#begin+ and +#end+ must be equal
134
+ # ((+#begin+ <=> +#end+) => 0) and both the boundaries must
135
+ # be excluded: ({RangeExtd#exclude_begin?} && +#exclude_end?+) == +true+.
136
+ # Note that ranges with equal +#begin+ and +#end+ with
137
+ # inconsistent two exclude status are not valid, and the built-in
138
+ # Range always has the "begin-exclude" status of false.
139
+ #
140
+ # In these conditions, none of Range instance would return true in {#empty?}.
141
+ #
142
+ # @example
143
+ # (nil..nil).empty? # => false
144
+ # (nil..3).empty? # => false
145
+ # (true..true).empty?# => nil
146
+ # (1...1).empty? # => nil
147
+ # (1..1).empty? # => false
148
+ # RangeExtd(1...1, true).empty? # => true
149
+ # RangeExtd(1...2, true).empty? # => true
150
+ # RangeExtd(1.0...2, true).empty? # => false
151
+ # RangeExtd(?a...?b, true).empty? # => true
152
+ # RangeExtd::NONE.empty? # => true
153
+ #
154
+ # @note {#empty?} returns nil when the object is invalid, and hence invalid objects
155
+ # may appear to be not empty. If you want to get +true+ when the object is either
156
+ # empty or invalid, use {#null?} instead.
157
+ #
158
+ # See {#valid?} and {RangeExtd.valid?} for the definition of the validity.
159
+ #
160
+ # @return [Boolean, nil]
161
+ def empty?
162
+ # This is basically for the sake of sub-classes, as any built-in Range instance
163
+ # always returns either nil or false.
164
+
165
+ if !valid?
166
+ return nil
167
+ elsif respond_to?(:is_none?) && is_none?
168
+ # RangeExtd::NONE
169
+ return true
170
+ elsif self.begin.nil? || self.end.nil?
171
+ return false
172
+ end
173
+
174
+ t = (self.begin() <=> self.end())
175
+ case t
176
+ when -1
177
+ if (defined?(self.exclude_begin?)) &&
178
+ exclude_begin? &&
179
+ exclude_end? &&
180
+ defined?(self.begin().succ) &&
181
+ (self.begin().succ == self.end())
182
+ true # e.g., ("a"<..."b")
183
+ else
184
+ false
185
+ end
186
+ when 0
187
+ if defined?(self.boundary) && self.boundary.nil?
188
+ # RangeExtd::NONE or RangeExtd::All
189
+ if self.exclude_end?
190
+ true # RangeExtd::NONE, though this should have been already recognized.
191
+ else
192
+ false # RangeExtd::ALL
193
+ end
194
+ else
195
+ if defined?(self.exclude_begin?)
196
+ t2 = self.exclude_begin?
197
+ else
198
+ t2 = false # == return false
199
+ end
200
+ (t2 && exclude_end?)
201
+ end
202
+ when 1
203
+ nil # redundant, as it should not be valid in the first place.
204
+ else
205
+ nil # redundant, as it should not be valid in the first place.
206
+ end
207
+ end # def empty?
208
+
209
+
210
+ # Returns true if it is either empty or invalid, or false otherwise.
211
+ #
212
+ # See {#empty?} and {#valid?}.
213
+ #
214
+ # Even {RangeExtd} (with {RangeExtd#is_none?} being false) can be +null+.
215
+ def null?
216
+ (! valid?) || empty?
217
+ end
218
+
219
+ # This method is overwritten in {RangeExtd}
220
+ #
221
+ # @return [FalseClass]
222
+ def is_none?
223
+ false
224
+ end
225
+
226
+ # true only if self is eql? to RangeExtd::ALL
227
+ #
228
+ # true if self is identical (+eql?+) to {RangeExtd::ALL}
229
+ #
230
+ # (This is different from {#==}.)
231
+ #
232
+ # @example
233
+ # (RangeExtd(RangeExtd::Infinity::NEGATIVE..RangeExtd::Infinity::POSITIVE).is_all?
234
+ # # => false because it is NOT RangeExtd
235
+ def is_all?
236
+ return false if !respond_to?(:exclude_begin?) # Must be RangeExtd
237
+ return false if exclude_begin? || exclude_end?
238
+ return false if is_none? # Essential! (b/c RangeExtd::NONE.is_all? looks like (nil..nil))
239
+
240
+ (self.begin.eql?(RangeExtd::Infinity::NEGATIVE) && self.end.eql?(RangeExtd::Infinity::POSITIVE))
241
+ end
242
+
243
+ # true if self is equivalent to {RangeExtd::ALL}
244
+ #
245
+ # @example
246
+ # (RangeExtd::Infinity::NEGATIVE..RangeExtd::Infinity::POSITIVE).equiv_all? # => true
247
+ # (nil..nil).equiv_all? # => true
248
+ # (nil...nil).equiv_all? # => false
249
+ def equiv_all?
250
+ return false if respond_to?(:is_none?) && is_none? # Essential! (b/c RangeExtd::NONE.is_all? looks like (nil..nil))
251
+ return false if exclude_end?
252
+ return false if respond_to?(:exclude_begin?) && exclude_begin?
253
+
254
+ (self.begin == RangeExtd::Infinity::NEGATIVE || self.begin.nil? || self.begin == -Float::INFINITY) &&
255
+ (self.end == RangeExtd::Infinity::POSITIVE || self.end.nil? || self.end == Float::INFINITY)
256
+ end
257
+
258
+
259
+ # Return true if self and the other are equivalent; if [#to_a] is defined, it is similar to
260
+ # (self.to_a == other.to_a)
261
+ # (though the ends are checked more rigorously), and if not, equivalent to
262
+ # (self == other)
263
+ #
264
+ # @example
265
+ # (3...7).equiv?(3..6) # => true
266
+ # (3...7).equiv?(3..6.0) # => false
267
+ # (3...7).equiv?(3.0..6.0) # => false
268
+ # (3...7).equiv?(3..6.5) # => false
269
+ # (3...7).equiv?(3.0...7.0) # => true
270
+ # (3...7.0).equiv?(3..6) # => true
271
+ # (3...7.0).equiv?(3.0..6) # => false
272
+ #
273
+ # @param other [Range, RangeExtd]
274
+ def equiv?(other)
275
+ t_or_f = (defined?(self.begin.succ) && defined?(other.begin.succ) && defined?(other.end) && defined?(other.exclude_end?))
276
+ if ! t_or_f
277
+ return(self == other) # succ() for begin is not defined.
278
+ else
279
+ # Checking the begins.
280
+ if defined?(other.exclude_begin?) && other.exclude_begin? # The other is RangeExtd with exclude_begin?==true.
281
+ if self.begin != other.begin.succ
282
+ return false
283
+ else
284
+ # Pass
285
+ end
286
+ elsif (self.begin != other.begin)
287
+ return false
288
+ end
289
+
290
+ # Now, the begins agreed. Checking the ends.
291
+ if (self.end == other.end)
292
+ if (exclude_end? ^! other.exclude_end?)
293
+ return true
294
+ else
295
+ return false
296
+ end
297
+ else # if (self.end == other.end)
298
+ if (exclude_end? ^! other.exclude_end?)
299
+ return false
300
+ elsif ( exclude_end? && defined?(other.end.succ) && (self.end == other.end.succ)) ||
301
+ (other.exclude_end? && defined?( self.end.succ) && (self.end.succ == other.end))
302
+ return true
303
+ else
304
+ return false
305
+ end
306
+ end # if (self.end == other.end)
307
+ end # if ! t_or_f
308
+
309
+ end # def equiv?(other)
310
+
311
+
312
+ ############## pravate methods of Range ##############
313
+
314
+ private
315
+
316
+ # True if obj is Comparable.
317
+ def is_comparable?(obj)
318
+ defined?(obj.<=) # Comparable?
319
+ end
320
+
321
+ # @param r [Object] to compare.
322
+ # @param method [Symbol] of the method name.
323
+ # @param method_pre [Symbol] of the backed-up original method name.
324
+ def _equal_core(r, method, method_pre)
325
+ if (! defined? r.exclude_end?) || (! defined? r.is_none?) || (! defined? r.empty?)
326
+ return false # Not Range family.
327
+ end
328
+
329
+ # If r is RangeExtd, this delegates the judgement to r;
330
+ # n.b., :== and :eql? are overwritten in RangeExtd and hence this method
331
+ # is never called when self is a RangeExtd.
332
+ return r.send(method, self) if r.respond_to?(:exclude_begin?)
333
+
334
+ # r is guaranteed to be a Range.
335
+ # Neither self nor r is guaranteed to be RangeExtd (or RangeExtd::NONE)
336
+ return false if !_both_same_nowhere_parity?(r) # inconsistent nil, non-nil, NOWHERE combination
337
+ (_both_eqleql_nil?(r, method) && (self.exclude_end? ^! r.exclude_end?)) || self.send(method_pre, r)
338
+ end # def _equal_core(r, method, method_pre)
339
+ private :_equal_core
340
+
341
+ # true if both ends in Range are equivalent to nil and RangeExtd::Infinity
342
+ #
343
+ # Note that boundaries are not taken into account in this routine.
344
+ # If, for example, {#exclude_end?} contradict, regardless of the returne
345
+ # value of this routine, it should not be "equal". The caller must handle it.
346
+ #
347
+ # @param other [Range, RangeExtd] Other object to compare with
348
+ # @option method [Symbol] One of nil, +:eql?+, and +==+. If nil, method is irrelevant.
349
+ def _both_eqleql_nil?(other, method=nil)
350
+ # Neither self nor r is guaranteed to be RangeExtd::NONE
351
+ is_self_begin_inf = (self.begin.nil? || RangeExtd::Infinity::NEGATIVE == self.begin)
352
+ is_other_begin_inf = (other.begin.nil? || RangeExtd::Infinity::NEGATIVE == other.begin)
353
+ is_self_end_inf = (self.end.nil? || RangeExtd::Infinity::POSITIVE == self.end)
354
+ is_other_end_inf = (other.end.nil? || RangeExtd::Infinity::POSITIVE == other.end)
355
+
356
+ method_ok = (method.nil? || (method == :==))
357
+ method_ok && is_self_begin_inf && is_other_begin_inf && is_self_end_inf && is_other_end_inf
358
+ end
359
+ private :_both_eqleql_nil?
360
+
361
+ # Returns the parity of both ends in Range with regard to {RangeExtd::Nowhere::NOWHERE}, non-nil, nil
362
+ #
363
+ # For example,
364
+ # if both begins are non-nil and both ends are {NilClass} nil, this returns true.
365
+ # If one end {RangeExtd::Nowhere::NOWHERE} the other end is {NilClass} nil, returns false
366
+ #
367
+ # Note that boundaries are not taken into account in this routine.
368
+ # If, for example, {#exclude_end?} contradict, regardless of the returne
369
+ # value of this routine, it should not be "equal". The caller must handle it.
370
+ #
371
+ # == Background
372
+ #
373
+ # Although {RangeExtd::Nowhere::NOWHERE} looks like nil, it is different
374
+ # in the context of {Range} and is used only for representing *nowhere*.
375
+ # Therefore, it should be recognised as a different value from nil.
376
+ #
377
+ # @param other [Range, RangeExtd] Other object to compare with
378
+ def _both_same_nowhere_parity?(other)
379
+ p_self_begin = _parity_nowhere_nonnil_nil( self.begin)
380
+ p_othe_begin = _parity_nowhere_nonnil_nil(other.begin)
381
+ p_self_end = _parity_nowhere_nonnil_nil( self.end)
382
+ p_othe_end = _parity_nowhere_nonnil_nil(other.end)
383
+
384
+ (p_self_begin == p_othe_begin) && (p_self_end == p_othe_end)
385
+ end
386
+ private :_both_same_nowhere_parity?
387
+
388
+ # Core routine for {#_both_same_nowhere_parity?} to determine the parity of a value
389
+ #
390
+ # Note that RangeExtd::Infinity objects are regarded as +nil+.
391
+ #
392
+ # @return [Integer] (-1, 0, 1) for {RangeExtd::Nowhere::NOWHERE}, non-nil, nil respectively.
393
+ def _parity_nowhere_nonnil_nil(val)
394
+ return 0 if !val.nil? && !RangeExtd::Infinity.infinity?(val)
395
+ (val.respond_to?(:nowhere?) && val.nowhere?) ? -1 : 1
396
+ end
397
+ private :_parity_nowhere_nonnil_nil
398
+ end # class Range
399
+
400
+ require_relative "../range_extd" if !defined?(RangeExtd)
401
+