| |||||||||||
| |||||||||||
Conditionals, loops, and iterators in Ruby
Ruby supports the following conditionals: if - perform a block if true unless - perform a block if false case - perform options when a condition is true. All three also accept an else block, and if supports an elsif block. If and unless both work as code modifiers (i.e. the statement can be written the other way around) and in all three cases code execution continues beyond the statement once it has been completed. Here's an example of the structure of each: print "Please enter an integer " value = gets.chomp.to_i print "Testing the number #{value}\n" # normal if, with elif and else if value > 5 puts "Value is greater than 5" elsif value > 2 puts "Greater that 2 but less than 5" else puts "Less than or equal to 2" end # an if that's a code modifier puts "That's very big" if value > 10 # An unless and else unless value > 5 puts "Value is not greater than 5" else puts "That's greater that 5" end # an unless that's a code modifier puts "That's not very big" unless value > 10 # Case - any one condition (or 'else' if none # of the conditions matches exactly) case value when 1,21,31 suffix = "st" when 2,22 suffix = "nd" when 3,23 suffix = "rd" else suffix = "th" end puts "It is the #{value}#{suffix} of the month" Let's run some tests on that: earth-wind-and-fire:~/ruby/r104 grahamellis$ ruby condi.rb Please enter an integer 2 Testing the number 2 Less than or equal to 2 Value is not greater than 5 That's not very big It is the 2nd of the month earth-wind-and-fire:~/ruby/r104 grahamellis$ ruby condi.rb Please enter an integer 14 Testing the number 14 Value is greater than 5 That's very big That's greater that 5 It is the 14th of the month earth-wind-and-fire:~/ruby/r104 grahamellis$ ruby condi.rb Please enter an integer 7 Testing the number 7 Value is greater than 5 That's greater that 5 That's not very big It is the 7th of the month earth-wind-and-fire:~/ruby/r104 grahamellis$ You'll note that my case takes a series of possible options on each when clause, and that it does NOT have a break at the end of each of the conditions, which you would expect to find in most switch type statements - case has been very neatly implemented in Ruby! LOOPS IN RUBY Ruby provides you with the basic while and unless loops and iterators. Let's get an example of while and unless out of the way first before looking at the much more useful, high level and efficient operators. A "while" loop defines that a statement or block of code is to be rerun time and time again while a condition remains true, and then execution is to continue after the statement or block. An "until" loop says that the block is to be performed until the condition goes true (i.e. while it is false). Just like the "if" and "unless", "while" and "until" are written with an 'end' key-worded block, or as modified after a piece of code. Sample code: # Examples of Ruby loop structures top = 4 # A while loop, counting up now = 0 while now < top puts "while #{now} .. #{top}" now += 1 end # While written in one line now = 0 print "#{now+=1} " while now < top print "\n" # An until loop now = 0 until now > top puts "until #{now} .. #{top}" now += 1 end # Until written in one line needed = 1 teams = 19 needed *= 2 until needed >= teams print "You have #{teams} teams so ideally ", "need #{needed}.\n" When that code is run, here are the results: earth-wind-and-fire:~/ruby/r104 grahamellis$ ruby loopy.rb while 0 .. 4 while 1 .. 4 while 2 .. 4 while 3 .. 4 1 2 3 4 until 0 .. 4 until 1 .. 4 until 2 .. 4 until 3 .. 4 until 4 .. 4 You have 19 teams so ideally need 32. earth-wind-and-fire:~/ruby/r104 grahamellis$ ITERATORS The method "each" when run on what we call a collection object will cause a block of code to be run on each of the elements of the collection object in turn. Yes, that's rather different to many other languages (though it does parallel foreach in PHP and for in Python). You can write a loop that looks reasonably conventional to step up through a series of numbers - example coming up - but in addition you can write far clearer and more elegant loops to process all the members of a collection in turn, without having to refer to them by their position number all the time. # Some for loops that might almost look familiar # From 1 to 20 for k in 1..20 print k," " end print "\n" # From 1, stopping short of 20 for k in 1...20 print k," " end print "\n" # An iterator object revealed! (5..15).each do |k| print k," " end print "\n" Here's how it runs. earth-wind-and-fire:~/ruby/r104 grahamellis$ ruby ddd.rb 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 5 6 7 8 9 10 11 12 13 14 15 earth-wind-and-fire:~/ruby/r104 grahamellis$ Note those .. and ... operators, and the subtle difference - in the first case, you're returned an iterator that runs up from the first to the last number, but in the second case the iterator stops one short of the last number. This means that is you have (say) a collection of 10 items numbered from 0 to 9 - which is quite common - you'll be able to write 0...10 or even 0...coll.length and not have to worry about a -1 correction. COMPARATORS IN RUBY There are multiple comparators in Ruby, and they're all adjusted dynamically to suit the objects on which they're being run. The three you'll need to remember will be: == - regular equality test, true if objects have same value eql? - method true if objects have same value AND TYPE equal? - true if both object have the same ID (i.e. same obj) A further test - === - is used by the case statement and can be independently overridden if you wish later on, and the <=> operator returns -1, 0 or +1 when comparing two objects, for less than, equal or greater than. Here's a demonstration of the comparisons, showing some differences: first = 10 second = 10.0 puts "Comparing #{first} with #{second}" puts "two = signs" if first==second puts "three = signs" if first===second puts "eql? method" if first.eql?second puts "equal? method" if first.equal?second second=first puts "Comparing #{first} with #{second}" puts "two = signs" if first==second puts "three = signs" if first===second puts "eql? method" if first.eql?second puts "equal? method" if first.equal?second And here's how it runs: earth-wind-and-fire:~/ruby/r104 grahamellis$ ruby ctors.rb Comparing 10 with 10.0 two = signs three = signs Comparing 10 with 10 two = signs three = signs eql? method equal? method earth-wind-and-fire:~/ruby/r104 grahamellis$ Ruby also supports lazy operators - "and" means "and if true", and "or" means "and if false". The ? : operator from other languages is supported too. stock = 0..5 for number in stock num = number # "and" is lazy. If the first part is false, then # the whole expression will be false - so ruby doesn't # bother to go on to the second test nor the assignment # it includes. num == 0 and num = "none" # "? ... :" is an "if true x else y" type operator. word = num == 1 ? "is" : "are" print "There #{word} #{num} in stock\n" end We run that and get: earth-wind-and-fire:~/ruby/r104 grahamellis$ ruby lazyops.rb lazyops.rb:12: warning: found = in conditional, should be == There are none in stock There is 1 in stock There are 2 in stock There are 3 in stock There are 4 in stock There are 5 in stock earth-wind-and-fire:~/ruby/r104 grahamellis$ so perhaps the lazy and / or aren't such a good idea! See also Ruby course - UK, Ireland, Europe Please note that articles in this section of our
web site were current and correct to the best of our ability when published,
but by the nature of our business may go out of date quite quickly. The
quoting of a price, contract term or any other information in this area of
our website is NOT an offer to supply now on those terms - please check
back via our main web site
Related Material
Ruby - Control Structures Ruby - Introduction resource index - Ruby Solutions centre home page You'll find shorter technical items at The Horse's Mouth and delegate's questions answered at the Opentalk forum. At Well House Consultants, we provide training courses on subjects such as Ruby, Perl, Python, Linux, C, C++, Tcl/Tk, Tomcat, PHP and MySQL. We're asked (and answer) many questions, and answers to those which are of general interest are published in this area of our site. | |||||||||||
PH: 0800 043 8225 or 01225 708225 • FAX: 0845 8382 405 or 01225 707126 • EMAIL: info@wellho.net • WEB: http://www.wellho.net • SKYPE: wellho | |||||||||||