IronShay

Ironing code, geek t-shirts and even presentations!

NAVIGATION - SEARCH

Learning Ruby in 15 Minutes

A problem I run into a lot when evangelizing IronRuby is the language barrier. Just like real life, people are scared when they visit a country where they do not know the local language. Same thing with C# developers who are afraid to learn other languages.

However, some languages are more easier to learn than others. For example, English would be much easier to learn than Hebrew. This is exactly the case with Ruby – it is a very easy-to-learn language and the title of this post is not a scam, I do mean to teach you all you need to know about Ruby in order to start working in the next 15 minutes. After you have these basics, my next post will be about IronRuby and the fundamentals you need to know when using it.

Sit tight, here we go.

Variables

Well, Ruby has a dynamic type system. This means that it really actually has a type system (unlike a lot of people think) but it is totally implicit. So to declare a variable you just write the name, followed by an equal sign and then the value:

# Creating variables
num = 1 # setting a variable named "num" with a numeric value of 1
str = "Hello" # setting a variable named "str" with a textual value of "Hello"
arr = [1, 2, 3] # setting a variable named "arr" with an array of 3 numbers - 1, 2 and 3
hash = { "key1" => "my value", "key2" => "another value" }  # creating a hash with key value pairs

# Reading variables
num + 1 # adding 1 to num
puts str # prints the value of str to the console
arr[0] # retrieve the first value of the array
hash["key1"] # retrieve the value from the hash with the key of "key1"

Symbols

Symbols are a cool thing in Ruby. They are used in various cases and you will identify them by the colon in front of their name. You can think of them as enum values – they are not strings but they are not variables either – they are there to be used as keys to other values. You will run into them a lot with hashes. For example, instead of the hash I created on the previous sample, the next one would be more “correct”:

hash = { :key1 => "my value", :key2 => "another value" }
hash[:key1]

Conditions

Conditions in Ruby are pretty straight forward:

if condition then
  # something
elsif other_condition then
  # somethng else
else
  # other something
end

The condition itself is very similar to C# – you use the == sign to compare between two values (or > and <). To concatenate multiple conditions, use the and and or keywords like if a > 1 and a < 5 then.

Additionally, Ruby conditions have a cool little twist – the unless condition. The unless condition is very similar to if. The difference between them is that unless is like if not. This means that you never need to write negative conditions like a != 1. Instead, you use the unless condition:

unless a == 1 then
  # something
end

Reverse Conditions

To enhance the readability of the code, Ruby offers something that is called “reverse conditions”. This language feature enables writing one-line conditions with the action to do before the condition. For example, the next statement adds 1 to variable a if a is greater than 5:

a = a + 1 if a > 5

Reverse conditions can be used with if as well as with unless.

Loops

Ruby features three loops out-of-the-box – while, until and for. while is the same as C#’s while:

while condition do
  #something
end

The until condition is similar to the concept of the unless condition – it is the same as while not:

a = 0
until a == 5 do
  puts a
  a = a + 1
end

The for loop is similar to the foreach loop in C# – it iterates through a collection:

a = [1,2,3]
for item in a do
  puts item
end
# prints
# 1
# 2
# 3

Apart for these loops, when coding Ruby you will find yourself using the enumeration capabilities of the different objects. For example, to run a loop 10 times, just use the times method of integer numbers:

10.times do |i|
  print i
end
# prints: "0123456789"

Another way, if you want to loop over all the number from 5 to 9, you can use the upto or downto methods of integer numbers:

5.upto(9) do |i|
  print i
end
# prints: "56789"

9.downto(5) do |i|
  print i
end
# prints: "98765"

In addition, to loop over collections, you can call their each method (instead of using the for loop):

a = [1,2,3]
a.each do |item|
  puts item
end
# prints:
# 1
# 2
# 3

Error Handling

Handling errors in Ruby is done very similar to C# or other languages. The flow is as such:

begin
  # something risky
rescue SomeException => s # catch specific exception type (SomeException) 
                                                        # and put in variable named s
  puts "Oh no!"
rescue Exception => x # catch all exceptions and put in x
  puts "Why??? Why???"
rescue # catch all exceptions without setting the exception to a variable
  puts "The horror!!!!"
end

Notice that only one rescue block will be executed. If multiple rescue blocks match the raised exception, the first match will be executed and the rest will be ignored.

Blocks

Blocks are very common in Ruby. Actually, every time you see code that is enclosed inside do and end keywords or curly brackets {}, you see a block. You can think of blocks as anonymous methods in C#.

So as mentioned, there are two ways to define a block – inside do and end keywords or inside curly brackets. There is no major difference between these two syntaxes but the common practice is to use curly brackets when you have only one line of code in your block and do-end on other cases.

When using Ruby methods and the different libraries, you will notice that a lot of methods retrieve blocks and execute them. In such a case, the block will be added to the method call at the end, after you pass all the other parameters. For example, the next code is totally legit:

my_method("some string param") do
  puts "Inside a block!"
end

Blocks can receive parameters as well. To specify the parameters, just write their names between vertical bars after the do keyword or after the opening curly brackets:

my_method("value...") do |param1, param2, param3|
  puts param1 + param2 + param3
end

my_method("value...") { |param1, param2, param3| puts param1 + param2 + param3 }

There are more types of code containers in Ruby like lambdas and procs and you will want to use them in slightly different scenarios. Anyway, I’m not going to discuss them here because they are not as common as blocks (but it is recommended you read a bit about them and know what they mean).

Methods

Methods are basically blocks with names… I guess this is a bit of a very generic definition but it’s generally what it is. The way to define a method is by using the def keyword, then the name of the method (method names in Ruby should start with a lowercase letter), then its parameters (if any), then the code and end at the end:

def method_name(param1, param2)
  # something
end

A method can be declared inside a class or outside it. In case you define it outside of a class, it will be available from anywhere within your code. When a method is declared inside a class, it is available only via a class instance (for instance methods) or the class object (for class methods).

Method Return Value

Any method returns a value in Ruby. You do not need to use any keyword (like return in C#) to return a value – the last statement return value will be returned to the caller.
For example, the next method will return 1:

def always_returns_1
  1
end

Additionally, you can use the return keyword to explicitly return a value. When the return keyword is used, it acts like in C# and also exits the method. For example, the next sample method always returns 1:

def always_returns_1
  return 1
  return 2
end

Calling Methods

Executing a method is very straight forward – just write its name and it will run. You should also specify parameters (if any) and pay attention here – parenthesis is optional.
For example, the next sample demonstrates the different method calls available:

def add(a, b)
  a + b
end
 
result1 = add(1, 2)
result2 = add 1, 2

Be careful when using parenthesis – the opening bracket must come exactly after the method name without any space. This means that add(1, 2) and add (1, 2) are not the same!

Classes

A class is an object that gathers methods, properties and variables that together generate a single logical unit, just like C# classes. The difference between C# classes and Ruby classes is that in Ruby, a class inherits from the Class object (which eventually is an Object object) and in C#, a class inherits directly from Object.

To define a class you start with the class keyword followed by the name of the class, which must start with an uppercase letter. For example, the next sample defines an empty class named EmptyClass:

class EmptyClass
  # Everything goes here
end

Instance Methods

To create instance methods, you just add method definitions inside the class definition (between the class name and the end keyword):

class MyClass
  def my_method
     # something
  end
  # more methods...
end

Constructor

Sometimes you need to run some initialization code when the class is created. This is done via a constructor method and in Ruby, the constructor is defined in a method named initialize.
For example, the next class will print “Hello there” when it is created:

class HelloClass
  def initialize
    puts "Hello there"
  end
end

Notice that a constructor method can retrieve parameters just like any other method. To do that, just specify parameters for the initialize method.

Class Methods

Class methods are like static methods in C# – they are methods which can be invoked without creating an instance of the class. To create a class method, use the self keyword before the name of the method. For example, instead of say_hello, name the method self.say_hello:

class MyClass
  def self.say_hello
    puts "Hello"
  end
end

Instance/Class Variables

Apart from methods, classes can contain variables. There are two kinds of variables:

  • Instance variables – they are instance-specific and are available to instance methods.
  • Class variables – they are shared between all instances of the class and are available to all methods of the class (both instance and class methods). Similar to static variables in C#.

Instance variables are declared with an at sign (@) in front of them. For example - @first_name. Class variables are declared with two at signs (@@) in front of them. For example – @@instance_counter.

This is very simple and I think the next list will make it even clearer:

  • first_name – local variable (available in the current scope only).
  • @first_name – instance variable (available in the current instance only).
  • @@first_name – class variable (available in all class instances).

Creating Class Instances

To create a class instance we use the new method on the class. This is a built-in behavior, just like the new keyword in C#. Calling the new method will eventually execute the class’ constructor (the initialize method).
For example, the next code contains a simple class definition with a constructor and afterwards I create an instance of the class:

class Hello
  def initialize
    puts "Hello"
  end
end

# Init the class
hello = Hello.new # prints "Hello"

If the initialize method contains parameters, you will need to pass them on the new call.

After the class instance exists, you can execute its instance methods using a dot. For example, the next sample contains a class definition and a method call afterwards:

class Hello
  def say_hello
    puts "Hello"
  end
end

hello = Hello.new
hello.say_hello # prints "Hello"

To execute class methods you don’t need to initialize a class instance and you just use the class name instead of the class instance:

class Hello
  def self.say_hello
    puts "Hello"
  end
end

Hello.say_hello

Using Code from Other Files

As your application grows, you will probably want to separate your code into several files to ease maintenance. Moreover, you will probably want to use Ruby libraries or even load .NET assemblies (with IronRuby). To do so, Ruby provides a method named require which retrieves the name of the file you want to load.

For example, the next sample will load a Ruby file named mylibrary.rb:

require 'mylibrary.rb'

You can also specify the full path to the file.

After you load a file with the require method, all the classes, methods, variables, whatever that exist in this file will be available in the current file (similar to the Add Reference concept in .NET).

[Loading .NET assemblies with IronRuby are done the same way but I will talk about it on the next post.]

Conclusion

Well, 15 minutes have passed and now you know all the basics of the Ruby language. You can now go to a Ruby restaurant and ask the waitress for a delicious meal with no worries. 
That is all you need to get started. That’s all. But if you like it, I do recommend you to learn more because Ruby have so much more to offer.

Stay tuned… the next post in this series will teach you all you need to know about IronRuby.

All the best,
Shay.

P.S. If you think something is missing from here, I need to clarify subjects, I need to delete it all or anything else, please let me know.



Comments (3) -

United Kingdom David Workman

Had a quick glance through and noticed a (admittedly common ;) ) error in your Exception handling.

Namely, a
    rescue
on it's own *will not* catch all exceptions. It will only catch exceptions that are derived from StandardError (which includes runtime exceptions and a majority of things you likely will want to catch). If you want to catch all exceptions you need to do
    rescue Exception
instead. Also, you missed the extremely useful and important parts of a general exception handler - 'ensure' (equivalent to 'finally' in some other languages) and 'raise' (without any arguments) to pass the exception on again because you just wanted to log it or something (should almost certainly be done in a 'rescue Exception' block as otherwise you're swallowing the exception silently)

Reply

United Kingdom David Workman

Also, reading further on, you put that class variables (with a @@) are like static variables in C#... they really aren't. In Ruby, a class variable with @@ are shared *between the entire hierarchy*. So you end up with this:

class Foo
  def initialize
    @@baz = "test"
  end
  def print
    puts @@baz
  end
end

class Bar < Foo
  def initialize
    @@baz = "more test"
  end
end

a = Foo.new
Bar.new
a.print #=> "more test"


There is a concept called 'class instance variables' that are closer to static variables in C#, but they are a bit more complicated to set up and understand... they are described well in the 'Metaprogramming Ruby' book which I think is a must-read for any ruby dev after a week or two of coding in the language Smile

Reply

Thanks @David! I'll incorporate your comments into the post. Thanks!

Reply

Pingbacks and trackbacks (7)+

Add comment