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.
- checksums.yaml +4 -4
- data/ChangeLog +31 -10
- data/Makefile +7 -3
- data/News +8 -0
- data/README.en.rdoc +1163 -250
- data/README.ja.rdoc +1163 -250
- data/Rakefile +11 -5
- data/lib/range_extd/infinity.rb +426 -0
- data/lib/range_extd/load_all.rb +19 -0
- data/lib/range_extd/nil_class.rb +41 -0
- data/lib/range_extd/nowhere.rb +135 -0
- data/lib/range_extd/numeric.rb +160 -0
- data/lib/range_extd/object.rb +53 -0
- data/lib/range_extd/range.rb +401 -0
- data/lib/{range_extd/range_extd.rb → range_extd.rb} +440 -628
- data/range_extd.gemspec +50 -0
- data/test/all_required_test.rb +173 -0
- data/test/test_range_extd.rb +649 -157
- data/test/test_range_extd_nowhere.rb +84 -0
- metadata +29 -16
- data/lib/range_extd/infinity/infinity.rb +0 -392
@@ -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
|
+
|