Pages

Friday, April 9, 2010

Containers, Blocks, and Iterators

Category    Ruby, Programming

Containers are objects that hold references to one or more other objects.

 
 

Arrays

 
 

A Ruby array holds a collection of object references identified by a non-negative integer index.

 
 

In an array class, [] is a method which accesses elements by index.

 
 

def [] (key)

if key.kind_of? (Integer)

result = @songs[key]

else

for I in 0…@songs.length

result = @songs[i] if key == aSong.name

end

return result

end

 
 

Hashes

 
 

Compared with arrays, hashes have one significant advantage: they can use any type of object as an index. However, they also have a significant disadvantage: their elements are not ordered, so you cannot use a hash as a stack or queue.

 
 

Blocks and Iterators

 
 

A better way of the [] mehtod:

 
 

def [] (key)

return @songs[key] if key.kind_of?(Integer)

return @songs.find { |aSong| aSong.name == key }

end

 
 

An iterator is a method that invokes a block of code repeatedly.

 
 

The uses of a block

A block is often the target of an iterator.

A block can be used to define a chunk of code that must run under some kind of transactional control.

 
 

class File

def File.openAndProcess(*args)

f = File.open(*args)

yield f

f.close()

end

end

 
 

File.openAndProcess("textfile", "r") do |aFile|

print while aFile.gets

end

 
 

In this way, the responsibility of closing an open file has been passed from the user of the file object to the file themselves.

 
 

The do…end block has lower precedence than {...}.

 
 

The method Kernel::block_given? returns true if a block is associated with the current method.

 
 

If the last parameter in a method definition is prefixed with an ampersand, Ruby looks for a code block whenever the method is called. The code block is converted to an object of class Proc and assigned to the parameter.

 
 

What is closure in a programming language?

Iterators

 
 

find, each, and collect

 
 

All the each iterator does is yield successive element of its collection.

In the collect iterator, the results returned by the block are used to construct a new array.

Programming in Ruby

Ruby is an genuine object-oriented language, meaning every thing in Ruby is an object or a class that is a combination of instance variables and instance methods.

 
 

"gin joint".length

  

9

"Rick".index('c')

  

2

-123.abs

  

123

 
 

The difference between a single quote literal and a double quote literal is how much Ruby processes it when it gets created.

A double quote literal looks for substitutes for an escape sequence and # (…) constructs.

 
 

The value returned by Ruby method is the value of the last expression evaluated, so don't need a return.

 
 

Ruby conventions:

A variable starts with a lower case ==> local variable

A variable or name starts with an upper case ==> class name, module name, or constant variable

A variable starts with $ ==> global variable

A variable starts with @ ==> instance variable

A variable starts with @@ ==> class variable

 
 

Arrays and Hashes

 
 

Both are index collections and can take any mixed type of objects. The only difference between them is arrays' indexes must be integer whereas hashes indexes can be any kind of objects.

 
 

array = Array.new

array = []

array = [1, 'K', 'It's a string', 3.14]

array = %w[cat dog apple]

 
 

hash = Hash.new

hash = Hash.new(0)

hash = {0 => 'cat', 'dog' => 'bark', 9 => -9}

 
 

Control Structures

 
 

Statement modifiers

puts "Ich liebe dich" if myLove == herLove

puts "love me only" while myAge < 1000


 

Regular Expression

As you expect, regular expressions are objects in Ruby. The match operator =~ returns the position it first found or nil if not found.


 

individuated s yy:mm:dd 1P(erllython)l e Perl or Python

'Ruby of *Peril x Ruby and zero or one move character and Perl

(Ruby 1st Perl/ 4 Ruby and one or move white space and Perl

if line =~ (perl python

puts " You got me."

end

pos = sub (lperll, 'ruby') H replace first perl with ruby

pos = grubs (Python.' Ruby) * replace every Python with Ruby


 


 

Blocks and Iterators

 
 

Code blocks are chunks of code that you can associate with method invocations. Chunks of code are between braces or 'do … end'. Once you've created a block, you can associate it with a call to a method. You might be better off thinking of the block and the method as coroutines, which transfer control back and forth between themselves.

 
 

 
 

 
 

Reading and 'Riting

 
 

The gets routine has a side effect; as well as returning the last line read, it also stores the last line into the global variable $_.

 
 

while gets

if /Ruby/

print

end

end

 
 

ARGF represents a stream input.

 
 

ARGF.each { |line| print line unless line =~ /ruby/ }

 
 

Classes, Objects, and Variables

 
 

class - how to declare, define, create,

To create a new class object, invoke the new method of the class. Song.new calls the class' initialize method to set up the class' internal state.

 
 

class Song

def initialize(name, artist, duration)

@name = name

@artist = artist

@duration = duration

end

end

 
 

aSong = Song.new('Let it be', 'The Beatles', 310)

 
 

The inspect message dumps a object's id and instance variables. While the message's default formatting leaves something to be desired, the to_s message can be overridden.

 
 

 
 

Inheritance and Messages

 
 

Inheritance allows you to create a class that is a refinement or specialization of another class. The less than character(<) lets you inherit from another class. Make sure that you override the initialize method and the to_s method properly. You may not want a subclass directly to access the instance variables of its super class to set up because it couples between them; that's a bad programming style. Rather, use super in the subclass for decoupling.

 
 

 
 

Inheritance and Mixins

 
 

Multiple inheritance can be dangerous since the inheritance hierarchy can become ambiguous. In real life, however, things often inherit attributes from multiple sources. A Ruby class can only have a single direct parent, but Ruby has a technique called Mixins to provide a multiple-inheritance-like functionality.

 
 

 
 

Objects and Attributes

 
 

An object is solely responsible for maintaining its own consistency. Ruby provides a convenient way of creating getters and setters.

 
 

class Song

attr_reader :name, :artist, :duration

attr_writer :name, :artist, :duration

end

 
 

 
 

Virtual Attributes

 
 

Use attribute methods to create a virtual instance variable that seems like a real instance variable to outside of the world.

 
 

class Song

def durationInMinute

@duratoin / 60.0

end

 
 

def durationInMinute=(value)

@duration = (value * 60).to_i

end

end

 
 

The setter here is like an operator overloading in C++. Type casting is different from C-like languages. Ruby deals everything as an object, even a number, so Ruby provides the to_i method for type casting.

 
 

In his landmark book Object-Oriented Software Construction , Bertrand Meyer calls this the Uniform Access Principle. By hiding the difference between instance variables and calculated values, you are shielding the rest of the world from the implementation of your class. You're free to change how things work in the future without impacting the millions of lines of code that use your class. This is a big win.

 
 

 
 

Class Variables and Class Methods

 
 

class Song

@@plays = 0 # a class variable

MaxPlays = 50 # a class constant variable

 
 

def Song.initPlays

@@plays = 0

end

end

 
 

For class variables, by convention, Ruby puts @@ in front of a class variable name.

 
 

 
 

Singletons and Other Constructors

 
 

A singleton is an object that is singly created from a class.

 
 

class Logger

private_class_method = new

@@logger = nil

def Logger.create

@@logger = new unless @@logger

@@logger

end

end

 
 

The Logger class can not be created by the conventional way using the new method. Also class methods can be used as pseudo-constructors.

 
 

 
 

Access Control

 
 

  • Public methods can be called by anyone---there is no access control. Methods are public by default (except for initialize, which is always private).
  • Protected methods can be invoked only by objects of the defining class and its subclasses. Access is kept within the family.
  • Private methods cannot be called with an explicit receiver. Because you cannot specify an object when using them, private methods can be called only in the defining class and by direct descendents within that same object.

     
     

    What does it mean by direct descendents?

    If a method is protected, it may be called by any instance of the defining class or its subclasses. If a method is private, it may be called only within the context of the calling 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.

     
     

    Access control is determined dynamically, as the program runs, not statically.

Final test

This would be the final test.

Email posting test

I need to maintain my blog.