Anthony Su

coding adventures

Ruby Jumpstart

This posts is an introduction to Ruby and aggregates information I have learned from Codeacademy and Programming the World Wide Web and Agile Developement with Rails

Please visit here for a full list of documentation and sources on the ruby language. Another interesting resource is the Ruby’s User Guide, originally written by Yukhiro Matsumoto.


Table of Contents

1 - Origins and Uses of Ruby
2 - Naming Conventions
3 - Scalars
4 - Input and Output
5 - Control Statements
6 - Code Blocks and Iterators
7 - Procs and Lambdas 8 - Control Statements
9 - Fundamentals of Arrays
10 - Hashes
11 - Methods
12 - Sorting
13 - Pattern Matching
14 - Classes
15 - Modules

Origins and Uses of Ruby

Ruby was created in Japan by Yuki “matz” Matsumoto and was publicly released in 1995. Ruby blended parts of his favorite languages (Perl, Smalltalk, Eiffel, Ada, and Lisp) to form a new language that balanced functional programming with imperative programming.[1] Ruby has achieved mass acceptance especially with the quick growth of Rails, the web application framework created by 37signals

One interesting aspect about Ruby is that everything in Ruby is an object meaning that there are instance variables with methods. Recall that in other languages such as C, primitive data types (like integers and characters) are not objects.

1.http://www.ruby-lang.org/en/about/

Everything in Ruby is an object.

Naming Conventions

Local variables, method parameters, and method names should all start with a lower case letter or underscore: box, water_bottle, g6. Instance variables should begin with an “at”@ sign, such as @id, @telephone_number The convention is to use underscores to separate words in a multiword method or variable name water_bottle as opposed to waterBottle.

Class names, module names, and constants muststart with an uppercase letter. By convention they use capitalization, rather than underscores, to distinguish the start of words within the name. Class names look like Object, PurcharseOrder, and LineItem. This naming convention is also known as upper camel case, since the shape of the lettering looks like the humps of camel.

Rails uses symbols to identify things. In particular, symbols are used when naming method parameters and lookingthings up in hashes Symbols are prefixed with colons : like :action or :id

Naming Examples
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#local variables method parameters
watch
ti89
xbox360
@zip\_code

#Class Names, module names, constants
Shape
MusicInstrument

#symbols
:id
#symbol Example
redirect\_to :action => "edit", :id => params[:id]

# Replace \_ with underscore. Need \ to escape underscore in markdown.

By convention class names, modules names and constants use capitalization to distinguish the start of words within the name. This is known as upper camelcase
because of its shape.

Scalars

Ruby has three categories of datatypes - scalars,arrays and hashes. There are two categories of scalar types numerics and character strings. Recall that everything in Ruby is an object.

Numeric Literals

All numeric data types in Ruby are descendants of the Numeric class. The immediate child classes of Numeric are Float and Integer. The Integer class has two child classes Fixnum and Bignum.
An integer literal that fits into the range of a machine word, which is often 32 bits, is a Fixnum object (minus 1 bit). If the integer exceeds the size of the the Fixnum object then it is coereced into a Bignum object. There is no length limitation(other than the computer’s memory size) on integer literals.

Underscore characters can appear embedded in integer literals, which helps readability.

Underscores in numeric literals
1
2
3
4
5
  1\_000 * 3
   #=> 3000 

  # Replace \_ with underscore. Need \ to escape underscore in markdown.

A numeric literal that has either an embedded decimal point or a following exponent is a Float object and uses the machines double precision floating point architecture. A decimal point must be both preceded and followed by at least one digit so .35 is not valid.You must use 0.35.

A decimal point must be both preceded and followed by at least one digit.

String Literals

All string literals are String. There are two categories of string literals, single quoted and double quoted. Single quoted literals cannot include characters(other than single quote characters) specified with escape characters. You can specify a single quote delimiter by preceding the delimiter with a %q. If the new delimiter is a parantheses, brace, bracket, or a point bracket, the corresponding closing element must be used.

Single quoted strings
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15


  'It\'s good'
  #=> It\'s good

  'Roses are red, \n violets are blue'
  #=> Roses are red, \n violets are blue

  %q$I don't know$
  #=> 'I don't know'

  %q{You don't know?}
  #=> 'You don't know?'


Double quoted strings differ from single quoted strings in two ways: 1. They can include special characters in escape sequences 2. The values of variables names can be interpolated into a string. With string interpolation a block of code between #{ } is evaluated and then converted into a string.

With string interpolation a block of code between #{ } is evaluated and then converted into a string.

Finally a different delimiter can be used by preceding the delimiter with a %Q.

Double quoted strings
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
 "That's cool"
 #=> That's cool

 %Q@That's cool@
 #=> That's cool

 "That's \t cool" #escape sequence for tab
 #=> That's     cool

 puts "3 + 3 = #{3 + 3}"
 #=> 3 + 3 = 6

 six = 6
 puts "3 + 3 = #{six}"
 #=> 3 + 3 = 6


Numeric Operators

Most of the operatoirs in Ruby are similar to those in other common languages like + for addition, - for subtraction, * for multiplication, / for division.

Note however that Ruby does not support increment(++) and decrement(–) operators. Note that ** is the exponentiation operator.

Exponentation in Ruby
1
2
3
4
 2 ** 3

 #=> 8

Operators can also serves as methods. * can be used for repetition and + can be used for string concatenation.

String Repetition in Ruby
1
2
3
4
5
 "Hello " * 3

 #=> Hello Hello Hello


Ruby does not support increment and decrement operators.

String Methods

The + symbol and << symbol are used to concatenate strings.

String Concatenation
1
2
3
4
 "Hello" + "World"
 #=> "HelloWorld" 
 "Hello" << "World"
 #=> "HelloWorld"

There are many String methods in Ruby.

Ruby method names can end with an exclamation mark(a bang or mutator method) or a question mark(a predicate method). A bang method changes the object in place. A predicate method indicates that a method is boolean: returns true or false.

A bang method is a method name ending with a ! and changes the the object in place.

Bang Method
1
2
3
4
5
6
7
8
9
10
11
  str = "String"
  #=> "String" 
  str.upcase
  #=> "STRING" 
  str # str is not modified
  => "String"
  str.upcase!
  #=> "STRING" 
  str # str has been modified in place
  #=> "STRING

A few String methods are summarized below.

capitalize Convert first letter to uppercase and the rest to lowercase
chop Removes the last character
chomp removes a new line fro mthe right end, if there is one
upcase converts all of the letters in the object to uppercase
downcase converts all of the letters
strip Removes the spaces on both ends
lstrip Removes the spaces on the left end
rstrip Removes the spaces on the right end
reverse Reverse the characters of the string
swapcase Converts all uppercase letters to lowercase and all lowercase letters to uppercase

Strings can also be accessed by an index where 0 is the first position. If a negative index is used, the index starts at the back where the last character is -1. Strings can also be index like [index,length].

String Indexing Examples
1
2
3
4
5
6
7
8
9
10
 "12345"[0]
 #=> 1

 "12345"[-5]
 #=> 1

 "12345"[-5,3]
 #=> "123" 


Input and Output

Sometimes you may want to work with Ruby on the command line. One way is to run irb on the command line to start the Interactive Ruby Shell and then experimenting with Ruby in the console. You can execute a script by running ruby scriptname The -c flag can be used to check syntax. For a full set of flags run man ruby You can also execute a script by putting #!/usr/bin/env ruby at the top of your script and running your script like so ./scriptname If you use this method make sure that your script is executable by running chmod +x. Generally ruby scripts end with the extension .rb

Output

print is used to output a string. puts behaves like print but adds a newline to the end of output.

Output Exaple
1
2
3
4
5
 print "Hello"
 #Hello => nil 
 puts "Hello"
 #Hello
 #=> nil 

puts behaves like print but adds a newline to the end of output

Input

gets is used to retrieve a line of input from the keyboard. The parsed input is a string, and you can use string methods to filter the string. Use methods such as to_i or to_f to convert the input into an integer or float respectively.

Input Example
1
2
3
4
num = gets.chomp.to\_i
#removes newline character from input and converts input to an integer
#=> 9123 
# Replace \_ with underscore. Need \ to escape underscore in markdown.

Control Statements

Control Statements are used to control execution flow of a program.

Control Expressions

Control Expressions are logical expressions used to for control statments. A relational operator has two operands and an operator Relational Operator

== equals
!= not equals
< less than
> greater than
<= less than or equal to
>= greater than or equal to
<=> Comparator: for a <=> b returns 1 if a > b , -1 if a < b, and 0 if a == b This operator is also very help for sorting.
eql? returns true if parameter and reciever object have same type and value.
equal? returns true if parameter is the same as the reciever object. Effectly checks for same references.

Relational Operators
1
2
3
4
5
6
7
8
9
10
11
12
13
"thunderstorm".eql?("thunderstorm")
 #=> true 

 "thunderstorm".equal?("thunderstorm")
 #=> false 
 # both thunderstorms refer to different objects

 str = "thunderstorm"
 #=> "thunderstorm" 
 str2 = str
 #=> "thunderstorm" 
 str.equal?(str)
 #=>true
Operator Precedence and associativity

Operator precendence specifies the order in which operations should be carried out. The following operators are listed in precedence from greatest to least (in descending order). Operators on the same line have the same precedence. Associativity tells you how to evaluate operations if two or more operators have the same precendence either start evaluating from the left or right. If operators are nonassociative that means that these operators cannot associative with themselves.

Associativity Example
1
2
3
4
  3 + 7 - 4
 #=> 6
 #Left Associativity
 #(3 + 7) -4
Nonassociative Example
1
2
3
 1 < 2 < 3
 # < is a nonassociative operator
 #NoMethodError: undefined method `<' for true:TrueClass

** Right

Operator Precedence
1
2
3
4
 2 ** 2 ** 3

 #=> 256
 # 2 ** ( 2 ** 3) => 2 ** 8

!, unary + and - Right
Here is a pretty interesting article on how to define your own unary operator

Unary Operators
1
2
3
4
--------+-+ 3
#=> -3
-+3
#=> -3

*, /, % Left
+, - Left
& Left
> , <, >= , <= Nonassociative
==, !=, <=> Nonassociative
&& Left
|| Left
=, +=, -=, *=, **=, /=, %=, &=, &&=, ||= Right
not Right
or, and Left

and and or are control-flow modifiers like if and unless

More about using and vs &&

Selection statements

Selection statements are used for conditional branching of execution.

Selection Statements
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
    if num == 1
      puts "one"
    elsif num == 2
      puts "two"
    elsif num == 3
      puts "three"
    else
      puts "I don't recognize this number"
    end

    case num
    when 1 then puts "one"
    when  2
      puts "two"
    when 3
      puts "three"
    else
       puts "I don't recognize this number"
    end

The case construct is the equivalent of a switch statement in other programming languages.

The then keyword following the when clauses can be replaced with a newline.

Loop Statements

Loop of statements repeatedly executed until a terminiting condition.

Loops in Ruby
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
 i = 10
 loop do
   i -= 1
   next if i % 2 == 1 #continue to next iteration if odd
   print "#{i}" #string interpolation
    break if i <= 0 #terminating condition that breaks out of loop
  end

  #=> 86420

  for num in 1...10 #up to but not including (exclusive)
      print num
  end

  #=> 123456789

  for num in 1..10 #up to including (inclusive)
      print num
  end

  #=> 12345678910

… and .. are range operators for exclusive and inclusive ranges.

next is the equivalent of a continue statement in other programming languages. The program continues to the next iteration of the loop.

Although if statements are fairly common in Ruby Applications, looping constructs are rarely used. Block and iterators often take their place.

In Ruby, looping constructs are rarely used. Instead, block and iterators take their place.

Code Blocks and Iterators

Code Blocks are groups of code between do … end or curly braces {}. By convention do…end is used for multiline blocks where as {} is used for single line blocks. do/end vs curly braces

Iterators are methods used to invoke blocks repeatedly. Note that blocks can accept parameters that are delimited like so |parameter|

times Iterator
1
2
3
4
5
6
7
8
9
10
11
12
10.times{|x| puts x}

# 0
# 1 
# 2
# 3
# 4
# 5
# 6
# 7
# 8
# 9
each Iterator
1
2
3
4
5
6
7
8
9
10
11
12
fruits = ["apple","rasberry","lemon","cranberry"]

# each element is fruit is passed as an argument to the block
# fruit is variable name of  the parameter in the block
fruits.each {|fruit| puts "#{fruit} pie"}
# apple pie
# rasberry pie
# lemon pie
# cranberry pie

# returns the fruits array
# => ["apple", "rasberry", "lemon", "cranberry"] 
Iterating over Hashes
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
ratings = {
  memento: 3,
  primer: 3.5,
  matrix: 3,
  skyfall: 4,
  uhf: 1,
}

good = ratings.select {|k,ratings| ratings > 3}
#=> {:primer=>3.5, :skyfall=>4} 
#=> is equivalent to { primer: 3.5, skyfall: 4}

ratings = {
  memento: 3,
  primer: 3.5,
  skyfall: 4,
  uhf: 1,
}


ratings.each{|key,value| puts "#{key.capitalize} Ratings: #{value}"}

# Memento Ratings: 3
# Primer Ratings: 3.5
# Skyfall Ratings: 4
# Uhf Ratings: 1

collect is an iterator that applies the block on each element of the array. It creates a new array containing the values returned by the block. If you used the bang method it modifies the array in place.

collect Iterator
1
2
3
4
5
6
7
8
9
10
11
12
13
14
    fruits = ["apple","rasberry","lemon","cranberry"]
#=> ["apple", "rasberry", "lemon", "cranberry"] 
   fruits.collect {|fruit| "#{fruit} pie"}
#=> ["apple pie", "rasberry pie", "lemon pie", "cranberry pie"] 
#note that a new array was created and fruits has stayed the same
   fruits
#=> ["apple", "rasberry", "lemon", "cranberry"] 
   fruits.collect! {|fruit| "#{fruit} pie"}
#=> ["apple pie", "rasberry pie", "lemon pie", "cranberry pie"] 
#note that because we used the bang method fruits has now changed
    fruits
#=> ["apple pie", "rasberry pie", "lemon pie", "cranberry pie"] 
    fruits.collect {|fruit| "#{fruit} pie"}
#=> ["apple pie pie", "rasberry pie pie", "lemon pie pie", "cranberry pie pie"] 

Methods can transfer control to a block and back again. This is can be done using the yield method, which invokes the block with an optional parameter.

Yield
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
def yield_num(num)
  puts "inside of method yield_num"
  puts "Yield!"

  yield num
  #passing your own number directly to the block
  yield 20
end

yield_num(5) { |num| puts "Your lucky number is #{num}"}

#=> inside of method yield_num
#=> Yield!
#=> Your lucky number is 5
#=> Your lucky number is 20

Methods can transfer control to a block and back again. This is known as the yield method, which invokes the block with an optional parameter.

Procs and Lambdas

TODO

Proc

Procs are full-fledged objects, so they have all the powers and abilities of objects. (Blocks do not.)

Unlike blocks, procs can be called over and over without rewriting them. This prevents you from having to retype the contents of your block every time you need to execute a particular bit of code.

http://www.robertsosinski.com/2008/12/21/understanding-ruby-blocks-procs-and-lambdas/ http://stackoverflow.com/questions/1435743/why-does-explicit-return-make-a-difference-in-a-proc http://ablogaboutcode.com/2012/01/04/the-ampersand-operator-in-ruby/

lambda

First, a lambda checks the number of arguments passed to it, while a proc does not. This means that a lambda will throw an error if you pass it the wrong number of arguments, whereas a proc will ignore unexpected arguments and assign nil to any that are missing.

Second, when a lambda returns, it passes control back to the calling method; when a proc returns, it does so immediately, without going back to the calling method.

Fundamentals of Arrays

An array is a series of elements. If you have arrays of arrays this is known as a multi-dimensional array. Array elements are indexed by integers with the first element being 0.

Ruby arrays differs from more traditional langauges such as C,C++, and Java because the lenght of an array is dynamic. They can shrinkand grown during program execution. If you’ve worked with C++, this is the same behaviior as a vector.

Generally arrays must store homogenous elements (elements of the same type). However Ruby arrays store heterogenous elements or a mix of elements.

Arrays
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Array.new(5)
#=>[nil, nil, nil, nil, nil] 

Arr.new(5,"fivetimes")
#=> ["fivetimes", "fivetimes", "fivetimes", "fivetimes", "fivetimes"] 

[1,2]
#=> [1, 2] 

[1,2][0] # get the first element from array
#=> 1 


Array.new(5,[1,2])
# => [[1, 2], [1, 2], [1, 2], [1, 2], [1, 2]] 

for-in

One method to loop over an array is to use the for-in statement.

for-in
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
arr = ["one","two","three","four"]

for x in arr
  puts x
end

#=>one
#=>two
#=>three
#=>four

multi = Array.new(5,[1,2])
# => [[1, 2], [1, 2], [1, 2], [1, 2], [1, 2]] 
for arr in multi # get nested array
  print "[ "
  for val in arr # get values from nested array
    print "#{val} "
  end
  puts "]"
end

#=> [ 1 2 ]
#=> [ 1 2 ]
#=> [ 1 2 ]
#=> [ 1 2 ]
#=> [ 1 2 ]

Arrays have an assortment of methods. Some common methods are demoed below.

Array methods
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
[1,2,3,4] + [13] # concatenate the arrays
#=> [1, 2, 3, 4, 13] 

[1,2,3,4] << [13] # append [13] to array
#=> [1, 2, 3, 4, [13]] 

[1,2,3,4] << 13   # append 13 to array
#=> [1, 2, 3, 4, 13] 

arr = [1,2,3,4]
arr.push(13) # adds 13 to right side of array
#=> [1, 2, 3, 4, 13] 

arr.pop # removes first element from right side
#=> 13

arr
#=> [1,2,3,4] 
# 13 is gone!

arr.unshift(13) # adds 13 to left side of array
#=> [13, 1, 2, 3, 4]

arr.shift #remove first element from left side
#=> 13 
arr
#=> [1, 2, 3, 4] 

arr.shift(2) #remove 2 more elements from left side
#=> [1, 2] 
arr
#=> [3, 4]

arr = [1,2,3,4]
arr.reverse
#=> [4, 3, 2, 1] 
arr
#=> [1, 2, 3, 4] #note that the original array has not changed 
arr.reverse!
#=> [4, 3, 2, 1] 
 arr
#=> [4, 3, 2, 1] #note that the original array changed because we called a ! method 

Arrays can also be treated as sets The & operator is used for set intersection, -, for set difference, and |, for set union

Sets
1
2
3
4
5
6
7
8
[1,2,3,4] & [2,45,6,7,8,9] # set intersect
#=> [2] 

[1,2,3,4] - [2,45,6,7,8,9] # set difference
#=> [1, 3, 4] 

[1,2,3,4] | [2,45,6,7,8,9] # set union
#=> [1, 2, 3, 4, 45, 6, 7, 8, 9] 

Hashes

Arrays are indexed by integers. There is another key, value collection called a hash where an object is reference by another object known as a symbol. If you’re coming from a background in JavaScript, PHP, you maybe used to acessing hashes using strings.

Hashes
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# this is the old syntax for a ruby symbols
# symbols are declared as :symbol
oldnumhash = {
    :four => 4,
    :five =>  5,
    :six => 6
}

oldnumhash.each{|k,v| puts "#{k} maps to #{v}"}
#=> four maps to 4
#=> five maps to 5
#=> six maps to 6

# Ruby 1.9 introduced an even simpler syntax
# Notice that this the colon (:) comes right after the key
numhash = {
    one: 1,
    two: 2,
    three: 3
}

puts numhash[:one]
#=> 1
puts numhash[:two]
#=> 2
puts numhash[:three]
#=> 3

Here is a good description of why symbols are used as hash keys in Ruby

“Using symbols not only saves time when doing comparisons, but also saves memory, because they are only stored once.

Symbols in Ruby are basically “immutable strings” . That means that they can not be changed, and it implies that the same symbol when referenced many times throughout your source code, is always stored as the same entity, e.g. has the same object id.

Strings on the other hand are mutable, they can be changed anytime. This implies that Ruby needs to store each string you mention throughout your source code in it’s separate entity, e.g. if you have a string “name” multiple times mentioned in your source code, Ruby needs to store these all in separate String objects, because they might change later on (that’s the nature of a Ruby string).

If you use a string as a Hash key, Ruby needs to evaluate the string and look at it’s contents (and compute a hash function on that) and compare the result against the (hashed) values of the keys which are already stored in the Hash.

If you use a symbol as a Hash key, it’s implicit that it’s immutable, so Ruby can basically just do a comparison of the (hash function of the) object-id against the (hashed) object-ids of keys which are already stored in the Hash. (much faster)

Notes:

If you do string comparisons, Ruby can compare symbols just by their object ids, without having to evaluate them. That’s much faster than comparing strings, which need to be evaluated.

If you access a hash, Ruby always applies a hash-function to compute a “hash-key” from whatever key you use. You can imagine something like an MD5-hash. And then Ruby compares those “hashed keys” against each other.”

Source: tilo’s answer from http://stackoverflow.com/questions/8189416/why-use-symbols-as-hash-keys-in-ruby

Each object is identified by an integer which can be retrieved using the method .object_id. As mentioned previously only one copy of a symbol exists at a given time, meaning that there exists only one object id for that symbol.

Object id
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# note that these string objects are different instances 
  puts "string".object_id
  puts "string".object_id

# these ids are different
#=>79341770
#=>79341710


# note that only one copy of the symbol :symbol exists at a time
puts :symbol.object_id
puts :symbol.object_id

# these ids are the same
#=>192008
#=>192008

Methods

TODO

Sorting

TODO

Pattern Matching

TODO

Classes

TODO

Modules

TODO

Comments