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

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




PostPosted: Fri Jun 25, 2004 10:07 pm   Post subject: [Ruby-tut] Decisions, decisions...

In programming the ability to control the flow of the program is critical. Ruby provides ample facilities for doing this.

In this tutorial I'll modify the previous tutorial's code to allow the computer to respond to my input differently depending on what I input.

It should respond as it did before if I input a normal name. However, if I input nothing, it should respond rudely, and if I input the names Calvin, Linus, or Sid, it should emit a Nelson-esque "Haaaaa Haaaa!".

First, though, I'd like to make one small addition to the code. As I posted it before, it simply reads a line of input, assigns it to the variable name, then inserts it into another string, which it prints. Unfortunately, this doesn't test for whether or not I input a bunch of spaces at the beginning or end of my name. I want to get rid of extraneous whitespace.

code:
puts "Hello, Ruby!"
print "I'm "
name = gets
name.strip!
puts "Ruby says, \"Hello, #{name}\""


The extra line calls the strip! method on the object we've given the name "name". "strip" indicates that it's stripping the extraneous whitespace off, while the ! is a visual indication that the method is changing the object permanently.

code:
name.strip


The above would simply create a new string object, remove the whitespaces in that new object, and return it. In fact, we can use this method to further streamline the new code, by removing the extra whitespace before the object is ever assigned to name.

code:
puts "Hello, Ruby!"
print "I'm "
name = gets.strip
puts "Ruby says, \"Hello, #{name}\""


Note: As in Java, and as in many other languages, the dot is used to access methods in Ruby.

If.... I only had a brain...

Ruby uses the if statement in much the same way as other languages.

code:
puts "Hello, Ruby!"
print "I'm "
name = gets.strip

if name == ""
   puts "Ruby says, \"fine, ignore me!\""
elsif name == "Calvin" or name == "Linus" or name == "Sid"
   puts "Ruby says, \"Haaaaa haaaaa!\""
else
   puts "Ruby says, \"Hello #{name}\""
end


Now, we could probably streamline this a bit and remove the redundant code by just sticking Ruby's message to us in a variable and then doing the printing later on.

code:
puts "Hello, Ruby!"
print "I'm "
name = gets.strip

if name == ""
   statement = "fine, ignore me!"
elsif name == "Calvin" or name == "Linus" or name == "Sid"
   statement = "Haaaaa haaaaa!"
else
   statement = "Hello #{name}"
end

puts "Ruby says, \"#{statement}\""


We're still not using the language to it's full potential, though, and all of those redundant "statement = " lines look bad. They look bad to me because I know that Ruby's if...elsif...end construct can return values as in the following code.

code:
puts "Hello, Ruby!"
print "I'm "
name = gets.strip

statement = if name == ""
   "fine, ignore me!"
elsif name == "Calvin" or name == "Linus" or name == "Sid"
   "Haaaaa haaaaa!"
else
   "Hello #{name}"
end

puts "Ruby says, \"#{statement}\""


We didn't even need the "return", even though Ruby has it, and I could have used it.

Though it's not truly a control structure, it's used so often in them that I feel obligated to offer a brief explanation of regular expressions here, since it can greatly simplify our test to see if Ruby should laugh at you.

A regular expression is a pattern against which text can be matched. A simple regular expression for our purposes would look like:

code:
/Calvin|Linus|Sid/


The slashes Ruby treats as a form of quotes which just happens to quote a regular expression. The | indicates the pattern should match either Calvin, Linus, or Sid. In this case it will match if they occur anywhere in the input name. Of course, one may argue that someone is safer if only their middle name is Linus, but then again, they deserve the ridicule if they mention that publicly.

Note: No offense is intended to anyone actually named Calvin, Linus, or Sid.

To match a reular expression against a string, we use the =~ operator, so our code now becomes the following.

code:
puts "Hello, Ruby!"
print "I'm "
name = gets.strip

statement = if name == ""
   "fine, ignore me!"
elsif name =~ /Calvin|Linus|Sid/
   "Haaaaa haaaaa!"
else
   "Hello #{name}"
end

puts "Ruby says, \"#{statement}\""


Now I should mention that including the "then" keyword allows for a great deal of flexibility in how the code is layed out.

code:
puts "Hello, Ruby!"
print "I'm "
name = gets.strip

statement = if name == "" then "fine, ignore me!" elsif name =~ /Calvin|Linus|Sid/ then "Haaaaa haaaaa!" else "Hello #{name}" end

puts "Ruby says, \"#{statement}\""


Just in Case

Of course, that last example might look better if we knew about Ruby's case construct. Similar to other languages' "switch", Ruby's counterpart is more powerful since it can work on types other than just integers.

code:
puts "Hello, Ruby!"
print "I'm "
name = gets.strip

statement = case name
   when ""
      "fine, ignore me!"
   when /Calvin|Linus|Sid/
      "Haaaaa haaaaa!"
   else
      "Hello #{name}"
end

puts "Ruby says, \"#{statement}\""


But that includes a lot of extra whitespace to make it clear how this construct works. Again, "then" can compact it all down.

code:
puts "Hello, Ruby!"
print "I'm "
name = gets.strip

statement = case name when "" then "fine, ignore me!" when /Calvin|Linus|Sid/ then "Haaaaa haaaaa!" else "Hello #{name}" end

puts "Ruby says, \"#{statement}\""


Even now, with all of this, I've neglected Ruby's postfix conditionals. Yep, we can actually stick the "if" at the end for quick one-liners.

In the following we'll make sure Ruby doesn't look inarticulate by having it not say anything in the odd event that the statement variable is empty.

code:
puts "Hello, Ruby!"
print "I'm "
name = gets.strip

statement = case name when "" then "fine, ignore me!" when /Calvin|Linus|Sid/ then "Haaaaa haaaaa!" else "Hello #{name}" end

puts "Ruby says, \"#{statement}\"" if statement != ""


More clear in this case though is the keyword "unless", which we can use anywhere "if" is used (though there's no elsunless, yet).

code:
puts "Hello, Ruby!"
print "I'm "
name = gets.strip

statement = case name when "" then "fine, ignore me!" when /Calvin|Linus|Sid/ then "Haaaaa haaaaa!" else "Hello #{name}" end

puts "Ruby says, \"#{statement}\"" unless statement == ""


But == "" looks so busy. Wouldn't it be great if Ruby's strings had a method which could determine if the string is empty for us, in a way that lends more meaning than what we're currently using?

Oh, they do.

code:
puts "Hello, Ruby!"
print "I'm "
name = gets.strip

statement = case name when "" then "fine, ignore me!" when /Calvin|Linus|Sid/ then "Haaaaa haaaaa!" else "Hello #{name}" end

puts "Ruby says, \"#{statement}\"" unless statement.empty?


The question mark at the end of the empty? method is a good visual indicator that the method return a boolean (true or false) value.

So, how can we make this even shorter, just because we're 1337 hackers?

Well, I mentioned in the "Hello, Ruby!" tutorial that the #{} construct was more powerful than the example I gave indicated, and it is. In addition to just inserting variables into a string, it can insert entire expressions.


code:
puts "Hello, Ruby!"
print "I'm "
name = gets.strip

puts "Ruby says, \"#{case name when "" then "fine, ignore me!" when /Calvin|Linus|Sid/ then "Haaaaa haaaaa!" else "Hello #{name}" end}\"" unless statement.empty?


That's all well and good, but now there's no statement variable to test at the end.

code:
puts "Hello, Ruby!"
print "I'm "
name = gets.strip

puts "Ruby says, \"#{statement = case name when "" then "fine, ignore me!" when /Calvin|Linus|Sid/ then "Haaaaa haaaaa!" else "Hello #{name}" end}\"" unless statement.empty?


And now there is!

One last thing

Warning: Crazy compacting of code follows. Wink

Now, let's say I don't need to use the variable name anywhere else after this. Why should I create it at all?

code:
puts "Hello, Ruby!"
print "I'm "

puts "Ruby says, \"#{statement = case gets.strip when "" then "fine, ignore me!" when /Calvin|Linus|Sid/ then "Haaaaa haaaaa!" else "Hello #{name}" end}\"" unless statement.empty?


What lets us do this now all in one line of code is that not only can you put a single expression into a string, but you can put many, separated by semi-colons. The return value of the last expression is what will be inserted into the string.

It should be noted that quotes can work oddly inside #{}, so we have to oddly quote "I'm " in the following.

code:
puts "Ruby says, \"#{puts "Hello, Ruby!"; print 'I\'m '; statement = case gets.strip when "" then "fine, ignore me!" when /Calvin|Linus|Sid/ then "Haaaaa haaaaa!" else "Hello #{name}" end}\"" unless statement.empty?


That's probably enough mind-warping code for one tutorial.
Sponsor
Sponsor
Sponsor
sponsor
Tony




PostPosted: Sun Jun 27, 2004 7:59 pm   Post subject: (No subject)

ruby should not be allowed in any programming contests that limit amount of lines Laughing
Latest from compsci.ca/blog: Tony's programming blog. DWITE - a programming contest.
wtd




PostPosted: Sun Jun 27, 2004 10:03 pm   Post subject: (No subject)

Google for "Perl golf". That'll really blow your mind.
rizzix




PostPosted: Mon Jun 28, 2004 10:16 am   Post subject: (No subject)

yea perl rox.. perl is xtreme! heh
DarkRider




PostPosted: Thu Feb 05, 2009 9:18 pm   Post subject: Re: [Ruby-tut] Decisions, decisions...

Sorry for bumping an old topic, but I started looking at Ruby and I think I found an error in this tutorial. Shouldn't this code:
Ruby:
puts "Ruby says, \"#{puts "Hello, Ruby!"; print 'I\'m '; statement = case gets.strip when "" then "fine, ignore me!" when /Calvin|Linus|Sid/ then "Haaaaa haaaaa!" else "Hello #{name}" end}\"" unless statement.empty?

be:
Ruby:
puts "Ruby says, \"#{puts "Hello, Ruby!"; print 'I\'m '; statement = case name = gets.strip when "" then "fine, ignore me!" when /Calvin|Linus|Sid/ then "Haaaaa haaaaa!" else "Hello #{name}" end}\"" unless statement.empty?

Assigning "Hello #{name}" to statement wouldn't work because name has not been declared yet, right? Shouldn't "code gets.strip when" be "code name = gets.strip when"? I have just started using Ruby so this may not be right, but whenever I try to run the code in the tutorial it would just exit without executing any code after this line. It runs properly when I change "case gets.strip when" to "case name = gets.strip when" though.
wtd




PostPosted: Fri Feb 06, 2009 1:10 am   Post subject: RE:[Ruby-tut] Decisions, decisions...

I think you're right about my code being faulty. Thanks for the vigilance.
Insectoid




PostPosted: Fri Feb 06, 2009 12:32 pm   Post subject: RE:[Ruby-tut] Decisions, decisions...

So, a semi-colon will denote a new line? allowing you to put multiple statements on a single line? semi-colons aren't necessary when you put everything on a new line (I understand).


OT, I notice you aren't on IRC much anymore, wtd. Is the baby taking up that much of your time? Have you forgotten about me? (joke, just observing your absence..... Not that I don't miss you or anything...)
wtd




PostPosted: Fri Feb 06, 2009 1:28 pm   Post subject: RE:[Ruby-tut] Decisions, decisions...

Baby and expanding work responsibilities.
Sponsor
Sponsor
Sponsor
sponsor
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  [ 8 Posts ]
Jump to:   


Style:  
Search: