Anda di halaman 1dari 223

RUBY

PROGRAMMING
Course #TE3601
Rev. 3/25/2013
RUBY PROGRAMMING
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
i


7150 Riverwood Drive, Suite J
Columbia, MD 21046
Tel: 410-290-8383
Fax: 410-290-9427
http://www.trainingetc.com
email: info@trainingetc.com
RUBY PROGRAMMING
Course #TE3601
Rev. 3/25/2013
RUBY PROGRAMMING
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
ii
This Page Intentionally Left Blank
RUBY PROGRAMMING
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
iii
Course Objectives
At the conclusion of this course, students will be able to:
Distinguish and use various Ruby datatypes
Master the use of arrays and hashes
Build home grown classes
Use the extensive pre bundled classes
Use the I/O facilities of Ruby to read and write binary and text
files
Master the use of Iterators to loop through various data
structures
Use Exceptions in handling various run time errors
Create Ruby modules
Use the wide variety of Ruby Modules that come with the Ruby
distribution
RUBY PROGRAMMING
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
iv
This Page Intentionally Left Blank
RUBY PROGRAMMING
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
v
Table of Contents
CHAPTER 1: AN INTRODUCTION TO RUBY
What is Ruby? ..............................................................................................1-2
Installing Ruby..............................................................................................1-3
Executing Ruby Code...................................................................................1-4
Getting Help..................................................................................................1-6
Dynamic Types.............................................................................................1-9
Ruby Reserved Words................................................................................1-10
Naming Conventions ..................................................................................1-11
Comments ..................................................................................................1-12
CHAPTER 2: STANDARD RUBY DATA TYPES
Numbers.......................................................................................................2-2
Strings ..........................................................................................................2-3
Simple Input and Output...............................................................................2-9
Converting String Input...............................................................................2-10
Regular Expressions...................................................................................2-11
Time Methods.............................................................................................2-14
CHAPTER 3: LANGUAGE COMPONENTS
The if Statement.........................................................................................3-2
The Logical Operators ..................................................................................3-3
The case Construct......................................................................................3-4
Loops............................................................................................................3-5
Iterators ........................................................................................................3-9
Numeric Iterators ........................................................................................3-10
String Iterators............................................................................................3-13
Methods......................................................................................................3-16
Odds and Ends...........................................................................................3-18
CHAPTER 4: COLLECTIONS
Arrays ...........................................................................................................4-2
Array Operator Methods ...............................................................................4-5
Array Equality Operator ................................................................................4-9
Arrays as Stacks and Queues ....................................................................4-10
Higher Dimensional Arrays .........................................................................4-11
Other Useful Arrays Methods......................................................................4-12
Command Line Arguments.........................................................................4-13
Hashes .......................................................................................................4-14
Common Hash Methods.............................................................................4-17
Sorting Hashes...........................................................................................4-18
Iterators with Arrays and Hashes................................................................4-20
Arrays and Methods....................................................................................4-21
Hashes and Methods..................................................................................4-22
Named Parameters.....................................................................................4-23
Symbols......................................................................................................4-24
RUBY PROGRAMMING
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
vi
Procs ..........................................................................................................4-26
Closures .....................................................................................................4-28
CHAPTER 5: CLASSES
Objects .........................................................................................................5-2
Brief History of OOP .....................................................................................5-3
OOP Vocabulary...........................................................................................5-4
Creating a New Class...................................................................................5-6
Using Objects ...............................................................................................5-8
Defining Operator Methods.........................................................................5-13
Inheritance..................................................................................................5-14
Ancestors....................................................................................................5-18
self...........................................................................................................5-20
Access Levels - public.............................................................................5-23
Access Levels private..........................................................................5-25
Access Levels - protected ......................................................................5-26
Access Levels - Specification.....................................................................5-27
Class Data and Class Methods...................................................................5-28
Adding Methods to Classes and Objects....................................................5-30
Special Global Variables.............................................................................5-31
Scope of Variables......................................................................................5-32
Built-in Classes...........................................................................................5-33
The Math Class..........................................................................................5-34
The NilClass Class .................................................................................5-35
TrueClass and FalseClass...................................................................5-36
Built-in Class Hierarchy ..............................................................................5-37
CHAPTER 6: INPUT AND OUTPUT
Introduction...................................................................................................6-2
Reading from the Standard Input..................................................................6-3
Writing to the Standard Output.....................................................................6-7
Reading and Writing Disk Files.....................................................................6-8
Reading Files Using Iterators......................................................................6-10
I/O With Command Line Commands ..........................................................6-12
Seeking About Files....................................................................................6-13
tell...........................................................................................................6-16
Capturing Data About Files.........................................................................6-17
Processing Directories................................................................................6-18
CHAPTER 7: EXCEPTIONS
Introduction...................................................................................................7-2
Exception Hierarchy......................................................................................7-3
Handling Exceptions.....................................................................................7-4
Multiple Rescue Clauses ..............................................................................7-7
Exceptions are Classes ................................................................................7-8
ensure.........................................................................................................7-9
retry.........................................................................................................7-10
RUBY PROGRAMMING
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
vii
raise.........................................................................................................7-11
Creating Your Own Exceptions...................................................................7-13
catch and throw......................................................................................7-14
CHAPTER 8: MODULES
Introduction...................................................................................................8-2
Using Core Ruby Classes.............................................................................8-3
Ruby Standard Library..................................................................................8-5
require.......................................................................................................8-6
Search Path..................................................................................................8-8
File Organization...........................................................................................8-9
load...........................................................................................................8-12
Modules......................................................................................................8-13
include.....................................................................................................8-16
Mixins .........................................................................................................8-17
Using the Comparable Module.................................................................8-20
Collection Classes ......................................................................................8-22
yield.........................................................................................................8-23
Using the Enumerable Module....................................................................8-26
CHAPTER 9: ODDS AND ENDS
Ruby Conventions ........................................................................................9-2
Bit Manipulation............................................................................................9-5
Substituting...................................................................................................9-8
Marshalling...................................................................................................9-9
Reflection....................................................................................................9-11
grep...........................................................................................................9-12
Classes are Objects....................................................................................9-13
Aliasing.......................................................................................................9-15
Testing........................................................................................................9-16
Test::Unit::TestCase.........................................................................9-17
Testing Your Own Classes .........................................................................9-22
Freezing Objects.........................................................................................9-24
Object Equality............................................................................................9-26

RUBY PROGRAMMING
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
viii
This Page Intentionally Left Blank
RUBY PROGRAMMING CHAPTER 1: AN INTRODUCTION TO RUBY
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
1-1
Chapter 1:
An Introduction to Ruby
1) What is Ruby?.......................................................................................................... 1-2
2) Installing Ruby......................................................................................................... 1-3
3) Executing Ruby Code .............................................................................................. 1-4
4) Getting Help ............................................................................................................. 1-6
5) Dynamic Types ......................................................................................................... 1-9
6) Ruby Reserved Words........................................................................................... 1-10
7) Naming Conventions.............................................................................................. 1-11
8) Comments ............................................................................................................... 1-12

RUBY PROGRAMMING CHAPTER 1: AN INTRODUCTION TO RUBY
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
1-2
What is Ruby?
In the mid 1990's, the Ruby programming language
surfaced in J apan, the home of Ruby's creator, Yukihiro
Matsumoto.
He is usually referred to as Matz.
Matz knew Python and Perl and thought that each of
those languages left something to be desired.
In particular, he did not like that both Perl and Python were not
fully object oriented.
Since that time, Python has become fully object oriented.

Ruby is often compared to Python and Perl, and each language
community has their own arguments as to why their language is
better.
Ruby has the following technical characteristics.
Interpreted rather than compiled
Dynamic typing rather than static typing
Completely object oriented.
Like other languages, Ruby has undergone various
revisions.
Version 1.9.3 was released in October of 2011.
Version 2.0.0 was released in February of 2013.
All things concerning Ruby can be located at:
http://www.ruby-lang.org/en
RUBY PROGRAMMING CHAPTER 1: AN INTRODUCTION TO RUBY
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
1-3
Installing Ruby
Instructions for downloading and installing Ruby can be
found at the following URL.
http://www.ruby-lang.org/en/downloads/
Versions of Ruby are available for download for many
different operating systems including:
Linux Windows Mac OS X
There are three ways of installing Ruby.
Each of the following techniques is explained in more detail at
the URL listed above.
Compiling from source
Package management systems
Third party tools

One of the more popular tools for installing Ruby in a Linux or
Mac OS X environment is the Ruby Version Manager (RVM).
RubyInstaller is an application that can be used to easily install
Ruby in a Windows environment.
RailsInstaller can be used if both Ruby and Rails are to be
used in a Windows environment.
One major benefit of the third party tools is the ability to
have different versions of Ruby installed side-by-side on
the same computer.
It is for this reason that RVM has been chosen to install Ruby
version 1.9.3 on the Linux machines in the classroom.
RUBY PROGRAMMING CHAPTER 1: AN INTRODUCTION TO RUBY
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
1-4
Executing Ruby Code
Since we will be using Linux here, all of the examples will
demonstrate executing programs in a Linux environment.
To execute a Ruby program from the command line, we
will first create an .rb file with your favorite text editor.
Although not required, the .rb file extension is the industry
standard for files containing Ruby code.
example1.rb
1. #!/usr/bin/ruby
2. puts "This text is output to the screen when run"
Once the file is created, how it is executed depends upon
the operating system being used.
In a Linux / Mac OS X environment, the first line of the file
usually contains the path to the Ruby interpreter.
Although not necessary in a Windows environment, it is
often used for cases when code developed in a Windows
environment might be run in a different environment.
In a Linux / Mac OS X environment, the file can be made
executable with the following command.
chmod 755 example1.rb

It can then simply be run with the following command.
example1.rb
Alternatively, the script can be run on all platforms without
the need to make it executable with the following
command.
ruby example1.rb
RUBY PROGRAMMING CHAPTER 1: AN INTRODUCTION TO RUBY
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
1-5
Executing Ruby Code
The execution and output of the script on the previous
page is shown below.
student@localhost:~/rubylabs/examples/1
$ ruby example1.rb
This text is output to the screen when run
$
Another way in which Ruby code can be executed is using
the interactive Ruby utility named irb.
This tool (like many others) is automatically included when
installing Ruby using third party tools.
Package management systems may require additional
packages to be installed for all the tools to become available.
The irb utility is demonstrated below.
Sample Ruby code, shown in bold below, is typed interactively
during the running of the irb session.
Typing exit will terminate the irb session.
student@localhost:~/rubylabs/examples/1
$ irb
1.9.3p392 :001 > 2 + 2
=> 4
1.9.3p392 :002 > puts "Hello"
Hello
=> nil
1.9.3p392 :003 > "Hello".reverse
=> "olleH"
1.9.3p392 :004 > x = "Hello"
=> "Hello"
1.9.3p392 :005 > puts x
Hello
=> nil
1.9.3p392 :006 > exit
$

Each statement entered is executed, and the results are
displayed on the console. Some statements have the result of
nil, the Ruby version of Python's None.
RUBY PROGRAMMING CHAPTER 1: AN INTRODUCTION TO RUBY
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
1-6
Getting Help
There are various ways in which a Ruby programmer can
get help with the Ruby language.
A good starting point is the following URL.
http://www.ruby-lang.org/en/documentation/



As shown above, there are links to navigate to places specific
to the various help topics.
The reference links listed below may be worth bookmarking in
your browser for easy reference.
The Ruby Core Reference
http://www.ruby-doc.org/core-1.9.3

The Ruby Standard Library Reference
http://www.ruby-doc.org/stdlib-1.9.3/
RUBY PROGRAMMING CHAPTER 1: AN INTRODUCTION TO RUBY
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
1-7
Getting Help
Another tool for getting help in Ruby is the Ruby Index
(ri) command line tool.
The ri tool can be used to view the Ruby documentation off-
line.
A closely related tool to ri is Ruby Documentation
(RDoc).
RDoc is a documentation system that creates nicely formatted
documentation from commented source files.
It is available through the rdoc command line tool.
ri is used to display the information generated by rdoc from
the Ruby source files.
The documentation that is displayed is in the format of
Unix/Linux man pages.,
The following example shows how to display
documentation for the String.
student@localhost:~/rubylabs/examples/1
$ ri String
$

student@localhost:~/rubylabs/examples/1
= String < Object

------------------------------------------------------------------------------
= Includes:
Comparable (from ruby site)

(from ruby site)
------------------------------------------------------------------------------
A String object holds and manipulates an arbitrary sequence of bytes,
typically representing characters. String objects may be created using
String::new or as literals.

Typing the letter q will quit out of the documentation.
RUBY PROGRAMMING CHAPTER 1: AN INTRODUCTION TO RUBY
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
1-8
Getting Help
The example below demonstrates how to get more
specific information, like the length method of the String
class.
student@localhost:~/rubylabs/examples/1
$ ri String.length
$

student@localhost:~/rubylabs/examples/1
= String.length

(from ruby site)
------------------------------------------------------------------------------
str.length -> integer
str.size -> integer

------------------------------------------------------------------------------

Returns the character length of str.

The RDoc files created during the installation of Ruby by
RVM can be found at the following location on your hard
drive.
/home/student/.rvm/docs/ruby-1.9.3-p392/rdoc/index.html

The format of the HTML files located in the rdoc directory
listed above is similar, but not identical, to those found in the
online documentation files for Ruby, specified earlier.
RUBY PROGRAMMING CHAPTER 1: AN INTRODUCTION TO RUBY
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
1-9
Dynamic Types
With the Ruby environment in place, the following
program demonstrates the dynamic type system of the
Ruby language.
Ruby programmers do not define the type of a variable.
Its type varies with the data that it holds.
The class method can be used to determine the type of the
object being referenced by the variable.
class.rb
1. #!/usr/bin/ruby
2. w = "Hello"
3. x = 123
4. y = 249.35
5. z = true
6. puts w.class, x.class, y.class, z.class

student@localhost:~/rubylabs/examples/1
$ruby class.rb
String
Fixnum
Float
TrueClass
$
Note that each of the following will yield the data type of
Class.
Fixnum.class
String.class
You can also make a test to determine the class of a
variable.
x = 123
if ( x.class == Fixnum )
puts "It's an integer"
end
RUBY PROGRAMMING CHAPTER 1: AN INTRODUCTION TO RUBY
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
1-10
Ruby Reserved Words
Several words we have seen are used for special
purposes in the Ruby language.
These words are reserved and cannot be used as the names of
variables or methods within your code.
The list of reserved words is shown below.
Ruby Reserved Words
BEGIN class in super
END def module then
__ENCODING__ defined? next true
__END__ do nil undef
__FILE__ else not unless
__LINE__ elsif or until
alias end redo when
and ensure rescue while
begin false retry yield
break for return
case if self

Only a few of these reserved words have been used in the
examples so far.
The majority of them will be explained as we proceed through
the course.
RUBY PROGRAMMING CHAPTER 1: AN INTRODUCTION TO RUBY
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
1-11
Naming Conventions
Ruby is a case sensitive language.
It means that name and Name are two different identifiers.
Identifiers in Ruby can be created from alphanumeric
characters and the underscore (_) character.
An identifier cannot begin with a number.
Ruby enforces some naming conventions.
If an identifier starts with a capital letter, it is a constant.
If it starts with a dollar sign ($), it is a global variable.
If it starts with @, it is an instance variable.
If it starts with @@, it is a class variable.
RUBY PROGRAMMING CHAPTER 1: AN INTRODUCTION TO RUBY
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
1-12
Comments
A comment in Ruby starts with # and continues to the end
of the line.
There are several comments in the code below.
comments.rb
1. #!/usr/bin/ruby
2. # This program contains several comments
3. x = 10 # a Fixnum
4. y = "Hello There" # a String
5. z = "# This is NOT a comment"

When the above program is executed from the command
line, the shell will interpret the first line of the program and
use the shebang to find the Ruby interpreter and run the
script.
Otherwise, the Ruby interpreter will treat the first line as a
Ruby comment just like the others in the file.
A multi-line or block comment can be used as follows.
block.rb
1. #!/usr/bin/ruby
2. puts "Before"
3. =begin
4. This next line is not executed
5. puts "Inside of begin/end block
6. =end
7. puts "After"

The output from the above program is shown below.
Before
After

Any lines between the =begin and the =end are not
executed by the Ruby interpreter.
RUBY PROGRAMMING CHAPTER 1: AN INTRODUCTION TO RUBY
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
1-13
Exercises
1. Start the irb command line tool and experiment with
some Ruby expressions.
2. Use the ri command line tool to get information for the
Fixnum datatype.
Next, use the ri tool again to get specific information about
one of the instance methods listed in the documentation for
Fixnum.
3. Locate the RDoc documenation for the Fixnum class in
the local documentation.
Recall that local Ruby documentation can be found at:
/home/student/.rvm/docs/ruby-1.9.3-p392/rdoc

4. Locate the online documentation for the Fixnum class.
Recall that the online Ruby Core Reference can be found at:
http://www.ruby-doc.org/core-1.9.3/

5. Create a file named first.rb in the following directory.
/home/student/rubylabs/exercises/1

In that file, assign values to several variables.
Perform a few operations with them.
Print the values of the variables.
RUBY PROGRAMMING CHAPTER 1: AN INTRODUCTION TO RUBY
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
1-14
This Page Intentionally Left Blank
RUBY PROGRAMMING CHAPTER 2: STANDARD RUBY DATA TYPES
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
2-1
Chapter 2:
Standard Ruby Data Types
1) Numbers.................................................................................................................... 2-2
2) Strings ....................................................................................................................... 2-3
3) Simple Input and Output ........................................................................................ 2-9
4) Converting String Input ........................................................................................ 2-10
5) Regular Expressions .............................................................................................. 2-11
6) Time Methods......................................................................................................... 2-14

RUBY PROGRAMMING CHAPTER 2: STANDARD RUBY DATA TYPES
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
2-2
Numbers
Ruby provides a number of built-in number classes.
We will explore some of the more commonly used classes.
The Integer class is the basis for the two classes
Fixnum and Bignum.
A Fixnum holds Integer values that can be represented
natively.
If any operation on a Fixnum exceeds this range, the value is
automatically converted to a Bignum.
The Float class represents inexact real numbers using
the native architecture's double-precision floating point
representation.
Almost all applications will involve some degree of integer
and floating point arithmetic.
Ruby's Arithmetic Operators are shown in the table below.
Operator Name Description
+ Addition Adds values on either side of the operator
- Subtraction Subtracts right operand from left operand
* Multiplication Multiplies values on either side of the operator
/ Di vision Divides left operand by right operand
% Modulus
Divides left operand by right operand and
returns remainder
** Exponent
Performs exponential (power) calculation on
operators
RUBY PROGRAMMING CHAPTER 2: STANDARD RUBY DATA TYPES
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
2-3
Strings
A string is a collection of zero or more characters.
Support for strings is available in Ruby from the built-in String
class.
A String object holds and manipulates an arbitrary sequence
of bytes, typically representing characters.
Users of strings should be aware of the methods that modify
the contents of a String object.
Typically, methods with names ending in "!" modify their
receiver.
Methods without a "!" typically return a new String.
Strings can be delimited using either double quotes (") or
single quotes (').
The double quotes are designed to interpret escaped
characters such as new lines and tabs so that they appear as
actual new lines and tabs when the string is rendered for the
user.
Single quotes, however, display the actual escape sequence
(for example displaying \n instead of a new line).
The program on the following page demonstrates the
difference between single and double quoted literal
strings.
RUBY PROGRAMMING CHAPTER 2: STANDARD RUBY DATA TYPES
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
2-4
Strings
quotes.rb
1. #!/usr/bin/ruby
2. s1 = "0 \t 1 \t 2 \t 3 \t 4 \n5 \t 6 \t 7 \t 8 \t 9"
3. s2 = '0 \t 1 \t 2 \t 3 \t 4 \n5 \t 6 \t 7 \t 8 \t 9'
4. puts "A double quoted String:"
5. puts s1
6. puts
7. puts "A single quoted String:"
8. puts s2

The output from the above program is shown below.
A double quoted String:
0 1 2 3 4
5 6 7 8 9

A single quoted String:
0 \t 1 \t 2 \t 3 \t 4 \n5 \t 6 \t 7 \t 8 \t 9
You can substitute the value of any Ruby expression into
a double quoted string using the sequence #{} as
demonstrated in the program below.
interpolation.rb
1. #!/usr/bin/ruby
2. x = 10
3. y = 20
4. puts "x = #{x} and y = #{y}"
5. puts "x + y = #{x + y}"

The output from the above program is shown below.
x = 10 and y = 20
x + y = 30

If single quotes were used in the code, the expressions
would not have been evaluated.
RUBY PROGRAMMING CHAPTER 2: STANDARD RUBY DATA TYPES
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
2-5
Strings
Several methods in the String class are shown below.
strings.rb
1. #!/usr/bin/ruby
2. text = "this is some text"
3. puts "The original text is: " + text
4. puts "The length of the text is #{text.length}"
5. puts "Capitalized: " + text.capitalize
6. puts "Upper Case: " + text.upcase
7. puts "Reversed: " + text.reverse
8. puts "Hello " * 5

The output from the above program is shown below.
The original text is: this is some text
The length of the text is 17
Capitalized: This is some text
Upper Case: THIS IS SOME TEXT
Reversed: txet emos si siht
Hello Hello Hello Hello Hello
The String class also has a split method, which
returns an array of strings based on the supplied delimiter.
splitting.rb
1. #!/usr/bin/ruby
2. text = "this,is,comma,separated"
3. result = text.split(",")
4. puts result

The output from the above program is shown below.
this
is
comma
separated

Arrays will be covered in detail in a later chapter.
RUBY PROGRAMMING CHAPTER 2: STANDARD RUBY DATA TYPES
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
2-6
Strings
Strings are references, so even though assignment is
simple, be aware of the following.
string_reference.rb
1. #!/usr/bin/ruby
2. message = "This is a string"
3. text = message
4. text.upcase!
5. puts message, text

The output from the above program is shown below.
THIS IS A STRING
THIS IS A STRING
If you truly want a separate string, you can use the dup
method as shown below.
string_dup.rb
1. #!/usr/bin/ruby
2. message = "This is a string"
3. text = message.dup
4. text.upcase!
5. puts message, text

The output from the above program is shown below.
This is a string
THIS IS A STRING
The next page discusses some of the more common
String methods.
RUBY PROGRAMMING CHAPTER 2: STANDARD RUBY DATA TYPES
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
2-7
Strings
The following two methods return the zero based position
of one string within the "host" string.
index returns the left-most position.
rindex returns the right-most position.
The special value of nil is returned by both methods if the
host string does not contain the string.
indexes.rb
1. #!/usr/bin/ruby
2. txt = "More than 10 years ago";
3. puts "Left a : #{txt.index("a")}"
4. puts "Middle a from Left: #{txt.index('a', 4)}"
5. puts "Right a: #{txt.rindex('a')}"
6. puts "Middle a from Right: #{txt.rindex('a', -9)}"

The output from the above program is shown below.
Left a : 7
Middle a from Left: 7
Right a: 19
Middle a from Right: 7
Stripping whitespace from a String can be done with the
following methods.
strip and strip!
Removes leading and trailing whitespace
lstrip and lstrip!
Removes leading whitespace
rstrip and rstrip!
Removes trailing whitespace

RUBY PROGRAMMING CHAPTER 2: STANDARD RUBY DATA TYPES
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
2-8
Strings
A string can also be accessed in whole or in parts using
the element reference operator [] (square brackets).
As we will see later in the course, this operator (like most
operators in Ruby) is implemented as a method of the data
type.
The example below demonstrates the versatility
embedded within the [] operator.
elements.rb
1. #!/usr/bin/ruby
2. s = "this is an example string"
3. puts s[0] # t in Ruby 1.9.x
4. # 116 in prior versions of Ruby
5. puts s[0].chr # t in all versions of Ruby
6. puts s[5,7] # start at pos 5 and get 7 chars
7. puts s[-6,3] # start 6 from the right end
8. s[0,0] = "Hello" #insert at position
9. puts s
10.
11. #start at position 0 replace 15 chars with something
12. s[0,15] = "something"
13. puts s

The output from the above program is shown below.
t
t
is an e
str
Hellothis is an example string
something example string
RUBY PROGRAMMING CHAPTER 2: STANDARD RUBY DATA TYPES
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
2-9
Simple Input and Output
Below is a small program that illustrates how a program
might get some simple input from a user.
input.rb
1. #!/usr/bin/ruby
2. print "Enter a line: "
3. line = gets
4. puts line.class, line.length

The output from the above program is shown below.
Enter a line: Michael
String
8
There are a few things to notice about the program.
The gets method gets a single line from the user.
The line contains the newline character.
The returned data is of type String.
The puts method outputs data to the display.
print is like puts except that it does not display a newline.
If you wished to do some arithmetic with a line obtained
with gets, you would have to convert the line to either an
integer or a float.
The following methods are widely used in Ruby programs.
to_i converts to integer
to_f converts to float
to_s converts to String
RUBY PROGRAMMING CHAPTER 2: STANDARD RUBY DATA TYPES
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
2-10
Converting String Input
A few conversion methods are shown below.
convert.rb
1. #!/usr/bin/ruby
2. print "Enter a line: "
3. line = gets.chop
4. sum = line.to_i + line.to_i
5. puts line + " plus " + line + " is " + sum.to_s

The output from the above program is shown below.
Enter a line: 10
10 plus 10 is 20
The chop method removes the last character of a string.
There is a similar method named chomp that removes the last
character of a string only if it is a newline character.
The to_i method will work fine for integer input but will
truncate string or floating point data.
The + method is used to concatenate two strings.
The to_s method may be needed to convert data to string data
before it is concatenated.
Below is a simplified version of the puts (or print)
method, using interpolation.
puts "#{line} plus #{line} is #{sum}"

RUBY PROGRAMMING CHAPTER 2: STANDARD RUBY DATA TYPES
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
2-11
Regular Expressions
Often, a program needs to determine if a string matches a
certain pattern.
Is it all digits?
Is it all alphabetic?
Is it an email address?
Modern programming languages deal with these problems
by using regular expressions.
A regular expression is a way of representing a pattern by using
special symbols.
Once a regular expression has been encoded, it is used to
determine if a string matches the pattern expressed by the
regular expression.
The regular expression matching operator is =~.
A test to determine if a string matches a pattern might look like
this.
if string =~ /PATTERN/
do something
end
A few of the special symbols used by Ruby in the
formulation of regular expressions are shown on the next
page.



RUBY PROGRAMMING CHAPTER 2: STANDARD RUBY DATA TYPES
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
2-12
Regular Expressions
The following characters are used to anchor the pattern.
Symbol Meaning Example
^
At the beginning
/^the/
$
at the end
/the$/
Here is a simple example.
regex1.rb
1. #!/usr/bin/ruby
2. puts "Please enter some text:"
3. line = gets.chomp
4.
5. result = line =~ /^the/
6. print "result data type: ", result.class, "\n"
7. print "result value: ", result, "\n"
8.
9. result = "ends with the" =~ /the$/
10. print "result data type: ", result.class, "\n"
11. print "result value: ", result, "\n"

The output from the above program is shown below.
Please enter some text:
hello
result data type: NilClass
result value:
result data type: Fixnum
result value: 10
You can use the i character at the end of the pattern to
ignore the case.
line =~ /^the/i
RUBY PROGRAMMING CHAPTER 2: STANDARD RUBY DATA TYPES
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
2-13
Regular Expressions
Other special symbols used to match patterns appear in
the following table.
Symbol Meaning Example
.
Any character
/A.B/
[ ]
Alternatives
/s[uoi]n/
\w
Letter or digit
/ \w\w /
\s
Whitespace character
/^\w\w\s/
\d
Digit character
/ \d\d /
{m,n}
m through n reps of preceding char
/A{2,4}B/
?
Zero or one of preceding char
/^[+-]?/
*
Zero or more of preceding char
/A.*B/
+
One or more of preceding char
/^\d+\s/

RUBY PROGRAMMING CHAPTER 2: STANDARD RUBY DATA TYPES
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
2-14
Time Methods
You can do various things with Time objects.
Below is a sample program illustrating a Time object.
timestuff.rb
1. #!/usr/bin/ruby
2. d = Time.new # or Time.now
3. puts d.class
4. puts d

The output from the program is shown below:.
Time
Sun Aug 15 09:57:48 -0400 2010 # UTC not GMT

As a historical side, with modern precision instruments, the
need for UTC was born.
UTC stands for Coordinated Universal Time in English and
Temps universel coordonn in French.
The acronym was abbreviated UTC as a compromise
between CUT and TUC in English and French, respectively.
Here are some other useful Time methods.
moretime.rb
1. #!/usr/bin/ruby
2. t = Time.new
3. puts t
4. puts "DAY: #{t.day}"
5. puts "MON: #{t.month}"
6. puts "YR: #{t.year}"
7. puts "HR: #{t.hour}"
8. puts "MIN: #{t.min}"
9. puts "SEC: #{t.sec}"
10. puts "TOMORROW: #{Time.at(t + 60 * 60 * 24)}"
11. puts "USING CTIME: #{t.ctime}"
RUBY PROGRAMMING CHAPTER 2: STANDARD RUBY DATA TYPES
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
2-15
Exercises
1. Write a program that prompts the user to enter the radius
of a circle.
Accept the user input into a variable.
Compute the area of the circle whose radius was input.
The formula for the area of a circle is pi times the square of
the radius.
Use 3.14159 for pi.
2. Write a program that prompts the user for a string and a
number on separate lines.
The program should print the string replicated by the number.
For example, if the string is "sample" and the number is 3,
then samplesamplesample should be printed.
3. Write a program that prompts the user for two numbers.
The first number will be the base.
The second number will be the exponent.
Print the result of raising the base to the exponent.
4. Write a program that accepts a string from the user.
Print the following about the string.
Print the length of the string.
Print the first five characters of the string.
Look for and print the result of calling the method in the
String class that will convert the string to lower case.
RUBY PROGRAMMING CHAPTER 2: STANDARD RUBY DATA TYPES
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
2-16
This Page Intentionally Left Blank
RUBY PROGRAMMING CHAPTER 3: LANGUAGE COMPONENTS
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
3-1
Chapter 3:
Language Components
1) The if Statement..................................................................................................... 3-2
2) The Logical Operators............................................................................................. 3-3
3) The case Construct ................................................................................................ 3-4
4) Loops ......................................................................................................................... 3-5
5) Iterators .................................................................................................................... 3-9
6) Numeric Iterators................................................................................................... 3-10
7) String Iterators....................................................................................................... 3-13
8) Methods................................................................................................................... 3-16
9) Odds and Ends ....................................................................................................... 3-18

RUBY PROGRAMMING CHAPTER 3: LANGUAGE COMPONENTS
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
3-2
The if Statement
Ruby has a rich set of control flow constructs, each of
which typically uses a relational operator.
Operator Meaning
==
Equal
!=
Not equal
>
Greater than
<
Less than
>=
Greater than or equal to
<=
Less than or equal to
The fundamental decision making construction in most
programming languages is the if statement.
The general form of an if statement in Ruby is shown below.
if condition
# statements to be executed if condition is true
end

The condition is always an expression whose value is
either true or false.

There may also be an else portion to the if statement.
if condition
# statements executed if condition is true
else
# statements executed if condition is false
end

Finally, there is an elsif construction as well.
RUBY PROGRAMMING CHAPTER 3: LANGUAGE COMPONENTS
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
3-3
The Logical Operators
There are many cases where a compound condition must
be evaluated.
This is where logical operators come into play.
The table below lists these logical operators.
Operator Meaning
!
Logical NOT
&&
Logical AND
||
Logical OR
not
Logical NOT
and
Logical AND
or
Logical OR
Below is a program that uses both the logical || operator
and the elsif construction.
elsif.rb
1. #!/usr/bin/ruby
2. print "Enter a number: "
3. grade = gets.to_i
4. if grade < 0 || grade > 100
5. puts "ILLEGAL GRADE"
6. elsif grade < 60
7. puts "You got an F"
8. elsif grade < 70
9. puts "You got a D"
10. elsif grade < 80
11. puts "You got a C"
12. elsif grade < 90
13. puts "You got a B"
14. else
15. puts "You got an A"
16. end
RUBY PROGRAMMING CHAPTER 3: LANGUAGE COMPONENTS
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
3-4
The case Construct
Some decision making is coded more clearly if you use a
case construction rather than a series of elsifs.
case.rb
1. #!/usr/bin/ruby
2. while true
3. print "Enter a number "
4. grade = gets
5. exit if grade =~ /exit|quit/i
6. case grade.to_i
7. when 90..100
8. puts "A"
9. when 80..89
10. puts "B"
11. when 70..79
12. puts "C"
13. when 60..69
14. puts "D"
15. when 0..59
16. puts "F"
17. else
18. puts "ILLEGAL"
19. end
20. end

The output from the above program is shown below.
Enter a number 85
B
Enter a number 75
C
Enter a number quit
Notice that the above code also illustrates the following.
Modifier form of the if statement
Regular expressions
RUBY PROGRAMMING CHAPTER 3: LANGUAGE COMPONENTS
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
3-5
Loops
The Ruby language offers the usual set of traditional
looping constructs, as well as some special looping
constructs known as iterators.
The example below demonstrates use of the traditional loops.
loops.rb
1. #!/usr/bin/ruby
2. print "For loop using inclusive range: "
3. for i in 0..10
4. print i, " "
5. end
6.
7. print "\nFor loop using exclusive range: "
8. for i in 0...10
9. print i, " "
10. end
11.
12. print "\nWhile loop: "
13. i = 0
14. while i < 10
15. print i , " "
16. i += 1
17. end
18.
19. print "\nUntil loop: "
20. i = 0
21. until i > 9 # executes if condition is false
22. print i , " "
23. i += 1
24. end
25. puts

The output from the above program is shown below.
For loop using inclusive range: 0 1 2 3 4 5 6 7 8 9 10
For loop using exclusive range: 0 1 2 3 4 5 6 7 8 9
While loop: 0 1 2 3 4 5 6 7 8 9
Until loop: 0 1 2 3 4 5 6 7 8 9
RUBY PROGRAMMING CHAPTER 3: LANGUAGE COMPONENTS
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
3-6
Loops
Loop control can be altered by using the following
statements.
break break out of the loop
next perform the next iteration of this loop
redo perform the same iteration again
The following example demonstrates the use of the
break statement within a for loop.
Any looping construct could have been used, not just a for
loop.
The break at the first value of the variable i that, when
squared, is greater than 500.
break.rb
1. #!/usr/bin/ruby
2. for i in 1..100
3. squared = i ** 2
4. if squared > 500
5. break
6. end
7. print "#{i}:#{squared} "
8. puts if i % 5 == 0 # modifier form of an if
9. end
10. puts

The output from the above program is shown below.
1:1 2:4 3:9 4:16 5:25
6:36 7:49 8:64 9:81 10:100
11:121 12:144 13:169 14:196 15:225
16:256 17:289 18:324 19:361 20:400
21:441 22:484
RUBY PROGRAMMING CHAPTER 3: LANGUAGE COMPONENTS
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
3-7
Loops
The following example demonstrates the use of the next
statement within a while loop.
next.rb
1. #!/usr/bin/ruby
2. total = 0;
3. while true
4. print "Please enter an integer: "
5. text = gets.chomp
6. break if text =~ /^quit$/i
7. next if text =~ /\D/ #contains a non-digit
8. total += text.to_i
9. puts " Subtotal is #{total}"
10. end
11. puts "Total is:", total

Sample output from the program is shown below.
Please enter an integer: 10
Subtotal is 10
Please enter an integer: 20
Subtotal is 30
Please enter an integer: asdf
Please enter an integer: 50
Subtotal is 80
Please enter an integer: quit
Total is:
80

Note that in addition to the next statement skipping input
that is not all digits, it also includes a break statement to
quit out of the loop.
The example on the following page demonstrates the use
of the redo statement.
RUBY PROGRAMMING CHAPTER 3: LANGUAGE COMPONENTS
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
3-8
Loops
redo.rb
1. #!/usr/bin/ruby
2. mistakes = 0
3. for i in 1..5
4. if mistakes == 2
5. puts "Too many mistakes"
6. break
7. end
8. puts "Please type the number shown: #{i}"
9. value = gets.to_i
10. if value != i
11. mistakes += 1
12. redo
13. end
14. puts " #{i} of 5 complete"
15. end
16. puts "Congrats - no mistakes" if mistakes == 0

Sample output from the program is shown below.
Please type the number shown: 1
3
Please type the number shown: 1
1
1 of 5 complete
Please type the number shown: 2
2
2 of 5 complete
Please type the number shown: 3
4
Too many mistakes

RUBY PROGRAMMING CHAPTER 3: LANGUAGE COMPONENTS
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
3-9
Iterators
Ruby also has a large set of looping constructs called
iterators.
An iterator in Ruby is a method that can invoke a block of code
repeatedly.
Ruby allows both {} and do/end iterator blocks.
When the body of the iterator consists of a single statement, the
{} syntax is suggested.
When the body of the iterator consists of multiple statements,
the do/end syntax is preferred.
Each value that is generated by the iterator can be
referenced within the block of code by assigning it to a
variable inside of vertical bars |variable_name|.
The variable_name is an arbitrary name assigned to the
generated value that can then be accessed by that variable
name each time through the iterator.
The next few pages will demonstrate iterators.
The first three examples will be iterators called on Integer
objects and consist of the times, upto, and step iterators.
Next, there will be two more examples that are called on
String objects and consist of the upto and each_line
iterators.
RUBY PROGRAMMING CHAPTER 3: LANGUAGE COMPONENTS
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
3-10
Numeric Iterators
Below is an example of the times iterator that can be
called on Integer objects.
times.rb
1. #!/usr/bin/ruby
2. 5.times { print "Hello " }
3. puts
4.
5. 5.times { |value| print "Hello#{value} " }
6. puts
7.
8. text = "a"
9. 5.times do
10. puts text
11. text += "a"
12. end
13.
14. 5.times do |val|
15. print val
16. print " squared is "
17. puts val**2
18. end

The output from the above program is shown below.
Hello Hello Hello Hello Hello
Hello0 Hello1 Hello2 Hello3 Hello4
a
aa
aaa
aaaa
aaaaa

0 squared is 0
1 squared is 1
2 squared is 4
3 squared is 9
4 squared is 16
RUBY PROGRAMMING CHAPTER 3: LANGUAGE COMPONENTS
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
3-11
Numeric Iterators
Below is an example of the upto iterator being called on
Integer objects.
upto_numeric.rb
1. #!/usr/bin/ruby
2. 1.upto(5) { print "Hello " }
3. puts
4.
5. 5.upto(10) { |value| print "#{value} " }
6. puts
7.
8. text = "a"
9. 1.upto(5) do
10. puts text
11. text += "a"
12. end
13.
14. 2.upto(4) do |val|
15. print val
16. print " squared is "
17. puts val**2
18. end

The output from the above program is shown below.
Hello Hello Hello Hello Hello
5 6 7 8 9 10
a
aa
aaa
aaaa
aaaaa
2 squared is 4
3 squared is 9
4 squared is 16
RUBY PROGRAMMING CHAPTER 3: LANGUAGE COMPONENTS
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
3-12
Numeric Iterators
Below is an example of the step iterator being called on
Integer objects.
step.rb
1. #!/usr/bin/ruby
2. 1.step(10) { |i| print i, " " }
3. puts
4.
5. 1.step(10,2) { |i| print i, " " }
6. puts
7.
8. 10.step(1,-1) { |i| print i, " " }
9. puts
10.
11. a = 10
12. b = 1
13. c = -2
14. a.step(b,c) do |value|
15. puts value
16. end

The output from the above program is shown below.
1 2 3 4 5 6 7 8 9 10
1 3 5 7 9
10 9 8 7 6 5 4 3 2 1
10
8
6
4
2
RUBY PROGRAMMING CHAPTER 3: LANGUAGE COMPONENTS
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
3-13
String Iterators
Below is an example of the upto iterator being called on
String objects.
The upto iterator for strings provides a way to generate other
strings.
upto_text.rb
1. #!/usr/bin/ruby
2. chars = ""
3. 'a'.upto('z') { |val| chars += val}
4. puts chars
5. chars = ""
6. "0".upto("9") { |val| chars += val}
7. puts chars
8. chars = ""
9. counter = 1
10. "aa".upto("cc") do |val|
11. chars += val
12. chars += "\n" if counter % 13 == 0
13. counter += 1
14. end
15. puts chars

The output from the above program is shown below.
abcdefghijklmnopqrstuvwxyz
0123456789
aaabacadaeafagahaiajakalam
anaoapaqarasatauavawaxayaz
babbbcbdbebfbgbhbibjbkblbm
bnbobpbqbrbsbtbubvbwbxbybz
cacbcc
RUBY PROGRAMMING CHAPTER 3: LANGUAGE COMPONENTS
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
3-14
String Iterators
There may be occasions when a Ruby string contains
many lines (i.e., many new line characters).
The default string iterator can process such a string a line at a
time.
each_strings.rb
1. #!/usr/bin/ruby
2. lines = "this\nis\na simple\r\nexample"
3. lines.each_line do | aLine |
4. aLine.chomp!
5. print aLine + " "
6. puts aLine.length
7. end
8. puts
9.
10. lines = "Hello"
11. lines.each_char do | aChar |
12. print aChar, "\t"
13. end
14. puts
15.
16. lines.each_byte do | aByte |
17. print aByte, "\t"
18. end
19. puts "\n\n"
20.
21. lines = "\u03C0" # Greek lowercase pi
22. lines.each_char do | aChar |
23. print aChar, " "
24. end
25. puts
26.
27. lines.each_byte do | aByte |
28. print aByte, " "
29. end
30. puts

The output from the program is shown on the next page.
RUBY PROGRAMMING CHAPTER 3: LANGUAGE COMPONENTS
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
3-15
String Iterators
The output below was generated by the application on the
previous page.
this 4
is 2
a simple 8
example 7

H e l l o
72 101 108 108 111


207 128

There are several things to note from the previous program.
The lowercase pi character is a String of a single
character.
When iterated through using the each_byte iterator, it
consisted of two bytes.
The chop and chomp methods treat both a \n and \r\n as
an end of line character that is removed.
RUBY PROGRAMMING CHAPTER 3: LANGUAGE COMPONENTS
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
3-16
Methods
In writing software, there is often the need to write the
same logic and have it operate on different data.
A sound strategy is to encapsulate the code and feed to it the
data on which it will operate.
Like other languages, this is accomplished in Ruby using
methods.
An example of such a method is shown next.
largest.rb
1. #!/usr/bin/ruby
2. def largest(a, b, c)
3. max = a > b ? a : b
4. max = c > max ? c : max
5. return max
6. end
7. print "input 3 numbers: "
8. a,b,c = gets.split
9. puts largest(a.to_i,b.to_i,c.to_i)

The output from the above program is shown below.
input 3 numbers: 3 2 10
10
The keyword def defines a method.
This is followed by the method name, which is followed by (if
there are any) a set of parameters enclosed within
parentheses.
The parameters are comma-separated.
The entire method is terminated with the keyword end.
RUBY PROGRAMMING CHAPTER 3: LANGUAGE COMPONENTS
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
3-17
Methods
Parameters are local.
If they happen to coincide with the name of a variable outside
the subroutine, they refer to different places in memory.
Variables defined within a method are also local.
The same named variables referenced outside of a method are
references to different places in memory.
The last evaluated expression within a function is the
value returned by the function.
Therefore, the previous function could have been written
without a return statement.
def largest(a, b, c)
max = a > b ? a : b
max = c > max ? c : max
end
A method can also have default parameters.
If the programmer does not supply a parameter, the default
value is used.
default.rb
1. #!/usr/bin/ruby
2. def total(first = 1, last = 10)
3. result = 0
4. first.upto(last) do | i |
5. result = result + i
6. end
7. result
8. end
9. puts total() # prints 55
10. puts total(5) # prints 45
11. puts total(10,20) # prints 165
RUBY PROGRAMMING CHAPTER 3: LANGUAGE COMPONENTS
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
3-18
Odds and Ends
You can execute command line commands within a Ruby
script. (Be careful if not on a Unix variant!)
datetime.rb
1. #!/usr/bin/ruby
2. puts "DATE: " + `date | cut -c1-10`
3. puts "TIME: " + `date | cut -c12-16`

The output from the above program is shown below.
Date: Wed June 21
Time: 12:51
You can also execute Ruby one-liners on the command
line.
For example, the following code displays the lines from file
matching the pattern the.
$ ruby -ne 'puts $_ if /the/' file
When a control structure contains one line, you can write
it using the modifier form.
while true
print "enter number or quit "
line = gets.chomp
exit if line == "quit"
puts line.to_i * line.to_i
end
RUBY PROGRAMMING CHAPTER 3: LANGUAGE COMPONENTS
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
3-19
Odds and Ends
There are various ways of assigning values.
Variables are just references.
x = "hello"
y = x
x[0] = 'M'
puts y # prints Mello

You can make multiple assignments.
x = y = z = 0

You can make parallel assignments.
a = 5
b = 10
c = 20
a,b,c = c,a,b
puts a # 20
puts b # 5
puts c # 10
Code can be executed when your program is being
loaded by using a BEGIN block. Likewise, code can be
executed after your program has terminated by using an
END block.
beginend.rb
1. #!/usr/bin/ruby
2. BEGIN {
3. puts "BEGIN: " + Time.now.to_s
4. }
5. sleep 5
6. END {
7. puts "END: " + Time.now.to_s
8. }
RUBY PROGRAMMING CHAPTER 3: LANGUAGE COMPONENTS
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
3-20
Odds and Ends
Ruby allows the __END__ directive so that you can
exclude, from execution, the bottom part of your program.
Using this directive allows you to write large portions of code,
while executing all but the last so many lines.
end.rb
1. #!/usr/bin/ruby
2. puts "line1"
3. puts "line2"
4. __END__
5. puts "line3"

The output from the above program is shown below.
line1
line2
You can place data below the __END__ line and have
your program read it with the pre-opened object DATA.
data.rb
1. #!/usr/bin/ruby
2. line = DATA.gets # read one line
3. x = DATA.read # read rest of lines
4. puts "FIRST LINE: " + line
5. x.each_line { | x | puts x }
6. __END__
7. Hello there, how are
8. you doing today?

The output from the above program is shown below.
FIRST LINE: Hello there, how are
you doing today?
RUBY PROGRAMMING CHAPTER 3: LANGUAGE COMPONENTS
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
3-21
Exercises
1. Write a program that inputs a number.
The program should print the square of the number and
whether the number is positive, negative, or zero.
2. Write a program that inputs two numbers, one per line.
The program should determine which number is larger or if they
are the same.
3. Write a program that prints out the numbers from zero to
some higher limit (but only if the number is divisible by 7).
The limit should be supplied interactively.
4. Write a program that reads five lines entered by the user
and displays those lines that both begin with a capital
letter and end with a lower case vowel.
5. Write a program that loops over lines entered by the user.
The program should print all those lines that represent .com
domain names (i.e., www.trainingetc.com).
RUBY PROGRAMMING CHAPTER 3: LANGUAGE COMPONENTS
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
3-22
This Page Intentionally Left Blank
RUBY PROGRAMMING CHAPTER 4: COLLECTIONS
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
4-1
Chapter 4:
Collections
1) Arrays........................................................................................................................ 4-2
2) Array Operator Methods ........................................................................................ 4-5
3) Array Equality Operator ........................................................................................ 4-9
4) Arrays as Stacks and Queues................................................................................ 4-10
5) Higher Dimensional Arrays .................................................................................. 4-11
6) Other Useful Arrays Methods............................................................................... 4-12
7) Command Line Arguments................................................................................... 4-13
8) Hashes ..................................................................................................................... 4-14
9) Common Hash Methods........................................................................................ 4-17
10) Sorting Hashes........................................................................................................ 4-18
11) Iterators with Arrays and Hashes ........................................................................ 4-20
12) Arrays and Methods .............................................................................................. 4-21
13) Hashes and Methods.............................................................................................. 4-22
14) Named Parameters................................................................................................. 4-23
15) Symbols ................................................................................................................... 4-24
16) Procs ........................................................................................................................ 4-26
17) Closures................................................................................................................... 4-28

RUBY PROGRAMMING CHAPTER 4: COLLECTIONS
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
4-2
Arrays
This section builds on some of the rudimentary ideas
covered in the previous chapter.
We are mostly concerned here with two collection types, arrays
and hashes.
An array is an ordered set of values, each of which can be
selected by using a subscript.
The subscript essentially "measures" the distance from the
beginning of where the array is stored in memory.
(see negative subscripts later!)
Arrays are dynamic, meaning their size may vary during
the running of the program.
Arrays can be created as shown below.
values = [ 10, 20, 30 ] # create
data = %W[ 5 10 15] # create
print values # 102030
puts values.length # 3
Elements can be accessed by using a subscript.
Notice the first element in the array will have subscript zero.
values[0] # 10
values[1] # 20
values[3] # nil
values[-1] # 30
You can add to an array as shown below.
values[5] = 50
RUBY PROGRAMMING CHAPTER 4: COLLECTIONS
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
4-3
Arrays
Arrays are typically processed with loops.
array_with_for_loop.rb
1. #!/usr/bin/ruby
2. values = [ 10, 20, 30 ]
3. values[5] = 50
4. for value in values
5. print value, " "
6. end

The output from the above program is shown below.
10 20 30 nil nil 50
You can also process an array by using the each method.
The each method is another example of a Ruby iterator.
The set of curly braces in the line below is called a block.
values.each { |value| print value + " " }

If the block contains more than one statement, you can use
the do end sequence rather than the curly braces.
ct = 0
values.each do |item|
if item > 0
ct += 1
end
end
puts ct

The variable inside the 'pipe' symbols obtains, in turn, each
item in the array.
Ruby arrays have a plethora of methods defined for them.
You can create an array object and give its size and default
values with the new method.
RUBY PROGRAMMING CHAPTER 4: COLLECTIONS
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
4-4
Arrays
For example, the array data will have 10 items, each with a
value of 0.
vals = Array.new(10) # 10 items, each nil
data = Array.new(10, 0) # 10 items, each 0
puts data.empty? # false
puts data.length # 10
Sometimes, it is necessary to create an empty array.
mydata = Array.new
puts mydata.empty? # true
puts mydata.length # 0
The join method is convenient for taking an array and
creating a String from it.
Each element in the resulting string is separated with your
choice of a delimiter.
This is useful when you need to print the elements of an
array on a single line.
printarray.rb
1. #!/usr/bin/ruby
2. data = [ 10, 20, 30, 40 ]
3. print data
4. puts data
5. p data
6. puts data.join(" ")

The output from the above program is shown below.
1020304010
20
30
40
[10, 20, 30, 40]
10 20 30 40
RUBY PROGRAMMING CHAPTER 4: COLLECTIONS
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
4-5
Array Operator Methods
The Array class also defines many operator methods.
We are referring here to operations on arrays, which are
implemented as methods but can be invoked syntactically as
operators.
The first few of these operators are used to simulate
(although not exactly) mathematical set operations.
& set intersection
| set union
- set difference
Below is an example demonstrating these operators.
sets.rb
1. #!/usr/bin/ruby
2. golf = %W[Bob Mike Joe Kevin Patti]
3. tennis = %W[Bob Patti Jason John]
4. puts "Golf: #{golf.join(' ')}"
5. puts "Tennis: #{tennis.join(' ')}"
6. both = tennis & golf
7. puts "Both (Intersection): #{both.join(' ')}"
8. players = tennis | golf
9. puts "All (Union): #{players.join(' ')}"
10. diff1 = tennis - golf
11. diff2 = golf - tennis
12. puts "Tennis - NOT Golf (Diff): #{diff1.join(' ')}"
13. puts "Golf - NOT Tennis (Diff): #{diff2.join(' ')}"

The output from the above program is shown below.
Golf: Bob Mike Joe Kevin Patti
Tennis: Bob Patti Jason John
Both (Intersection): Bob Patti
All (Union): Bob Patti Jason John Mike Joe Kevin
Tennis - NOT Golf (Diff): Jason John
Golf - NOT Tennis (Diff): Mike Joe Kevin
RUBY PROGRAMMING CHAPTER 4: COLLECTIONS
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
4-6
Array Operator Methods
Some other array operators are shown below.
*, +, [], <<, ==
The * operator for arrays has two forms, depending upon
the type of the right hand operand.
String
Fixnum
In the following example, we show how each operand
affects the results.
star.rb
1. #!/usr/bin/ruby
2. names = %w[moe larry curly]
3. names = names * 2
4. puts names.join(" ")
5. names = names * " and "
6. puts names

The output from the above program is shown below.
moe larry curly moe larry curly
moe and larry and curly and moe and larry and curly
Next, we look at the + operator for arrays.
In Ruby, this is how you concatenate arrays.
Note that if you really wish to multiply or add respective
elements of an array, you will have to write your own loop.

RUBY PROGRAMMING CHAPTER 4: COLLECTIONS
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
4-7
Array Operator Methods
The + operator simply concatenates two arrays.
Since this is a simple operator, the example below melds other
array methods as well.
[ ]
sort
size, length
concat.rb
1. #!/usr/bin/ruby
2. teachers = %W[Dave alan Mike Barb]
3. sales = Array['bonnie', "sheri"]
4. susans = ['SusanD', 'SusanS', 'SusanL']
5. others = %W[Marvin Charles]
6. staff = teachers + sales + others + susans
7. puts staff.length
8. puts staff.size
9. puts staff.sort

The output from the above program is shown below.
11
11
Barb
Charles
Dave
Marvin
Mike
SusanD
SusanL
SusanS
alan
bonnie
sheri
RUBY PROGRAMMING CHAPTER 4: COLLECTIONS
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
4-8
Array Operator Methods
The << operator allows you to append an item to the end
of an array.
The array must exist before it can be appended to.
The following loop gets strings from the user and prints
the strings in reverse sorted order.
append.rb
1. #!/usr/bin/ruby
2. lines = []
3. puts "Input words, one per line. End with "
4. puts "ctrl-d on Linux (ctrl-z) on windows!"
5. while line = gets
6. line.chop!
7. lines << line
8. end
9. puts lines.sort.reverse

The output from the above program is shown below.
Input words, one per line. End with
ctrl-d on Linux (ctrl-z) on windows!
this
is
the
plan
this
the
plan
is
$
Note the ease with which you can combine methods.
For example:
puts lines.sort.reverse.join("|")
RUBY PROGRAMMING CHAPTER 4: COLLECTIONS
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
4-9
Array Equality Operator
For arrays, the == operator tests to see whether
respective elements of an array are equal.
This method returns one of two Boolean values, true or
false.
Here is an example that exhaustively covers the
possibilities.
equal.rb
1. #!/usr/bin/ruby
2. one = [1, 2, 3]
3. two = [1, 2, 3]
4. three = [1,2, 4]
5. four = [1, 2, 3, 4]
6. puts one == two
7. puts one == three
8. puts one == four
9. puts [] == []

The output from the above program is shown below.
true
false
false
true

The last line in the code above simply compares two empty
arrays.
The idea of two objects being equal is not a simple issue.
At the heart of this matter is whether two object references are
equal vs. the objects to which they refer.

RUBY PROGRAMMING CHAPTER 4: COLLECTIONS
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
4-10
Arrays as Stacks and Queues
A stack is a data structure that allows for additions and
deletions at the end.
Stacks are widely used in many computer problems.
You can use an array to implement a stack.
The example below demonstrates several of the available
methods.
stack.rb
1. #!/usr/bin/ruby
2. data = []
3. puts "Push a few numbers onto an array."
4. 1.upto(5) { |number| data.push(rand(100) ) }
5. puts data
6. puts "Now pop a few of them off the array."
7. 1.upto(3) do |item|
8. puts data.pop
9. sleep(1)
10. end
11. puts data.size.to_s + " elements remain."
12. puts "Now clear the array"
13. data.clear
14. puts data.size.to_s + " elements now remain."
There is no difference between << and push.
They are two different interfaces to the same functionality.
It is equally easy to alter the beginning of an array by
using either shift or unshift.
shift returns and removes the 0
th
element of the array.
unshift adds one or more items to the beginning of the array.

RUBY PROGRAMMING CHAPTER 4: COLLECTIONS
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
4-11
Higher Dimensional Arrays
Ruby does not support native two-dimensional arrays, but
this is not a hazard.
You can simply build an array of arrays.
The example below demonstrates various techniques for
looping through a multidimensional array.
twodim.rb
1. #!/usr/bin/ruby
2. a = [ [1, 2], [3, 4], [5, 6] ]
3. puts "Use an iterator."
4. a.each { | x | p x }
5. puts "Now use nested iterators."
6. a.each do |x|
7. x.each { |y| print "#{y} " }
8. puts
9. end
10. puts "Now use subscripts."
11. i = 0
12. while ( i < a.length )
13. j = 0;
14. while ( j < a[i].length )
15. print "#{a[i][j]} "
16. j += 1
17. end
18. puts
19. i += 1
20. end
An array's flatten method can be used to extract all
elements into a simple array.
RUBY PROGRAMMING CHAPTER 4: COLLECTIONS
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
4-12
Other Useful Arrays Methods
Other useful array methods are shown below.
array_others.rb
1. #!/usr/bin/ruby
2. vals = []
3. n = "\n"
4. 0.upto(10) {|i| vals[i] = rand(10)}
5. print "Values: ", vals.inspect, n
6. print "Unique Values: ", vals.uniq.inspect, n
7. print "Index of 4 from left: ", vals.index(4), n
8. print "Index of 4 from right: ", vals.rindex(4), n
9. print "Index NOT in the array: ", vals.index(30), n
10. print "Remove all occurrences of element: ", \
11. vals.delete(4), n
12. print "Values after deletion: ", vals.inspect, n
13. print "Remove element from given index: ", \
14. vals.delete_at(5), n
15. print "Values after deletion: ", vals.inspect, n
16. print "Insert into position 7 a value of 99: ", \
17. vals.insert(7, 99).inspect, n
18. print "Values after insert: ", vals.inspect, n
19. print "Results of each_with_index:\n"
20. vals.each_with_index {|val, i| print "#{i}:#{val} "}

The output from the above program is shown below.
Values: [8, 0, 5, 7, 1, 3, 0, 0, 7, 6, 1]
Unique Values: [8, 0, 5, 7, 1, 3, 6]
Index of 4 from left: nil
Index of 4 from right: nil
Index NOT in the array: nil
Remove all occurrences of element: nil
Values after deletion: [8, 0, 5, 7, 1, 3, 0, 0, 7, 6, 1]
Remove element from given index: 3
Values after deletion: [8, 0, 5, 7, 1, 0, 0, 7, 6, 1]
Insert into position 7 a value of 99:
[8, 0, 5, 7, 1, 0, 0, 99, 7, 6, 1]
Values after insert: [8, 0, 5, 7, 1, 0, 0, 99, 7, 6, 1]
Results of each_with_index:
0:8 1:0 2:5 3:7 4:1 5:0 6:0 7:99 8:7 9:6 10:1
RUBY PROGRAMMING CHAPTER 4: COLLECTIONS
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
4-13
Command Line Arguments
Ruby has a built-in array named ARGV, which represents
the arguments passed to the command from the
command line.
This array does not include the command name.
Below is a simple program that displays the sum of the
integers between the two arguments given on the
command line.
sumfrom.rb
1. #!/usr/bin/ruby
2. if ARGV.length != 2
3. puts "Usage sumfrom.rb low high"
4. exit 1
5. end
6. low = ARGV[0].to_i
7. high = ARGV[1].to_i
8. sum = 0
9. low.upto(high) { | i | sum += i }
10. puts sum

The output from the above program is shown below.
$ sumfrom.rb
usage: sumfrom.rb low high
$ sumfrom.rb 1 10
55
$ sumfrom.rb 10 20
165
Most of the code above is self-explanatory.
The strings from the command line need to be converted to
integers in order to compute with them.
RUBY PROGRAMMING CHAPTER 4: COLLECTIONS
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
4-14
Hashes
There are a many problems where software solutions
involve paired data.
Arrays are not sufficient to handle these particular problems.
A hash solves this problem.
A hash is a data structure of unordered pairs.
Each pair consists of a key and a value.
The key is used to fetch the value.
A hash effectively saves you the cost of a lookup.
The following example demonstrates the use of a hash.
hash.rb
1. #!/usr/bin/ruby
2. caps = {
3. "Maryland" => "Annapolis",
4. "Virginia" => "Richmond",
5. "New Jersey" => "Trenton",
6. "Massachusetts" => "Boston"
7. }
8. while true
9. print "Enter a State "
10. st = gets.chop
11. next if st.length == 0
12. break if st == "quit"
13. if caps.has_key?(st)
14. puts "#{caps[st]} is capitol of #{st}"
15. else
16. puts "No such state as #{st}."
17. end
18. end
RUBY PROGRAMMING CHAPTER 4: COLLECTIONS
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
4-15
Hashes
The code from the previous example is discussed below
in detail.
The code contains a hash of four pairs.
The states are the keys and the capitols are the values.
caps = {
"Maryland" => "Annapolis",
"Virginia" => "Richmond",
"New Jersey" => "Trenton",
"Massachusetts" => "Boston"
}

If the length of the text from the user is the empty string, the
next iteration of the while loop will be executed.
next if st.length == 0

If the length of the text was not the empty string it is then
checked to see if the user wants to quit from the loop.
break if st == "quit"

Next, we see whether this particular key is in the hash.
if caps.has_key?(st)
puts "#{caps[st]} is capitol of #{st}"
else
puts "No such state as #{st}."
end

If the key is present, we display the value for that key.
puts "#{caps[st]} is capitol of #{st}"
RUBY PROGRAMMING CHAPTER 4: COLLECTIONS
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
4-16
Hashes
Although the situation varies according to the problem,
hashes are often built dynamically during the running of
the program, rather than being initialized as in the
previous program.
In the program that follows, name value pairs are entered at the
program prompt, read by the program, and stored in a hash.
bank.rb
1. #!/usr/bin/ruby
2. bank = Hash.new(0)
3. while true
4. print "Enter name and amount of deposit: "
5. line = gets.chop
6. name, deposit = line.split
7. break if name == "quit"
8. bank[name] += deposit.to_i
9. end
10. bank.each { |n, v| puts "#{n}\t#{v}" }
Note that hash keys are unique, so in the following
sequence, the value 10 will be printed.
bank['mike'] += 3
bank['mike'] += 4
bank['mike'] += 3
puts bank['mike']

The program above splits each line into two fields and then
adds the value in the second field to the value part of the pair
whose key is given in the first field.
RUBY PROGRAMMING CHAPTER 4: COLLECTIONS
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
4-17
Common Hash Methods
Here are the most common methods used in connection
with hashes.
Create an empty hash.
caps = Hash.new

Create an empty hash with a default value for unseen keys.
caps = Hash.new("Empty")

Access the keys.
caps.each_key do | key |
puts key
end

Access the values.
caps.each_value { | value | puts value }

Access the pairs.
caps.each do | key, value |
puts key + " => " + value
end

Delete a pair.
caps.delete('Maryland')

Get the keys.
keys = caps.keys # array of keys

Get the values.
keys = caps.values # array of values

Additionally, take note of clear and invert.
RUBY PROGRAMMING CHAPTER 4: COLLECTIONS
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
4-18
Sorting Hashes
If you wanted to print just the keys in sorted order, the
following would work.
puts bank.keys.sort.join(" ")
If you just wanted to see the values in sorted order, you
could code the following.
puts bank.values.sort.join(" ")
If you wanted to sort the pairs by keys, then the following
would work.
puts score.sort.join(" ")

Unlike sorting the keys and the values, this particular sort is on
the hash itself.
In this situation, the pairs are sorted on the keys, by default.

However, in order to gain some insight into how that sort works,
examine the following.
score = { 'a' => 2, 'x' => 5, 'c' => 1 }
score.sort.class # Array
score.sort.size # 3
score.sort[0] # ['a', 2 ]
score.sort[1] # ['c', 1 ]

You can see that the hash sort method returns an array of as
many two-element arrays as there were pairs in the hash.
RUBY PROGRAMMING CHAPTER 4: COLLECTIONS
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
4-19
Sorting Hashes
Each two-element array contains a name and a value pair.
If you give the sort a block of code, you can compare whichever
part of the two-element array that you wish.
By default, the comparison is made on the keys.
However, you can also compare on the values.
score.sort { | a,b |a[1] <=> b[1] }

The comparison operator <=>, also known as the spaceship
operator, will be discussed in more detail in a later chapter.
In any case, the variables a and b each represent an array
of two elements.
Each two-element pair represents a key and a value.
In this case, we are comparing the values rather than the
keys.
If we had coded as shown below, then we would get the
default behavior, shown on the previous page.
score.sort { | a,b |a[0] <=> b[0] }
RUBY PROGRAMMING CHAPTER 4: COLLECTIONS
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
4-20
Iterators with Arrays and Hashes
One of the strengths of the Ruby language lies within the
many iterators that operate on collections.
Below are a few array iterators that we have not yet seen.
You can delete all the elements of an array for which a certain
block of code is true.
x = [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ,10]
puts x.join(" ")
y = x.delete_if { |item| item % 2 == 0 }
puts y.join(" ") # 1 3 5 7 9

You can collect all the elements of an array and perform some
function on them.
x = [ 1, 2, 3, 4, 10]
z = x.collect { | elem | elem * 2 }
puts z.join(" ") # 2 4 6 8 20
Hashes also have some iterators defined.
You can delete a pair if the following key, value pair is a match.
score = Hash.new
score['John'] = 80
score['Alice'] = 97
score['Tim'] = 73
score['Peter'] = 83
score['Jake'] = 79
y = score.delete_if {| key, val | key =~ /^J/ }
puts y # Alice97Tim73Peter83


RUBY PROGRAMMING CHAPTER 4: COLLECTIONS
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
4-21
Arrays and Methods
It is common to have a method operate on an array.
arrfun.rb
1. #!/usr/bin/ruby
2. def subr(x)
3. sum = 0
4. for item in x
5. sum += item
6. end
7. sum
8. end
9. b = [5,6,7,8]
10. puts "TOTAL IS " + subr(b).to_s
11. a = [1,2,3,4,5,6,7,8]
12. puts "TOTAL IS " + subr(a).to_s
13. puts "TOTAL IS " + subr([1,2,3]).to_s

The output from the above program is shown below.
TOTAL IS 26
TOTAL IS 36
TOTAL IS 6
RUBY PROGRAMMING CHAPTER 4: COLLECTIONS
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
4-22
Hashes and Methods
Passing a hash to a method is also trivial.
hash_total.rb
1. #!/usr/bin/ruby
2. def hash_total(aHash)
3. sum = 0
4. aHash.values.each { | item | sum += item }
5. sum
6. end
7. score = { 'a' => 2, 'x'=> 5, 'c' => 1 }
8. puts hash_total (score)
9. puts hash_total ( 'a' => 2, 'x'=> 5, 'c' => 1 )
If you need to send a simple value to a method, along with
a hash, the hash parameter may be first or last.
It is usually more convenient to pass the hash as the last
argument.
In this case, the {}'s are not necessary.
hash_parameters.rb
1. #!/usr/bin/ruby
2. def hashfirst(aHash, any)
3. puts aHash
4. puts "-----------"
5. puts any
6. puts "==========="
7. end
8.
9. def hashlast(any, aHash)
10. puts any
11. puts "-----------"
12. puts aHash
13. puts "==========="
14. end
15.
16. hashfirst({'a' => 2, 'x'=> 5, 'c' => 1}, 10)
17. hashlast(10, 'a' => 2, 'x'=> 5, 'c' => 1 )
18. hashlast(10, {'a' => 2, 'x'=> 5, 'c' => 1} )
RUBY PROGRAMMING CHAPTER 4: COLLECTIONS
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
4-23
Named Parameters
When you use a method, you usually need to know the
order in which you pass arguments.
For example, if you were to write a method to raise a base to a
power, you might proceed as follows.
def myraise(base, power)
base ** power
end

When users need to use this method, they need to know that
the base is the first argument and the power is the second
argument.
Therefore, the first call below raises 2 to the 5th power but
the second call raises 5 to the 2nd power.
puts myraise(2,5)
puts myraise(5,2)
Using hashes, you can name the parameter.
In this way, the order of the parameter passing is irrelevant.
To demonstrate this, we call the method in one of the
following ways.
puts raise(:base => 2, :power => 5)
puts raise(:power => 5, :base=> 2)
puts raise( { :power => 5, :base=> 2 })

We define the method as follows.
def raise(array)
base = array[:base]
power = array[:power]
base ** power
end
RUBY PROGRAMMING CHAPTER 4: COLLECTIONS
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
4-24
Symbols
A symbol is similar to a string.
Although not exactly the same, a symbol can be used in many
of the same places as a string.
A symbol is a set of characters prefixed by a colon.
Notice the following example.
symbols.rb
1. #!/usr/bin/ruby
2. name = :Mike
3. puts name
4. if ( name == :Mike )
5. puts "SAME"
6. puts :same
7. end
8. if ( "Mike" == :Mike )
9. puts "SAME"
10. puts :same
11. else
12. puts "NOT ALWAYS SAME"
13. end

The output from the above program is shown below.
Mike
SAME
same
NOT ALWAYS SAME
A symbol can be converted to a string with to_s.
if ( "Mike" == :Mike.to_s )
puts "SAME NOW!"
end

RUBY PROGRAMMING CHAPTER 4: COLLECTIONS
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
4-25
Symbols
Symbols are used mostly as keys to hashes.
You will see this often in Rails code.
caps = { "Maryland" => "Annapolis",
"Virginia" => "Richmond",
"Massachusetts" => "Boston"
}

The code above can be written as:
caps = { :Maryland => "Annapolis",
:Virginia => "Richmond",
:Massachusetts => "Boston"
}

Now, the references to the keys can be made as follows.
puts caps[:Maryland]
caps[:Texas] = "Austin"
puts caps[:Texas]

When you are dealing with hashes, it is often easier to use
symbols rather than strings.
Because strings and symbols are not exactly the same, be
careful in the above scenario not to write:
puts caps["Maryland"]

Use either one or the other!

RUBY PROGRAMMING CHAPTER 4: COLLECTIONS
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
4-26
Procs
Ruby has Procs, blocks, methods, and lambdas.
A Proc is a block of code that is bound to a set of local
variables.
Once bound, the code may be called in different contexts and
still access those variables.
A Proc is both a method and an object.
Sometimes a Proc is called a functor.
Below is a simple example using a Proc object.
proc = Proc.new { puts "this is it" }
proc.call

In this case, the block is associated with the Proc object and
is actually launched into execution later with the call
method.
A Proc object can also be returned from a method.
def increase()
return Proc.new {|n| n + 1 }
end

inc1 = increase() # refer to Proc
inc2 = increase() # refer to Proc

inc1.call(5) # 6
inc2.call(7) # 8

In the above example, inc1 and inc2 refer to the Proc
object returned from increase.
Then, the Proc is executed twice through the call method.
RUBY PROGRAMMING CHAPTER 4: COLLECTIONS
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
4-27
Procs
A Proc object can be passed to a method.
In this case, the parameter receiving the block must use the &
notation.
response.rb
1. #!/usr/bin/ruby
2. def run_it(one, two, &fun)
3. fun.call(one,two)
4. end
5. mult = Proc.new { | x, y | x * y }
6. add = Proc.new { | x, y | x + y }
7. puts run_it(2, 3, &mult)
8. puts run_it(5, 3, &add)

The output from the above program is shown below.
6
8
In the above example, there are two variables, mult and
add.
Each is a reference to a Proc.
The syntax to pass the references and the syntax to receive
them in a method requires the & notation.
Note that the following two forms are equivalent.
proc1 = proc { puts "Hello" }
proc2 = Proc.new { puts "Hello" }


RUBY PROGRAMMING CHAPTER 4: COLLECTIONS
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
4-28
Closures
A closure is a Proc object that retains the value of its
variables between method calls.
Here is an example of a closure.
closure.rb
1. #!/usr/bin/ruby
2. def counter
3. var = 0
4. Proc.new { var = var + 1 }
5. end
6. ref = counter()
7. for i in (1..5)
8. puts ref.call
9. end
10. puts ref.call

The output from the above program is shown below.
1
2
3
4
5
6
var is defined within the counter method.
Therefore, its scope is the counter method.
However, the Proc that is returned retains its value between
invocations.
RUBY PROGRAMMING CHAPTER 4: COLLECTIONS
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
4-29
Exercises
1. Write a program that reads one line of input containing
several numbers.
Split the line and store the elements in an array.
Now, compute and print the sum of the squares of these
elements.
Here is a possible run of the program.
Give me some numbers on a single line: 10 20 30
Sum of squares is 1400

2. Write a method that receives, as its only argument, one
array parameter.
The array contains elements generated from the rand method.
The method should return the largest element in the array.
3. Write a method that receives an array, say x, and returns
an array containing just those elements of x that are
positive.
4. The file rubylabs/starterss/banking_data.txt
contains banking transactions.
Each line in that file contains a name and a deposit.
Write a program that uses a hash of name, deposit pairs.
As you read these pairs, the hash should accumulate values
for specific names.
After all data has been read, the program should print just
those pairs whose balances are greater than 1000.
Sort the output by name.
Then, sort by balance.
(See the topic on sorting hashes earlier in this chapter. )
RUBY PROGRAMMING CHAPTER 4: COLLECTIONS
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
4-30
Exercises
5. In mathematics, there are a series of numbers that have
garnered much attention.
This sequence of numbers is known as the Fibonacci
sequence.
Each number is obtained by adding the previous two.
The first two numbers are 0 and 1.
0,1,1,2,3,5,8,13..
Write a method (a closure) that delivers the next
Fibonnacci number.
Each time the method is called, it should return the next
number in the sequence.
RUBY PROGRAMMING CHAPTER 5: CLASSES
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
5-1
Chapter 5:
Classes
1) Objects ...................................................................................................................... 5-2
2) Brief History of OOP............................................................................................... 5-3
3) OOP Vocabulary...................................................................................................... 5-4
4) Creating a New Class............................................................................................... 5-6
5) Using Objects............................................................................................................ 5-8
6) Defining Operator Methods.................................................................................. 5-13
7) Inheritance.............................................................................................................. 5-14
8) Ancestors................................................................................................................. 5-18
9) self........................................................................................................................ 5-20
10) Access Levels - public......................................................................................... 5-23
11) Access Levels private...................................................................................... 5-25
12) Access Levels - protected ................................................................................. 5-26
13) Access Levels - Specification................................................................................. 5-27
14) Class Data and Class Methods.............................................................................. 5-28
15) Adding Methods to Classes and Objects.............................................................. 5-30
16) Special Global Variables ....................................................................................... 5-31
17) Scope of Variables.................................................................................................. 5-32
18) Built-in Classes....................................................................................................... 5-33
19) The Math Class ...................................................................................................... 5-34
20) The NilClass Class............................................................................................. 5-35
21) TrueClass and FalseClass ........................................................................... 5-36
22) Built-in Class Hierarchy........................................................................................ 5-37
RUBY PROGRAMMING CHAPTER 5: CLASSES
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
5-2
Objects
Matz created Ruby out of desire to have a powerful
scripting language that was totally object oriented.
He knew Python and Perl and did not like that neither of the
languages was totally object oriented.
One of the central implementation issues in Object
Oriented Programming (OOP) is the creation and use of
objects.
Although we have not yet studied OOP in-depth, we did see
many examples of the creation of objects and the use of
methods performing actions on those objects.
Time
today = Time.new # create a Time object
puts today.year # execute the year method

Array
data = Array.new(10) # create an Array object
howmany = data.size # execute the size method

String
text = "Hello" # shortcut for String.new
h = String.new("Hi") # create a String object
puts h.length # execute length method
Suppose you wish to create your own kinds of objects,
those that are germane to your problem domain.
This chapter gives the details on both how this is accomplished
in Ruby and the issues relating to it.
RUBY PROGRAMMING CHAPTER 5: CLASSES
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
5-3
Brief History of OOP
The basis for OOP started in the early 1960s.
A breakthrough involving instances and objects was achieved
at MIT with the PDP-1.
The first programming language to use objects was Simula 67.
It was designed for creating simulations and was developed
by Kristen Nygaard and Ole-J ohan Dahl in Norway.
The term "object oriented programming" was first used by
Xerox PARC in the Smalltalk programming language.
The term was used to refer to the process of using objects as
the foundation for computation.
The Smalltalk team was inspired by the Simula 67 project, but
they designed Smalltalk so that it would be dynamic.
Smalltalk was also the first programming language to introduce
the inheritance concept.
It is this feature that is the signature characteristic of OOP.
Although there are many OOP languages, the following
are arguably the most successful, in terms of "market
share."
C++
J ava

RUBY PROGRAMMING CHAPTER 5: CLASSES
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
5-4
OOP Vocabulary
There are two fundamental concepts that need clarity as a
springboard for the entire set of OOP concepts.
Class
Object
The easiest way to understand these two terms is to use a
word ratio.
Object is to class as variable is to data type.
Suppose there is a programming language allowing this.
integer howmany = 10
Student myStudent("Leigh", "Mathematics", 25)

It is intuitive that howmany is a variable of type integer, which
initially holds the value 10.
Hopefully, it is equally intuitive that myStudent is a variable of
type Student.
Given the two lines of code above, you can also assume that
the integer is atomic (i.e., composed of one item).
On the other hand, the Student is compound.
The other issue is that most programming languages have
a data type that allows you to use integers natively (i.e.,
the data type is built into the language).
Language creators realize that most programs will need
integers.
RUBY PROGRAMMING CHAPTER 5: CLASSES
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
5-5
OOP Vocabulary
On the other hand, no programming language can
anticipate your needs within your own problem domain.
Therefore, if you are programming in the realm of a school,
then it is most likely desirable that you have a data type called
Student.
Likewise, if your problem domain is business, then it might be
convenient to have data types such as Expense, Invoice, or
Sale.
It is convenient, therefore, to distinguish between those
simple types that most languages offer and those more
complex types that you have to build.
Therefore, a sensible way to think about the two code lines on
the previous page follows.
howmany is a variable of type integer.
myStudent is an object of class Student.
Of course, Ruby is a language with dynamic typing, and
everything is an object.
Yet the discussion above is relevant in order to motivate the
creation of new types.
In Ruby, you use the class keyword to build (create) a
class.
Then, once it is created and known to your program, you can
create one or more objects (instances of that class) in that
program.

RUBY PROGRAMMING CHAPTER 5: CLASSES
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
5-6
Creating a New Class
In Ruby, these programmer defined data types can be
created with the class keyword.
A new class definition contains:
attributes (which describe characteristics); and
methods (which describe behavior).
Some hypothetical classes, and what they might contain,
are shown below.
The class File will have the following.
attributes: size, owner, permissions
methods: open, close, remove

The class Automobile will have the following.
attributes: weight, length, width
methods: start, stop, accelerate
Two pieces of terminology must be fully understood.
Class
A Class definition is a template that includes the common
attributes and methods for all instances of this type.
Object
An object is an instance of a class, in the same way that a
variable is an instance of a data type.
RUBY PROGRAMMING CHAPTER 5: CLASSES
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
5-7
Creating a New Class
A class is created in the following way.
class Employee
def initialize(name, jobtitle)
@name = name
@title = jobtitle
end
end

The code above defines a new class named Employee.
With the definition above, you can infer that an Employee is
modeled as a name and a job title.
To create an instance of this class (i.e., an object), one
codes as follows.
worker = Employee.new("Jane", "President")

When an instance of a new class is created, the initialize
method will be called automatically.
Therefore, with our Employee modeling, the initialize
method expects to be fed two arguments.
When the new method is executed, space for the
Employee object is created, and then Ruby calls the
initialize method and passes arguments to it.
The class name must begin with an upper case character.
Instance variables ( @name, @title) begin with the @ symbol.
Parameters (name, jobtitle) are local variables, and
therefore begin with a lower case character.

RUBY PROGRAMMING CHAPTER 5: CLASSES
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
5-8
Using Objects
Once an object is created, you will need to use the
methods within the class definition to allow the object to
do any work.
One of the first methods you will probably add is a method
that allows the object to return its state (i.e., all of its data).
Using this method, you can display the entire object.
Given the minimal Employee class defined previously,
you might add the additional code shown in bold below to
test the Employee class.
employee1.rb
1. #!/usr/bin/ruby
2. class Employee
3. def initialize(name, jobtitle)
4. @name = name
5. @title = jobtitle
6. end
7. end
8.
9. worker1 = Employee.new("Mike", "Instructor")
10. puts worker1

The output from the above program is shown below.
#<Employee:0xb78a96e0>
When you execute the above program, you will notice that
the output is less than desirable.
This is because when you attempt to print an entire object, a
default method named to_s is used to display the object.
As you can see, the class name is printed, followed by an
encoding of the object's ID.
RUBY PROGRAMMING CHAPTER 5: CLASSES
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
5-9
Using Objects
That to_s method is inherited from the Object class,
which is available to every Ruby program.
You will typically want to override this method with your own
version of to_s.
It might look like the following.
def to_s
return "#@name: #@title"
end

Note that you do not need the { } symbols when the data is
object data.
Now, if you execute a revised version of the Employee class, as
found in the file named employee2.rb, the results will look
like this.
Mike: Instructor
You will probably also want to add methods to:
return the name;
return the jobtitle; and
change the jobtitle.
The revised employee source code might look like the
code on the following page.

RUBY PROGRAMMING CHAPTER 5: CLASSES
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
5-10
Using Objects
employee3.rb
1. #!/usr/bin/ruby
2. class Employee
3. def initialize(name, jobtitle)
4. @name = name
5. @title = jobtitle
6. end
7. def to_s
8. return @name + " is: " + @title
9. end
10. def getname
11. return @name
12. end
13. def gettitle
14. return @title
15. end
16. def newtitle=(newtitle)
17. @title = newtitle
18. end
19. end
20.
21. worker1 = Employee.new("Mike", "Instructor")
22. puts "Worker is: " + worker1.to_s
23. puts "Name is: " + worker1.getname
24. puts "Title is: " + worker1.gettitle
25. worker1.newtitle=("Manager")
26. puts "Title is: " + worker1.gettitle
27. puts "Worker is: " + worker1.to_s

The output from the above program is shown below.
Worker is: Mike is: Instructor
Name is: Mike
Title is: Instructor
Title is: Manager
Worker is: Mike is: Manager
RUBY PROGRAMMING CHAPTER 5: CLASSES
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
5-11
Using Objects
An attribute can be accessed for different reasons.
You may wish to return an instance variable from an object.
You may wish to alter an instance variable of an object.
You may wish to do both of the above tasks.
We have seen examples of this in the Employee class.
Ruby allows a notational convenience.
We will use a different class to illustrate this notational
convenience as illustrated in the following class.
student.rb
1. #!/usr/bin/ruby
2. class Student
3. attr_reader :name
4. attr_writer :major
5. attr_accessor :age
6. def initialize(name, major, age)
7. @name = name
8. @major = major
9. @age = age
10. end
11. end
12. s = Student.new("Mike", "Math", 23)
13. puts s.name
14. s.major = "Trig"
15. s.age = 50
16. puts s.age

The output from the above program is shown below.
Mike
50

RUBY PROGRAMMING CHAPTER 5: CLASSES
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
5-12
Using Objects
The notational conveniences used in the Student class
are described in more detail below.
The line attr_reader :name is an abbreviation for the
following method.
def name
return @name
end

The line attr_writer :major is an abbreviation for the
following method.
def major=(major)
@major = major
end

Finally, the line attr_accessor :age is an abbreviation for
the two methods below.
def age
@age
end
def age=(age)
@age = age
end
Recall that when you invoke a Ruby method, parentheses
are not required.
Therefore, the methods that allow the setting of an attribute can
be executed as shown here.
s.major= "Trig"
s.major=("Trig")

Likewise, the methods that get the attribute can be invoked as:
puts s.name
name = s.name()
RUBY PROGRAMMING CHAPTER 5: CLASSES
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
5-13
Defining Operator Methods
Classes can also ascribe meaning to operators.
As an example of this, we will create a Fraction class and
demonstrate how to encode a multiplication method.
fraction.rb
1. #!/usr/bin/ruby
2. class Fraction
3. def initialize(n,d)
4. @n = n
5. @d = d
6. end
7. def *(frac)
8. numer = frac.getn
9. denom = frac.getd
10. temp = Fraction.new(@n * numer, @d * denom)
11. end
12. def getn
13. @n
14. end
15. def getd
16. @d
17. end
18. def to_s
19. @n.to_s + "/" + @d.to_s
20. end
21. end
22. f1 = Fraction.new(2,3)
23. f2 = Fraction.new(4,5)
24. puts f1
25. puts f2
26. f3 = f1 * f2
27. puts f3

The output from the above program is shown below.
2/3
4/5
8/15
RUBY PROGRAMMING CHAPTER 5: CLASSES
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
5-14
Inheritance
The cornerstone of object-oriented programming is the
notion that one class can be derived from another class.
This relationship is sometimes called the is-a relationship.
For example:
a GradStudent is a Student; and
a Manager is an Employee.

We will use the terms superclass and subclass to discuss which
class is derived from which.
Object Oriented programming languages, such as Ruby,
implement the is-a relationship as follows.
Subclass objects can use methods defined in the superclass
without having to re-encode them.
GradStudent and Manager are subclasses in the above
example, while Student and Employee are superclasses.
In other words, subclasses inherit superclass functionality.
The major benefit of this inheritance is code reuse.
To demonstrate the principles of inheritance, we will show
how to derive the GradStudent class from the Student
class.
In this modeling, we assume that a GradStudent is a
Student that is paid a stipend.
RUBY PROGRAMMING CHAPTER 5: CLASSES
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
5-15
Inheritance
With respect to the GradStudent class, we would like to
write code, like that shown below, without having to
rewrite the code for the name and the age methods, which
already exists in the Student class.
g1 = GradStudent.new("Joel", "Art", 45, 2000)
puts g1
puts g1.name
puts g1.age = 46
puts g1.age
puts g1.stipend

The first step toward this goal is to express that the
GradStudent class is a subclass of the Student class.
The syntax for describing the inheritance relationship
follows.
class GradStudent < Student
attr_accessor :stipend
def initialize(name, major, age, stipend)
super(name, major, age)
@stipend = stipend
end
end

Specifically, it is the following line that describes the
inheritance.
class GradStudent < Student

It specifies that GradStudent is a subclass of Student.
This means that all Student methods can be used by
GradStudent objects.

RUBY PROGRAMMING CHAPTER 5: CLASSES
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
5-16
Inheritance
The other line of code that is of interest in the
GradStudent class is shown below.
super(name, major, age)

The super method is the way in which the initialize
method, in the GradStudent superclass, is called.
This is a simple way to initialize the Student portion (@name,
@major, @age) of a GradStudent object.
The to_s method in the Student class is inherited, but
its behavior will be insufficient.
Therefore, the GradStudent class should not depend upon
the to_s method in the Student class.
The GradStudent should override it with its own to_s
method.
There are a few ways to do this. One way is:
def to_s
"#@name #@major #{@age} #{@stipend}"
end
The data members of the Student class are accessible
in GradStudent methods.
This brings up a larger issue, one of accessibility, which we will
address shortly.
A better way of writing the to_s method is shown below.
def to_s
"#{super.to_s} #{@stipend}"
end
RUBY PROGRAMMING CHAPTER 5: CLASSES
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
5-17
Inheritance
In general, Ruby will search for a method in the class on
which the method is executed.
If the method is not found in that class, then Ruby searches in
the superclass of the class in question.
Since there can be a chain of classes, there is ultimately one
class that is the root of all other classes.
In the Ruby world, this class is named Object.
The super keyword is typically used with methods rooted
in Object, but this is not a mandate.
Student does not have an explicit parent class. In Ruby,
every class is ultimately descended from Object.
Therefore, the Student class could have been declared in
either of the following ways.
class Student
...
...
end

class Student < Object
...
...
end
RUBY PROGRAMMING CHAPTER 5: CLASSES
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
5-18
Ancestors
The following code demonstrates a recursive function that
yields the ancestry of a particular class.
ancestors.rb
1. #!/usr/bin/ruby
2. def my_family(obj_class)
3. puts obj_class
4. return if obj_class == Object
5. my_family(obj_class.superclass)
6. end
7.
8. class A
9. end
10.
11. class B < A
12. end
13.
14. class C < B
15. end
16.
17. c = C.new
18. my_family(c.class)

The output from the above program is shown below.
C
B
A
Object
You can also use the ancestors class method from the
Module class.
ClassName.ancestors

The program on the next page uses a programmer-built
function to demonstrate this method.
RUBY PROGRAMMING CHAPTER 5: CLASSES
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
5-19
Ancestors
hierarchy.rb
1. #!/usr/bin/ruby
2. def hierarchy(c)
3. classes = c.ancestors
4. puts "#{c}: #{classes.size} in all."
5. classes.each_with_index do |v, i|
6. puts "#{i + 1} #{v}"
7. end
8. puts '*' * 30
9. end
10. hierarchy(String)
11. hierarchy(Fixnum)

The output from the above program is shown below.
String: 5 in all.
1 String
2 Enumerable
3 Comparable
4 Object
5 Kernel
******************************
Fixnum: 7 in all.
1 Fixnum
2 Integer
3 Precision
4 Numeric
5 Comparable
6 Object
7 Kernel
******************************
RUBY PROGRAMMING CHAPTER 5: CLASSES
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
5-20
self
Whenever a method is called on an object, the object on
which it is called is referred to as the host object (or
referrer object, or receiver object).
Therefore, in the following statements, g1 is the host object.
puts g1.name
puts g1.age
puts g1.stipend
In these cases, Ruby secretly passes, to the method, a
reference to the host object.
Inside these methods, you can refer to this reference as self.
This reference has robust utility, but for now, we just offer
some code to prove the claim that self refers to the host
object (i.e., itself).
self.rb
1. #!/usr/bin/ruby
2. class Sample
3. def test
4. puts self.object_id
5. end
6. end
7. a = Sample.new
8. a.test()
9. puts a.object_id

The output from the above program is shown below.
22878940
22878940
RUBY PROGRAMMING CHAPTER 5: CLASSES
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
5-21
self
There are other uses of self.
For example, there are some occasions when it is convenient to
chain methods together.
Notice the difference in the following two code segments.
Unchained
c = Car.new
c.start()
c.accelerate_to(25)
c.left()
c.right()

Chained
c = Car.new
c.start.accelerate_to(25).left().right()

The code to execute the chained methods depends upon the
the methods returning self.
The above code is demonstrated in the example on the
following page.
RUBY PROGRAMMING CHAPTER 5: CLASSES
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
5-22
self
chains.rb
1. #!/usr/bin/ruby
2. class Car
3. def start
4. puts "Starting.";
5. return self
6. end
7.
8. def accelerate_to(p)
9. puts "Accelerating to #{p}.";
10. return self
11. end
12.
13. def left
14. puts "Turning left. ";
15. return self
16. end
17.
18. def right
19. puts "Turning right.";
20. return self
21. end
22. end
23.
24.
25. c = Car.new();
26. c.start.accelerate_to(25).left().right()

The output from the above program is shown below.
Starting.
Accelerating to 25.
Turning left.
Turning right.
RUBY PROGRAMMING CHAPTER 5: CLASSES
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
5-23
Access Levels - public
Recall that the state for a particular object is the collection
of all attributes for that object.
Typically, the state of an object is changed via methods from
the object's class.
By controlling the access to the methods for a class, you can
control access to the state of an object.
By default, all methods of a class are public, except the
initialize method, which is always private.
public methods can be called from outside the class or from
within the class.
public.rb
1. #!/usr/bin/ruby
2. class Myclass
3. def fun1
4. puts "fun 1 is public"
5. end
6. def fun2
7. puts "fun 2 is public"
8. fun1 # call #2 to fun1
9. self.fun1 # call #3 to fun1
10. end
11. end
12. s = Myclass.new
13. s.fun1 # call #1 to fun1
14. s.fun2

The output from the above program is shown below.
fun 1 is public
fun 2 is public
fun 1 is public
fun 1 is public
RUBY PROGRAMMING CHAPTER 5: CLASSES
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
5-24
Access Levels - public
There are three calls to fun1 in the previous code.
s.fun1 # call #1
fun1 # call #2
self.fun1 # call #3

The first call, s.fun1, is executed from outside of the class
definition.
This is allowable because this method is a public method.
In this call, s is the host object.
s refers to the object on which this method is called.
The fun1 method is also called twice from within the class
definition.
fun1
self.fun1

The second reference above uses the receiver object named
self.
This is not a necessity and is merely shown here for
instructional purposes.
RUBY PROGRAMMING CHAPTER 5: CLASSES
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
5-25
Access Levels private
The private access level is used for those methods that
are called by other methods of the same class but not by
the public at large.
private methods cannot be called on a receiver object.
private.rb
1. #!/usr/bin/ruby
2. class Myclass
3. def fun2
4. fun1
5. end
6.
7. private
8. def initialize
9. end
10.
11. def fun1
12. puts "fun 1 is private"
13. end
14. end
15. s = Myclass.new
16. s.fun2

The output from the above program is shown below.
fun 1 is private
private methods within a superclass can be called from
any method in within a subclass of the superclass.
The initialize method is private by default, whether it
is listed in the private section or not.
RUBY PROGRAMMING CHAPTER 5: CLASSES
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
5-26
Access Levels - protected
A protected method is similar to a private method
except that the restriction of having no host referrer is
removed.
A protected method in a class is intended to be used by
the class in which these methods are defined, as well as
in derived classes.
Therefore, a protected method can be called from any
method in a derived class.
protected methods cannot be called from the public at large.
protected.rb
1. #!/usr/bin/ruby
2. class Base
3. protected
4. def fun1
5. puts "fun is protected"
6. end
7. end
8.
9. class Derived < Base
10. def dfun(param)
11. fun1()
12. self.fun1()
13. param.fun1()
14. end
15. end
16. d = Derived.new
17. e = Derived.new
18. d.dfun(e)

The output from the above program is shown below.
fun is protected
fun is protected
fun is protected
RUBY PROGRAMMING CHAPTER 5: CLASSES
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
5-27
Access Levels - Specification
Access levels can be specified in the style we have seen.
In addition, they can be specified as shown below.
access_levels.rb
1. #!/usr/bin/ruby
2. class SuperClass
3. def fun1
4. puts "fun1 called"
5. end
6. def fun2
7. puts "fun2 called"
8. end
9. def fun3
10. puts "fun3 called"
11. end
12. def fun4
13. puts "fun4 called"
14. end
15.
16. public :fun1, :fun2
17. private :fun3
18. protected :fun4
19. end
Using the above style, it is possible that the initialize
method of a class could be declared as something other
than its default level of private.
Although technically possible, changing the access level of this
method should be discouraged.
RUBY PROGRAMMING CHAPTER 5: CLASSES
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
5-28
Class Data and Class Methods
As we have already seen, each object has its own data.
However, there are times when data needs to be shared by a
class.
As a simple example, you might want to count the number of
objects of a particular class that have been allocated.
Whereas instance data uses one @ symbol, class data
uses two @@s.
class Student
@@howmany = 0
def initialize(name, major, age)
@name = name
@major = major
@age = age
@@howmany += 1
end
end
Class data is not a part of an object, as is instance data.
Rather, class data can be seen as global, with respect to a
class.
Sometimes a class needs methods that are invoked on the
class and not on objects of a class.
In fact, the new method is a class method, as is the
ancestors method.
RUBY PROGRAMMING CHAPTER 5: CLASSES
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
5-29
Class Data and Class Methods
In the Student class, we add the class method
Student.howmany.
Note the syntax of creating a class method is either.
def Student.howmany
@@howmany
end

def self.howmany
@@howmany
end
Here are several examples of executing a class method.
stu1 = Student.new("Mike", "Math", 23)
stu2 = Student.new("John", "Trig", 24)
puts Student.howmany

Notice how class methods are executed.
stu2 = Student.new("John", "Trig", 24)
puts Student.howmany

Contrast the execution of class methods with the execution of
an instance method.
age = stu1.age
name = stu1.name
major = stu1.major
RUBY PROGRAMMING CHAPTER 5: CLASSES
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
5-30
Adding Methods to Classes and Objects
In Ruby, whether you create your own classes or use an
existing class, you may add methods to that class.
For example, it might be convenient to add some methods to
the String class.
Below is a program that does just that.
addtostring.rb
1. #!/usr/bin/ruby
2. class String
3. def first
4. self[0]
5. end
6. def last
7. self[-1]
8. end
9. end
10.
11. s = String.new("Hi There")
12. puts s.first
13. puts s.last
14. puts s.length

The output from the above program is shown below.
H
e
8
You can also add methods to a specific object only.
r = String.new("This is it")
def r.tryme
"See: it works"
end
puts r.tryme # See: it works



RUBY PROGRAMMING CHAPTER 5: CLASSES
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
5-31
Special Global Variables
The Ruby language pre-defines several global variables to
ease the programmer's burden.
Here is a partial list.
Global
Variable
References
$! latest error message
$@ location of error
$_ string last read by gets
$. line number of last line read from file
$& string last matched by a regular expression
$~
last regular expression match: array of sub-
expressions
$n nth sub-expression in the last match
$= case insensitivity flag
$/ input record separator
$\ output record separator
$0 name of the script file
$* command line arguments
$$ process ID
$? exit status of last executed child process
$: set of directories for module searches
$, output field separator

Note that all of these variables begin with the $ symbol.
To see all of the globals, execute:
puts global_variables

RUBY PROGRAMMING CHAPTER 5: CLASSES
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
5-32
Scope of Variables
All Ruby entities (i.e., variables, functions, and global
variables) are of a class.
As we have seen in Ruby, the actual type of these entities
changes as the program is executing.
Beyond that, each variable has a known scope - the place
within the program where it can be accessed.
Instance variables are known inside the methods of the
class in which they are defined.
These variables begin with the @ symbol.
Class variables are known inside the class where they are
defined.
These variables begin with the @@ symbols.
A global variable is known everywhere in a program.
These variables begin with the $ symbol.
All other variables are local variables.
The scope of these local variables is either:
a block;
a function; or
the entire program except blocks and functions.
RUBY PROGRAMMING CHAPTER 5: CLASSES
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
5-33
Built-in Classes
This chapter has demonstrated how you can build your
own classes.
The Ruby language itself comes with many built-in classes,
such as those listed below.
String
Array
Hash
Fixnum
Float
Class
Math
Time
NilClass
TrueClass
FalseClass
The remaining examples will concentrate on a more in-
depth look at methods from several of the above classes.
RUBY PROGRAMMING CHAPTER 5: CLASSES
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
5-34
The Math Class
Below is a program that uses some of the functionality
from the Math class.
All functionality in this class uses the class method syntax.
math.rb
1. #!/usr/bin/ruby
2. if ARGV.length != 1
3. puts "ARG COUNT INCORRECT"
4. exit(1)
5. end
6. num = ARGV[0].to_f
7. puts Math.sqrt(num)
8. puts Math.log10(num)
9. puts Math.hypot(3,4)

The output from the several runs of the above program is
shown below.
$ math.rb
ARG COUNT INCORRECT


$ math.rb 100
10.0
2.0
5.0
RUBY PROGRAMMING CHAPTER 5: CLASSES
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
5-35
The NilClass Class
Most likely, you will not intentionally use the NilClass,
but you may see objects of this type in error messages.
Here is an example featuring the NilClass.
nilclass.rb
1. #!/usr/bin/ruby
2. def fun(s)
3. return "OK" if s.length > 0
4. return nil
5. end
6. s = "Hello"
7. puts fun(s).reverse
8. t = ""
9. puts fun(t).reverse

The output from the above program is shown below.
KO
nilclass.rb:9: undefined method `reverse' for
nil:NilClass (NoMethodError)
In the above code, the fun method returns nil when the
parameters length is not greater than zero.
nil is the only member of the NilClass.
Since everything in Ruby is of a class, nil itself is of the
NilClass.
There is no reverse method in the NilClass class.
Therefore, when you see this kind of error message, you
should be able to debug this problem more easily.
RUBY PROGRAMMING CHAPTER 5: CLASSES
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
5-36
TrueClass and FalseClass
Ruby has no official Boolean type.
However, Ruby does have the classes TrueClass and
FalseClass.
Here is an example demonstrating these classes.
truefalse.rb
1. #!/usr/bin/ruby
2. while true
3. print "enter string "
4. line = gets.chop
5. x = line == "quit"
6. puts x.class
7. if x
8. break
9. end
10. end

The output from the above program is shown below.
enter string mike
FalseClass
enter string quit
TrueClass
RUBY PROGRAMMING CHAPTER 5: CLASSES
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
5-37
Built-in Class Hierarchy

The diagram below is a tree representation of the built-in
Ruby classes.


BasicObject
Object
Array Binding Dir ENV Encoding Enumerator
Enumerator::Generator Enumerator::Yielder
Exception
FalseClass
Fiber File::Stat Hash
IO
MatchData Method
Module
Mutex
NilClass
Numeric
Proc Process::Status Random Range Regexp
RubyVM RubyVM::Env RubyVM::InstructionSpace String
Struct
Symbol Thread ThreadGroup Time TrueClass UnboundMethod
ARGF
File Class Struct::Tms
Float Complex Integer Rational
Bignum Fixnum
Data
Encoding::Converter
The Exception hierarchy
will be detailed in the
chapter on Exceptions
RUBY PROGRAMMING CHAPTER 5: CLASSES
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
5-38
Exercises
1. Define a Book class that has the following attribues.
title, author, pages
This class should be able to support the following interface.
b1 = Book.new("The Book", "Watts" ,250)
puts b1.title()
puts b1.author()
b1.pages = 100
puts b1.pages()
puts b1.to_s

2. Next, define an EBook class, which is derived from Book.
The EBook class should support the following interface.
eb1 = EBook.new("Exodus", "Uris", 800, "10Megs")
puts eb1.title()
puts eb1.author()
eb1.pages = 900
puts eb1.size()
puts eb1.pages()
puts eb1.to_s()

3. Write a + method in the EBook class.
The method should return the sum of the pages in the two
EBook objects.
4. Add a class data variable to the Book class whose value
is the total number of pages over all Book objects (but not
EBook objects).
Also, write a method to retrieve this value.
Make sure the above code works.
Be careful not to count an EBook!

RUBY PROGRAMMING CHAPTER 5: CLASSES
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
5-39
5. Write a program that determines if the argument object
that is sent to a method is the same instance as the host
object.
For example, the following case can be detected.
class X
def fun(param) # you fill this in
end
end
a = X.new
b = X.new
a.fun(a) # argument same as host
a.fun(b) # argument not same as host

6. Find the errors in the following code.
Class x
public:
function sayhello
puts "Hello\n";
end
private:
sub initialize(int x)
@@data = x
end
end
r = x.new(2,3)
sayhello();
RUBY PROGRAMMING CHAPTER 5: CLASSES
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
5-40
This Page is Intentionally Left Blank
RUBY PROGRAMMING CHAPTER 6: INPUT AND OUTPUT
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
6-1
Chapter 6:
Input and Output
1) Introduction.............................................................................................................. 6-2
2) Reading from the Standard Input.......................................................................... 6-3
3) Writing to the Standard Output............................................................................. 6-7
4) Reading and Writing Disk Files.............................................................................. 6-8
5) Reading Files Using Iterators ............................................................................... 6-10
6) I/O With Command Line Commands.................................................................. 6-12
7) Seeking About Files................................................................................................ 6-13
8) tell........................................................................................................................ 6-16
9) Capturing Data About Files.................................................................................. 6-17
10) Processing Directories ........................................................................................... 6-18

RUBY PROGRAMMING CHAPTER 6: INPUT AND OUTPUT
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
6-2
Introduction
Until now, we have relied upon the methods listed below
when we have needed input and output.
input
line = gets

output
puts line
print line
p line

These methods, along with other methods and some global
variables, are defined in the Kernel Module.
Generally speaking, input and output have a target and a
destination.
For example, input could be obtained from:
the keyboard,
a disk file, or
a process.
Likewise, output could be sent to:
the display,
a disk file, or
a process.
Additionally, you will need to know how to process the
standard files vs. processing disk files.
There is also the issue of text files vs. binary files.
Most of the methods seen in this section live in the IO class.
RUBY PROGRAMMING CHAPTER 6: INPUT AND OUTPUT
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
6-3
Reading from the Standard Input
Starting from a familiar base, we will look at a simple
program that reads lines from the standard input and then
simply prints them,
stdin1.rb
1. #!/usr/bin/ruby
2. while line = gets
3. puts line
4. end

The above code can be executed in various ways.
Read lines entered at the keyboard.
$ stdin1.rb

Redirect the standard input from a file.
$ stdin1.rb < somefile

Read from command line argument files.
$ stdin1.rb file1 file2 file3 ...

Read lines from another command, via a pipe.
$ some_command | stdin1.rb
The gets method is robust.
It can read a line at a time from the standard input.
It can also read from command line argument files when they
are provided.
RUBY PROGRAMMING CHAPTER 6: INPUT AND OUTPUT
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
6-4
Reading from the Standard Input
You can slightly shorten the previous example by using
the built in global variable, $_ .
stdin2.rb
1. #!/usr/bin/ruby
2. while gets
3. puts $_
4. end
If you want to strictly read lines from the standard input
and ignore command line arguments, then you can use a
magic constant defined in the Object class, named
STDIN.
stdin3.rb
1. #!/usr/bin/ruby
2. while STDIN.gets
3. puts $_
4. end
There are two other magic constants.
STDOUT
STDERR
stderr.rb
1. #!/usr/bin/ruby
2. while gets
3. if $_.length == 1
4. STDERR.puts "illegal string"
5. else
6. STDOUT.puts $_
7. end
8. end
RUBY PROGRAMMING CHAPTER 6: INPUT AND OUTPUT
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
6-5
Reading from the Standard Input
Depending upon the application at hand, you will need to
decide how much data to read at one time.
A character A line A file
The program below reads a character at a time.
character.rb
1. #!/usr/bin/ruby
2. puts "Please type in some characters"
3. 1.upto(3) do
4. x = STDIN.getc
5. puts x.chr
6. end

The output from the above program is shown below.
Please type in some characters
abc
a
b
c
Alternatively, you could use putc.
character2.rb
1. #!/usr/bin/ruby
2. puts "Please type in some characters"
3. 1.upto(5) do
4. x = STDIN.getc
5. putc x
6. end

The output from the above program is shown below.
Please type in some characters
abcde
abcde
RUBY PROGRAMMING CHAPTER 6: INPUT AND OUTPUT
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
6-6
Reading from the Standard Input
The readlines method can be used to read all the lines
from the standard input into an array.
read_all_lines.rb
1. #!/usr/bin/ruby
2. a = readlines
3. i = 1
4. a.each do |item|
5. puts i.to_s + "\t" + item
6. i += 1
7. end

The output from the above program is shown below.
$ readalllines.rb < readalllines.rb
1 #!/usr/bin/ruby
2 a = readlines
3 i = 1
4 a.each do |item|
5 puts i.to_s + "\t" + item
6 i += 1
7 end

In the above code, the readlines method reads all of the
lines in the input stream into an array.
Each element of the array holds one line from the input file.
Next, we will examine a few programs containing methods
that write to the standard output.

RUBY PROGRAMMING CHAPTER 6: INPUT AND OUTPUT
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
6-7
Writing to the Standard Output
If you want to format your output, then the printf
method is the one to use.
Some examples of the syntax used within printf is shown
below:
%nd n =field width, d =integer
%ns n =field width, s =string
%n.df n =field width, .d =decimal positions, f =float

Below is an example using printf.
printf.rb
1. #!/usr/bin/ruby
2. num = 10
3. str = "tra"
4. frac = 3.5
5. for i in (1..4)
6. printf("%5d %-20s%12.6f\n", num, str, frac)
7. num *= 10
8. str += " la"
9. frac *= 10
10. end

The output from the above program is shown below.
1 0 t r a 3 .5 0 0 0 0 0
1 0 0 t r a l a 3 5 .0 0 0 0 0 0
1 0 0 0 t r a l a l a 3 5 0 .0 0 0 0 0 0
1 0 0 0 0 t r a l a l a l a 35 0 0 .0 0 0 0 0 0

Width=5 Width=20 Width=12, Prec=6

Borders around data above added to assist in visualizing the
padding used within the printf .
RUBY PROGRAMMING CHAPTER 6: INPUT AND OUTPUT
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
6-8
Reading and Writing Disk Files
Next, we look at a few programs that process disk files
The basic logic of any of these programs is:
open the file,
process the file, and
close the file.
Opening a file is typically accomplished by creating a
File object and using the reference to it.
file = File.new("somefilename", "mode")

The program below will copy a file.
It is designed such that the input and output files are named
on the command line.
copyfile.rb
1. #!/usr/bin/ruby
2. if ( ARGV.length != 2 )
3. puts "Usage: #{$0} input output"
4. exit
5. end
6. input = File.new(ARGV[0], "r")
7. output = File.new(ARGV[1], "w")
8. while line = input.gets
9. output.puts line
10. end
11. output.close
12. input.close

Note the use of the global variable $0 in the above program.
This global variable contains the program name.
RUBY PROGRAMMING CHAPTER 6: INPUT AND OUTPUT
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
6-9
Reading and Writing Disk Files
In the previous example, note that the second argument to
the File.new method is the mode with which the file is
opened.
The following modes are possible.
Mode Short Description Long Description
r read
r+ read/write
Implies that the file already exists.
If it does not, an error will be
issued.
w write, creates new file
w+ read/write, existing file
Implies that the file does not exist.
If it does exist, it will be truncated
and then recreated empty.
a append
a+ read/write, starts at end of file
Implies that the appends will be at
the end of the file. If the file does
not exist, it will be created.

Some programs need to know whether or not a file exists.
The program below checks for file existence.
do_they_exist.rb
1. #!/usr/bin/ruby
2. ARGV.each do | item |
3. if (FileTest.exist?(item) )
4. puts item + " exists"
5. else
6. puts item + " does not exist"
7. end
8. end
A module named FileTest provides additional methods
to the File class that allow a battery of tests to be
performed on files.
RUBY PROGRAMMING CHAPTER 6: INPUT AND OUTPUT
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
6-10
Reading Files Using Iterators
One of Rubys strengths is the use of iterators.
The next few programs illustrate the following three iterators
that can be used with File objects.
each_byte
each_line
foreach
The following program uses each_byte to count the
frequencies of alphabetic characters.
counts.rb
1. #!/usr/bin/ruby
2. words = Hash.new(0)
3. input = File.new(ARGV[0])
4. input.each_byte do |ch|
5. x = ch.chr.downcase
6. words[x] += 1 if x =~ /[a-z]/
7. end
8. input.close
9. wrap = 0
10. words = words.sort
11. words.each do |key,val|
12. print key + ":" + val.to_s + " "
13. wrap += 1
14. if(wrap % 10 == 0)
15. puts
16. end
17. end

The output from the above program is shown below.
$counts.rb counts.rb
a:11 b:3 c:6 d:11 e:12 f:3 g:1 h:7 i:7 k:2
l:3 n:10 o:10 p:7 r:14 s:11 t:7 u:5 v:3 w:11
x:3 y:4 z:1
RUBY PROGRAMMING CHAPTER 6: INPUT AND OUTPUT
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
6-11
Reading Files Using Iterators
The following program uses the each_line iterator to
count the number of lines in a set of files.
countlines.rb
1. #!/usr/bin/ruby
2. ARGV.each do |thisfile|
3. i = 0
4. f = File.new(thisfile, "r")
5. f.each_line { i += 1 }
6. puts thisfile + " has " + i.to_s + " lines."
7. f.close
8. end

The output from the above program is shown below.
$ countlines.rb countlines.rb copyfile.rb
countlines.rb has 8 lines.
copyfile.rb has 12 lines.
each_line can be passed a delimiter character in case
your application wants to count things other than lines.
For example, each_line("."), would have resulted in the
program counting declarative sentences rather than lines.
There is also the IO.foreach iterator that opens a file,
applies a block of code to each line of the file, and then
closes the file automatically.
IO.foreach("myfile") { |x| puts x }
RUBY PROGRAMMING CHAPTER 6: INPUT AND OUTPUT
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
6-12
I/O With Command Line Commands
Ruby allows you to communicate with commands that you
might start from your systems command line.
Do not use interactive commands, such as the date command
on a Windows platform.
Some example commands are shown below:
Linux / Mac
ls, date, etc

Windows
dir, sort, etc
The popen class method from the IO class is used to
open a stream to a process.
Once opened, you simply treat that stream the way you would
treat any of the others that we have seen so far.
popen.rb
1. #!/usr/bin/ruby
2. p = IO.popen("dir", "r")
3. lines = p.readlines
4. lines.each do |line|
5. puts line if line =~ /^\d/
6. end
7. p.close

The program above reads lines from the dir command and
prints them if they begin with a digit.
RUBY PROGRAMMING CHAPTER 6: INPUT AND OUTPUT
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
6-13
Seeking About Files
Some programs need only to write to files while other
programs need only to read from files.
Still other programs need to update files through both reads
and writes.
An update operation typically consists of reading a 'record',
examining it, and potentially modifying it.
The read, examine, and modify cycle require both read
and write access to the file.
There are several choices here.
r+ read/write
w+ read/write, existing file
a+ read/write, starts at end of file

The first of the three choices usually is the right one but it
assumes that the file already exists.
All three modes allow both read and write access.
In the case of updating a record, once you have examined
a record, you are beyond that record in the file that you
are reading.
If you need to modify that record, you will need to 'position the
file' back at the beginning of that record.
The seek method allows you to move within a file so many
bytes either forward or backward relative to some origin.
The method itself has the following interface.
seek(num_bytes, origin)
RUBY PROGRAMMING CHAPTER 6: INPUT AND OUTPUT
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
6-14
Seeking About Files
Here is a list of behaviors that are possible when you use
seek.
Note that f is a file object.
Position the file zero bytes from the beginning of the file.
f.seek(0, IO::SEEK_SET)
f.seek(0, 0)

Position the file zero bytes from the end of the file.
f.seek(0, IO::SEEK_END)
f.seek(0, 2)

Position the file ten bytes earlier than the current position.
f.seek(-10, IO::SEEK_CUR)
f.seek(-10, 1);

Once the seek has been executed, any reads and writes are
relative to the new position.
The example on the following page will use the following
data file to demonstrate the seek method.
data
1. Michael
2. Dave
3. Susan
RUBY PROGRAMMING CHAPTER 6: INPUT AND OUTPUT
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
6-15
Seeking About Files
The following example demonstrates the seek
capabilities.
seek.rb
1. #!/usr/bin/ruby
2. f = File.new("data", "r+")
3. puts "Read entire file."
4. while line = f.gets
5. print "#{$.}:#{line[0...-1]} "
6. end
7.
8. puts "\n", "*" * 20, "Seek to beginning."
9. f.seek(0,0)
10. puts f.gets
11.
12. print "*" * 20, "\nSeek to end & add record:"
13. f.seek(0,2)
14. line = STDIN.gets
15. f.puts line
16.
17. puts "*" * 20, "Seek to beginning."
18. puts "Read file again."
19. f.seek(0,0)
20. while line = f.gets
21. print "#{$.}:#{line[0...-1]} "
22. end
23. f.close

The output from the above program is shown below.
Read entire file.
1:Michael 2:Dave 3:Susan
********************
Seek to beginning.
Michael
********************
Seek to end & add record:Alan
********************
Seek to beginning.
Read file again.
5:Michael 6:Dave 7:Susan 8:Alan
RUBY PROGRAMMING CHAPTER 6: INPUT AND OUTPUT
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
6-16
tell
There are also occasions when you need to know where
you are within a file.
The tell method tells you where you are as a byte offset from
the beginning of the file.
tell.rb
1. #!/usr/bin/ruby
2. chars = String.new
3. f = File.new("letters", "w+");
4. "A".upto("Z") { |letter| chars << letter }
5. print "Current file position: " + f.tell.to_s + "\n"
6. puts "Writing " + chars
7. f.puts chars
8. print "Current file position: " + f.tell.to_s + "\n"
9. puts "Now seeking to beginning of file."
10. f.seek(0,0)
11. print "Current file position: " + f.tell.to_s + "\n"
12. puts "Seek 10 bytes and read "
13. f.seek(10,0)
14. puts f.gets()

The output from the above program is shown below.
file position: 0
Writing ABCDEFGHIJKLMNOPQRSTUVWXYZ
file position: 27
Now seeking to beginning of file.
file position: 0
Seek 10 bytes and read
KLMNOPQRSTUVWXYZ

The 3rd line of output above (file position: 27) is a
result of running the above script in a Linux environment.
Had it been a Windows environment the position would have
been 28 instead of 27.
RUBY PROGRAMMING CHAPTER 6: INPUT AND OUTPUT
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
6-17
Capturing Data About Files
The programs in this section have been concerned with
the data within files.
Often, however, one is concerned with data about files (meta-
data) rather than the data within files, such as file size and
modification dates
You can use the stat method of the File class to gain
access to this metadata.
status.rb
1. #!/usr/bin/ruby
2. stats = File.stat(ARGV[0])
3. $\ = "\n"
4. print "Last Access Time: ", stats.atime
5. print "Last Modification Time: ", stats.mtime
6. print "CTIME IS: ", stats.ctime
7. print "\tIN Linux CTIME represents the last time the"
8. print "\tstat information was changed."
9. print "\tIn Windows CTIME represents creation time"
10. print "MODE IS: ", stats.mode
11. printf "%o\n", stats.mode
12. print "Size: ", stats.size
13. print "Is a File ?: ", stats.file?
14. print "Is a Dir ?: ", stats.directory?
15. print "FileType: ", stats.ftype

The output from the above program is shown below.
$ ruby status.rb status.rb
Last Access Time: Fri Nov 18 11:45:33 -0500 2011
Last Modifcation Time: Fri Nov 18 11:43:56 -0500 2011
CTIME IS: Fri Nov 18 11:45:31 -0500 2011
IN Linux CTIME represents the last time the
stat information was changed.
In Windows CTIME represents creation time
MODE IS: 33261
100755
Size: 504
Is a File ?: true
Is a Dir ?: false
FileType: file
RUBY PROGRAMMING CHAPTER 6: INPUT AND OUTPUT
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
6-18
Processing Directories
If you need to process the set of files within a directory,
you can use the following method.
Dir.entries("dirname")

A small program to illustrate this method is shown below.
dirlist.rb
1. #!/usr/bin/ruby
2. files = Dir.entries(".")
3. files.each { |file| puts file }

The output from the above program is shown below.
.
..
stderr.rb
character.rb
counts.rb
dirlist.rb
stdin1.rb
popen.rb
character2.rb
data
do_they_exist.rb
changedir.rb
stdin3.rb
tell.rb
copyfile.rb
letters
status.rb
stdin2.rb
printf.rb
countlines.rb
seek.rb
read_all_lines.rb
RUBY PROGRAMMING CHAPTER 6: INPUT AND OUTPUT
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
6-19
Processing Directories
It may be necessary for some programs to know the name
of the directory from which they are started.
Likewise, it may sometimes be necessary for a program to
change to another directory.
changedir.rb
1. #!/usr/bin/ruby
2. current = Dir::pwd
3. puts "Currently in: " + current
4. Dir::chdir("..")
5. puts "Now in: " + Dir::pwd
6. Dir::chdir(current)
7. puts "Now in: " + Dir::pwd

The program above shows how to:
obtain the current working directory, and
change directories.
RUBY PROGRAMMING CHAPTER 6: INPUT AND OUTPUT
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
6-20
Exercises
1. Write a program that reads lines from a file named on the
command line and displays the lines of that file containing
a digit.
$ program filename

2. Write a program that reads files within a directory named
on the command line and displays the number of lines in
each file.
3. Write a program that displays all lines from a set of files
that match a pattern.
Also, print the name of the file and the line number of the file
for each line that matches.
The interface for the program should be:
$ program pattern filename....

Hint: When you use a regular expression to try to match a
pattern held within a variable, use:
if ( string =~ /#{var}/ )
end

4. Write a program that receives a directory from the
command line and displays the files in that directory and
their modification times.
The program should first display the information sorted
alphabetically by file name, and then
sorted by modification time.
5. Write a program that reads a text file and stores
beginning positions of lines in an array.
Then, loop through the array, seeking those beginning positions
and printing each line as you go.
RUBY PROGRAMMING CHAPTER 7: EXCEPTIONS
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
7-1
Chapter 7:
Exceptions
1) Introduction.............................................................................................................. 7-2
2) Exception Hierarchy................................................................................................ 7-3
3) Handling Exceptions................................................................................................ 7-4
4) Multiple Rescue Clauses.......................................................................................... 7-7
5) Exceptions are Classes............................................................................................. 7-8
6) ensure..................................................................................................................... 7-9
7) retry...................................................................................................................... 7-10
8) raise...................................................................................................................... 7-11
9) Creating Your Own Exceptions............................................................................ 7-13
10) catch and throw................................................................................................. 7-14

RUBY PROGRAMMING CHAPTER 7: EXCEPTIONS
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
7-2
Introduction
In the last chapter, some of the code was concerned with
reading and writing data to and from files.
In this kind of operation, there is always the possibility that the
program may try to open a file that:
does not exist,
does not have the correct permissions, or
cannot be opened for some other reason.

A run time exception may occur in numerous other places
within a program.
Division by zero
Changing to a non-existent directory
Calling a method with the wrong number of arguments
Calling a method that does not exist
An Exception is an object that is created when a run-
time error is detected and then raised during the execution
of the program.
The core Exception hierarchy is shown on the next page.
This chapter explores the ways in which Ruby programmers
handle exceptions at run time.
Several specific exceptions will be used in the examples, so
that you will become familiar with processing and using
exceptions.
RUBY PROGRAMMING CHAPTER 7: EXCEPTIONS
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
7-3
Exception Hierarchy

BasicObject
Object
Exception
NoMemoryError
ScriptError
LoadError
Gem::LoadError
NotImplementedError
SyntaxError
SecurityError
SignalException
Interrupt
StandardError
ArgumentError
EncodingError
Encoding::CompatibilityError
Encoding::ConverterNotFoundError
Encoding::InvalidByteSequenceError
Encoding::UndefinedConversionError
FiberError
IOError
EOFError
IndexError
KeyError
StopIteration
Math::DomainError
NameError
NoMethodError
RangeError
FloatDomainError
LocalJumpError
RegexpError
RuntimeError
Gem::Exception
SystemCallError
TypeError
ZeroDivisionError
ThreadError
SystemExit
Gem::SystemExitException
SystemStackError
fatal
Gem::CommandLineError
Gem::DependencyError
Gem::DependencyRemovalException
Gem::DocumentError
Gem::EndOfYAMLException
Gem::FilePermissionError
Gem::FormatException
Gem::GemNotFoundException
Gem::GemNotInHomeException
Gem::InstallError
Gem::InvalidSpecificationException
Gem::OperationNotSupportedError
Gem::RemoteError
Gem::RemoteInstallationCancelled
Gem::RemoteInstallationSkipped
Gem::RemoteSourceException
Gem::VerificationError
Operating systems typically report errors using plain integers. Module Errno is
created dynamically to map these operating system errors to Ruby classes, with
each error number generating its own subclass of SystemCallError. As the
subclass is created in module Errno, its name will start Errno::.

There are over 100 subclasses of SystemCallError, as an example:
File.open("does/not/exist") would raise the following Exception:
Errno::ENOENT
Ruby's
Exception Hierarchy
RUBY PROGRAMMING CHAPTER 7: EXCEPTIONS
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
7-4
Handling Exceptions
As a simple example to illustrate run time error handling,
consider the following program that performs a calculation
based on some user input.
compute1.rb
1. #!/usr/bin/ruby
2. while(true)
3. print "Enter a number "
4. line = gets
5. puts 100/line.to_i
6. end

The output from the above program is shown below.
Enter a number 10
10
Enter a number 5
20
Enter a number 0
Compute1:5:in /: divided by 0 (Zero Division
Error) from compute1:5
All goes well in the program above until the user enters
the value zero.
The program tries to perform a division by zero, and a run time
error is generated.
Since the program has not been written to prepare for such a
situation, the Ruby run time system generates the error
message that is sent to the display.
A better solution is to have the program itself handle this
exception.
RUBY PROGRAMMING CHAPTER 7: EXCEPTIONS
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
7-5
Handling Exceptions
Programmer-provided exception handling can be enabled
or disabled in various parts of a Ruby program by placing
your code within begin and end sections.
Inside these begin and end sections, you can have one or
more rescue clauses.
A simple example is shown below.
compute2.rb
1. #!/usr/bin/ruby
2. while(true)
3. print "Enter a number "
4. line = gets
5. begin
6. puts 100/line.to_i
7. rescue ZeroDivisionError
8. puts "Division By Zero detected"
9. end
10. end

If a ZeroDivisionError occurs within the begin and end
blocks, then control is transferred to the rescue clause.
In this case, a message is printed, and the program
continues.
The output from the above program is shown below.
Enter a number 5
20
Enter a number 0
Division By Zero detected
Enter a number
...


RUBY PROGRAMMING CHAPTER 7: EXCEPTIONS
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
7-6
Handling Exceptions
In the previous example, when a run time error occurred,
the program handled the error and then continued.
You could arrange to terminate the program when the
exception is raised.
This can be accomplished by executing the raise method
from your handler.
This causes the Ruby default response to be executed.
rescue ZeroDivisionError
puts "Division By Zero detected"
raise

Alternately, you could place the begin, end, and rescue
keywords so that the rescue clause is outside of the loop.
In this way, the program will end when the exception is
raised.
compute3.rb
1. #!/usr/bin/ruby
2. begin
3. while(true)
4. print "Enter a number "
5. line = gets
6. puts 100/line.to_i
7. end
8. rescue ZeroDivisionError
9. puts "Division By Zero detected"
10. end

RUBY PROGRAMMING CHAPTER 7: EXCEPTIONS
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
7-7
Multiple Rescue Clauses
If the rescue clause does not have a specific exception, it
behaves as a general exception handler for all run time
errors.
It is as though the StandardError exception has been raised.
An example that handles ZeroDivisionError differently
than it handles all other exceptions is shown below.
compute4.rb
1. #!/usr/bin/ruby
2. begin
3. file = File.new(ARGV[0], "r")
4. while (line = file.gets)
5. puts 100/line.to_i
6. end
7. file.close
8. rescue ZeroDivisionError
9. puts "Zero Divide"
10. rescue
11. puts "IO and Other Exceptions"
12. end

The output from the above program is shown below.
$ compute4.rb xyz
IO and Other Exceptions
$ compute4.rb numbers
10
5
Zero Divide

The numbers file used above is shown below
numbers
1. 10
2. 20
3. 0
4. 30
RUBY PROGRAMMING CHAPTER 7: EXCEPTIONS
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
7-8
Exceptions are Classes
When an exception is raised, an Exception object is
created.
A reference to this object is stored in the variable $!.
Each Exception object has methods associated with it.
A few of them are listed below.
backtrace
message
to_s
You can also specify a variable (in the interest of clarity) that
refers to the Exception object.
The code below illustrates these ideas.
compute5.rb
1. #!/usr/bin/ruby
2. begin
3. file = File.new(ARGV[0], "r")
4. while (line = file.gets)
5. puts 100/line.to_i
6. end
7. file.close
8. rescue ZeroDivisionError
9. puts "Zero Divide: " + $!.backtrace.to_s
10.
11. rescue => error
12. puts "IO Exception: " + error.message
13. end
RUBY PROGRAMMING CHAPTER 7: EXCEPTIONS
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
7-9
ensure
There are other facets of handling exceptions.
For example, if a file is opened and an exception is raised, the
code that closes the file may never be executed.
The ensure clause guarantees that the code executed within it
will be called whether the exception is raised or not.
ensure.rb
1. #!/usr/bin/ruby
2. begin
3. file = File.new(ARGV[0], "r")
4. while line = file.gets
5. puts line
6. end
7. rescue
8. puts "FILE OPENED FAILED"
9. ensure
10. puts "CHECKING FILE CLOSURE"
11. unless ( file.nil? )
12. puts "CLOSE IT"
13. file.close();
14. end
15. end

Note also that the ensure code could have been coded as:
puts "CHECKING FILE CLOSURE"
file.close() unless file.nil?


RUBY PROGRAMMING CHAPTER 7: EXCEPTIONS
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
7-10
retry
Most times, when an Exception is raised, not much can be
done to correct the offensive condition.
However, you can affect a clean exit from the program.
On the other hand, some run time errors can be corrected.
The retry statement causes the entire begin, end
sequence to be repeated.
retry.rb
1. #!/usr/bin/ruby
2. begin
3. while (line = gets)
4. puts 100/line.to_i
5. end
6. rescue ZeroDivisionError
7. puts "Zero not allowed here"
8. retry
9. end
RUBY PROGRAMMING CHAPTER 7: EXCEPTIONS
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
7-11
raise
A rescue clause may be used to handle the exception
entirely or to handle a portion of an exception and pass
the rest of the handling up the call stack.
When this is the case, the raise statement may be used.
Notice the following program and its output.
levels.rb
1. #!/usr/bin/ruby
2. def first
3. begin
4. second()
5. rescue
6. puts "inside first"
7. raise
8. end
9. end
10.
11. def second
12. begin
13. x = 10/0
14. rescue ZeroDivisionError
15. puts "inside second"
16. raise
17. end
18. end
19.
20. begin
21. first()
22. rescue ZeroDivisionError
23. puts "inside main"
24. end

The output from the above program is shown below.
inside second
inside first
inside main
RUBY PROGRAMMING CHAPTER 7: EXCEPTIONS
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
7-12
raise
There are other ways to use raise.
In its complete form, raise can be used as follows.
raise ExceptionType, "a message" if trueExpression

For example, you may have a method that performs some
action on an array.
If the array is empty, you may choose to raise an
Exception.
raise.rb
1. #!/usr/bin/ruby
2. def multiply(arr)
3. msg = "Array is empty at line #{__LINE__}"
4. raise RuntimeError, msg if arr == []
5. value = arr[0]
6. arr.each_index { |item| arr[item] *= value }
7. end
8. data = [3,4,5,6]
9. begin
10. multiply(data)
11. p data
12. nodata = [ ]
13. multiply(nodata)
14. rescue => err
15. puts "RunTimeError: " + err.message
16. end
17. p nodata

The output from the above program is shown below.
[9,12,15,18]
RunTimeError: Array is empty at line 3
[]
RUBY PROGRAMMING CHAPTER 7: EXCEPTIONS
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
7-13
Creating Your Own Exceptions
Each Exception class is part of a hierarchy of classes
that has Exception at its base.
You might have occasion to create your own Exception
classes.
If you do, you will derive your class from Exception.
An example is shown below.
size.rb
1. #!/usr/bin/ruby
2. class SizeException < StandardError
3. MAX = 100
4. attr_accessor :size
5. def initialize(val, msg)
6. super(msg)
7. @size = val
8. end
9. end
10.
11. begin
12. while( s = gets.to_i )
13. if s > SizeException::MAX
14. raise SizeException.new(s, "ERROR")
15. end
16. puts s * s
17. end
18. rescue SizeException
19. puts "VALUE TOO HIGH: " + $!.size.to_s
20. puts $!.message
21. end

The output from the above program is shown below.
100
10000
101
VALUE TOO HIGH: 101
ERROR
RUBY PROGRAMMING CHAPTER 7: EXCEPTIONS
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
7-14
catch and throw
catch and throw allow you to make jumps in your code
somewhat like a labeled "go to."
A catch clause introduces a body of code.
The catch clause uses a symbol as shown below.
catch(:somename) do
end

When the throw is executed, control passes to the very end of
the catch clause.
You can see how the throw is executed in the code below.
catch.rb
1. #!/usr/bin/ruby
2. def fun
3. throw :done
4. end
5. catch (:done) do
6. while(line = gets)
7. puts "before test"
8. fun() if line.to_i < 10
9. puts "after test"
10. end
11. end
12. puts "now here"

The output from the above program is shown below.
11
before test
after test
9
before test
now here
RUBY PROGRAMMING CHAPTER 7: EXCEPTIONS
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
7-15
Exercises
1. Derive an exception class named StringTooBig from
Exception.
Embed a constant in this class, and have it determine whether
a string is too big.
Then, read strings from the user and raise this exception
whenever a string is too big.
If the string is not too big, then print a suitable message.
End the loop by checking for the string named end.
2. Derive StringTooSmall from Exception and embed a
constant with a lower value than the constant in
StringTooBig above.
Proceed as you did in above, but trap both StringTooBig or
StringTooSmall.

RUBY PROGRAMMING CHAPTER 7: EXCEPTIONS
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
7-16
This Page Intentionally Left Blank
RUBY PROGRAMMING CHAPTER 8: MODULES
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
8-1
Chapter 8:
Modules
1) Introduction.............................................................................................................. 8-2
2) Using Core Ruby Classes......................................................................................... 8-3
3) Ruby Standard Library........................................................................................... 8-5
4) require................................................................................................................... 8-6
5) Search Path............................................................................................................... 8-8
6) File Organization ..................................................................................................... 8-9
7) load........................................................................................................................ 8-12
8) Modules................................................................................................................... 8-13
9) include................................................................................................................. 8-16
10) Mixins...................................................................................................................... 8-17
11) Using the Comparable Module .......................................................................... 8-20
12) Collection Classes................................................................................................... 8-22
13) yield...................................................................................................................... 8-23
14) Using the Enumerable Module ............................................................................. 8-26
RUBY PROGRAMMING CHAPTER 8: MODULES
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
8-2
Introduction
The majority of the code that we have written so far has
demonstrated the fundamentals of the Ruby language.
In some cases, we have placed a class definition inside the
same file where the class is being used.
Normally, a class would exist within its own file and then be
made available to any program that needed it.
In other cases, we may need to use one or more libraries
provided by sources other than our own.
In the case of one or more libraries, there is always the
problem of more than one library using the same named
method.
One library might be a word processing library whose methods,
among others, might be named word and line.
Another library might be a graphics library whose methods,
among others, might be named circle and line.
If both of these libraries were loaded into one program,
which method would be called when the programmer
invoked the line method?
Questions like these will be answered in this chapter.

RUBY PROGRAMMING CHAPTER 8: MODULES
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
8-3
Using Core Ruby Classes
In the programs that we have seen, we have used many
of the built-in Ruby classes.
String
Math
Time
etc.
You do not have to do anything special in your Ruby
programs to use these classes.
These classes are referred to as the Core Ruby Classes.
The following program will list the Core Ruby Classes.
Similar to the hierarchy shown in the earlier chapter on classes.
classes.rb
1. #!/usr/bin/ruby
2. classes = Object.constants.select do |c|
3. Object.const_get(c).is_a?(Class)
4. end
5. ct = 0
6. puts classes.size
7. classes.sort.each do |i|
8. puts if ct % 3 == 0
9. printf "%-20s", i
10. ct += 1
11. end

The output from the above program is shown on the following
page.
A deprecation warning appears at the top of the output due
to the Config module (defined as a constant in Object)
being deprecated in favor of RbConfig in Ruby version
1.9.3.
RUBY PROGRAMMING CHAPTER 8: MODULES
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
8-4
Using Core Ruby Classes
Here is the output of the program on the previous page.
classes.rb:3:
Use RbConfig instead of obsolete and deprecated Config.
70

ArgumentError Array BasicObject
Bignum Binding Class
Complex Data Dir
EOFError Encoding EncodingError
Enumerator Exception FalseClass
Fiber FiberError File
Fixnum Float FloatDomainError
Hash IO IOError
IndexError Integer Interrupt
KeyError LoadError LocalJumpError
MatchData Method Module
Mutex NameError NilClass
NoMemoryError NoMethodError NotImplementedError
Numeric Object Proc
Random Range RangeError
Rational Regexp RegexpError
RubyVM RuntimeError ScriptError
SecurityError SignalException StandardError
StopIteration String Struct
Symbol SyntaxError SystemCallError
SystemExit SystemStackError Thread
ThreadError ThreadGroup Time
TrueClass TypeError UnboundMethod
ZeroDivisionError

RUBY PROGRAMMING CHAPTER 8: MODULES
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
8-5
Ruby Standard Library
Ruby also provides a standard library of classes.
You may wish to use some of these classes depending upon
your particular application.
See http://ruby-doc.org/stdlib for complete
documentation on each of the classes in the standard library.
We will show an example of using the Set class from the
standard library.
This class offers a more complete set of methods to handle set
operations than those methods offered by the Array class.
Here is a program that tries to create a new Set object.
set1.rb
1. #!/usr/bin/ruby
2. s = Set.new([1, 2, 3])

The output from the above program is shown below.
set1.rb:2: uninitialized constant Set (NameError)

As you can see, there is a problem.
In order to use the classes in the Standard Ruby library, you
need to import the code for that library.
RUBY PROGRAMMING CHAPTER 8: MODULES
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
8-6
require
One way to use a class from the Standard Ruby library is
to use the require and/or require_relative
methods.
The use of require can be seen in the example below.
set2.rb
1. #!/usr/bin/ruby
2. require 'set'
3. s1 = Set.new([1,2,3])
4. s2 = Set.new([2,3,4])
5. 10.upto(12) { |item| s1.add(item) }
6. 11.upto(13) { |item| s2.add(item) }
7. print "s1: ", s1.inspect, "\n"
8. print "s2: ", s2.inspect, "\n"
9. print "(s1 & s2): ", (s1 & s2).inspect, "\n"
10. print "(s1 | s2): ", (s1 | s2).inspect, "\n"
11. print "(s1 - s2): ", (s1 - s2).inspect, "\n"
12. print "(s2 - s1): ", (s2 - s1).inspect, "\n"

The output from the above program is shown below.
s1: #<Set: {11, 12, 1, 2, 3, 10}>
s2: #<Set: {11, 12, 13, 2, 3, 4}>
(s1 & s2): #<Set: {11, 12, 2, 3}>
(s1 | s2): #<Set: {11, 1, 12, 13, 2, 3, 4, 10}>
(s1 - s2): #<Set: {1, 10}>
(s2 - s1): #<Set: {13, 4}>
The require method loads and executes the file that you
require.
Required files end with the suffix .rb
When you require a file, you can omit the extension.
Required files typically only contain classes and methods.
Therefore, when these files are loaded and executed, you will
not see any output, since no code actually calls these methods.
RUBY PROGRAMMING CHAPTER 8: MODULES
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
8-7
require
If the file being required has executable statements
outside of a class or a method, that code will be executed.
This can be seen in the following example.
a_ruby_file.rb
1. #!/usr/bin/ruby
2. puts "This is outside of any class or method"
3. def simple
4. puts "This is inside of a method called simple"
5. end
6. puts "This is also outside of any class or method"

Now, we will show a program that requires a_ruby_file.rb.
Note carefully the output when require_ruby_file.rb is
executed.
require_ruby_file.rb
1. #!/usr/bin/ruby
2. require './a_ruby_file'
3. puts "Calling simple"
4. simple()
5. puts "Returned from call to simple"

The output from the above program is shown below.
This is outside of any class or method
This is also outside of any class or method
Calling simple
This is inside of a method called simple
Returned from call to simple

Note that the require './a_ruby_file' could have
been replaced with require_relative 'a_ruby_file'
instead.
RUBY PROGRAMMING CHAPTER 8: MODULES
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
8-8
Search Path
When Ruby searches for required files, it uses the built-in
array referenced by the global variable, $:.
This array contains the directories where Ruby will search for
required files.
If you supply the complete path name to the required file,
then just that name is used and $: is ignored.
Here is a simple program that prints the contents of $:.
paths.rb
1. #!/usr/bin/ruby
2. $:.each {|path| puts path }

The actual paths listed will be dependent upon: the version of
Ruby installed on your machine, where it was installed and
what OS you are running.
You can add to the $: variable in various ways.
Push a directory onto $: from within a program.
$:.push("mydir")

Use the RUBYLIB environment variable.
For example, on Linux, you can execute the following
command in the appropriate start up file.
$ export RUBYLIB=mydir

Use the -I flag on the command line to push a directory (sub
in this case) onto the $: array.
$ ruby -I sub program.rb
RUBY PROGRAMMING CHAPTER 8: MODULES
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
8-9
File Organization
We have seen several programs that have dealt with user
created classes.
These programs have had the class definition in the same file
as the code that uses that definition.
This is an inferior file organization since the class is now only
usable in this file and not to the programmer public at large.
Typically, each class definition will be in its own file.
Then, any program wishing to use that class simply imports it
by using the require method.
A single file can contain more than one class, but this is
atypical.
To illustrate these concepts, we will show a simple
example of a class, a superclass, and a program that uses
both of them.
We will use stripped down versions of the GradStudent class
and its superclass Student, seen earlier in the course.
Student.rb
1. #!/usr/bin/ruby
2. class Student
3. def initialize(name)
4. @name = name
5. end
6. def to_s
7. @name
8. end
9. end
RUBY PROGRAMMING CHAPTER 8: MODULES
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
8-10
File Organization
Any program wishing to use the Student class would
proceed as shown below.
useStudent.rb
1. #!/usr/bin/ruby
2. require_relative 'Student'
3. s1 = Student.new("Mike")
4. s2 = Student.new("Jane")
5. puts s1
6. puts s2
Next, we define the GradStudent class followed by a
program that uses it.
GradStudent.rb
1. #!/usr/bin/ruby
2. require_relative 'Student'
3. class GradStudent < Student
4. def initialize(name, stipend)
5. @name = name
6. @stipend = stipend
7. end
8. def to_s
9. return "#{super.to_s}: #@stipend"
10. end
11. end

A program that uses the GradStudent class is shown below.
useGradStudent.rb
1. #!/usr/bin/ruby
2. require_relative 'GradStudent'
3. gs1 = GradStudent.new("Jim", 2000)
4. gs2 = GradStudent.new("Joan", 3000)
5. puts gs1
6. puts gs2
RUBY PROGRAMMING CHAPTER 8: MODULES
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
8-11
File Organization
The program below uses both the Student and
GradStudent classes.
useBoth.rb
1. #!/usr/bin/ruby
2. require_relative 'Student'
3. require_relative 'GradStudent'
4. s1 = Student.new("Mike")
5. gs1 = GradStudent.new("Jim", 2000)
6. puts s1
7. puts gs1

Ruby tracks required files so there is no need to worry about
the required or required_relative file(s) being loaded
and executed more than once.
RUBY PROGRAMMING CHAPTER 8: MODULES
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
8-12
load
The load method also imports and executes a file.
When you use load, you need to use the .rb extension.
load 'Student.rb'
While the use of the .rb extension is one way in which load
differs from require, it is not the only difference.
If you require the same file more than once, all requires
after the first will simply not load.
This means that while you are using the required file, any
change to the required file has no effect on the environment in
which it is being used.
On the other hand, the load method can be used to load
the same file more than once.
The implication here is that any changes to the loaded file will
become effective when the file is re-loaded.
The consequences loading the same file multiple times
within the running of a program can be seen more clearly
in the following.
irb sessions
Rails programming




RUBY PROGRAMMING CHAPTER 8: MODULES
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
8-13
Modules
Now that we are familiar with require, we can tackle
issues relating to it.
Suppose for example, we have two libraries, each of them
containing the methods as shown here.
wordlib1.rb
1. #!/usr/bin/ruby
2. def word
3. puts "I am a word in wordlib"
4. end
5. def line
6. puts "I am a line in wordlib"
7. end

graphlib1.rb
1. #!/usr/bin/ruby
2. def circle
3. puts "I am a circle in graphlib"
4. end
5. def line
6. puts "I am a line in graphlib"
7. end
Suppose further that we have a program that requires the
two libraries above. Here is an example.
program1.rb
1. #!/usr/bin/ruby
2. require_relative "graphlib1"
3. require_relative "wordlib1"
4. line()
5. circle()
6. word()

It is the line method from wordlib1 that is executed.
This is because the wordlib1 library was required last.
RUBY PROGRAMMING CHAPTER 8: MODULES
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
8-14
Modules
What is needed is a way to distinguish between methods
that have the same name but are located in different files.
This is where the Ruby module facility is needed.
A module actually has two separate uses in Ruby.
creating a separate namespace so as to avoid name clashes
mixins
First, let us look at how modules can be used to avoid the
name clash problem from the previous example
The disambiguation of the method names can be accomplished
by restructuring the two .rb files.
wordlib2.rb
1. #!/usr/bin/ruby
2. module Words
3. def Words.word
4. puts "I am a word in wordlib"
5. end
6. def Words.line
7. puts "I am a line in wordlib"
8. end
9. end

graphlib2.rb
1. #!/usr/bin/ruby
2. module Graphics
3. def Graphics.circle
4. puts "I am a circle in graphlib"
5. end
6. def Graphics.line
7. puts "I am a line in graphlib"
8. end
9. end

RUBY PROGRAMMING CHAPTER 8: MODULES
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
8-15
Modules
Now, we have two modules.
A module is like a class except a module can have no:
instances; or
subclasses.
To use the modules, we change the test program as
shown here.
program2.rb
1. #!/usr/bin/ruby
2. require_relative "graphlib2"
3. require_relative "wordlib2"
4. Words.line
5. Graphics.line
6. Words.word
7. Graphics.circle

The output from the above program is shown below.
I am a line in wordlib
I am a line in graphlib
I am a word in wordlib
I am a circle in graphlib
Note that a module can also contain one or more
constants.
module Arith
MAX = 10000
end

You would access such a constant in a program using the
following notation.
puts Arith::MAX
RUBY PROGRAMMING CHAPTER 8: MODULES
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
8-16
include
The include method takes all the methods from another
module and includes them into the current module.
This works nicely when you have a class, and you wish to
extend its functionality by including methods from one or more
modules into a class.
Ruby refers to this as a mixin class.
This is how Ruby handles multiple inheritance of
implementation.
You can also use the include method to make life easy
in terms of referencing certain methods.
Be careful when using include for this purpose of any possible
undesirable side effects.
clash.rb
1. #!/usr/bin/ruby
2. puts Math.sqrt(20)
3. include Math
4. puts sqrt(20)
5. def sqrt(p)
6. return p
7. end
8. puts sqrt(20)
9. puts Math.sqrt(20)

The output from the above program is shown below.
4.47213595499958
4.47213595499958
20
4.47213595499958
RUBY PROGRAMMING CHAPTER 8: MODULES
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
8-17
Mixins
The inclusion of a module within a class definition is called
a mixin.
Ruby uses this concept as an alternative to multiple inheritance,
which is fraught with disambiguation issues.
The idea behind mixins is that one class can mix in the
functionality of one or more modules.
In the example below, the Utility module is mixed in with
the Employee class.
utilityTest1.rb
1. #!/usr/bin/ruby
2. module Utility
3. def hello
4. return "Hello"
5. end
6. def goodbye
7. return "Goodbye"
8. end
9. end
10. class Employee
11. include Utility
12. def initialize(name)
13. @name = name
14. end
15. def to_s
16. @name
17. end
18. end
19. e = Employee.new("Susan")
20. puts e.hello
21. puts e
22. puts e.goodbye

The output from the above program is shown below.
Hello
Susan
Goodbye
RUBY PROGRAMMING CHAPTER 8: MODULES
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
8-18
Mixins
The idea behind the Utility module is that any class
wishing to use the its functionality can simply include it
with the statement:
include Utility

Usually, the module to be mixed in will be in a file by itself.
utility.rb
1. #!/usr/bin/ruby
2. module Utility
3. def hello
4. return "Hello"
5. end
6. def goodbye
7. return "Goodbye"
8. end
9. end

Then, any class wishing to mix in the Utility functionality
proceeds as follows.
utilityTest2.rb
1. #!/usr/bin/ruby
2. require_relative "utility"
3. class Employee
4. include Utility
5. def initialize(name)
6. @name = name
7. end
8. def to_s
9. @name
10. end
11. end
12. e = Employee.new("Susan")
13. puts e.hello
14. puts e
15. puts e.goodbye
RUBY PROGRAMMING CHAPTER 8: MODULES
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
8-19
Mixins
There is just one hitch in the above code.
If the module to be mixed in is not in the same file where it is
mixed, then there must first be a require of that file.
That is why the first few lines of the employee file looks like
what is shown below.
require "utility"
class Employee
include Utility

Of course, the Employee class is best placed in a file by itself
as shown below.
Employee.rb
1. #!/usr/bin/ruby
2. require_relative "utility"
3. class Employee
4. include Utility
5. def initialize(name)
6. @name = name
7. end
8. def to_s
9. @name
10. end
11. end

utilityTest3
1. #!/usr/bin/ruby
2. require_relative "Employee"
3. e = Employee.new("Susan")
4. puts e.hello
5. puts e.goodbye

The output from the above program is shown below.
Hello
Goodbye

RUBY PROGRAMMING CHAPTER 8: MODULES
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
8-20
Using the Comparable Module
Recall the Fraction class from earlier in the course.
As written there, it provides no way to compare two fractions (to
see if one is larger or smaller, etc.).
If the writer of the Fraction class desired comparison
functionality, there are two choices.
Define each comparison method within the Fraction class.
Include the Comparable module within the Fraction
class.
The Ruby language defines a module named
Comparable.
This module contains seven comparison methods:
<, <=, >, >=, ==, !=, between?
Any class that you write, such as Fraction, can mix
these methods into it.
The only caveat is that Comparable assumes that your class
defines the <=> method.
This <=> method should return -1, 0, or 1, depending on the
relationship of its two operands.
puts 2 <=> 3 # -1
puts 2 <=> 2 # 0
puts 2 <=> 1 # 1
On the next page, you can see the revised Fraction
class, along with an application that compares fractions.



RUBY PROGRAMMING CHAPTER 8: MODULES
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
8-21
Using the Comparable Module
fraction.rb
1. #!/usr/bin/ruby
2. class Fraction
3. attr_accessor :n, :d
4. include Comparable
5. def initialize(n,d)
6. @n = n; @d = d
7. end
8. def *(f)
9. Fraction.new(@n * f.n(), @d * f.d())
10. end
11. def to_s
12. @n.to_s + "/" + @d.to_s
13. end
14. def <=>(frac)
15. left = @n.to_f/@d
16. right = frac.n().to_f/frac.d()
17. left <=> right
18. end
19. end

usefraction.rb
1. #!/usr/bin/ruby
2. require_relative "Fraction"
3. low = Fraction.new(2,5)
4. mid = Fraction.new(3,5)
5. high = Fraction.new(4,5)
6. print "low:", low, " mid:", mid, " high:", high,"\n"
7. puts "mid > low: " + (mid > low).to_s
8. puts "mid < high: " + (mid < high).to_s
9. print "mid between low, high: ",
10. mid.between?(low,high)

The output from the above program is shown below.
low:2/5 mid:3/5 high:4/5
mid > low: true
mid < high: true
mid between low, high: true
RUBY PROGRAMMING CHAPTER 8: MODULES
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
8-22
Collection Classes
A collection class refers to any class that can store more
than one object (i.e., a collection).
You could consider the Array and Hash classes as collections.
The Collect class, defined below, is nothing more than a
wrapper class around an Array.
Collect.rb
1. #!/usr/bin/ruby
2. class Collect
3. def initialize()
4. @array = Array.new(0)
5. end
6. def add(item)
7. @array.push(item)
8. end
9. def to_s
10. @array.join(" ")
11. end
12. def howmany
13. @array.size
14. end
15. end

useCollect.rb
1. #!/usr/bin/ruby
2. require_relative 'Collect'
3. c = Collect.new()
4. c.add(10)
5. c.add(15)
6. puts c.to_s
7. c.add(12)
8. c.add(17)
9. puts c.to_s

The output from the above program is shown below.
10 15
10 15 12 17
RUBY PROGRAMMING CHAPTER 8: MODULES
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
8-23
yield
There should be no surprises in the previous code.
Our Collect class is simply a wrapper around the Array class.
Now, suppose we wish to add methods such as min, max,
sort, and find.
We have a few choices here:
Encode these methods into the Collect class, or
Mix in the methods from Enumerable.
The Enumerable mixin provides collection classes with
several traversal and searching methods.
Any class that includes Enumerable must provide an each
method, which yields successive members of the collection.
As it turns out, the each method will look like this.
def each
@array.each {|item| yield item}
end

However, we need to take a slight detour and explain
yield.
Note that a block may be associated with a method call.
simple() { puts "The associated block" }
When the call above is executed, a yield statement
within simple causes the associated block to execute.
This can be seen in the example on the following page.
RUBY PROGRAMMING CHAPTER 8: MODULES
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
8-24
yield
simple1.rb
1. #!/usr/bin/ruby
2. def simple
3. puts "starting method"
4. yield
5. puts "inside method body"
6. yield
7. puts "ending method"
8. end
9. simple() { puts "The associated block" }

The output from the above program is shown below.
starting method
The associated block
inside method body
The associated block
ending method

Whenever a yield is executed, it invokes the code in the
block.
When the block exits, control picks back up immediately after
the yield.
The yield statement can also have parameters.
The parameters are passed to the associated block.
In the definition of the block, the argument list appears between
vertical bars.
The example on the following page defines a yield with
multiple parameters.
RUBY PROGRAMMING CHAPTER 8: MODULES
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
8-25
yield
simple2.rb
1. #!/usr/bin/ruby
2. def simple(a, b)
3. yield a, b, 10
4. end
5. simple(1,5) { | x, y, z | puts x + y + z }
6. simple(7,3) { | x, y, z | puts x - y - z }

The output from the above program is shown below.
16
-6

Notice that the code inside the block can vary with each call
to the simple method.
A method can be called with or without the block.
simple(1,10)

In these cases, the method needs to determine whether it was
called with or without the block.
simple3.rb
1. #!/usr/bin/ruby
2. def simple(a, b)
3. puts "Inside simple:"
4. yield a, b, 10 if block_given?
5. end
6. simple(1,10) { | x, y, z | puts x + y + z }
7. simple(7,3)
Now that we know about yield, we can revisit the use of
the each method in the Collect class.


RUBY PROGRAMMING CHAPTER 8: MODULES
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
8-26
Using the Enumerable Module
Now that we know how each is written, we can mix in the
Enumerable module and take advantage of its methods.
Collect2.rb
1. #!/usr/bin/ruby
2. class Collect2
3. include Enumerable
4. def initialize()
5. @array = Array.new(0)
6. end
7. def add(item)
8. @array.push(item)
9. end
10. def to_s
11. @array.join(" ")
12. end
13. def howmany
14. @array.size
15. end
16. def each
17. @array.each {|item| yield item}
18. end
19. end

Keep in mind that it is the methods in the Enumerable module
that call the each method.
The yield in the each method is actually yielding to the code
block associated from whichever Enumerable method was
called.
For example, in the code on the following page, there is a
call to sort and a call to find_all.
These are Enumerable methods that have code blocks.
RUBY PROGRAMMING CHAPTER 8: MODULES
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
8-27
Using the Enumerable Module
useCollect2.rb
1. #!/usr/bin/ruby
2. require_relative "Collect2"
3. c = Collect2.new()
4. c.add(10)
5. c.add(15)
6. c.add(12)
7. c.add(17)
8. print "SORT ARRAY: " , c.sort.inspect, "\n"
9. print "EVENS: "
10. print c.find_all { |x| x % 2 == 0 }.inspect

The output from the above program is shown below.
SORT ARRAY: [10, 12, 15, 17]
EVENS: [10, 12]

The important item to notice is that the sort and the
find_all methods are used on a Collect2 object, even
though these methods are not in the Collect2 class.
These methods are mixed in using the include facility
provided by Ruby.
Therefore, it is as though the functionality from the included
module, Enumerable, is part of the Collect2 class.
RUBY PROGRAMMING CHAPTER 8: MODULES
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
8-28
Exercises
1. Start an irb session and require a particular file.
Then require it again.
Notice the results of each require.
In the same session, load that same file and then load it
again.
View the results.
It would also be instructive to change the file between the
two load calls.
2. Create the class Auto with the methods initialize
and to_s in the file Auto.rb.
An Auto object should have attributes fuel and mpg.
Then, create a separate file named useAuto.rb that does the
following:
Creates a few Auto objects and displays information about
each object.
3. Create a file named Mod.rb that contains a module
named Mod.
The module should incorporate the following String
functionality.
A method to multiply a string by a number object.
A method to return a string minus the last n characters.
Now, write a program useMod.rb that uses the functionality in
Mod.rb.
4. Take the GradStudent class from this chapter and mix
in the Comparable module.
Use the stipend as the comparable item.
RUBY PROGRAMMING CHAPTER 8: MODULES
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
8-29
Exercises
5. Write and test the following class.
class Fraction
attr_reader :n, :d
def initialize(n,d)
@n = n; @d = d
end
def to_s
return "#@n/#@d\n"
end
end

6. Write and test the following class.
class Farray
def initialize
@array = Array.new()
end
def add(f)
@array.push(f)
end
def display
@array.each { |f| puts f }
end
end
RUBY PROGRAMMING CHAPTER 8: MODULES
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
8-30
Exercises
7. Add whatever you need in the above two classes to make
the following program work.
fractions = [ Fraction.new(1,4),
Fraction.new(3,4),
Fraction.new(2,4),
Fraction.new(0,4)]
all = Farray.new()
fractions.each { |frac| all.add(frac) }
puts "BEFORE SORT\n"
fractions.display()
found = all.sort()
puts "AFTER SORT\n"
puts found

The Farray class will need to:
define each
include Enumerable
The Fraction class will need to:
define <=>
The results of the program should look like this.
BEFORE SORT
1/4
3/4
2/4
0/4
AFTER SORT
0/4
1/4
2/4
3/4
RUBY PROGRAMMING CHAPTER 9: ODDS AND ENDS
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
9-1
Chapter 9:
Odds and Ends
1) Ruby Conventions.................................................................................................... 9-2
2) Bit Manipulation...................................................................................................... 9-5
3) Substituting............................................................................................................... 9-8
4) Marshalling............................................................................................................... 9-9
5) Reflection ................................................................................................................ 9-11
6) grep........................................................................................................................ 9-12
7) Classes are Objects ................................................................................................ 9-13
8) Aliasing.................................................................................................................... 9-15
9) Testing..................................................................................................................... 9-16
10) Test::Unit::TestCase.................................................................................. 9-17
11) Testing Your Own Classes .................................................................................... 9-22
12) Freezing Objects..................................................................................................... 9-24
13) Object Equality ...................................................................................................... 9-26

RUBY PROGRAMMING CHAPTER 9: ODDS AND ENDS
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
9-2
Ruby Conventions
Throughout this course, we have seen various String
methods that come in pairs.
In general, numerous methods, from many different classes,
have two versions.
The one with the ! at the end of the function name will
change the host object.
The one without the ! at the end of the function name will
not change the host object.
Here are some examples from the String class.
capitalize capitalize!
upcase upcase!
downcase downcase!
reverse reverse!
chop chop!
Generally speaking, a Boolean function is one which
returns true or false.
Ruby has the class TrueClass and FalseClass, each with
one instance, true and false, respectively.
Functions that return Boolean values will have a question mark
as the last character in the method name.
array.empty?
number.zero?
hash.has_key?(key)
array.nil?
RUBY PROGRAMMING CHAPTER 9: ODDS AND ENDS
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
9-3
Ruby Conventions
Ruby considers nil and false to be false, and all
other values to be true.
This is one of the major differences between Perl and Ruby.
Ruby provides various ways to initialize certain objects.

foo = ""
foo = String.new

foo = []
foo = Array.new

foo = {}
foo = Hash.new
Use semi-colons to separate statements if you wish to
have more than one statement on a line.
x = 5; y = 6; z = x + y; puts z
Use white space around the assignment operator except
when assigning default values in parameter lists.
x = 5 # not x=5
Do not use whitespace to separate a method name from
its parameter list.
Within the parameter list itself, however, whitespace is fine.
Object.method (param) # do not do this
RUBY PROGRAMMING CHAPTER 9: ODDS AND ENDS
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
9-4
Ruby Conventions
Beware of the following caveat!
puts nil || "foo"

Parses to:
puts( nil || "foo" )

And prints:
"foo"

Whereas:
puts nil or "foo"

Parses to:
puts( nil ) || "foo"

And prints:
nil

Ruby allows both do/end and {} iterator blocks.
Stick to do/end except when the entire iterator block fits on a
single line.
data = [15, 20, 5, 8, 25]
data.each do |x|
puts x
x *= 2
puts x
end

large = data.find_all { |x| x > 10 }
RUBY PROGRAMMING CHAPTER 9: ODDS AND ENDS
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
9-5
Bit Manipulation
Most applications deal with decimal numbers.
Occasionally, you will want to use other bases such as binary,
octal, and hexadecimal.
If you wish to specify the bit pattern in a variable, you can
always express the value using octal or hexadecimal.
For example, suppose you need a variable to be initialized with
the following bits.
v = 0010101100101110

Since Ruby allows octal constants, one way to proceed is to
group the bits three at a time and then express each value
as an octal constant.
0 010 101 100 101 110
0 2 5 4 5 6

v1 = 025456 # leading zero for octal

Alternately, since Ruby allows hex constants, you can group
the bits four at a time and then express each value as a hex
constant.
0010 1011 0010 1110
2 b 2 e

v2 = 0x2b2e # leading zero x for hex

You can verify your work by using the %o and %x format
specifics provided by sprintf.
result = sprintf("%o %x", v1, v2)
RUBY PROGRAMMING CHAPTER 9: ODDS AND ENDS
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
9-6
Bit Manipulation
There are also methods named hex and oct.
These methods take a hexadecimal and octal string
(respectively) and convert it to a decimal number.
hexoct.rb
1. #!/usr/bin/ruby
2. print "Enter hex digits: "
3. ln= gets.chop
4. puts "#{ln} is " + ln.hex.to_s + " decimal."
5. print "Enter oct digits: "
6. ln= gets.chop
7. puts "#{ln} is " + ln.oct.to_s + " decimal."

The output from the above program is shown below.
Enter hex digits: ff
ff is 255 decimal.
Enter oct digits: 77
77 is 63 decimal.
You can also use the to_s method by giving it a base
argument.
Notice the following code.
bases.rb
1. #!/usr/bin/ruby
2. x = 100
3. bases = [2,8,10,16]
4. bases.each { |base| puts x.to_s(base) }

The output from the above program is shown below.
1100100
144
100
64
RUBY PROGRAMMING CHAPTER 9: ODDS AND ENDS
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
9-7
Bit Manipulation
Ruby has a number of operators to manipulate the
individual bits of a numeric value.
Note the way these operators work.
a = 055; # Octal (base 8)
b = 0x44; # Hexadecimal (base 16)

a and b in memory (assume 16 bits):
a 0 000 000 000 101 101
b 0 000 000 001 000 100

a | b 0 000 000 001 101 101 OR

a & b 0 000 000 000 000 100 AND

a ^ b 0 000 000 001 101 001 EXCLUSIVE OR

~a 1 111 111 111 010 010 COMPLEMENT

a >> 3 0 000 000 000 000 101 RIGHT SHIFT

b << 3 0 000 001 000 100 000 LEFT SHIFT

These operators obey the following rules for respective
bits.

Op 1 Op 2
| & ^
0 0 0 0 0
0 1 1 0 1
1 0 1 0 1
1 1 1 1 0

RUBY PROGRAMMING CHAPTER 9: ODDS AND ENDS
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
9-8
Substituting
The sub and gsub methods allow one string to be
substituted for another within a host string.
sub only substitutes the first occurrence of a string that is
matched.
x = "hello and hello and hello"
puts x.sub("hello", "bye")

gsub substitutes for all occurrences of a string.
x = "hello and hello and hello"
puts x.gsub("hello", "bye")
The arguments to these functions can be regular
expressions or blocks.
Regular Expression
x = "10 + 10 = 20"
puts x.gsub(/[0-9]/, "")

Block
x = "10 + 10 = 20"
y = x.gsub(/\d\d/) { |m| m.reverse }
RUBY PROGRAMMING CHAPTER 9: ODDS AND ENDS
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
9-9
Marshalling
The reading and writing of class objects was carefully
omitted in the discussion of input and output.
This topic is generally called marshalling.
Although this is an extensive topic, we show here the rudiments
of how you write and read class objects.
The first program dumps an Employee object to a file.
dump.rb
1. #!/usr/bin/ruby
2. class Employee
3. def initialize(name, pay)
4. @name = name
5. @pay = pay
6. end
7. def to_s
8. "#@name: #@pay"
9. end
10. end
11.
12. e1 = Employee.new("Mike", 85_500)
13. puts e1
14. f = File.open("dumpfile", "w");
15. Marshal.dump(e1,f)

The output from the above program is shown below.
Mike: 85500

The object has been serialized and dumped to the file
named dumpfile.
Any object is can be marshaled in this way.
Generally speaking, marshaled data can be dumped, stored
in a variable, sent over the network, etc.
RUBY PROGRAMMING CHAPTER 9: ODDS AND ENDS
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
9-10
Marshalling
Now that the data has been saved, we need to load it
back into memory.
This might take place in the same program or in other
programs.
In the following example, the saved data is loaded into an
Employee object in another program.
load.rb
1. #!/usr/bin/ruby
2. class Employee
3. def initialize(name, pay)
4. @name = name
5. @pay = pay
6. end
7. def to_s
8. "#@name: #@pay"
9. end
10. end
11. f = File.open("dumpfile", "r");
12. data = Marshal.load(f)
13. puts "data is of type #{data.class}"
14. puts data

The output from the above program is shown below.
data is of type Employee
Mike: 85500
RUBY PROGRAMMING CHAPTER 9: ODDS AND ENDS
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
9-11
Reflection
Reflection is the process by which a program can observe
and modify its own structure and behavior.
Typically, the difference between data and instructions is
a matter of how the information is treated by the computer
and programming language.
Normally, instructions are executed and data is processed.
However, in some languages, programs can also treat
instructions as data and, therefore, make reflective
modifications.
Reflection is most commonly used in high-level
programming languages and scripting languages like
Ruby.
Although this is an advanced topic, we mention it here and
point the student toward the documentation.
Here is a sample of some Ruby methods that can be used in
reflection.
instance_of?
is_a?
kind_of?
methods
object_id,
private_methods
protected_methods
public_methods
respond_to?
singleton_methods
RUBY PROGRAMMING CHAPTER 9: ODDS AND ENDS
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
9-12
grep
grep is one of those functions that comes from the
Enumerable module.
This important function returns an array of elements that match
a pattern.
Any class that includes Enumerable can use grep.
Since Array includes Enumerable, then grep can be used
to find all array elements matching a certain pattern.
For example, to find all files in the current directory that
begin with a 'c', you could write the following.
Dir.entries(".").grep(/^c/)
The following example demonstrates using grep to list
the values for all of the constants in the Date class that
contain "ABBR" in their name.
date_constants.rb
1. #!/usr/bin/ruby
2. require 'date'
3. puts Date::constants.grep(/ABBR/).join(" ")
4. puts Date::ABBR_DAYNAMES.join(" ")
5. puts Date::ABBR_MONTHNAMES[1,12].join(" ")

The output from the above program is shown below.
ABBR_MONTHNAMES ABBR_DAYNAMES
Sun Mon Tue Wed Thu Fri Sat
Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
RUBY PROGRAMMING CHAPTER 9: ODDS AND ENDS
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
9-13
Classes are Objects
Every method in Ruby has a host object on which it is
executed.
This is obvious in some cases.
data = Array.new
data.size

text = String.new("This is it")
text.split

bank = Hash.new
bank.keys

Math.sqrt(25)

In other cases, it is not so obvious.
puts "Hello"
print "Hello"
printf "%-20s", "hello"
In the not so obvious cases above, it turns out that
Object is the host.
The puts method is actually in the Kernel module, which is
included in Object.
Each class is an object of the Class class.
Therefore, you can have a method executed when a class is
loaded.
RUBY PROGRAMMING CHAPTER 9: ODDS AND ENDS
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
9-14
Classes are Objects
Within the following class definition are several executable
lines of code that are placed outside of methods.
These lines are executed when the class is loaded.
meta.rb
1. #!/usr/bin/ruby
2. class X
3. puts "Top: " + self.class.to_s
4.
5. def self.welcome
6. puts "You just loaded X"
7. end
8.
9. welcome
10. end
11.
12. puts X.class

The output from the above program is shown below.
Top: Class
You just loaded X
Class
This programming paradigm is often seen in Rails
programming.
It forms the basis of what is sometimes called meta-
programming.
RUBY PROGRAMMING CHAPTER 9: ODDS AND ENDS
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
9-15
Aliasing
Ruby also allows the aliasing of method names.
Here are a few examples of how this works.
In the code below, we create a method, alias it, and then
create another method with the same name as the first.
alias.rb
1. #!/usr/bin/ruby
2. def method1
3. "original method1"
4. end
5. alias original method1
6. def method1
7. "improved method1"
8. end
9. puts method1
10. puts original

The output from the above program is shown below.
improved method1
original method1

Note that you could also have used symbols for the alias:
alias :newmtd :oldmtd

This concept also applies to methods within a class.
This technique is often used in Rails programming.
RUBY PROGRAMMING CHAPTER 9: ODDS AND ENDS
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
9-16
Testing
Programmers perform tests all the time.
If there is a method to reverse a string, you might write a small
program segment like the one below to test if method works as
intended.
string = "hello"
if ( string.reverse() == "olleh")
puts "ALL OK HERE"
end

You could write tests, like the one above, each time you
wanted to verify a small portion of your code.
However, in the Ruby world, a framework has already been
written for you to save assist with the writing of these tests.
Any Ruby code that you wish to test, using the built-in
framework, must follow the following recipe.
require the file 'test/unit'.
Create a class derived from Test::Unit::TestCase.
All methods in this new class will contain one or more tests
in the form of assertions.
Each method name must begin with the four characters
"test".
The example on the following page demonstrates using
the built-in testing framework as described above.
RUBY PROGRAMMING CHAPTER 9: ODDS AND ENDS
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
9-17
Test::Unit::TestCase
test1.rb
1. #!/usr/bin/ruby
2. require 'test/unit'
3. class MyTestClass < Test::Unit::TestCase
4. def test_exponents
5. x = 2
6. assert(x ** 3 == 8)
7. assert(x ** 4 == 32)
8. end
9. def test_reverse
10. assert("Hello".reverse == "olleH")
11. end
12. def test_symbol
13. assert(:Hello.reverse == "olleH")
14. end
15. def test_length
16. assert("Hello\n".length == 6)
17. end
18. def not_a_test
19. puts "This is not a test"
20. end
21. end

Notice the following points about the above code.
There are four methods.
Each method contains one or more assertions.
The above code is executed like any other Ruby program.
Ruby does not normally call methods of a class when the class
is loaded into memory.
The require 'test/unit' statement will result in the
testing framework automatically calling all of the methods
within the class whose method names start with "test" as
the class is loaded.
The output of running the above example is shown on the
following page.
RUBY PROGRAMMING CHAPTER 9: ODDS AND ENDS
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
9-18
Test::Unit::TestCase
The output from the example on the previous page is
shown below.
Loaded suite test1
Started
F..E
Finished in 0.012071 seconds.

1) Failure:
test_exponents(MyTestClass) [test1.rb:7]:
<false> is not true.

2) Error:
test_symbol(MyTestClass):
NoMethodError: undefined method `reverse' for
:Hello:Symbol
test1.rb:13:in `test_symbol'

4 tests, 4 assertions, 1 failures, 1 errors
The tests are executed in alphabetical order.
Therefore, they would be executed as follows.
test_exponents
test_length
test_reverse
test_symbol

The following line represents the results of the tests.
F..E

A dot (.) indicates success.
An F represents a failure (an test that is not true).
An E represents a Ruby error.
This is followed by descriptions of the errors and failures.
RUBY PROGRAMMING CHAPTER 9: ODDS AND ENDS
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
9-19
Test::Unit::TestCase
The results of the tests for the previous example are as
follows:
test_exponents - Failure
test_length - Success
test_reverse - Success
test_symbol - Error
test_exponents failed because the second assertion
returned false.
This is because the following statement is not true.
2 ** 4 == 32
The test_symbol produced an error because there is no
reverse method that can be applied to a Ruby symbol.
Within the example there are 4 tests comprised of 5
assertions.
Ultimately, the number of tests, assertions, failures, and errors
are reported.
4 tests, 4 assertions, 1 failures, 1 errors
Within each test, when there is a failure, no other
assertions are attempted.
Likewise, if there is an error, no further assertions are
attempted.
The assertion within test_symbol was not reported due to
the error that occurred first.
RUBY PROGRAMMING CHAPTER 9: ODDS AND ENDS
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
9-20
Test::Unit::TestCase
The assert method takes a Boolean as its first
argument, which is generally intended to be true.
An optional second argument can be passed that represents a
custom message to display when an assertion fails.
Another assertion method is named assert_equal.
This method can take three arguments.
The first argument is your expected results.
The second argument is the actual Ruby expression that,
when executed, will produce a result.
The third argument is optional and represents a custom
message to display when an assertion fails.
Therefore, the assert_equal method is really allowing you to
test a result against what you think it ought to be.
Here is another Ruby program that defines a few tests
using assert_equal.
test2.rb
1. #!/usr/bin/ruby
2. require 'test/unit'
3. class MyTestClass < Test::Unit::TestCase
4. def test_concatenation
5. x = "How are you"
6. x = x << " today"
7. assert_equal(17, x.length())
8. end
9. def test_length_of_string
10. assert_equal(12, "How are you\n".length())
11. end
12. def test_conversion_to_binary
13. assert_equal("100111", 39.to_s(2))
14. end
15. end
RUBY PROGRAMMING CHAPTER 9: ODDS AND ENDS
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
9-21
Test::Unit::TestCase
Here is an example where the assertions are false.
test3.rb
1. #!/usr/bin/ruby
2. require 'test/unit'
3. class MyTestClass < Test::Unit::TestCase
4. def test_float_divide
5. assert_equal(1.333, 4.0 / 3.0)
6. end
7. def test_int_divide
8. assert_equal(1.333, 4 / 3)
9. end
10. def test_custom_msg
11. assert_equal(1, 2, "1 and 2 are NOT equal")
12. end
13. end

The output from the above program is shown below.
Loaded suite test3
Started
FFF
Finished in 0.011708 seconds.

1) Failure:
test_custom_msg(MyTestClass) [test3.rb:11]:
1 and 2 are NOT equal.
<1> expected but was
<2>.

2) Failure:
test_float_divide(MyTestClass) [test3.rb:5]:
<1.333> expected but was
<1.33333333333333>.

3) Failure:
test_int_divide(MyTestClass) [test3.rb:8]:
<1.333> expected but was
<1>.

3 tests, 3 assertions, 3 failures, 0 errors
RUBY PROGRAMMING CHAPTER 9: ODDS AND ENDS
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
9-22
Testing Your Own Classes
You can test your own classes in the following two ways.
Adding your test class to the same file with the class you are
testing.
Place the test class in a separate file and require it.
In either case, the special method named setup can be
used to create some test data.
The use of setup to create some test data is demonstrated
in the following example.
testclass1.rb
1. #!/usr/bin/ruby
2. require 'test/unit'
3. class Person
4. attr_accessor :name, :title
5. def initialize(name, title)
6. @name = name
7. @title = title
8. end
9. def to_s
10. @name + ": " + @title
11. end
12. end
13.
14. class Tests < Test::Unit::TestCase
15. def setup
16. @d = Person.new("John", "Job 1");
17. end
18. def test_to_s1
19. assert_equal("John: Job1", @d.to_s)
20. end
21. def test_to_s2
22. assert_equal("John : Job1", @d.to_s)
23. end
24. end
RUBY PROGRAMMING CHAPTER 9: ODDS AND ENDS
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
9-23
Testing Your Own Classes
Be aware of subtle errors that can lead to tests that result
in an error prior to the assertion being performed.
This can be demonstrated in the seemingly innocent example
below.
testclass2.rb
1. #!/usr/bin/ruby
2. require 'test/unit'
3. class Executive
4. attr_writer :title
5. def initialize(title)
6. @title = title
7. end
8. end
9. class Tests < Test::Unit::TestCase
10. def setup
11. @d = Executive.new("President")
12. end
13. def test_reader
14. assert("President", @d.title)
15. end
16. end

If you execute the Ruby code above, you will get the following
error message.
1) Error:
test_reader(Tests):
NoMethodError: undefined method `title' for
#<Executive:0xb77e5600 @title="President">
testclass2.rb:14:in `test_reader'

The subtlety here is that the title attribute is a writer.
The object's title can be altered by assigning to it, but the
title cannot be extracted from the object as we have
attempted to do.
RUBY PROGRAMMING CHAPTER 9: ODDS AND ENDS
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
9-24
Freezing Objects
An object can be frozen with the freeze method.
This means that any attempt to alter this object will result in an
exception.
freeze1.rb
1. #!/usr/bin/ruby
2. str = 'A simple string.'
3. str.freeze
4. begin
5. str << ' An attempt append to the string.'
6. rescue => err
7. puts "#{err.class} #{err}"
8. end

The output from the above program is shown below.
TypeError can't modify frozen string
Ruby sometimes copies objects and freezes the copies.
When you use a string as a hash key, Ruby actually copies the
string, freezes the copy, and uses the copy as the hash key.
That way, if the original string were to change later in the
program, the hash key is not affected.
Another common programmer-level use of this feature is
to freeze a class in order to prevent future modifications to
it.
It is important to realize that it is the object that is frozen, not
the variable the freeze method was called on.
This is demonstrated in the example on the following page.
RUBY PROGRAMMING CHAPTER 9: ODDS AND ENDS
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
9-25
Freezing Objects
Therefore, it is the object that is frozen and not the
variable. Notice the following code.
freeze2.rb
1. #!/usr/bin/ruby
2. # Freezing an object does not freeze its reference
3. str = 'The Original String'
4. puts str.object_id
5. str.freeze
6. str = "Some Other String"
7. puts str.object_id
8.
9. # Attempting to modify a frozen object
10. a = b = 'Another String To Test'
11. b.freeze
12. puts a.frozen? # true
13. puts b.frozen? # true
14. begin
15. a.upcase!
16. rescue => err
17. puts "#{err.class} #{err}"
18. end
19. a = "A Completely Different String"
20. puts a.frozen? # false
21. puts b.frozen? # true

The output from the above program is shown below.
-608052958
-608052978
true
true
TypeError can't modify frozen string
false
true
RUBY PROGRAMMING CHAPTER 9: ODDS AND ENDS
2013 /training/etc Inc. REPRODUCTION OF THESE MATERIALS IS PROHIBITED.
9-26
Object Equality
The following three methods are available for testing the
"equality" of objects.
equal?
Determines if two objects have the same object id (are the
same object).

==
Determines if two objects have the same value.

eql?
Determines if two objects have the same value as well as
the same type.
The following example demonstrates the three methods
described above.
equality.rb
1. #!/usr/bin/ruby
2. a = 25
3. b = 25.0
4. c = 25.00
5. $\ = "\n"
6. print "a = 25 b = 25.0 c = 25.00"
7. print "a equal? b : ", a.equal?(b)
8. print "a == b : ", a == b
9. print "a eql? b : ", a.eql?(b)
10.
11. print "b equal? c : ", b.equal?(c)
12. print "b == c : ", b == c
13. print "b eql? c : ", b.eql?(c)

Anda mungkin juga menyukai