DOC

advertisement
Introduction to Ruby
Ruby (http://www.ruby-lang.org/en/ ) is a reflective, dynamic, objectoriented, single-pass interpreted programming language. It also has some
functional programming features such as blocks and closures.
Ruby has recently gained a lot of notice due to the rising popularity of Ruby
on Rails, a MVC based web development framework.
Features of Ruby –













Purely object oriented
Dynamically typed
Has blocks and closures
Iterators are built in
Provides multiple inheritance through mixins
Uses “duck typing,” i.e., unbounded polymorphism
Reflection and metaprogramming
Perl-compatible regular-expression support at syntax level
Built-in support for certain design patterns
Mark-and-sweep garbage collection
OS-independent threading
Easy interface to C modules
Portable—developed mostly on GNU/Linux, but works on many types
of UNIX, Mac OS X, Windows 95/98/Me/NT/2000/XP, DOS, BeOS,
OS/2, etc
Ruby is said to follow the “Principle of Least Surprise.”
Installation
Download and installation instructions can be found at http://www.rubylang.org/en/downloads/
A one-click installer is available for Windows.
History
Ruby was created by Yukihiro “Matz” Matsumoto in 1993.
It was first released in 1995.
Matz named it after a colleague’s birthstone.
Lecture 4
Object-Oriented Languages and Systems
1
Matz blended parts of his favorite languages (Perl, Smalltalk, Eiffel, Ada,
and Lisp) to form a new language that balanced functional programming
with imperative programming.
In 2006, Ruby achieved mass acceptance. With active user groups formed
in the world’s major cities and Ruby-related conferences filled to capacity. It
is the 10th most popular language in 2007 according to the TIOBE
programming language popularity index (http://www.tiobe.com/tpci.htm), a
position it has maintained.
Much of the growth is attributed to the popularity of software written in
Ruby, particularly the Ruby on Rails web framework
(http://www.rubyonrails.org/)
Comparison with Java
Ruby
Java
Interpreted
Compiled to byte code
Dynamically typed
Statically typed
Purely object oriented
Distinction between primitives and object
types
Unbounded polymorphism
Inheritance and Interfaces
Multiple inheritance through
mixins
Interfaces
Not present (can do the same thing in
Syntactic regular-expression
Java by creating a pattern with
support
java.util.regex, etc.)
Syntactic support for hashes
nil is an object  no nullpointer exceptions
CSC/ECE 517 Lecture Notes
Hashes (HashMap, Hashtable) present in
Collections; no special syntax
null means no reference to object
(http://onestepback.org/articles/10things/9everythingi
sanobject4.html)
© 2009 Edward F. Gehringer
2
Everything is a message
Method invocations are compiled, not
treated as messages at run time.
Possible to capture calls to
non-existent methods using
method_missing
Not possible
All classes are open to
extension
Classes cannot be extended at run time
Dynamic evaluation of code
using eval
Not possible easily
Reflection is easy
Reflection is much more verbose (use
methods defined in class Class)
Blocks are closures
Anonymous inner functions are closures
but less powerful
(This list is taken from http://jimweirich.tadalist.com/lists/public/14055)
Basics
Ruby code can be directly evaluated in the Interactive Ruby Browser. The
results are immediately returned in the IRB.
Ruby code is saved in files with the extension .rb and can be run by
invoking the command ‘ruby filename.rb’
The files can be made executable on UNIX systems (without typing ruby)
by adding the shebang line as the first line in the file
#!/usr/bin/ruby
The “Hello, world” program can be written as
puts “Hello, world!”
>>Hello, world!
Functions are defined by the keyword def. The keyword end is to the
closing parenthesis in other languages.
def hello(i = 3)
Lecture 4
Object-Oriented Languages and Systems
3
i.times do
puts "Hello"
end
end
hello
>>Hello
>>Hello
>>Hello
The arguments to a function can be initialized.
Parentheses in a function call are optional
So we can write hello(4) or hello 4. Both mean the same.
Function arguments can be aggregated –
def hi(*names)
puts "Hello #{names.join(', ')}"
end
hi('Adam', 'Ben', 'Cathy')
>>Hello Adam, Ben, Cathy
The last statement in the function is the return value. There is no need for
an explicit return. And all statements return a value.
Dynamic Typing
Variables in Ruby are not given a type. Their “type” depends upon the
value assigned to them.
PI = 3.14159 #constants are named in uppercase by convention
a = 3
b = 4
c = [1,2,3,4] #Array
Comments in Ruby start with # and run to the end of the line.
CSC/ECE 517 Lecture Notes
© 2009 Edward F. Gehringer
4
Dynamic typing makes many features possible, such as unbounded
polymorphism and blocks, which are not available in statically typed
languages such as Java and C++.
Everything is an object
Ruby is purely object-oriented.
Everything in Ruby is an object. Even numbers and strings are objects.
1.succ
>>2
"hi".upcase
>>HI
[3,1,4,2].sort
>>[1,2,3,4]
“Hi”.class
>>String
-------------------------------------------------Arrays
An array in Ruby is an ordered list of elements.
Simple examples illustrate the use of arrays:
a = [] # empty array
b = [1, 2, 3] # array of FixNums
c = ['Hi', 'Hello'] #Array of strings
Special syntax to create array of strings without the quotes:
d = %w{Hi Hello}
Appending elements to an Array –
b << 4
>>[1, 2, 3, 4]
Array indexes start from zero.
Negative indexes count backward. So b[-1] refers to the last element of b.
Arrays can also be created using the new keyword. new is used to create
objects of any type. More about new will follow later.
Lecture 4
Object-Oriented Languages and Systems
5
e = Array.new
e << 7
puts e
>> 7
Hashes
Ruby has syntax support for hashes. What’s a “hash”? Any ideas? An
“array” that can be indexed by arbitrary keys.
Hashes can be created in three ways.
Using the keyword new, or special syntax using Hash[] or {}
capitals = {
"USA" => "Washington DC",
"India" => "New Delhi",
"China" => "Beijing"
}
puts capitals["USA"]
>>Washington DC
numbers = Hash['one', 1, 'two', 2]
puts numbers['two']
>>2
h = Hash.new
h["a"] = 'b'
puts h['a']
>>b
Blocks
Blocks are anonymous regions of code that can be associated with a
method call.
In Ruby, essentially blocks are closures, i.e.,
 they can be passed around as values,
 executed on demand by “anyone” who has the value,
CSC/ECE 517 Lecture Notes
© 2009 Edward F. Gehringer
6
 at which time, they can refer to variables accessible in the context
where they were created.
Blocks can be stored in variables and invoked when required.
This powerful feature allows one to modify the behavior of a method at run
time, and hence is an alternative to polymorphism.
Similar functionality in other languages:





C's function pointers
C++'s function objects
Python's lambdas and list comprehensions
Perl's anonymous functions
Java's anonymous inner classes
These features live mostly in the corners of those languages, shunned by
novice programmers. But closures are basic to Ruby.
Here is a simple example –
def mymethod
puts "In the method"
yield #Method passed control to block using yield
puts "Back to the method"
end
mymethod { puts "Inside the block" }
This outputs --
>>In the method
>>Inside the block
>>Back to the method
[1,2,3].each { |i| puts i}
>>1
>>2
>>3
Blocks can also be parametrized –
def para_block
yield("Dick")
end
Lecture 4
Object-Oriented Languages and Systems
7
para_block {|name| puts "Hello #{name}"}
The output:
>>Hello Dick
Iterators
An iterator is an object that is used to traverse over a collection such as an
array.
In Ruby, the iterator is internal: it is a method of the collection which can
call a block of code.
In other programming languages the iterator is an external object that
maintains its state and is used to iterate over the collection.
Using blocks, iterators can be implemented more concisely and clearly.
class Fixnum
def repeat
for i in 1..self.to_i
yield
end
end
end
Now, call the method with a block:
3.repeat {puts "Hello"}
>>Hello
>>Hello
>>Hello
Closures
A closure is a block of code that “closes over”; that is, can access the
lexical environment of its definition.
# Class to generate adders
class AdderGen
def initialize(n)
@block = lambda {|a| n + a}
end
CSC/ECE 517 Lecture Notes
© 2009 Edward F. Gehringer
8
def add(a)
@block.call a
end
end
twoAdder = AdderGen.new 2
incrementer = AdderGen.new 1
puts incrementer.add(4)
puts twoAdder.add(6)
>>5
>>8
Here the instance variable @block is a closure.
 It remembers the parameter with which the initialize method was
called even after the initialize method exits.
 This value is used when the block is called in the add method.
 lambda comes from lambda calculus in functional programming. It is
used to generate new functions dynamically.
Uses of closures:
Write a program that prints out the contents of a file line by line, and
insures that the file is always closed. Let’s add to the built-in file class.
class File
def File.open_and_process(*args)
f = File.open(*args)
yield f
f.close()
end
end
File.open_and_process("testfile", "r") do |file|
while line = file.gets
puts line
end
end
This is line one
This is line two
Lecture 4
Object-Oriented Languages and Systems
9
This is line three
And so on...
Currying
Currying means creating a new function out of an existing function by fixing
the value of some of its input parameters.
A simple example illustrates the concept. Consider a function which raises
its first parameter to the power specified by the second parameter.
def power(x,y)
val = 1
1.upto(y) {|a| val = val * x}
val
end
Now, one might want to define a function to square or cube a number.
Instead of defining a new method, the existing one can be curried. In
Ruby, we can curry a method using lambda. This is how the square and
cube functions are created:
square = lambda {|x| power(x,2)}
cube = lambda {|x| power(x,3)}
puts square.call(4)
puts cube.call(3)
>>16
>>27
CSC/ECE 517 Lecture Notes
© 2009 Edward F. Gehringer
10
Download