IntroductiontoRuby 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. Lecture 4 Object-Oriented Languages and Systems 1
Matz named it after a colleague s birthstone. 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 10 th 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 Interpreted Ruby Dynamically typed Purely object oriented Unbounded polymorphism Multiple inheritance through mixins Syntactic regular-expression support Syntactic support for hashes Java Compiled to byte code Statically typed Distinction between primitives and object types Inheritance and Interfaces Interfaces Not present (can do the same thing in Java by creating a pattern with java.util.regex, etc.) Hashes (HashMap, Hashtable) present in Collections; no special syntax CSC/ECE 517 Lecture Notes 2009 Edward F. Gehringer 2
nilis an object no nullpointer exceptions Everything is a message Possible to capture calls to non-existent methods using method_missing All classes are open to extension Dynamic evaluation of code using eval Reflection is easy Blocks are closures null means no reference to object (http://onestepback.org/articles/10things/9everythingisanobject4.html) Method invocations are compiled, not treated as messages at run time. Not possible Classes cannot be extended at run time Not possible easily Reflection is much more verbose (use methods defined in class Class) 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 rubyfilename.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! Lecture 4 Object-Oriented Languages and Systems 3
Functions are defined by the keyword def.the keyword end is to the closing parenthesis in other languages. defhello(i=3) i.timesdo 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 hello4. Both mean the same. Function arguments can be aggregated defhi(*names) puts"hello#{names.join(',')}" end hi('adam','ben','cathy') >>HelloAdam,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#constantsarenamedinuppercasebyconvention a=3 b=4 c=[1,2,3,4]#array CSC/ECE 517 Lecture Notes 2009 Edward F. Gehringer 4
Comments in Ruby start with # and run to the end of the line. 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=[]#emptyarray b=[1,2,3]#arrayoffixnums c=['hi','hello']#arrayofstrings Special syntax to create array of strings without the quotes: d=%w{hihello} Appending elements to an Array b<<4 >>[1,2,3,4] Array indexes start from zero. Lecture 4 Object-Oriented Languages and Systems 5
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. e=array.new e<<7 putse >>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"=>"WashingtonDC", "India"=>"NewDelhi", "China"=>"Beijing" } putscapitals["usa"] >>WashingtonDC numbers=hash['one',1,'two',2] putsnumbers['two'] >>2 h=hash.new h["a"]='b' putsh['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., CSC/ECE 517 Lecture Notes 2009 Edward F. Gehringer 6
they can be passed around as values, executed on demand by anyone who has the value, 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 defmymethod puts"inthemethod" yield#methodpassedcontroltoblockusingyield puts"backtothemethod" end mymethod{puts"insidetheblock"} This outputs -- >>Inthemethod >>Insidetheblock >>Backtothemethod [1,2,3].each{ i putsi} >>1 >>2 >>3 Blocks can also be parametrized Lecture 4 Object-Oriented Languages and Systems 7
defpara_block yield("dick") end para_block{ name puts"hello#{name}"} The output: >>HelloDick 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. classfixnum defrepeat foriin1..self.to_i yield end end end Now, call the method with a block: 3.times{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. #Classtogenerateadders CSC/ECE 517 Lecture Notes 2009 Edward F. Gehringer 8
classaddergen definitialize(n) @block=lambda{ a n+a} end defadd(a) @block.calla end end twoadder=addergen.new2 incrementer=addergen.new1 putsincrementer.add(4) putstwoadder.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. classfile deffile.open_and_process(*args) f=file.open(*args) yieldf f.close() end end File.open_and_process("testfile","r")do file whileline=file.gets putsline end Lecture 4 Object-Oriented Languages and Systems 9
end Thisislineone Thisislinetwo Thisislinethree Andsoon... 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. defpower(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)} putssquare.call(4) putscube.call(3) >>16 >>27 CSC/ECE 517 Lecture Notes 2009 Edward F. Gehringer 10