Topic: ruby

Programming Ruby 1.9

The basics

1   class Book
2     def initialize(isbn, price)
3       @isbn = isbn
4       @price = price
5     end
6   end
7 
8   book = Book.new("isbn", 3)

initialize is a special method in Ruby programs. When you call Book.new to create a new object, Ruby allocated memory to hold an uninitialized object and then calls that object's initialize method. T

initialize is an objects constructor. The call to Book.new calls the Book's constructor (initialize) and allocates a new instance of Book.

@isbn in an instance field of the class. when you want to declare a instance field you must prefix the name of the variable with the "@" sign.

To customize how an object is displayed via puts or p you can override the "to_s" method.

 1   class Movie
 2     def initialize(name, studio, year_published)
 3       @name = name
 4       @studio = studio
 5       @year_published = year_published
 6     end
 7     def to_s
 8       "Name: #{@name}, Studio: #{@studio}, Year: #{@year_published}"
 9     end
10   end
11 
12   p Movie.new("MegaMind", "DreamWorks", 2010)

Attributes (methods)

By default instance variables are private and cannot be accessed from outside the class. You can define "attributes" on the class to be able to see and change the internal state of the class. These are equivelant to properties in c#.

You can define read only attribute explicitly, like this.

 1   class VideoGame
 2     def initialize(name)
 3       @name = name
 4     end
 5     def name
 6       @name
 7     end
 8   end
 9 
10   game = VideoGame.new("call of duty")
11   puts game.name

Ruby has a handy little shorthand to save you from having to type out your read only attributes. It's called "attr_reader".

 1   class VideoGame
 2 
 3     attr_reader :name
 4 
 5     def initialize(name)
 6       @name = name
 7     end
 8   end
 9 
10   game = VideoGame.new("call of duty")
11   puts game.name

To create a method that would allow me to change the name of a video game I can define a method named "name=".

 1   class VideoGame
 2 
 3     def initialize(name)
 4       @name = name
 5     end
 6     def name=(new_name)
 7       @name = new_name
 8     end
 9   end
10 
11   game = VideoGame.new("call of duty")
12   game.name="GTA4"

There's also a shorthand for having to write your own setter methods. It's called attr_writer.

 1   class VideoGame
 2 
 3     attr_writer :name
 4 
 5     def initialize(name)
 6       @name = name
 7     end
 8   end
 9 
10   game = VideoGame.new("call of duty")
11   game.name="GTA4"

There's also a shorthand for defining a setter, and getter for your instance variable called "attr_accessor"

 1   class VideoGame
 2 
 3     attr_accessor :name
 4 
 5     def initialize(name)
 6       @name = name
 7     end
 8   end
 9 
10   game = VideoGame.new("call of duty")
11   game.name="GTA4"
12   puts game.name

Access Control

You get 3 levels of protection:

  • Public methods (default): can be called by anyone.
  • Protected methods: can be invoked by defining class and subclasses.
  • Private methods: can only be called within the context of the current object.

It is never possible to access another object's private methods directly, even if the object is of the same class as the caller.

 1   class MyClass
 2     def public_method
 3     end
 4 
 5   protected
 6     def protected_method
 7     end
 8 
 9   private
10     def private_method
11     end
12 
13   public 
14     def another_public_method
15     end
16   end
17   
18 # or
19 
20   class AnotherClass
21     def public_method
22     end
23 
24     def protected_method
25     end
26 
27     def private_method
28     end
29 
30     public      :public_method
31     protected   :protected_method
32     private     :private_method
33   end

Variables

Variables are used to keep track of objects; each variable holds a reference to an object. A variable is simply a reference to an object.

1   movie = Movie.new("man on fire")
2   another_movie = movie
3   movie = Movie.new("batman")
4 
5   puts movie.name
6   puts another_movie.name

Referenced from Programming Ruby 1.9 The Pragmatic Programmers' Guide

installing ruby

  $ sudo apt-get update
  $ sudo apt-get install curl
  $ bash < <( curl -s https://rvm.beginrescueend.com/install/rvm )

Add to .bashrc

source $HOME/.rvm/scripts/rvm

then.

  $ rvm notes # follow instructions to install missing libs
  $ sudo apt-get install build-essential bison openssl libreadline5 libreadline-dev curl git-core zliblg zliblg-dev libssl-dev vim libsqlite3-0 libsqlite3-dev sqlite3 libreadline-dev libxml2-dev git-core subversion autoconf
  $ rvm install 1.9.2
  $ rvm use 1.9.2
  $ ruby -v

documentation

  $ ri GC
  $ ri GC::enable
  $ ri assoc

ruby is object-oriented

arrays and hashes

arrays and hashes are indexed collections. both store collections of objects, accessible using a key.

e.g array literal

1   a = [ 1, 'cat', 3.14 ] # array with three elements
2   puts "the first element is #{a[0]}"

ruby has a shortcut for creating arrays of strings

1   a = [ 'ant', 'bee', 'cat', 'dog', 'elk' ]
2   a[0] # => "ant"
3   a = %w[ ant bee cat dog elk ]
4   a[0] # => "ant"

hashes are similar to arrays. you must supply two objects for every entry, one for the key, the other for the value.

 1   dead_rappers = {
 2     'tupac'   => '1996'
 3     'biggie'   => '1997'
 4     'big l'   => '1999'
 5     'eazy e'   => '1995'
 6     'odb'   => '2004'
 7   }
 8 
 9   p dead_rappers['tupac']   # => '1996'
10   p dead_rappers['biggie']  # => '1997'
11   p dead_rappers['big pun']  # => nil

a hash by default returns nil when indexed by a key it doesn't contain. to change the default value you can specify it when creating a new hash.

1   histogram = Hash.new(0) # the default value 0
2   histogram['ruby'] # => 0
3   histogram['ruby'] = histogram['ruby'] + 1
4   histogram['ruby'] # => 1

symbols

are simple constant names that you don't have to predeclare and that are guaranteed to be unique. a symbol literal starts with a colon and is normally followed by some kind of name:

1   walk(:north)
2   walk(:east)

there's no need to assign some kind of value to a symbol - ruby takes care of that for you. ruby also guarantees that no matter where it appears in your program, a particular symbol will have the same value.

e.g

1   def walk(direction)
2     if direction == :north
3       # ...
4     end
5   end

symbols are frequently used as keys in hashes.

like this

1   dead_rappers = {
2     :tupac    => '1996'
3     :biggie   => '1997'
4     :bigl     => '1999'
5     :eazye    => '1995'
6     :odb      => '2004'
7   }
8 
9   dead_rappers[:odb] # => '2004'

in ruby 1.9 you can use name: value pairs to create a hash if the keys are symbols.

1   dead_rappers = {
2     tupac:    '1996'
3     biggie:   '1997'
4     bigl:     '1999'
5     eazye:    '1995'
6     odb:      '2004'
7   }
8   puts "big l died in #{dead_rappers[:bigl]}"

control structures

the if/elseif/else structure

1   today = Time.now
2 
3   if today.saturday?
4     puts "do chores around the house"
5   elsif today.sunday?
6     puts "chill out"
7   else
8     puts "go to work"
9   end

the while loop

1   i = 0
2   while i < 100
3     i+=1
4   end

ruby treats nil as a false, so you can write this.

1   while line = gets
2     puts line.downcase
3   end

statement modifiers are a cool shortcut if the body of an if or while statement is just a single express.

 1   if radiation > 3000
 2     puts "danger, will robinson"
 3   end
 4 
 5   puts "danger, will robinson" if radiation > 3000
 6 
 7   square = 4
 8   while square < 1000
 9     square = square * square
10   end
11 
12   square = square*square while square < 1000

blocks

this is a code block:

1   { puts "hello" }

so is this:

1   do 
2     club.enroll(person)
3     person.socialize
4   end

the only thing you can do with a block is associate it with a call to a method. you can do this by putting the start of the block at the end of the source line containing the method call.

1   greet { puts "hi" }

the method greet is given a block. if the method has parameters, then they appear before the block:

1   verbose_greet("mo", "a geek") { puts "hi" }

a method can invoke the block by calling yield.

1   def call_block
2     puts "start of method"
3     yield
4     yield
5     puts "end of method"
6   end
7 
8   call_block { puts "in the block" }
  output:
  start of method
  in the block
  in the block
  end of method

you can also pass arguments to the block. within the block you need to list the names of the parameters to receive these arguments between vertical bars.

1   def who_says_what
2     yield("mo", "hello")
3     yield("morilla", "yo")
4   end
5 
6   who_says_what {|person, phrase| puts "#{person} says #{phrase}"

code blocks are used throughout the ruby library to implement iterators, which are methods that return successive elements from some kind of collection, such as an array:

1   animals = %w( ant bee cat dog elk )
2   animals.each {|animal| puts animal }
3   [ 'cat', 'dog', 'horse' ].each {|name| print name, " "}
4   5.times { print "*" }
5   3.upto(6) {|i| print i }
6   ('a'..'e').each {|char| print char}