Scientific Programming II

Winter Seminar

Programming in Ruby


Installing Ruby

Windows

Install Ruby using the RubyInstaller. Other versions of Ruby can be found at the RubyInstaller website.

Mac OS X

Chances are you have Ruby installed already. Open /Applications/Utilities/Terminal.app and type

ruby --version

You should get an output like:

ruby 2.0.0p481 (2014-05-08 revision 45883) [universal.x86_64-darwin14]

Linux

You may have Ruby preinstalled, depending on your distro. Open a terminal and type

ruby --version

If you get an error, install Ruby using your distro's package manager.


IRB

irb is Ruby's REPL (read-eval-print-loop). When run from the command line, you will be presented with a prompt like this:

irb(main):001:0>

Here, you can type any Ruby code, have it evaluated, and the results printed out as output. It is very handy for testing bits of Ruby code.


Variables

Ruby is a dynamically typed language, meaning that variables do not need to specify types, since Ruby is very smart and can figure it out on its own. The following code snippet illustrates this:

x = 5
puts x # puts() is equivalent to println()
x = "Hello, world!"
print x # print() is equivalent to print()

First, x is an integer, then it is set to a string! In Java, this would be illegal, but Ruby is perfectly ok with it.


Functions

Ruby functions are many, many times more powerful than Java functions. Before we see how, let's look at a simple function:

def say_hello(name)
    puts "Hello, #{name}!"
end

say_hello("Mr. Davis")
say_hello "Sterling Archer"

This example illustrates a few important things about functions, and the Ruby language in general. Let's look at this function next to its Java equivalent:

public void sayHello(String name)
{
    System.out.println("Hello, " + name + "!");
}
def say_hello(name)
    puts "Hello, #{name}!"
end

Classes

Let's look at a simple class definition for a rational number, or fraction:

class Fraction
    def initialize(numer, denom)
        @numer = numer
        @denom = denom
    end

    def numer
        @numer
    end

    def denom
        @denom
    end

    def numer=(numer)
        @numer = numer
    end

    def denom=(denom)
        @denom = denom
    end

    def to_s
        "#{@numer}/#{@denom}"
    end
end

two_thirds = Fraction.new(2, 3)

puts two_thirds

two_thirds.denom = 4

puts "Two thirds is not #{two_thirds}!"

We've defined a simple class with two instance variables, numer and denom. There are setters and getters (using Ruby's awesome syntactic sugar), and even a method to convert the Fraction to a string!

Things to note:

However...this is not how we actually write classes in Ruby. That's a lot of typing, and we as Ruby programmers hate unnecessary typing. So, let's refactor this class into good, Ruby style:

class Fraction
    attr_accessor :numer, :denom

    def initialize(numer, denom)
        @numer = numer
        @denom = denom
    end

    def to_s
        "#{@numer}/#{@denom}"
    end
end

Much better! The keyphrase attr_accessor will automagically create getters and setters for each property (written as Ruby symbols when prepended with :). Using attr_writer or attr_reader will create only setters or getters, respectively. You can use any or all of these at once, for different properties.


Arrays

Ruby arrays are more akin to linked lists in Java, in that they are not bound to a specific size, or even stored type! Let's look at a quick example of Ruby arrays:

arr1 = []
arr2 = Array.new

arr1 << 1
arr1 << "Hello!"

arr2 << "I shouldn't print!"
arr2.pop
arr2 << 42

arr3 = Array.new(3, 5)

puts arr1    # => [1, "Hello!"]
puts arr2[0] # => 42
puts arr3    # => [5, 5, 5]

Control Structures

if and unless
x = 5

if x.eql? 42 then
    puts "So long, and thanks for all the fish!"
elsif x.eql? 5 then
    puts "X is 5!"
else
    puts "This is an else clause!"
end

There is also an "opposite if" expression in Ruby, called unless, which can be very helpful

x = 5

unless x.eql? 42 then
    puts "X is not the answer to life, the universe, and everything"
end
while and until
i = 0

while i < 10 do
    puts i
    i += 1
end

i = 0

until i.eql? 10 do
    puts i
    i += 1
end
Iterating over arrays
arr = Array.new(5) do |index|
    index * 2
end # Create an array of five elements, with each value being (index * 2)

arr.each do |elem|
    puts elem
end

arr.each_index do |index|
    puts "Element at index #{index} is #{arr[index]}"
end

Getting input
puts "Welcome to my program!"
print "Enter a number: "
num = gets.chomp!.to_i 
# Without the call to chomp!(), we would have the newline character as well
# to_i() will convert the string from gets() to an integer
puts "You entered #{num}!"