1. Ruby

Ruby is a dynamic, reflective, object-oriented, general-purpose programming language.

1.1. "Hello, World!" Ruby program

puts 'Hello, World!'

1.2. Executing Ruby source files

Ruby source files are by convention marked with the .rb extension. To execute the hello world program you have to save it into a file, e.g. hello.rb. You can then run it from the command line.

ruby hello.rb
Hello, World!

If you want to omit the ruby before your file name you have to add a shebang line as the first line in your file.

#!/usr/bin/ruby

If you are using a Unix-like operating system you also have to make the file executable with chmod.

chmod +x hello.rb

1.3. The Ruby console

The Ruby console offers a quick way to execute Ruby code. It allows you to type in Ruby commands and evaluates them. You can call it from your terminal by issuing the command irb. Type in our hello world program:

puts 'Hello, World!'

Press enter→ and the code will be executed.

You can even prototype methods and classes inside the console.

irb(main):001:0> def reverse(ary)
irb(main):002:1> ary.reduce([]) { |a, e| a.unshift(e) }
irb(main):003:1> end
=> :reverse
irb(main):004:0> reverse([1, 2, 3, 4])
=> [4, 3, 2, 1]

2. Installation of Ruby

2.1. Installation with rbenv

rbenv is a small tool that allows you to install multiple ruby versions and switch between them on the fly.

Add this to your bash file (ubuntu: ~/.bashrc) and restart your console:

eval "$(rbenv init -)"

Install build dependencies:

apt-get install autoconf bison build-essential libssl-dev libyaml-dev libreadline6-dev zlib1g-dev libncurses5-dev libffi-dev libgdbm3 libgdbm-dev

You can now build and install the newest ruby version.

rbenv install 2.3.1

You now have to set the default ruby version you’d like to use and you are good to go.

rbenv global 2.3.1
ruby -v

3. Debugging

3.1. Debugging with print statements

The easiest way to debug a ruby program is to use print statements. This has the advantage that it works out of the box, without any extra dependencies.

number = 5
puts number
=> 5

While puts is very useful, it also has it’s limitations.

ary = [1, 2, [3, 4]]
puts ary
=> 1
=> 2
=> 3
=> 4
=> 5

Thankfully Ruby has a pretty print class that can print out arrays and other enumerables in a more meaningful way.

require 'pp'
ary = [1, 2, [3, 4]]
pp ary
=> [1, 2, [3, 4]]

Some useful methods to use in conjunction with 'puts' are

  • instance_variables: all instance variables of the object

  • methods: all available methods of the class instance

  • methods(false): without inherited methods

  • instance_methods: all available methods of the object instance, get’s called on the class itself

  • instance_methods(false): without inherited methods

Because of Rubys nature of being a dynamic language it’s not always clear which code actually gets called by a statement but we have a way to find out.

puts some_object.method(:method_name).source_location
=> ["/path/to/file.rb", 13]

Sadly this approach won’t work for 'super', since you can’t create a method object from it. To find out which code get’s executed by 'super' it is possible to traverse the classes ancestors and look for the method definition.

self.class.ancestors.each do |klass|
  puts klass.instance_method(:method_name).source_location if klass.method_defined?(:method_name)

To find out the calling methods it is possibly to print the stack trace.

def a
  b
end

def b
  puts caller
end

a
=> /path/file.rb:2 in 'a'
=> /path/file.rb:9 in '<main>'

If your program makes use of a framework like Rails or Sinatra your stacktrace might be quite convoluted. It might be useful to filter the stack trace by your project name.

puts caller.select { |line| line.include? 'project_name' }

or

puts caller.select { |line| line['project_name'] }

3.2. Debugging with pry-byebug

Interactive step-by-step debugging can be done with pry-byebug, which adds debugging and stack navigation to the ruby console pry. To use it you have to add it as a dependency to your project. If your project uses bundler must you add it to your Gemfile.

group :development do
  # your other dev dependencies
  gem 'pry-byebug'
end

If you don’t use bundler you may add it to your *.gemspec file.

Gem::Specification.new do |s|
  # ...
  s.add_development_dependency 'pry-byebug'
end

Now you can add breakpoints in your code where you want to jump into a pry session.

require 'pry'
binding.pry

Since this is ruby code you can make your breakpoint conditional.

binding.pry if user.deleted?

Once you have entered pry you can execute statements like you would normally do in your ruby console but you also have byebugs debugging capabilities at hand.

    2:  def factorial(n, acc = 1)
    3:    binding.pry
=>  4:    return acc if n <= 1
    5:    fact(n - 1, n * acc)
    6:  end

pry(#<Math>)> n
=> 4
pry(#<Math>)> acc
=> 1
pry(#<Math>)> next

    2:  def factorial(n, acc = 1)
    3:    binding.pry
    4:    return acc if n <= 1
=>  5:    fact(n - 1, n * acc)
    6:  end

pry(#<Math>)> n
=> 4
pry(#<Math>)> continue

    2:  def factorial(n, acc = 1)
    3:    binding.pry
=>  4:    return acc if n <= 1
    5:    fact(n - 1, n * acc)
    6:  end

pry(#<Math>)> n
=> 3

You can also move around the callstack with the commands 'up' and 'down'.

The complete list of available commands can be found in the pry-byebug documentation.

If you need more assistance we offer Online Training and Onsite training as well as consulting