CSC 517
Regular expressions
Ruby was invented as “a better Perl,” and hence has excellent built-in
support for regular expressions.
This is why it is useful as a scripting language. Here’s an example:
"faculty".sub(/c/, "")
"cheese".gsub(/e/, "o")
There are many facets to regular expressions. A Ruby regular expression
is an object, and can be created by a call to new.
e ='\d\w*')
It can also be specified like this:
e = /\d\w*/
The \d and \w are character-class abbreviations.
We can, of course, use regular-expression objects in pattern matching:
'a0a0a0'.sub(e, "")
Any PCRE (Perl-compatible regular expression) can go between the two
Making substitutions couldn't be easier than this:
str = str.gsub(/Steel/,'Titanium')
puts str
>>Titanium is the toughest material
We can constrain matching to occur at the start (^) or end ($) of a string.
"cheese".sub(/^e/, "o")
>> "cheese"
Lecture 6
Object-Oriented Languages and Systems
A character class is a set of characters between brackets. Any character
within the class matches a character class.
"anecdote".sub(/[aeio]/, "u")
A hyphen may be used to signify a range:
"now is the time".sub(/[a-y]/, "z")
Repetition can be specified by several special characters.
"choose".sub(/o+/, "e")
"choose".sub(/o?/, "e")
Modules and Mixins
Modules in Ruby are a way to group together methods, classes and
constants. They are similar to namespaces in languages such as
Of course, whenever you mix namespaces, you have the possibility
of name clashes.
Say you have a graphics library that contains classes for Window and
(window.rb) and Border (border.rb).1
Both window.rb and border.rb have a top method, which gives
the position of the top of the Window and the top of the Border,
A considerably cornier example can be found in the Module chapter of
Programming Ruby.
CSC/ECE 517 Lecture Notes
© 2010 Edward F. Gehringer
CSC 517
An application programmer wants to lay out windows with borders,
and thus loads both window.rb and border.rb into the program.
What’s the problem here?
Let’s consider how we might “solve” this. Take a minute, and write
down all the possibilities you can think of.
Ruby’s answer is the module mechanism.
Modules define a namespace. What’s a namespace?
The window functions can go into one module
module Window
# ..
def Window.bottom
# ..
and the border functions can go into another
module Border
# ...
def Border.width
# ..
Look at the names of module constants and methods. What do they
remind you of? Class constants and methods! Same conventions.
Lecture 6
Object-Oriented Languages and Systems
When a program needs to use these modules, it can simply load the
two files using the Ruby require statement, and reference the
qualified names.
require 'window'
require 'border'
trueTop = + Border.Top
Some differences between require and include:
 include makes features available, but does not execute the
 require loads and executes the code one time (like a C
 load loads and executes the code every time it is
However, only include will work to create mixins (see below).
The most interesting use of modules is to define mixins.
When you include a module within a class, all its functionality
becomes available to the class.
Not only can modules contain class methods; they can also contain
instance methods.
Let’s contrast this with #include in (what languages?) How are
mixins different? #include files define methods that can be called
(like class methods) but not applied to objects (like instance
Let’s contrast this with multiple inheritance in (what languages?).
How are mixins different? The same methods can be added to any
number of different classes, regardless of where they are in the
inheritance hierarchy.
So, instead of implementing interfaces as in Java, one uses mixins in
Ruby when one wants to simulate multiple inheritance.
CSC/ECE 517 Lecture Notes
© 2010 Edward F. Gehringer
CSC 517
Consider the following code:
module Introspect
def kind
puts "#{}"
class Animal
include Introspect
def initialize(name)
@name = name
class Car
include Introspect
def initialize(model)
@model = model
d ="Cat")
c ="Ferrari")
d.kind # kind method is available through …
c.kind # .. the mixin Introspect
Lecture 6
Object-Oriented Languages and Systems
Exercise: Take a look at the TeachingAssistant example defined here
and answer here.
 What happens if you remove the different to_s methods?
 What does this tell you about the way that Ruby resolves
conflicts among names inherited from mixins?
A good example of the power of modules is Comparable, from the
Ruby library.
To use comparable in a class, the class needs to define a method
called <=> (sometimes called “rocket”).
Once we define this method, we get a lot of useful comparison
functions, such as <, >, <=, >=, == and the method between? for
What is this like in Java?
Here is an example. Suppose that we have a Line class:
class Line
def initialize(x1, y1, x2, y2)
@x1, @y1, @x2, @y2 = x1, y1, x2, y2
We compare two lines on the basis of their lengths.
We add the Comparable mixin as follows:
class Line
include Comparable
def length_squared
(@[email protected]) * (@[email protected]) + (@[email protected]) * (@[email protected])
CSC/ECE 517 Lecture Notes
© 2010 Edward F. Gehringer
CSC 517
def <=>(other)
self.length_squared <=> other.length_squared
<=> returns 1,0, or –1, depending on whether the first argument is
greater than, equal to, or less than the second argument.
We delegate the call to <=> of the Fixnum class, which compares
the squares of the lengths.
Now we can use the Comparable methods on Line objects:
l1 =, 0, 4, 3)
l2 =, 0, 10, 10)
puts l1.length_squared
if l1 < l2
puts "Line 1 is shorter than Line 2"
else if l1 > l2
puts "Line 1 is longer than Line 2"
puts "Line 1 is just as long as Line 2"
>>Line 1 is shorter than Line 2
Composing Modules
Enumerable (p. 120 of Pickaxe book) is a standard mixin, which can be
included in any class.
It has a very useful method inject, which can be used to repeatedly
apply an operation to adjacent elements in a set:
[1, 2, 3, 4, 5].inject {|v, n| v+n }
Lecture 6
Object-Oriented Languages and Systems
Many built-in classes include Enumerable, including Array and Range.
(‘a’ .. ‘z’).inject {|v, n| v+n }
Exercise: Use inject to define a factorial method.
Let’s define a VowelFinder class that includes Enumerable. It will
have an each method for returning successive vowels from a string.
class VowelFinder
include Enumerable
def initialize(string)
@string = string
def each
@string.scan(/[aeiou]/) do |vowel|
yield vowel
Here’s an example of its use:"abacadabra").inject {|v, n| v+n}
However, would be nice not to have to type out the “inject” each time, if
we just want to work on a different collection. “+” does different things for
different classes.
 When used with numbers, it
 When used with strings, it
CSC/ECE 517 Lecture Notes
© 2010 Edward F. Gehringer
CSC 517
Let’s define a module that encapsulates the call to inject and +.
module Reducible
def sum_reduce
inject {|v, n| v+n}
class Array
include Reducible
class Range
include Reducible
class VowelFinder
include Reducible
[1, 2, 3, 4, 5].sum_reduce
('a' .. 'z').sum_reduce
vf =
("The quick brown fox jumped over the lazy dog.")
puts vf.sum_reduce
Exercise: Define a method that returns a string containing the vowels, so
that the above can be done with only one method call.
Simulating Multiple Inheritance
Modules can be used to simulate multiple inheritance in Ruby.
Lecture 6
Object-Oriented Languages and Systems
Suppose one wants to add tags to Strings. Then one can define
a Taggable module and include it into the class.
require 'set' # A collection of unordered values
with no duplicates
# Include this module to make your class taggable. The names of the
# instance variable and the setup method are prefixed with
# to reduce the risk of namespace collision. You must call
# taggable_setup before you can use any of this module's methods.
module Taggable
attr_accessor :tags
def taggable_setup
@tags =
def add_tag(tag)
@tags << tag
def remove_tag(tag)
class TaggableString < String
include Taggable
def initialize(*args)
CSC/ECE 517 Lecture Notes
© 2010 Edward F. Gehringer
CSC 517
s ='It was the best of times,
it was the worst of times.')
s.add_tag 'dickens'
s.add_tag 'quotation'
s.tags # =>
#<Set: {"dickens", "quotation"}>
What happens if we execute
puts s ?
Exercise: Add a to_s method to the taggable-string example. Then
submit it here.
Is Multiple Inheritance Good?
Multiple inheritance is generally used in one of four ways.
• Multiple independent protocols. A class is created by
combining completely different superclasses.
For example, in Eiffel, the library class WINDOW is a
subclass of SCREENMAN, RECTANGLE, and
• Mix and match. Several classes are created specially for
subsequent combination. Mixins are an example of this.
• Submodularity. While creating a situation, modularity of
subparts is noticed and factored out. For example, in a class
representing mortgages, one might factor out FIXED_RATE
and ADJUSTABLE mortgages.
• Separation of interface and implementation. An abstract
class is created to define the interface.
A second class is created to encapsulate the implementation
E.g., a Stack class could be created as a subclass of
StackInterface and StackImplementation.
Lecture 6
Object-Oriented Languages and Systems
Problems posed by multiple inheritance: Multiple inheritance can
increase reusability and consistency in a system.
However, with its power also comes complexity and ambiguity.
The following problems arise:
• Name collision. Two features with the same name are
inherited from different superclasses.
The parent classes may be correct and consistent. But there
is a conflict when a descendant class inherits a method with
the same name (e.g., initialize) from each.
• Repeated inheritance. Because there may be more than
one path from a class to its ancestor classes, a class can
inherit from the same superclass more than once.
We will consider this problem shortly.
• Method combination. An object may need to execute
methods with the same name defined in different
superclasses (e.g., intialize).
• Implementation difficulties. Because classes may be
combined in various ways, it is difficult to represent objects
and find methods without a lot of search or indirection.
• Misuse. Because a class has the ability to inherit from as
many other classes as necessary, there is a tendency to use
inheritance more often than it should be used.
Consider declaring an ApplePie class to inherit from
Apple and Cinnamon.
Why is this not good?
ApplePie should simply be a client of Apple and
CSC/ECE 517 Lecture Notes
© 2010 Edward F. Gehringer
CSC 517
Resolution of naming conflicts: Suppose class C inherits two different
methods for copy, from two different superclasses.
In Ruby, compound selectors are used (, etc).
Renaming in Eiffel: In Eiffel, no name conflicts are permitted between
inherited features.
There is a rename clause to remove them:
class C inherit
A rename x as x1, y as y1;
B rename x as x2, y as y2;
feature …
This inherit clause would be illegal without renaming.
Sometimes renaming can be used to give more appropriate names to
The TREE class defines a routine called insert_subtree.
For class WINDOW, this is not an appropriate name; add_subwindow
is much better.
Renaming allows the better name to be used.
Extending Specific Objects
There are two common methods for specifying objects: set based or
prototype based.
Within a set-based language:
 We describe a class that abstracts what we know to be true of
the object we are attempting to specify.
 We create instances of the object from the class to perform the
actual work.
 Just as classes describe objects, classes are described by
 Each object instance is unique and holds its own internal values.
Lecture 6
Object-Oriented Languages and Systems
 We can create more specific subclasses of a given class that
either modify the properties of the parent or add additional
 When an object receives a message it does not understand, it
consults its ancestors, asking each of them to handle the
Within a prototype-based language:
 We create an object that is a concrete representation of the object
we are attempting to specify, called a prototype.
 We copy, or clone, the prototype to obtain multiple instances of
the object.
 Each instance holds only what is unique to itself and a reference
to its prototype, called an extension.
 There is no true distinction between an instance and a prototype.
Any instance can be cloned, becoming the prototypical object for
its duplicates.
 When an object receives a message it does not understand, it
delegates the message to its prototypes, asking each of them to
grant it the ability to handle the message.
We can quickly see the philosophical differences between sets and
In a set-based object system, we define objects top down by specifying
the abstract and using that specification to create the specific.
For example, to describe a Cat object we collect properties that we believe
to be common to all Cats and create a Cat class. Then we use that class
to create unique Cats.
In a prototype object system, we define objects bottom up by specifying a
specific instance and modifying it as necessary to represent other
For example, to describe a Cat Escher we create an object that contains
her properties (female, black fur, annoying).
CSC/ECE 517 Lecture Notes
© 2010 Edward F. Gehringer
CSC 517
If we later discover a Cat Berlioz, we specify what we know about
Berlioz (male, orange fur) and assume that the remainder is identical to the
prototypical Cat Escher.
This system naturally evolves the assumption that all Cats are annoying.
Some researchers believe that prototype object systems make better
usage of the human ability to generalize from their experience with
concrete situations.
How does this apply to Ruby?
Ruby can act as a set-based language: Using include augments a class
definition, and hence adds functionality to all objects of a class.
But it can also act as a prototype-based language: There is a way to add
functionality to just specific instances of a class, by using the
Object#extend method.
Let us suppose that there is a mild-mannered Person class.
class Person
attr_reader :name, :age, :occupation
def initialize(name, age, occupation)
@name, @age, @occupation = name, age, occupation
def mild_mannered?
jimmy ='Jimmy Olsen', 21, 'cub reporter')
clark ='Clark Kent', 35, 'reporter')
# => true
# => true
Lecture 6
Object-Oriented Languages and Systems
But it happens that some Person objects are not as mild-mannered as
they might appear. Some of them have super powers.
module SuperPowers
def fly
def leap(what)
"Leaping #{what} in a single bound!"
def mild_mannered?
def superhero_name
If we use include to mix the SuperPowers module into the Person
class, it will give every person super powers. Some people are bound to
misuse such power. Instead, we'll use extend to give super powers only
to certain people:
puts clark.superhero_name
puts clark.mild_mannered?
puts jimmy.mild_mannered?
CSC/ECE 517 Lecture Notes
© 2010 Edward F. Gehringer
Random flashcards

30 Cards


17 Cards

African nomads

18 Cards

Create flashcards