Programming C, C++, Java, PHP, Ruby, Turing, VB
Computer Science Canada 
Programming C, C++, Java, PHP, Ruby, Turing, VB  

Username:   Password: 
 RegisterRegister   
 [Ruby-tut] Doing something... again and again and...
Index -> Programming, Ruby -> Ruby Tutorials
View previous topic Printable versionDownload TopicRate TopicSubscribe to this topicPrivate MessagesRefresh page View next topic
Author Message
wtd




PostPosted: Thu Jul 01, 2004 9:01 pm   Post subject: [Ruby-tut] Doing something... again and again and...

Loops in Ruby are where things get really wild, and more than a little excting. Programmers have grown accustomed to doing a lot of work to get loops in other languages to behave exactly the way they want, with lots of extra variables introduced to get around inflexible syntax.

Ruby changes that by, for the most part, eschewing traditional looping constructs. Instead the block concept I demonstrated in my previous tutorial, "Method to my madness", allows for endless customization, and this makes for code that's easier to read and understand.

Let's take a simple example. Print out numbers from zero to nine to standard output. First I'll demonstrate in C++, and then in Ruby.

code:
#include <iostream>

int main()
{
   for (int i = 0; i <= 9; i++)
   {
      std::cout << i << std::endl;
   }
}


code:
0.upto 9 { |i| puts i }


Even considering only the code for the loop in C++, and the lengthier printing code, the Ruby version is more concise and better demonstrates what's actually going on. Another example of this would be doing the same thing, but in increments.

code:
0.step(9, 3) { |i| puts i }


In each of these examples, the methods "upto" and "step" each yield the necessary values to the code block supplied. These are called "iterators", and Ruby is chuck full of them.

Perhaps the most useful iterator, though, is the "each" iterator. But first...

A bit on arrays

Arrays in Ruby are heterogenous collections. They can store any kind of object. As in many other languages, the first index is zero. The syntax to construct them is quite simple.

code:
my_array = ["hello", 42, 3.14159, "world"]


Arrays are not the only thing that can define the "each" method, but they are probably among the most common in use. The each method simply yields each of the array's elements in order.

code:
my_array.each do |array_element|
   puts array_element
end


This is considerably more straightforward than using the equivalent "for" loop in most other languages. However, in using this method, you lose the index integer. That's easily enough remedied by using an iterator which also yields the index.

code:
my_array.each_with_index do |array_element, index|
   puts "#{index}\t#{array_element}"
end


Now, when I said that Ruby eschews the traditional looping constructs in favor of iterators, I didn't mean that it leaves them out of the language. "while" and it's opposite, "until", are both readily available.

code:
i = 0
while i <= 9
   puts i
   i += 1
end


Or perhaps more descriptively:

code:
i = 0
until i > 9
   puts i += 1
end


Then there are the one line versions.

code:
i = 0
while i <= 9 do puts i; i += 1 end


And just as if and unless can be taced onto the end of an expression, so too can while and until. Here begin...end is a single expression, but it encapsulates multiple expressions.

code:
i = 0
begin puts i; i += 1 end while i <= 9


Or:

code:
i = 0
begin puts i; i += 1 end until i > 9


These patterns could also be duplicated using Ruby's "loop" keyword, which, without intervention from "break", will continue forever.

code:
i = 0
loop do
   break if i > 9
   puts i
   i += 1
end


This replaces hacks such as:

code:
while (1) { ... }


As with other looping constructs, do and end can be replaced with curly brackets.

code:
i = 0
loop {
   break if i > 9
   puts i
   i += 1
}


However, preferred style is to use "do" and "end" whenever the loop spans multiple lines.

Ruby also has "for". It's essentially syntactic sugar for the "each" method. Anything which defines the "each" iterator can be used in a for loop. As an example, File objects have an each iterator, so the following two examples are effectively identical. The file is a function I recently wrote to replace strings in C++ std::string objects.

code:
File.open("str_replace.cpp").each do |line|
   puts line
end


code:
for line in File.open("str_replace.cpp")
   puts line
end


And the Tony version. Wink

code:
for line in File.open("str_replace.cpp") do puts line end


The only difference between these is that variables introduced in the for...in version remain in place after the loop ends.

code:
for x in [1,2,3]
   y = x * 2
   puts y
end

puts y


The above is perfectly valid, since I created the "y" variable in the loop. However, in the following the "y" is local to the block and doesn't exist in the main program.

code:
[1,2,3].each do |x|
   y = x * 2
   puts y
end

puts y
Sponsor
Sponsor
Sponsor
sponsor
ericfourfour




PostPosted: Sat Dec 16, 2006 3:27 pm   Post subject: (No subject)

I can't get the first example to work:
code:
0.upto 9 { |i| puts i }

I even copy pasted it directly.

I get this output:
code:
irb(main):008:0> 0.upto 9 { |i| puts i }
SyntaxError: compile error
(irb):8: parse error, unexpected '{', expecting $
0.upto 9 { |i| puts i }
          ^
        from (irb):8
wtd




PostPosted: Sat Dec 16, 2006 3:40 pm   Post subject: (No subject)

That's actually a mistake on my part.

code:
0.upto(9) { |i| puts i }
Display posts from previous:   
   Index -> Programming, Ruby -> Ruby Tutorials
View previous topic Tell A FriendPrintable versionDownload TopicRate TopicSubscribe to this topicPrivate MessagesRefresh page View next topic

Page 1 of 1  [ 3 Posts ]
Jump to:   


Style:  
Search: