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.



1300
1301
1302
# File 'lib/range_extd/range_extd.rb', line 1300

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


1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
# File 'lib/range_extd/range_extd.rb', line 1371

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.



1308
1309
1310
# File 'lib/range_extd/range_extd.rb', line 1308

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

#eql_prerangeextd?Object

No overwriting.



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

alias :eql_prerangeextd? :eql?

#equal_prerangeextd?Object

No overwriting.



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

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


1449
1450
1451
1452
1453
1454
1455
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
# File 'lib/range_extd/range_extd.rb', line 1449

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



1429
1430
1431
# File 'lib/range_extd/range_extd.rb', line 1429

def is_all?
  false
end

#is_none?FalseClass



1424
1425
1426
# File 'lib/range_extd/range_extd.rb', line 1424

def is_none?
  false
end

#null?Boolean

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



1419
1420
1421
# File 'lib/range_extd/range_extd.rb', line 1419

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


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

def valid?
  RangeExtd.valid?(self)
end