Range

The Range class is used to represent intervals – sequences with a start and end value. It is directly based on Ruby’s Range class.

// In the browser
JS.require('JS.Range', function(Range) { ... });

// In CommonJS
var Range = require('jsclass/src/range').Range;

A Range may be constructed using integers, strings, or any type of object that responds to the succ() method. Ranges are a lightweight way to represent sequences of objects, and as collections they respond to all the Enumerable methods.

A range is constructed using a start and end value, and an optional flag that indicates whether the end value is included when iterating.

new Range(1,5)           // -> 1,2,3,4,5
new Range(4,8,true)      // -> 4,5,6,7

new Range('a','d')       // -> 'a','b','c','d'
new Range('B','G',true)  // -> 'B','C','D','E','F'

The Range object only stores the start and endpoints, not the intermediate values: these are generated using succ() when iterating. For example, here’s a quick class that implements enough of an API to be used as a Range delimiter. We need succ() to return the next object in the sequence, and compareTo() to allow a Range to determine whether a given object is within the range:

var NumberWrapper = new Class({
    initialize: function(value) {
        this._value = value;
    },

    compareTo: function(object) {
        var a = this._value, b = object._value;
        return a < b ? -1 : (a > b ? 1 : 0);
    },

    succ: function() {
        return new this.klass(this._value + 1);
    },

    inspect: function() {
        return '#<NumberWrapper:' + this._value + '>';
    }
});

We can use this class in a Range and iterating will generate the intermediate objects:

var nums = new Range(new NumberWrapper(16),
                     new NumberWrapper(24),
                     true);

nums.forEach(function(number) {
    console.log(number.inspect());
});

// -> #<NumberWrapper:16>
//    #<NumberWrapper:17>
//    #<NumberWrapper:18>
//    #<NumberWrapper:19>
//    #<NumberWrapper:20>
//    #<NumberWrapper:21>
//    #<NumberWrapper:22>
//    #<NumberWrapper:23>

The full Range object API is listed below. Ranges also respond to all the Enumerable methods based on the forEach() method.

begin()

Returns the start value of the Range.

forEach(block, context)

Calls block with each item in the Range in turn. context is optional and specifies the binding of this within the block function.

// Calls the function with
// arguments 1,2,3,4
new Range(1,4).forEach(function(number) {
    // ...
});

end()

Returns the end value of the Range.

equals(other)

Returns true iff other is a Range with the same start and end values and the same value for excludesEnd(). Note that the ranges new Range(1,4) and new Range(1,5,true) are not equal.

excludesEnd()

Returns true iff the Range excludes its end value during iteration.

first()

Returns the start value of the Range.

includes(item)

Returns true iff item is contained in the Range, that is if it is between the start and end values of the range.

new Range(1,4).includes(3)         // -> true
new Range(2,6,true).includes(6)    // -> false

Note that an object may be considered to be included in a range even though it does not appear during iteration and may even lie outside the iteration range. For example the following expression is true as 8.5 is less than 9:

new Range(6,9,true).includes(8.5)   // -> true

Aliased as covers(), member() and match(), so a Range may be used as the argument to Enumerable#grep.

last()

Returns the end value of the Range.

step(n, block, context)

Iterates over every nth item in the Range, calling block with each. Returns an Enumerator if called with no block.

new Range('G','V').step(5).entries()
    // -> ["G", "L", "Q", "V"]