Range
The JS.Range class is used to represent intervals – sequences with a start
and end value. It is directly based on Ruby’s Range
class. 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 JS.Range(1,5) // -> 1,2,3,4,5
new JS.Range(4,8,true) // -> 4,5,6,7
new JS.Range('a','d') // -> 'a','b','c','d'
new JS.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 JS.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 JS.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 JS.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 JS.Range(1,4)
and new JS.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 JS.Range(1,4).includes(3) // -> true new JS.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 JS.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 JS.Range('G','V').step(5).entries()
// -> ["G", "L", "Q", "V"]