You can always modified the variable in the for-loop.
Let's for example look at this:
[rgss]for i in 0..4 # for variable in collection
i *= 2
# Do something
end
[/rgss]
The .each method is on the used for yielding (retrieving) successive members of the collection.
0..4 creates a Range object. It's on this object the .each method is used.
We can freely change
i because it will be set to a new variable in the next iteration. (Unless the same object is present in the collection more than once, which is not the case with ranges)
Since we know this we can make our own objects. Look at this class I have just made:
[rgss]class Iterator
##
# Includes the Enumerable module to provide a number of lovely functions
# Note: The functions provided are not safe to use when dealing with
# infinite collections. (The game can easily freeze)
#
include Enumerable
##
# Object Initialization
# min : Minimum value.
# max : Maximum value.
# start : The starting value of the iterator. (Default is min)
# &block : An optional block which is called for retrieving successors.
# Default is incrementing the value by 1. (Same as Range)
#
def initialize(min, max, start = min, &block)
@min = min
@max = max
@start = start
@block = (block == nil ? Proc.new {|n| n+1} : block)
end
##
# Yields successive members until a member is out of range.
# Assumes that the start value and each successor can be compared to the
# mininum and maximum values.
# Note: The collection if the start value is out of range.
#
def each
# Sets the current value to the start value
value = @start
# Check that the value is in range
while value >= @min && value <= @max
# Let's give the value
yield value
# Retrieve the successor
value = @block.call(value)
end
end
end
[/rgss]
I have included the
Enumerable module since it provides a number of functions which are often nice to have available.
The idea behind this iterator is to specify a minimum value, maximum value and a Proc for calculating successive members. You can optionally specify the starting value. (Default is the minimum value)
I think how it can be used will be more obvious with an example:
[rgss]arr = []
for i in Iterator.new(0,8) {|n| n+2}
arr << i
end
p *arr
[/rgss]
Guess what it does :P
If we want it to go the other way we can do that by specifying the starting value:
[rgss]arr = []
for i in Iterator.new(0,8,8) {|n| n-2}
arr << i
end
p *arr
[/rgss]
So now we are counting down.
The starting value can be different from the minimum and maximum values:
[rgss]arr = []
for i in Iterator.new(-8,8,0) {|n| n > 0 ? (n*-1)-1 : (n*-1)+1}
arr << i
end
p *arr
[/rgss]
Yes, we here have a Turing complete language available for describing successors.
If we want we could just make an .each method on an object. It really depends on what you prefer and what's the easiest to do in your situation. Example where a method is added to a string:
[rgss]foo = "Oh noes"
def foo.each
a = 7
b = 2
x = 0
20.times do
x = a + b*x
yield x
end
end
arr = []
for i in foo
arr << i
end
p *arr
[/rgss]
*hugs*
- Zeriab