- 4.1 Motivation
- 4.2 Strings and Methods
- 4.3 Other Data Structures
- 4.4 Ruby Classes
- 4.5 Exercises
4.2 Strings and Methods
Our principal tool for learning Ruby will be the Rails console, which is a command-line tool for interacting with Rails applications. The console itself is built on top of interactive Ruby (irb), and thus has access to the full power of Ruby. (As we'll see in Section 4.4.4, the console also has access to the Rails environment.) Start the console at the command line as follows:
$ script/console Loading development environment (Rails 2.3.8) >> |
By default, the console starts in a development environment, which is one of three separate environments defined by Rails (the others are test and production). This distinction won't be important in this chapter; we'll learn more about environments in Section 6.3.1.
The console is a great learning tool, and you should feel free to explore—don't worry, you (probably) won't break anything. When using the console, type Ctrl-C if you get stuck, or Ctrl-D to exit the console altogether.
Throughout the rest of this chapter, you might find it helpful to consult the Ruby API.4 It's packed (perhaps even too packed) with information; for example, to learn more about Ruby strings you can look at the Ruby API entry for the String class.
4.2.1 Comments
Ruby comments start with the pound sign # and extend to the end of the line. Ruby (and hence Rails) ignores comments, but they are useful for human readers (including, often, the original author!). In the code
# Return a title on a per-page basis. def title . . . |
the first line is a comment indicating the purpose of the subsequent function definition.
You don't ordinarily include comments in console sessions, but for instructional purposes I'll include some comments in what follows, like this:
>> 17+42 # Integer addition => 59 |
If you follow along in this section typing or copying-and-pasting commands into your own console, you can of course omit the comments if you like; the console will ignore them in any case.
4.2.2 Strings
Strings are probably the most important data structure for web applications, since web pages ultimately consist of strings of characters sent from the server to the browser. Let's get started exploring strings with the console.
>> "" # An empty string => "" >> "foo" # Anonempty string => "foo" |
These are string literals (also, amusingly, called literal strings), created using the double quote character " . The console prints the result of evaluating each line, which in the case of a string literal is just the string itself.
We can also concatenate strings with the + operator:
>> "foo" + "bar" # String concatenation => "foobar" |
Here is the result of evaluating "foo" plus "bar" in the string "foobar" .5
Another way to build up strings is via interpolation using the special syntax #{}:6
>> first_name = "Michael" # Variable assignment => "Michael" >> "#{first_name} Hartl" # Variable interpolation => "Michael Hartl" |
Here we've assigned the value "Michael" to the variable first_name and then interpolated it into the string "#{first_name} Hartl". We could also assign both strings a variable name:
>> first_name = "Michael" => "Michael" >> last_name = "Hartl" => "Hartl" >> first_name+""+ last_name # Concatenation, with a space in between => "Michael Hartl" >> "#{first_name} #{last_name}" # The equivalent interpolation => "Michael Hartl" |
Note that the final two expressions are equivalent, but I prefer the interpolated version; having to add the single space "" seems a bit awkward.
Printing
To print a string, the most commonly used Ruby function is puts (pronounced "put ess", for "put string"):
>> puts "foo" # put string foo => nil |
The puts method operates as a side-effect: the expression puts "foo" prints the string to the screen and then returns literally nothing: nil is a special Ruby value for "nothing at all". (In what follows, I'll sometimes suppress the => nil part for simplicity.)
Using puts automatically appends a newline character \n to the output; the related print method does not:
>> print "foo" # print string (same as puts, but without the newline) foo=> nil >> print "foo\n" # Same as puts "foo" foo => nil |
Single-Quoted Strings
All the examples so far have used double-quoted strings, but Ruby also supports single-quoted strings. For many uses, the two types of strings are effectively identical:
>> 'foo' #A single-quoted string => "foo" >> 'foo' + 'bar' => "foobar" |
There's an important difference, though; Ruby won't interpolate into single-quoted strings
>> '#{foo} bar' # Single-quoted strings don't allow interpolation => "\#{foo} bar" |
Note how the console returns values using double-quoted strings, which requires a backslash to escape characters like #.
If double-quoted strings can do everything that single-quoted strings can do, and interpolate to boot, what's the point of single-quoted strings? They are often useful because they are truly literal, and contain exactly the characters you type. For example, the "backslash" character is special on most systems, as in the literal newline \n. If you want a variable to contain a literal backslash, single quotes make it easier:
>> '\n' # Aliteral backslash n => "\\n" |
As with the # character in our previous example, Ruby needs to escape the backslash with an additional backslash; inside double-quoted strings, a literal backslash is represented with two backslashes.
For a small example like this, there's not much savings, but if there are lots of things to escape it can be a real help:
>> 'Newlines (\n) and tabs (\t) both use the backslash character \.' => "Newlines (\\n) and tabs (\\t) both use the backslash character \\." |
4.2.3 Objects and Message Passing
Everything in Ruby, including strings and even nil , is an object. We'll see the technical meaning of this in Section 4.4.2, but I don't think anyone ever understood objects by reading the definition in a book; you have to build up your intuition for objects by seeing lots of examples.
It's easier to describe what objects do, which is respond to messages. An object like a string, for example, can respond to the message length, which returns the number of characters in the string:
>> "foobar".length # Passing the "length" message to a string => 6 |
Typically, the messages that get passed to objects are methods, which are functions defined on those objects.7 Strings also respond to the empty? method:
>> "foobar".empty? => false >> "".empty? => true |
Note the question mark at the end of the empty? method. This is a Ruby convention indicating that the return value is boolean: true or false. Booleans are especially useful for control flow:
>> s = "foobar" >> if s.empty? >> "The string is empty" >> else >> "The string is nonempty" >> end => "The string is nonempty" |
Booleans can also be combined using the && ("and"), || ("or"), and ! ("not") operators:
>> x = "foo" => "foo" >> y ="" => "" >> puts "Both strings are empty" if x.empty? && y.empty? => nil >> puts "One of the strings is empty" if x.empty? || y.empty? "One of the strings is empty" => nil >> puts "x is not empty" if !x.empty? => "x is not empty" |
Since everything in Ruby is an object, it follows that nil is an object, so it, too, can respond to methods. One example is the to_s method that can convert virtually any object to a string:
>> nil.to_s "" |
This certainly appears to be an empty string, as we can verify by chaining the messages we pass to nil :
>> nil.empty? NoMethodError: You have a nil object when you didn't expect it! You might have expected an instance of Array. The error occurred while evaluating nil.empty? >> nil.to_s.empty? # Message chaining true |
We see here that the nil object doesn't itself respond to the empty? method, but nil.to_s does.
There's a special method for testing for nil -ness, which you might be able to guess:
>> "foo".nil? => false >> "".nil? => false >> nil.nil? => true |
If you look back at Listing 4.2, you'll see that the title helper tests to see if @title is nil using the nil? method. This is a hint that there's something special about instance variables (variables with an @ sign), which can best be understood by contrasting them with ordinary variables. For example, suppose we enter title and @title variables at the console without defining them first:
>> title # Oops! We haven't defined a title variable. NameError: undefined local variable or method 'title' >> @title #An instance variable in the console => nil >> puts "There is no such instance variable." if @title.nil? There is no such instance variable. => nil >> "#{@title}" # Interpolating @title when it's nil "" |
You can see from this example that Ruby complains if we try to evaluate an undefined local variable, but issues no such complaint for an instance variable; instead, instance variables are nil if not defined. This code also explains why the code
Ruby on Rails Tutorial Sample App | <%= @title %> |
becomes
Ruby on Rails Tutorial Sample App | |
when @title is nil : Embedded Ruby inserts the string corresponding to the given variable, and the string corresponding to nil is "" .
The last example also shows an alternate use of the if keyword: Ruby allows you to write a statement that is evaluated only if the statement following if is true. There's a complementary unless keyword that works the same way:
>> string = "foobar" >> puts "The string '#{string}' is nonempty." unless string.empty? The string 'foobar' is nonempty. => nil |
It's worth noting that the nil object is special, in that it is the only Ruby object that is false in a boolean context, apart from false itself:
>> if nil >> true >> else >> false # nil is false >> end => false |
In particular, all other Ruby objects are true, even 0:
>> if 0 >> true # 0 (and everything other than nil and false itself) is true >> else >> false >> end => true |
4.2.4 Method Definitions
The console allows us to define methods the same way we did with the home action from Listing 3.5 or the title helper from Listing 4.2. (Defining methods in the console is a bit cumbersome, and ordinarily you would use a file, but it's convenient for demonstration purposes.) For example, let's define a function string_message that takes a single argument and returns a message based on whether the argument is empty or not:
>> def string_message(string) >> if string.empty? >> "It's an empty string!" >> else >> "The string is nonempty." >> end >> end => nil >> puts string_message("") It's an empty string! >> puts string_message("foobar") The string is nonempty. |
Note that Ruby functions have an implicit return, meaning they return the last statement evaluated—in this case, one of the two message strings, depending on whether the method's argument string is empty or not. Ruby also has an explicit return option; the following function is equivalent to the one above:
>> def string_message(string) >> return "It's an empty string!" if string.empty? >> return "The string is nonempty." >> end |
The alert reader might notice at this point that the second return here is actually unnecessary—being the last expression in the function, the string "The string is nonempty." will be returned regardless of the return keyword, but using return in both places has a pleasing symmetry to it.
4.2.5 Back to the title Helper
We are now in a position to understand the title helper from Listing 4.2:8
module ApplicationHelper # Return a title on a per-page basis. # Documentation comment def title # Method definition base_title = "Ruby on Rails Tutorial Sample App" # Variable assignment if @title.nil? # Boolean test for nil base_title # Implicit return else "#{base_title} | #{@title}" # String interpolation end end end |
These elements—function definition, variable assignment, boolean tests, control flow, and string interpolation—come together to make a compact helper method for use in our site layout. The final element is module ApplicationHelper: code in Ruby modules can be mixed in to Ruby classes. When writing ordinary Ruby, you often write modules and include them explicitly yourself, but in this case Rails handles the inclusion automatically for us. The result is that the title method is automatically available in all our views.