These are some very rough/sketchy notes that I took while doing the exercises on the introductory track of the Ruby language at codeacademy. They were written from the point-of-view of an amateur programmer in C and Python (read: "me").

Since this is my first time with Ruby and I only have about 1 week of experience with it, these notes are likely to contain many mistakes, many simplifications, many omissions or simply gross errors. I would love to be informed of such facts so that I can fix them and not write code that is burdensome for others to maintain.

Operators

  • Math operators: +, -, *, /, %, ** (just like Python)
  • Relational operators: ==, <, >, <=, >= (just like other languages)
  • Boolean operators: &&, ||, ! (just like C/C++/Perl)
  • The combined comparison operator ("spaceship operator", like Perl): <=> (follows the spirit of what strcmp in C does)
  • Conditional assignment operator (||=) only assigns a value to a variable if that variable is bound to nil.

Numbers

  • You can write number literals embedding an underscore (_) for readability purposes.

Basic I/O

  • Output: print and puts. Both print strings to stdout, but puts also appends a new line to the end.
  • Input: gets accepts an input from stdin and returns a string.
  • To convert a string foo to an integer, use the Integer(foo) constructor. It throws an exception if it cannot convert the value.

Strings

  • Strings have at least some methods: .length, .reverse, .upcase, .downcase, .capitalize, .chomp (like Perl, removes the trailing endline)
  • .upcase seems to have problems with non-ASCII characters, like é.
  • Interpolation is performed by putting the name name of the variable inside a string and delimited as #{name} at the place we want the interpolation to occur.
  • Methods like .capitalize don't change the string (they return a new string capitalized). To change the string, you call the method .capitalize! (with a ! at the end of the name of the method).
  • Other useful methods: .gsub for globally substituting a regular expression (and its variant .gsub! for inplace modification), and .include? to verify if the first string includes another.
  • Another method: .split(" "), to split on the string specified as argument.

Control flow

If

  • The syntax of a if is:

    if expression1
      block1
    elsif expression2
      block2
    else
      block3
    end
    

    note that it ends with the word end, there are no need for parentheses, no braces, no colons, and the keyword for "else if" is elsif (different from Python's elif).

  • The "if" can also be started with the keyword unless instead, which checks if the expression is false rather than true (as is the case of if).

While

  • The syntax of the while is similar to other languages:

    while condition
      block
    end
    
  • A variation of the while is the until, with the same syntax, except for the until in place of the while, and that it iterates when the condition is false, instead of true.

For

  • The simple case of iterating over a range of numbers is:

    for i in 1...10
      block
    end
    

    Like ranges in Python, the 10 is not included (the variable i iterates from 1 to 9).

    For an inclusive range, we use two dots (1..10), instead of three dots (1...10).

Loop

  • To iterate a block, we can use the loop keyword, as in:

    loop { block } # with braces
    

    or as in

    loop do # note the pair do/end in place of braces
      block
    end
    
  • It is useful to use break when using loop to break out of the infinite iterations.

  • Similarly, we can use next as in other languages (the same as continue in C or C++).

Arrays

  • The equivalent to Python's lists are arrays and they are declared in the same fashion:

    my_array = [1, 2, 3, 4, 5]
    
  • Arrays in Ruby are 0-based.

  • Every array has an iterator called the .each method. The basic syntax is:

    object.each { |item| block } # do something
    

    which can be written as:

    object.each do |item| block end
    

    where the name between | | is bound to (a copy of?) each element of object in turn. The equivalent in Python would be:

    for item in object:
        block
    
  • Arrays can be sorted with the .sort method (or its sibling .sort!). When passing a parameter, it is useful to use the spaceship operator (<=>) (like Perl) to specify a custom order (similar in spirit to what we do with Python's key argument to the sort method of a list). Example:

     my_array.sort! {|a, b| a <=> b} # Ascending order
     my_array.sort! {|a, b| b <=> a} # Descending order
    
  • The .push method appends an element to an Array (similar to Python's .append).

  • The empty Array is denoted by [], like an empty list in Python.
  • An iterator (like (1..10)) can be converted to an array with the .to_a method.

Hashes

  • A literal hash is defined by the syntax:

    my_hash = {
        "key1" => "abc",
        "key2" => 2,
        "key3" => false
    }
    

    Quite similar to the version in Python:

    my_hash = {
        "key1": "abc",
        "key2": 2,
        "key3": False
    }
    

    In fact, in Ruby 1.9, you can write, instead:

    my_hash = {
        key1: "abc",
        key2: 2,
        key3: false
    }
    

    which is very similar to Python or JSON.

  • The empty hash, OTOH, is defined by calling the constructor .new of the class Hash:

    my_hash = Hash.new
    

    The syntax used by Python can also be used: my_hash = {}

  • Iterating over a hash is done the same way as done for an array, but the .each method gives both the key and the value, as in:

    my_hash.each do |k, v|
      puts "#{k}: #{v}"
    end
    
  • To iterate only on keys, we use the method .each_key. To iterate only on values, we use the method .each_value.

  • A hash can be sorted with the .sort_by method (to sort by keys, values or any expression involving them) and since it can be ordered, we can reverse (in-place) the order of its elements with the .reverse! method. This makes Ruby's hashes to "taste" like Python's OrderedDict's.
  • When one initializes a hash, one can specify a default value to the .new method (e.g., foo = Hash.new(0)), which makes it convenient to do the equivalent of Python's defaultdict or Counter.
  • You can select part of a hash by using the .select method and giving it a block. For example:

    good_movies = movie_ratings.select{|k, v| v > 3}
    

Functions/methods

  • Functions in Ruby are defined with the word def (as in Python) and end with the word end, as other composite constructs. Example:

    def square(n)
      return n*n
    end
    
  • Parentheses are optional in Ruby, unless they create ambiguity. So, to call the function above, one can use any of the following:

    square(2)
    square 2
    
  • A function can take a block as a parameter (and this is what .each does, for instance).

  • Functions can take a variable number of elements with the splash operator (denoted by *), which puts the extra parameters in an Array (like Python).
  • Functions can have default parameters, which are set in the "prototype", just like in Python or C++.
  • If the return keyword is omitted from the method, Ruby uses an implicit return, where the value of the last executed expression is returned to the caller of the method.

Symbols

  • Any instances of a given symbol share the same ID. This is due to the fact that they are immutable.
  • Symbols start with a colon (:) and they can contain any character that is valid for a variable name.
  • It is possible to convert between a symbol and a string with the methods .to_s and .to_sym.

Comments

  • Single line comments use the hash symbol (#).
  • Ruby also has multiline comments, which are delimited by a line beginning with =begin and a line beginning with =end.

Lambda functions

  • A lambda function in Ruby is defined, as expected, as, for example:

    foo = lambda { |x| x.to_sym }
    
  • The basic differences between a lambda and a proc is that:

    • A lambda checks the number of elements that it receives, while a proc doesn't and assigns nil to parameters that it didn't receive (a proc seems to ignore extra parameter that it wasn't expecting).
    • When a lambda returns, the control goes back to the function that called the lambda, while when a proc returns, the control is returned also from the function that called the proc.

Classes

  • "Everything is an object in Ruby." (At least one exception are blocks).
  • To test if an object is of a given class, you use the method .is_a? on the object and the type as argument (e.g., foo.is_a? Integer)
  • The "null" value in Ruby is nil. It is equivalent to None in Python.
  • The only "falsy" values in Ruby are false and nil. The others are "truthy", differently from C/C++/Perl/Python.
  • For a given object, the method .object_id returns what is the "address" of that object.
  • Classes in Ruby are created with the syntax

    class ClassExample
        # body
    end
    

    (That is for a class that has is not derived from other regular classes).

  • Constructors in Ruby are called initialize. An instance of a class is created by calling the method .new on the class name (and passing parameters as needed for the initialize method).
  • Instance variables are named with 1 at sign (@) as a prefix. Class variables are named with 2 at signs (@@) as a prefix. Global variables are named with a dollar sign ($) as a prefix.
  • Class methods are declared inside a class prefixed with self. and they are called with the class name suffixed with the name of the method. For example, for a class MyClass, with a class method class_method, we call it as MyClass.class_method.
  • When overriding a method in a subclass, one can call the method from the parent class with the keyword super, as in super(arg1, arg2).
  • Ruby doesn't support multiple inheritance. In place of multiple inheritance, Ruby offers mixins.
  • To access one attribute, say @my_attrib, in Ruby classes, one usually creates two methods to manipulate it: a method with the name my_attrib, that returns the value of @my_attrib (a getter) and a method with the name my_attrib= that accepts a parameter to set @my_attrib to (a setter).

    There is syntatic sugar for creating both getters or setters.

    For a getter, you declare attr_reader :my_attrib (the member name as a symbol).

    For a setter, you declare attr_writer :my_attrib.

    If you need both a getter and a setter, then you can abbreviate them with attr_accessor.

  • All methods, by default, are public in Ruby. To explicitly mark something as public, you use the keyword public. To mark something as private, you use the keyword private.

Modules

  • You can import a module with the keyword require (as in Perl) and the name of the module in quotes.
  • One example of a module is the benchmark module, which provides the Benchmark class, which has the method .realtime, which takes a block and reports how much time it used.
  • To create a module, use a syntax similar to that of a class, but substituting the keyword class with module.
  • The scope resolution operator in Ruby is the double colon (::), like in Perl.
  • To create a method inside a module, you have to prefix it by the name of the module with a dot or with self., if you want to create a method to be called outside the module.

    The same also holds for creating class methods (as opposed to instance methods): they can be simply named self.foo to get a class method called foo.

  • While some modules are already "preloaded" by the interpreter (e.g., Math), others need to be explicitly loaded. We do this by using require 'foo' to load the module (in the file foo?).

Mixins

  • A mixin is the use of a module to "enrich" a class, adding "instance" methods of the module to the class.

    It is, in a sense, a way to have some of multiple inheritance in Ruby (without its headaches?)

  • Using the word include Foo imports the items of the module Foo in the current namespace for instances of a class.
  • Using the word extend Foo imports the items of the module Foo in the current namespace as class methods/attributes.

Conventions

  • Local variables are named in lower case, with parts separated by underscores, as in my_name.
  • Methods that return boolean values have a question mark (?) at the end of their name.
  • Methods that have destructive side-effects (like changing their input) have an exclamation mark (!) at the end of their name.
  • Code is indented by 2 spaces.
  • Like other languages, constants are written in all caps, with words separated by underscores. For example, MAX_VALUE.
  • Global variables are prefixed with a dollar sign (e.g., $Foo).
  • Classes are named in camel case (no initial lowercase).
  • The "poetic mode" in Ruby recommends one to omit the parentheses on function calls (whenever unambiguous) and, in essence, to write as little "bureaucracy" (like the explicit return keyword in methods).
blog comments powered by Disqus