In our last section I introduced some Ruby programming basics. Now we’re moving in to methods and classes.
chomp() are called methods. In our above example,
gets() accepts a single line of data from the user and assigns the string to
name. So how can we know what methods are available to us as programmers? The all-knowing, all-powerful Ruby Docs.
chomp barely scratch the surface. We can do things like count the number of characters or lines in a string or file, reverse the lines of a string or file, cut a string apart and join it in alphabetical order, or operate all methods on it at once. For example:
puts "I am a Rubyist Historian".length() #=> 24 puts "Learning some Ruby-fu".reverse() #=> uf-ybuR emos gninraeL puts "Ruby is fracking awesomesauce.".split("").sort().join() #=> .Raaabcceeefgiikmnorsssuuwy
Run this in the terminal and you should get the commented results. For the first example, we would technically say that we are invoking the length method on object “I am a Rubyist Historian.” (Or, even more abstractly, “I am a Rubyist Historian” is an object of type string.) Everything before the period is the receiver while everything after the period indicates the method(s) you wish to invoke upon the object.
We can also create methods. We’ll return to our original “hello, name” program. But this time we’re going to write our own method and invoke it. Methods are defined with the keyword
def followed by the method name and the method’s parameters between parentheses (parentheses here are optional, but I use them for readability’s sake. Remember, if you do not use parentheses you need to have a single space in its place, e.g.,
name hello is the same as
name(hello)). So to build a new “hello, name” program using a defined method, we could write:
# defining function 'hello' to ask # for parameter 'name' def hello(name) 'Hello ' + name end puts "Please enter your name: " name = gets.chomp puts hello(name)
NB: Indentations does not matter to Ruby, but for readability’s sake, we include them.
Become very familiar with defining functions. This allows us to define functions for later use and set code apart to keep the program organized (as Prof. Steve Ramsay persistently reminded us in his course, programs are designed for people to read, not just computers). You also want to avoid redundancy. As a final note, what happens inside of functions is not visible outside the function. We can make things visible by using the global variable (adding $ to the beginning of the variable you want visible, e.g.,
$result) but, as Prof. Ramsay warned us: global variables are evil. No, really, they are. The last thing you’ll want is a global variable to plague parts of your code without your knowledge.
Similarly to methods, we can define classes in Ruby. Recall that Ruby is an object oriented programming language. By using classes, we’re fully entering the realm of OOP and learning how to create our own objects. We know that objects are closely allied with a type (object of type string, for example) and that certain behaviors go with certain objects. Objects are a data structure and a state, and also have behaviors that we call methods.
Ruby classes are templates for creating new kinds of objects. Classes are created by using the
class keyword, and take note that classes are capitalized and methods are lowercase. By using OOP we are making data central through what’s called procedural programming where we’re defining relationships between and among objects.
Let’s say you wanted a program that allowed you to input author names and ISBNs. First we define the class starting off the definition with
class followed by the class name, capitalized:
class Books # . . . end
We’ll use the
initialize method here, which allows programmers to set the state of constructed objects. We store these as instance variables inside the object, which we incidate through the use of the
@ symbol. This makes variables visible within a class – this is not a global variable. But the instance variables means we can allow each object to have its own unique state.
initialize is a special method in Ruby. Ruby allocates memory to hold
uninitialized objects and then calls the object’s
initialize method. The method passes any parameters that were passed to
Enough talk, let’s write the code and explain things further:
class Books attr_accessor :fname, :lname, :isbn def initialize( fname, lname, isbn ) @fname = fname @lname = lname @isbn = isbn end def to_s @lname + ", " + @fname + ", ISBN: " + @isbn end end author = Books.new("Walt", "Whitman", "1234567890") puts author
What we’ve done here is passed the instance variables
@isbn a string by calling the class constructor
Books.new(“Walt”, “Whitman”, “1234567890”)). We could just as easily said
Books.new(“William”, “Shakespeare”, “1234567890”). Note that
attr_accessor is not declaring an instance variable, it’s only creating the accessor methods. Ruby decouples instance variables and accessor methods.
Books takes three variables,
isbn. These parameters act like local variables within the method and follow the same lowercase naming convention. Yet, if we kept them as local variables they would vanish once
initialize returned. So, we use an accessor to keep the variables usable throughout the class.
Note also that we redefined the
to string (.to_s) type cast as well. By default, when Ruby uses
puts it calls on the
.to_s type cast to convert data into a string. But we want
.to_s to be more useful. We can override the default implementation to display whatever we’d like it to display.
- Ruby Class Tutorial, Juixe Techknow
See something that’s wrong? Examples that don’t work? Explanations that are unclear or confusing? Embarrassing typographic errors? Drop me an email at jason.heppler+feedback at gmail and I’ll fix things right up!
Topic structure, examples, and explanations for the Rubyist Historian are inspired by, credited to, and drawn from Stephen Ramsay and his course Electronic Text.