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.



1385
1386
1387
# File 'lib/range_extd/range_extd.rb', line 1385

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)


1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
# File 'lib/range_extd/range_extd.rb', line 1456

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)


1393
1394
1395
# File 'lib/range_extd/range_extd.rb', line 1393

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

#eql_prerangeextd?Object

No overwriting.



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

alias :eql_prerangeextd? :eql?

#equal_prerangeextd?Object

No overwriting.



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

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)


1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
# File 'lib/range_extd/range_extd.rb', line 1534

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)


1514
1515
1516
# File 'lib/range_extd/range_extd.rb', line 1514

def is_all?
  false
end

#is_none?FalseClass

Returns:

  • (FalseClass)


1509
1510
1511
# File 'lib/range_extd/range_extd.rb', line 1509

def is_none?
  false
end

#null?Boolean

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

Returns:

  • (Boolean)


1504
1505
1506
# File 'lib/range_extd/range_extd.rb', line 1504

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)


1417
1418
1419
# File 'lib/range_extd/range_extd.rb', line 1417

def valid?
  RangeExtd.valid?(self)
end