Class: Range
Overview
Direct Known Subclasses
Instance Method Summary collapse
-
#==(r) ⇒ Object
It is extended to handle RangeExtd objects.
-
#empty? ⇒ Boolean?
Returns true if self is empty.
-
#equal_prerangeextd? ⇒ Object
No overwriting.
-
#equiv?(other) ⇒ Boolean
Return true if self and the other are equivalent; if [#to_a] is defined, it is similar to (self.to_a == other.to_a) (though the ends are checked more rigorously), and if not, equivalent to (self == other).
-
#equiv_all? ⇒ Boolean
true if self is equivalent to RangeExtd::ALL.
-
#is_all? ⇒ Boolean
true only if self is eql? to RangeExtd::ALL.
-
#is_none? ⇒ FalseClass
This method is overwritten in RangeExtd.
-
#null? ⇒ Boolean
Returns true if it is either empty or invalid, or false otherwise.
-
#size(*rest) ⇒ Integer, NilClass
RangeExtd::Infinity objects are considered.
-
#size_prerangeextd? ⇒ Object
Same as #==, but the comparison is made with eql?() method.
-
#valid? ⇒ Boolean
Returns true if self is valid as a comparable range.
Instance Method Details
#==(r) ⇒ Object
It is extended to handle RangeExtd objects. For each element, that is, Range#begin and Range#end, this uses their method of ==().
As long as the comparison is limited within Range objects, the returned value of this method has unchanged.
A note of caution is, some ranges which the built-in Range accepts, are now regarded as NOT valid, such as, (1…1) and (nil..nil) (the latter was not permitted in Ruby 1.8), though you can still use them;
(1...1).valid? # => false
On the other hand, RangeExtd class does not accept or create any invalid range; for any RangeExtd object, RangeExtd#valid? returns true. For example, there is no RangeExtd object that is expressed as (1…1) (See #valid? for detail).
For that reason, when those non-valid Range objects are compared with a RangeExtd object, the returned value may not be what you would expect. For example,
(1...1) == RangeExtd(1, 1, true, true) # => false.
The former is an invalid range, while the latter is a rigidly-defined empty range.
Consult #valid? and RangeExtd#== for more detail.
37 38 39 |
# File 'lib/range_extd/range.rb', line 37 def ==(r) _equal_core(r, :==, :equal_prerangeextd?) end |
#empty? ⇒ Boolean?
Returns true if self is empty. Returns nil if self is not valid (nb., any RangeExtd instance is valid.) Otherwise false.
The definition of what is empty is as follow.
-
the range must be valid: #valid? => true
-
if it is either a beginless or endless Range, returns false.
-
if the range id discrete, that is,
#beginhas#succmethod, there must be no member within the range: returns Range#to_a.empty? -
if the range is continuous, that is,
#begindoes not have#succmethod,#beginand#endmust be equal ((#begin<=>#end) => 0) and both the boundaries must be excluded: (RangeExtd#exclude_begin? &&#exclude_end?) ==true. Note that ranges with equal#beginand#endwith inconsistent two exclude status are not valid, and the built-in Range always has the “begin-exclude” status of false.
In these conditions, none of Range instance would return true in #empty?.
See #valid? and RangeExtd.valid? for the definition of the validity.
161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 |
# File 'lib/range_extd/range.rb', line 161 def empty? # This is basically for the sake of sub-classes, as any built-in Range instance # always returns either nil or false. if !valid? return nil elsif respond_to?(:is_none?) && is_none? # RangeExtd::NONE return true elsif self.begin.nil? || self.end.nil? return false end t = (self.begin() <=> self.end()) case t when -1 if (defined?(self.exclude_begin?)) && exclude_begin? && exclude_end? && defined?(self.begin().succ) && (self.begin().succ == self.end()) true # e.g., ("a"<..."b") else false end when 0 if defined?(self.boundary) && self.boundary.nil? # RangeExtd::NONE or RangeExtd::All if self.exclude_end? true # RangeExtd::NONE, though this should have been already recognized. else false # RangeExtd::ALL end else if defined?(self.exclude_begin?) t2 = self.exclude_begin? else t2 = false # == return false end (t2 && exclude_end?) end when 1 nil # redundant, as it should not be valid in the first place. else nil # redundant, as it should not be valid in the first place. end end |
#equal_prerangeextd? ⇒ Object
No overwriting.
10 |
# File 'lib/range_extd/range.rb', line 10 alias_method :equal_prerangeextd?, :== |
#equiv?(other) ⇒ Boolean
Return true if self and the other are equivalent; if [#to_a] is defined, it is similar to
(self.to_a == other.to_a)
(though the ends are checked more rigorously), and if not, equivalent to
(self == other)
274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 |
# File 'lib/range_extd/range.rb', line 274 def equiv?(other) t_or_f = (defined?(self.begin.succ) && defined?(other.begin.succ) && defined?(other.end) && defined?(other.exclude_end?)) if ! t_or_f return(self == other) # succ() for begin is not defined. else # Checking the begins. if defined?(other.exclude_begin?) && other.exclude_begin? # The other is RangeExtd with exclude_begin?==true. if self.begin != other.begin.succ return false else # Pass end elsif (self.begin != other.begin) return false end # Now, the begins agreed. Checking the ends. if (self.end == other.end) if (exclude_end? ^! other.exclude_end?) return true else return false end else # if (self.end == other.end) if (exclude_end? ^! other.exclude_end?) return false elsif ( exclude_end? && defined?(other.end.succ) && (self.end == other.end.succ)) || (other.exclude_end? && defined?( self.end.succ) && (self.end.succ == other.end)) return true else return false end end # if (self.end == other.end) end # if ! t_or_f end |
#equiv_all? ⇒ Boolean
true if self is equivalent to RangeExtd::ALL
249 250 251 252 253 254 255 256 |
# File 'lib/range_extd/range.rb', line 249 def equiv_all? return false if respond_to?(:is_none?) && is_none? # Essential! (b/c RangeExtd::NONE.is_all? looks like (nil..nil)) return false if exclude_end? return false if respond_to?(:exclude_begin?) && exclude_begin? (self.begin == RangeExtd::Infinity::NEGATIVE || self.begin.nil? || self.begin == -Float::INFINITY) && (self.end == RangeExtd::Infinity::POSITIVE || self.end.nil? || self.end == Float::INFINITY) end |
#is_all? ⇒ Boolean
true only if self is eql? to RangeExtd::ALL
true if self is identical (eql?) to RangeExtd::ALL
(This is different from #==.)
235 236 237 238 239 240 241 |
# File 'lib/range_extd/range.rb', line 235 def is_all? return false if !respond_to?(:exclude_begin?) # Must be RangeExtd return false if exclude_begin? || exclude_end? return false if is_none? # Essential! (b/c RangeExtd::NONE.is_all? looks like (nil..nil)) (self.begin.eql?(RangeExtd::Infinity::NEGATIVE) && self.end.eql?(RangeExtd::Infinity::POSITIVE)) end |
#is_none? ⇒ FalseClass
This method is overwritten in RangeExtd
222 223 224 |
# File 'lib/range_extd/range.rb', line 222 def is_none? false end |
#null? ⇒ Boolean
Returns true if it is either empty or invalid, or false otherwise.
Even RangeExtd (with RangeExtd#is_none? being false) can be null.
215 216 217 |
# File 'lib/range_extd/range.rb', line 215 def null? (! valid?) || empty? end |
#size(*rest) ⇒ Integer, NilClass
RangeExtd::Infinity objects are considered
Other than those, identical to the original #size
Size is tricky. For example, (nil..).size should be nil according to the specification https://ruby-doc.org/core-3.1.2/Range.html#method-i-size but it returns Float::INFINITY (in Ruby-3.1)
See RangeExtd#size for more in-depth discussion.
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
# File 'lib/range_extd/range.rb', line 63 def size(*rest) rbeg = self.begin rend = self.end # Both sides are (general) Infinity if (rbeg.respond_to?(:infinity?) && rbeg.infinity? && rend.respond_to?(:infinity?) && rend.infinity?) if rbeg.negative? && rend.positive? # should be nil according to the specification # https://ruby-doc.org/core-3.1.2/Range.html#method-i-size # but this returns Float::INFINITY (in Ruby-3.1) return (nil..).size elsif rbeg.positive? && rend.negative? return (Float::INFINITY..(-Float::INFINITY)).size else ## NOTE: # (Infinity..Infinity) => 0 (as in Ruby 2.1) # (Infinity..Infinity) => FloatDomainError (as in Ruby 3.1) return (Float::INFINITY..Float::INFINITY).size end end # Checking Infinities. # if rbeg.respond_to?(:infinity?) && rbeg.infinity? # but not self.end! return (..rend).size elsif rend.respond_to?(:infinity?) && rend.infinity? # but not self.begin! return (rbeg..).size end size_prerangeextd?(*rest) end |
#size_prerangeextd? ⇒ Object
Same as #==, but the comparison is made with eql?() method. def eql?®
_equal_core(r, :eql?, :eql_prerangeextd?)
end
49 |
# File 'lib/range_extd/range.rb', line 49 alias_method :size_prerangeextd?, :size |
#valid? ⇒ Boolean
By definition, all the RangeExtd instances are valid, because RangeExtd#initialize (RangeExtd.new) checks the validity.
Returns true if self is valid as a comparable range.
See RangeExtd.valid? for the definition of what is valid and more examples.
116 117 118 |
# File 'lib/range_extd/range.rb', line 116 def valid? RangeExtd.valid?(self) end |