The Ruby Programming Language

Lecture Notes for CS 142
Fall 2010
John Ousterhout

  • Readings for this topic:
    • Read Chapter 1 of The Ruby Programming Language, then skim Chapters 2-7 to get a feel for the operators, statements, and class facilities. You can read more of the details as you are working on the projects.
    • Read Sections 8.9 and 8.10 of The Ruby Programming Language. You will need this information for Project #2.
  • Ruby basics:
    • Scripting language (more dynamic, interpreted than Java)
    • Very dynamic, flexible: metaprogramming facilities (write programs that write programs)
    • Pure object oriented: absolutely everything is an object
    • Large language, many features
  • Simple code example:
    sum = 0
    i = 1
    while i <= 10 do
        sum += i*i
        i = i + 1
    puts "Sum of squares is #{sum}\n"
  • Syntactic differences from Java and C:
    • No variable declarations
    • Newline terminates statements (semicolons OK too)
    • do...end instead of {...}.
    • Optional parentheses in method invocation
  • Built-in datatypes:
    • Numbers:
      • Integer (Fixnum and Bignum)
      • Float
      • Complex
      • BigDecimal
      • Rational
    • Strings:
      • Single quotes (only a few backslash sequences)
      • Double quotes (lots of backslash sequences)
      • %q (like ''), %Q (like ""):
        s1 = %q(String contains quotes: '"')
        s2 = %Q|More quotes ("") and subs: #{x}|
      • Here documents:
        doc = <<END
        First line
        Second line
    • Symbols:
      • Notation: :foo
      • A string constant, more efficient in many situations
      • Typically used for unique identifiers such as variable and method names, hash keys, etc.
    • true, false, nil
    • Arrays:
      x =
      y = ["Alice", 23, 7.3]
      • -1 index refers to last element
    • Hashes:
      x =
      y = {"item" => "Corn Flakes", "weight" => 18}
      y = {:item => "Corn Flakes", :weight => 18}
    • Range: [1..20]
  • Variables:
    • Untyped: types associated with values, not variables
      • Any variable can hold any value
    • No declarations: variables created on first assignment
    • Variable scope determined syntactically:
      • $foo: global variable
      • @foo: instance variable in an object
      • @@foo: class variable
      • MAX_USERS: constant (by convention)
      • Anything else is a local variable
  • Operators and expressions: fairly similar to Java.
  • Statements:
    if x < 10 then
    elsif x < 20 
    while x < 10 do
    array = [14, 22, 34, 46, 92]
    for value in array do
    • No Java-like for loop
  • Methods:
    • Factorial example:
      def fac(x)
        if x <= 0 then
          return 1
        return x*fac(x-1)
    • Every method is associated with a class (default: private method of Object class).
    • Methods always return values:
      • Result of last expression
      • Default: nil.
    • Optional parentheses in method invocation (can be confusing)
      puts "Hello world"
      f (3+2)+1
    • Default values for arguments:
      def inc(value, amount=1)
    • Variable-length argument lists:
      def max(first, *rest)
        max = first
        for x in rest do
          if (x > max) then
              max = x
        return max
    • Name-value arguments: use a hash.
    • Can omit curly braces to supply value for last argument:
      def create_widget(size, properties)
      create_widget(6, {:id => "table22", :class => "Cart"})
      create_widget(6, :id => "table22", :class => "Cart")
  • Iterators, blocks, and yield:
    • Ruby makes it possible to define new control structures called iterators.
    • Example:
      oddNumbers(3) do |i|
        print(i, "\n")
      def oddNumbers(count)
        number = 1
        while count > 0 do
          number += 2
          count -= 1
    • do ... end is a block: a chunk of code passed to the oddNumbers method.
    • Blocks usually have arguments: i
    • yield invokes the block passed to the method, passing it arguments.
    • A block is a closure: it has access to all variables visible at the point of its declaration
    • Any method can be passed a block.
    • for loops are actually implemented as an iterator; the following 2 loops have identical behavior:
      array = [14, 22, 34, 46, 92]
      for value in array do
        print(value, "\n")
      array.each do |value|
        print(value, "\n")
    • each is a method implemented by the Array class; it iterates over the elements of its array.
    • Can use for on any object that supplies an each method.
  • Classes:
    • Example:
      class Point
        def initialize(x, y)
          @x = x
          @y = y
        def x
        def x=(value)
          @x = value
      p =,4)
      p.x => 3
      p.x = 44;
    • initialize method called during object construction
    • No direct access to instance variables: instead, define methods foo and foo=.
    • Methods can be public, protected, or private.
    • Inheritance: class Child < Parent
    • Duck typing:
      • No type-based restrictions on invoking methods
      • Can invoke a method foo on any object for which a foo method is defined.
  • Module: a group of methods that can be shared by many classes;
    • Similar to multiple inheritance or mixins.
    • Like the implementation of a Java interface.
    • Example: Enumerable
      • Your class implements each method.
      • Mix in the Enumerable module to get many additional methods.
        class MyClass
          include Enumerable
          def each
      • Example Enumerable methods:
        • sort
        • map: create a new collection by applying a block to each element
        • select: create a new collection of elements that meet certain criteria
        • min, max
  • Metaprogramming: programs that help you write programs
    • Reflection: like Java, can examine the state and structure of a Ruby program while it is running.
    • eval: can create new programs on-the-fly and execute them.
    • Can define new classes, methods, and modules on-the-fly.
    • The following code automatically defines accessor methods for x and y:
      attr_reader :x :y
      Class definition is not compiled, it's executed.
    • method_missing: can catch invocations of undefined methods:
      • Define new methods "just-in-time" when referenced.
      • Simulate the existence of a large variety of methods.
    • And much more... facilities for domain specific languages, etc.