(March 2016)
Ruby is an interpreted language.
Statements end at the end of the line (like Python). The line continuation character is a backslash.
Everything is an object.
Ruby files are named like “my_file.rb”.
The Ruby REPL is ibr
.
The command line documentation utility is ri
:
% ri Float
% ri String.chop
The package manager is gem
.
# This is a single-line comment.
foo = "bar" # A comment after a statement
=begin
************************************************
This is a much longer multi-line comment that is
delineated by the '=begin' and '=end' directives (?)
before and after this comment. (The splats are purely
decorative.)
************************************************
=end
Simple math:
1 + 3 # => 4
2 * 2 # => 4
3 ** 2 # => 9 (exponential)
5 % 2 # => 1 (remainer)
Large numbers can be writting with underscore speparator (just for visual comfort):
1_999_999 == 1999999
String concatenation looks like:
"foo" + "bar" # => "foobar"
Interpolating a variable in a string looks like:
"Hello, #{name}. How are you?"
You can do stuff with strings:
"hello".capitalize # => "Hello"
"hello".reverse # => "olleh"
"hello".next # => "hellp"
"hello".upcase # => "HELLO"
"HELLO".downcase # => "hello"
"HellO".swapcase # => "hELLo"
"hello".length # => 5
"hello".empty? # => false
"hello".include? "hell" # => true
"hello".chop # => "hell"
"hello".reverse.reverse # => "hello"
Type coersion (converting between classes) can be accomplished like this:
3.to_s # => "3" (integer to string)
"3".to_i # => 3 (string to integer)
3.14.to_i # => 3 (float to integer)
3.to_f # => 3.0 (integer to float)
Use snake_case for variable and method names (and file/directory names):
my_foo = "Bar"
new_my_foo += "Baz" # => "BarBaz"
All caps constants:
PI = 3.14159265
Global variables begin with a dollar sign:
$global_variable = "foo"
Symbols start with a colon.
:a_symbol
Using symbols in an array of hashes:
widgets = [
{:color => 'red', :weight => 3},
{:color => 'blue', :weight => 22},
{:color => 'green', :weight => 11},
]
widgets.sort_by { |w| w[:color]}.each do |w|
puts "The weight is #{w[:weight]} pounds."
end
Arrays:
foo = ["foo", "bar", "baz", "bat"]
foo[0] # => "foo"
Arrays can contain mixed classes of objects:
bar = ["fred", 3, foo]
Some array methods:
foo.push('baz')
foo.length # => 4
foo.sort
foo.reverse
foo.delete(3) # Deletes all array element == 3.
foo + ["nerf"] # => ["foo", "bar", "baz", "bat", "nerf"]
foo - ["bar"] # => ["foo", "baz", "bat", "nerf"]
Populate an array:
my_array = []
for i in 0..99 do
my_array[i] = 1
end
Hashes:
zoo = {
"tiger" => "Mamal",
"turtle" => "Reptile",
"beetle" => "Insect"
}
Add one hash element:
zoo["whale"] = "Mamal"
Iterate through hases like:
zoo.each do |key, value|
puts key + " : " + value
end
Hash methods:
zoo.each_pair # Same as zoo.each
zoo.each_key
zoo.each_value
Use CamelCase for classes and modules:
class MyClass
...
end
Do loop:
# Prints "foo" three times
i = 3
i.times do # i can be a literal, like '3.times do'
puts "foo"
end
While loop:
i = 0
while i < 10
puts "Count: " + i.to_s
i += 1 # Ruby doesn't have a ++ increment or -- decrement operator.
end
Iterators:
colors = ["red", "blue", "green", "indigo"]
colors.each do |color|
puts "The color is: " + color
end
also:
colors.length.times do |i|
puts "Color: " colors[i]
end
also:
colors.sort.each do |color|
puts "Color: " color
end
Iterate through hases like:
zoo.each do |key, value|
puts key + " : " + value
end
if foo == "bar"
x = 1
elsif foo == "baz"
x = 2
else
x = 0
end
Function with no arguments:
def doSomething
puts "Something"
end
doSomething # => "Something"
Function with arguments:
def doSomethingSpecific(thing, my_default = true)
if my_default
puts thing
end
end
doSomethingSpecific("Pizza") # => "Pizza"
Yield:
def marines
yield("missle turret")
yield("bunker")
end
marines do |m|
puts "Unit: " + m
end
Also:
def players
yield("Jay", "LaBelle")
yield("Jake", "Kallie")
end
players do |first, last|
puts first + " " + last
end
Variables scopes vis-a-vis classes and objects:
Define classes like:
class Animal
attr_reader :species # Make @species readable from outside object
attr_writer :species # Make @species writable outside object
# attr_accessor makes the object value both readable and writable
def initialize(species)
@species = species # The @ denotes a object variable.
end
end
Instantiate an object from a class:
myAnimal = Animal.new("tiger")
Play with the object:
myAnimal.species # => "tiger"
myAnimal.species = "rabbit"
Another class:
class Vehicle
attr_accessor :wheels, :topSpeed, :passengerCapacity
def initialize
@wheels = @topSpeed = @passengerCapacity = ""
end
define to_s
"Vehicle with " + @wheels + " wheels " \
+ "and a top speed of " + @topSpeed \
+ " and a " + @passengerCapacity + " passenger capacity.\n"
end
end
Custom object iterators:
class Garage
def each
@vehicles.each {|v| yield v}
end
def eachTopSpeed
@vehicles.each {|v| yield v.toSpeed}
end
end
Public and private object methods:
class SomeClass
def method1 # default to public
...
end
private # subsequent methods are private.
def method2 # private method
...
end
def method3 # private method
...
end
public # Set back to public.
def method4 # public method
...
end
end
Inheritance:
class Motorcycle < Vehicle
def initialize(wheels, topSpeed, passengerCapacity, sidecar)
super(wheels, topSpeed, passengerCapacity)
@sidecar = sidecar
end
def to_s
super + "Sidecar: " + @sidecar
end
end
Exceptions
begin
statements which may raise exceptions.
rescue [exception class names]
statements when an exception occurred.
rescue [exception class names]
statements when an exception occurred.
ensure
statements that will always run
end
The last exception is stored in the $! variable (and its type can be determined using $!.type).
You can just use require to include one Ruby file in another. If the other file is a module, though, it provide a protected namespace.
module Foo
BAR = 3
def Foo.narf
# stuff...
end
end
Module used like:
require "Foo"
x = Foo::narf
Note that modules also provide mixin/superclass/multiple-inheritance functionality.
irb
is the REPL. pry
is an alternative, though not installed by default.
gem
is the package manager.
% gem search ^imap
% gem search ^easy_imap$ --details
% gem install easy_imap
% gem list
% gem uninstall easy_imap
ri
is the documentation viewer.
% ri rand
rake
is a gem that’s like make
for Ruby.
Ruby doesn’t seem to have a straight equivalent of Python’s virtualenv, but we can get a similar effect by setting some environment variable in activate.sh and deactivate.sh scripts for a project.
activate.sh:
export OLD_GEMHOME="$GEM_HOME"
export GEM_HOME="$PWD/gems"
export OLD_GEM_PATH="$GEM_PATH"
export GEM_PATH=""
export OLD_PATH="$PATH"
export PATH="$GEM_HOME/bin:$PATH"
deactivate.sh:
export GEM_HOME="$OLD_GEM_HOME"
unset OLD_GEM_HOME
export GEM_PATH="$OLD_GEM_PATH"
unset OLD_GEM_PATH
export PATH="$OLD_PATH"
unset OLD_PATH
Random:
1 + rand(6) # Random number between 1 and 6
Serialize and de-serialize objects:
require 'yaml'
x = [1, 2, 3, 4]
# Serialize to yaml object:
serialized = x.to_yaml
# De-searialize from yaml object:
de-serialized = YAML.load(serialized)
# Serialize to a file:
File.open('/path/to/file.yaml', 'w') { |f| f.write(YAML.dump(x)) }
# De-serialize from a file:
y = YAML.load(File.read('/path/to/file.yaml'))
Sqlite:
require 'sqlite3'
db = SQLite3::Database.new 'mydata.db' # ... or open() for an existing database.
db.execute 'CREATE TABLE foo (a, b, c)'
db.execute "INSERT INTO foo VALUES ('gold', 'coin', 7)"
x = [
['black', 'cube', 5],
['yellow', 'tire', 8],
['red', 'castle', 4]
]
query = db.prepare "INSERT INTO foo (a, b, c) VALUES (?, ?, ?)"
x.each do |a|
query.execute(a[0], a[1], a[2])
end