Class: Range

Inherits:
Object show all
Defined in:
lib/range_extd/range_extd.rb

Overview

Class Range

Summary

Modifies #==, #eql? and add methods of #valid?, #empty?, #null?, #is_none? and #is_all?.

Direct Known Subclasses

RangeExtd

Instance Method Summary collapse

Instance Method Details

#==(r) ⇒ Object

It is extended to handle RangeExtd objects. For each element, that is, #begin and #end, this uses their method of ==(). See #eql?.

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.



1331
1332
1333
# File 'lib/range_extd/range_extd.rb', line 1331

def ==(r)
  equal_core(r, :==, :equal_prerangeextd?)
end

#empty?Boolean?

Note:

to check whether it is either empty or invalid, use #null?.

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.

  1. the range must be valid: #valid? => true

  2. if the range id discrete, that is, #begin has

    #succ

    method, there must be no member within the range:

    #to_a.empty? => true

  3. if the range is continuous, that is, #begin does not have

    #succ

    method, #begin and #end must be equal

    ((#begin <=> #end) => 0) and both the boundaries must be excluded: (#exclude_begin? && #exclude_end?) => true. Note that ranges with equal #begin and #end with 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?, too.

Examples:

(nil..nil).empty?  # => nil
(1...1).empty?     # => nil
(1..1).empty?      # => false
RangeExtd(1...1,   true).empty? # => true
RangeExtd(1...2,   true).empty? # => true
RangeExtd(1.0...2, true).empty? # => false
RangeExtd(?a...?b, true).empty? # => true
RangeExtd::NONE.empty?          # => true

Returns:

  • (Boolean, nil)


1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
# File 'lib/range_extd/range_extd.rb', line 1402

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 defined?(self.is_none?) && self.is_none?
    return true
  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?  # for RangeOpen
      # RangeExtd::NONE or RangeExtd::All
      if self.exclude_end?
        true  # RangeOpen::NONE
      else
        false # RangeOpen::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

#eql?(r) ⇒ Boolean

Same as #==, but the comparison is made with eql?() method.

Returns:

  • (Boolean)


1339
1340
1341
# File 'lib/range_extd/range_extd.rb', line 1339

def eql?(r)
  equal_core(r, :eql?, :eql_prerangeextd?)
end

#eql_prerangeextd?Object

No overwriting.



1336
# File 'lib/range_extd/range_extd.rb', line 1336

alias :eql_prerangeextd? :eql?

#equal_prerangeextd?Object

No overwriting.



1304
# File 'lib/range_extd/range_extd.rb', line 1304

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)

Examples:

(3...7).equiv?(3..6)      # => true
(3...7).equiv?(3..6.0)    # => false
(3...7).equiv?(3.0..6.0)  # => false
(3...7).equiv?(3..6.5)    # => false
(3...7).equiv?(3.0...7.0) # => true
(3...7.0).equiv?(3..6)    # => true
(3...7.0).equiv?(3.0..6)  # => false

Parameters:

Returns:

  • (Boolean)


1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
# File 'lib/range_extd/range_extd.rb', line 1480

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

#is_all?FalseClass

Returns:

  • (FalseClass)


1460
1461
1462
# File 'lib/range_extd/range_extd.rb', line 1460

def is_all?
  false
end

#is_none?FalseClass

Returns:

  • (FalseClass)


1455
1456
1457
# File 'lib/range_extd/range_extd.rb', line 1455

def is_none?
  false
end

#null?Boolean

Returns true if it is either empty or invalid. false otherwise. See #empty? and #valid?.

Returns:

  • (Boolean)


1450
1451
1452
# File 'lib/range_extd/range_extd.rb', line 1450

def null?
  (! valid?) || empty?
end

#valid?Boolean

Note:

By definition, all the RangeExtd instances are valid, because 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.

See #empty? and #null?, too.

Examples:

(nil..nil).valid? # => false
(0..0).valid?     # => true
(0...0).valid?    # => false
(2..-1).valid?    # => false
RangeExtd(0...0, true)   # => true
(3..Float::INFINITY).valid?  # => true
RangeExtd::NONE.valid?       # => true
RangeExtd::ALL.valid?        # => true

Returns:

  • (Boolean)


1363
1364
1365
# File 'lib/range_extd/range_extd.rb', line 1363

def valid?
  RangeExtd.valid?(self)
end