The Ruby Programming Language

David Flanagan, Yukihiro Matsumoto

O'Reilly Media, Inc.

Ruby is designed to make programmers happy. – Yukihiro Matsumoto, the creator of Ruby

Ruby is a completely object-oriented language, where every value is an object.

Ruby is a scripted language, so it executes the program starting with the first line and continues line by line until the end.

1.class     # => Fixnum: the number 1 is a Fixnum
false.class # => FalseClass
nil.class   # => NilClass

Because everything is an object, you can invoke methods on integers:

3.times { print "Ruby!" }       # => "Ruby! Ruby! Ruby!"
1.upto(9) { |x| print x }       # => "123456789"

You can also call iterators on arrays.

a = [3, 2, 1]

a.each do |el|
    print el+1
end

In Ruby, parentheses are optional.

Hashes are another data structure used to map key objects to value objects.

h = {
    :one => 1,
    :two => 2
}

h[:one]             # => 1
h[:three] = 3       # adds new key/value pair

h.each do |key, value|
    print "#{value}:#{key} "
end

Methods are defined with the def keyword.

def square(x)
    x*x
end

So Ruby has implicit returns and they call functions “methods” instead, it would be similar to this in TypeScript:

function square(x: number) {
    return x*x;
}

In Ruby, classes and modules are “open” so you can modify and extend them at runtime, the following code would override the Math module square function:

def Math.square(x)
    x*x
end

So even if something is part of the core you can easily customise it to suit your needs.

In Ruby you can assign more than one value at a time:

x, y = 1, 2

Methods can also return more than one value:

def coordinates(gps)
    # do something
    [x, y]
end

lat, long = coordinates(x)

In Ruby your functions can also end with ? or ! where a function like empty? returns a boolean, and delete! is used to signal caution. For instance, you could use sort() when working with immutable data, but sort!() when it would mutate the data.

You can also easily create ranges with ellipsis:

1..3        # All x where 1 <= x <= 3
1...3       # All x where 1 <= x < 3

This could be useful for switch statements:

generation = case birthyear
    when 1946..1963: "Baby Boomer"
    when 1964..1976: "Generation X"
    when 1977..2000: "Generation Y"
    else nil
end

Some things the author suggests to watch out for when getting started with Ruby is that strings are mutable, and values like 0 and "" are truthy (while in JavaScript they are falsy).

If you want to test Ruby and see the output, use the puts method as that will call the equivalent of toString() on each value, while print does more or less the same thing without adding a newline character.

To use the interactive shell use irb and to read the documentation use ri:

ri Array
ri Array.sort
ri Hash#each
ri Math::sqrt

Ruby also has symbols which are probably like atoms in Elixir:

:symbol     # A Symbol literal

And nil is used for null values, and it seems because everything is an object you can also call the nil? function to get a boolean value:

o == nil    # is o nil?
o.nil?      # another way

You can also easily get the class and superclass of objects because everything is an object… an interesting way of programming…

o.class
o.class.superclass
o.class == String
o.instance_of? String
o.is_a? Integer

You can also make objects immutable with the freeze method:

s = "water"
s.freeze
s.frozen?
s.upcase!   # Error: can't modify frozen string

I don’t really like the syntax without curly braces for functions that’s optional… either make it forced or not allowed… I find it a lot easier to reason about blocks of code if it has clear indentation and braces. Even parentheses are optional:

puts "Hello World"
puts("Hello World")

So even calling functions is done without parentheses, so it seems like magic:

greeting = "Hello"
x = greeting.length
x = greeting.length()   # same

x.class
x.class()       # same

That would probably make Ruby easier to adopt if you could see all the parentheses of these magic functions, it looks a lot more like PHP or JavaScript then.

Ruby has an excellent API for reflection which makes it a good candidate for meta-programming, which is writing programs to help you write other programs. This is great for generating DSLs or Domain-Specific Languages, such as this custom XML generator:

pagetitle = "Test Page for XML.generate"
XML.generate(STDOUT) do 
  html do
    head do
      title { pagetitle }
      comment "This is a test"
    end
    body do
      h1(:style => "font-family:sans-serif") { pagetitle }
      ul :type=>"square" do
        li { Time.now }
        li { RUBY_VERSION }
      end
    end
  end
end

The code has a lot of custom functions like head, comment, h1 that map to XML tags. That looks really nice… the rest of the meta-programming was a bit too complex for me at this stage but I have a much better understanding of what they mean when they use the term now.