Technology

Ruby, An Introduction to a Programmer’s Best Friend

11 Dec 2014 1:54am, by

Editor’s Note: The New Stack is a sponsor for RubyConf India. Leading up to the conference, The New Stack will feature posts by the speakers on topics about Ruby on Rails. We try to do this for all the conferences we sponsor. For example, we have been featuring posts by speakers from GopherCon, scheduled for February in Bangalore.

When I was first introduced to Ruby, I asked, “Why Ruby?”  I got two common replies:

  • It makes you think about programming differently (especially if you come from a non-OOP background).
  • It makes you happy.

Ruby was designed from a programmer’s point-of-view for productivity. Its syntax is elegant and it’s truly object-oriented.

Ruby is a dynamic, reflective, object-oriented, general-purpose programming language. It was designed and developed in the mid-1990s by Yukihiro “Matz” Matsumoto in Japan.

Matz’s idea for Ruby is clear from the below statement:

I was talking with my colleague about the possibility of an object-oriented scripting language. I knew Perl (Perl4, not Perl5), but I didn’t like it really, because it had the smell of a toy language (it still has). The object-oriented language seemed very promising. I knew Python then. But I didn’t like it, because I didn’t think it was a true object-oriented language — OO features appeared to be add-on to the language. As a language maniac and OO fan for 15 years, I really wanted a genuine object-oriented, easy-to-use scripting language. I looked for but couldn’t find one. So I decided to make it.

Here, I’ll walk you through an introduction to Ruby.

Let’s start off with the basics.

Strings:

There are some nice things happening here. The basic String interpolations work as you’d expect. You can concatenate Strings together with the + method. You can even “multiply” Strings.

So what’s the cool stuff? The way that it is implemented. For instance, the + method acts on  the String object “Hello, “”. The meaning of + depends on the object receiving that method. Here, it is an object of type String, where it means “add String ‘Matz’ to String ‘Hello, ‘“”.

Conventionally, methods with a ? at the end return boolean values. And methods with a ! perform some “dangerous” operation like mutating the String.

Everything is an object, including integers and floating point numbers. We’ll come back to this in a bit. For people familiar with object oriented programming, it’s nice to see that everything is object oriented, even basic operations like the addition of numbers.

Also notice that for every statement, the Ruby interpreter returns something, even if that something is nil. In Ruby, every statement is an expression and will result in a value.

Identifiers with their first character in the uppercase are constants.

Coming back to our String example, if we had an integer on the left hand side of a +, the + would result in addition of that and whatever was on the right hand side. Since Ruby allows you to reopen classes, you could open up the Fixnum class and redefine the + method to mean… subtraction! Although you might get fired, I’m sure it’d be fun for your entire team. Lol.

Greet is a simple class with a bunch of methods in it.

Variable Scope

There are four variable scopes:
– Global ($)
Global variables are available for use throughout your program.
– Class (@@)
Class variables are available to all instances (objects) of a class.
– Instance (@)
Instance variables are available only inside the current instance, ie., each instance has its own copy.
– Local
Local variables are limited in scope to within a method or a block.

The attr_accessor method sets up getter and setter methods for a list of variables. Simple things, but it saves you the time you’d spend doing something like:

‘… for every damn variable.

Did you notice how the attr_accessor accepted :name. That’s a symbol. It’s like a String, but it’s used like an identifier. They’re different from Strings and all symbols with the same name share the same memory.

the initialize method in a class is run on instantiation, ie., when the object is created. Objects are created with the .new method defined on the class constant.

You can omit the return keyword in Ruby. The last line executed in a block of code is the value that is returned.

Hold on, you can use methods on classes?! Remember I told you that everything was an object? Well, your class definition happens to be an object of type Class with the constant Greet pointing to it. Don’t believe me? Try it out for yourself.

The new method takes arguments which are supplied to the initialize method. Default values for method parameters can be specified using param=default_value in the method definition.

g is an instance of Greet.

Our getter and setter methods in action:

The last method show how you can use format specifiers and an Array of values to make up a String.

Arrays and Hashes

Arrays and hashes are used to store related data in Ruby. You can create a new Array or a Hash with:

Of course, they’re used quite often and can be created literally like this:

Arrays are nothing but a collection of references to objects. So they can store anything you’d like, including other arrays.

Just references to objects.
You can slice an Array any way you like:

Hashes are associative Arrays (like dictionaries) and hold key-value pairs. The keys and values can be an object of any type.

Usually though, they’re used with symbols as keys, so much so that they have their own shorthand syntax:

Values can be accessed like this:

Printing Objects

What if I want to print an instance of Greet? How does Ruby know what to print? Remember numbers are just objects as well, so I can do puts 23 and it outputs the String “23”. How does Ruby know how to convert an object of Fixnum and make a String out of it? If you look at all the methods in the Fixnum class, there’s a to_s method. puts simply calls the to_s method on the number 23.

Therefore, all we need to make instances of Greet printable is to define a to_s method. Let’s reopen Greet and add a to_s method.

if, unless, while, until, for

You can do this as well:

You can use the unless keyword in place of if when you do not want to perform an action if the condition is true.

Looping in Ruby is usually done using iterators, but the language does provide the while and for loops.

You can use until to loop while the condition is false, similar to a while loop.

For loops:

Range

Ranges in Ruby are used to define a set of values with a starting and an end. So if I wanted to loop over values from 0 to 5 I’d do this:

You can have character ranges as well.

Two dots: Inclusive of last value.
Three dots: Exclusive of last value.

Blocks and Iterators

Shouldn’t an object know how to iterate over itself? Just like a String should know how long it is.

“I am thirty-one characters long”.length

You can just as simply use .size for the length. Ruby, in some places, where it makes sense, has multiple methods that do the same thing. Use what feels natural.

Blocks and iterators in Ruby are really powerful and really useful. Most times you really aren’t interested in maintaining an Array index externally. You just want to loop over the damn thing! Here’s how you’d do it in Ruby:

It basically takes every element in the Array fruits and provides it as fruit to the block of code between the do … end. This is a block.

A block is basically a chunk of code that you pass to a method, not different from how you’d pass data as arguments. Let’s have a look at how you’d make your own iterator to give you a better understanding.

Let’s make an iterator that processes only every other element.

That might have been a bit overwhelming, so let’s break it down.

We reopen the Array class and on line 5 we create a while loop. It loops as long as current_index is smaller than the size of the original Array.

Line 6 is where the magic happens. We can call the block we passed to every_other with yield along with any arguments. Here, we pass an alternate element on each loop. Again, the elements are passed through the block of code that we passed  and we append the value returned by the block to new_array.

We then return the new_array once we are done.

{ |var1, var2| statements }
is the same as
do |var1, var2|
statement
end

On line 12, we call every_other on the Array [1, 2, 3, 4, 5] and pass it a block that takes one argument. That’s the argument we provide to yield in the method definition.

Basically, we took every alternate element and ran each of them through the block i ** 2.

For a more in-depth look at blocks, procs and lambdas, have a look at this brilliant article on Ruby Blocks, Procs, and Lambdas.

Comparable

Let’s say you define a new class and you want to sort an Array of those objects. Imagine the amount of work that you’d have to do. Ruby has an elegant solution.

Okay, so we have a person class. Each person has a name and an age. You include the Comparable module which comes with a whole suite of goodness. All it requires you to do is define a method, ⇔, that returns -1, 0, or +1 for less than, equal to or greater than cases.

On line 32, we do just that. Other is another object that has an age attribute. We compare the age values of this person and the other person. Since the ⇔ method has already been defined for numbers, we need not bother ourselves with anything else.

We create a list of people and call sort on it. And voila! All the persons are sorted by their ages.

Similarly, you can make your class enumerable, but we’ll leave that for another time.

Check out this page for more information

Composition vs Inheritance

Zed Shaw has a brilliant section devoted to this. While inheritance is a useful, composition is usually a better way to achieve the same sort of functionality without having two classes that are tightly coupled and probably hard to test.

Ruby has only single inheritance, so even if you go with inheritance, you won’t end up with the diamond problems.

You saw how Ruby uses composition is the previous section when we included the comparable module into our class.

an_object = Baz.new # an_object now comes with all the methods in Foo.

an_object.extend(Bar)   # an_object now has the methods in Bar, but all other instances of Baz are unaffected

Ruby supports a lot of advanced metaprogramming features. It allows things like evaluating a String to define a new method during runtime.

You can use the method respond_to? to check if an object responds to a particular method.

Regular Expressions

Ruby has a Perl-like regex syntax, with regular expression literals written using the /…/ syntax.

A lot of programming involves dealing with Strings of text, so regular expressions are extremely useful

Ruby comes with a neat command-line debugger, quite similar to GDB, so if you’re ever stuck, you can always run your program with the debug flag.

The Ruby documentation is brilliantly written, so if you want to learn more about a particular part of Ruby, that should be where you first look.

Gems

Ruby comes with its own package manager. The Gemfile in your project maintains a list of gems (packages) that your code depends on, and a single command will install all the necessary packages that your program needs to run. Version numbers may be included

You can even have groups of gems different for development and production, too!

Rails and DSLs

Rails was Ruby’s killer app and what made it the cool kid on the block back around 2006. Since then Ruby has matured as a language and Rails as a framework. Rails wouldn’t be what it is without Ruby. Ruby allowed Rails to make elegant uses of its syntax and structure. If you are a web developer, you have got to go try out Rails for yourself. ‘Nuff said.

Rails and other applications make use of Domain Specific Languages when it’s better to take the programming language to the background. Ruby, with its strong support for metaprogramming, allows you to transform what would otherwise be a mess.

Here’s more on how to create your own internal DSL.

Conclusion

Ruby is a brilliant language…

At the end of the day, even if you don’t use Ruby in your day-to-day life, learning it will open your mind up to some brilliant concepts and will definitely change how you think about programming.

“A language that doesn’t affect the way you think about programming is not worth knowing” — Alan Perlis

Ruby lives up to its name of being a language for the programmer. It doesn’t make you want to pull your hair out. You will just want to write more Ruby code.

For some very interesting articles for people who are already familiar with Ruby, you should see this page.

Darshan is a engineering student and web developer with a passion for computers, flying and hacking.

A newsletter digest of the week’s most important stories & analyses.

View / Add Comments

Please stay on topic and be respectful of others. Review our Terms of Use.