Ruby for Perl programmers
All material Copyright Hal E. Fulton, 2002.Use freely but acknowledge the source.
What is Ruby?
âĒ A scripting language
âĒ An object-oriented language
âĒ A dynamic language
âĒ A Very High Level Language (VHLL)
âĒ A human-oriented language
âĒ An open-source project
Ruby is General-Purpose
âĒ One-liners at the command line
âĒ âQuick and dirtyâ scripts
âĒ System administration tasks
âĒ CGI scripts
âĒ GUI apps
âĒ Networking and distributed apps
A Brief History of RubyâĶ
âĒ 1993 Conceived by Yukihiro Matsumoto (âMatzâ)âĒ 1995 First release (Japan)âĒ 1999 Version 1.4 releasedâĒ 2000 Programming Ruby published;
comp.lang.ruby createdâĒ 2001 Version 1.6 released;
Ruby in a Nutshell publishedâĒ 2001 The Ruby Way publishedâĒ 2002 The Ruby Developerâs Guide published;
Teach Yourself Ruby in 21 Days published
Where does Ruby get its ideas?
âĒ Perl (regular expressions, some syntax)
âĒ SmallTalk (dynamic features, OOP)
âĒ CLU (iterators)
âĒ LISP (dynamic features)
âĒ C (operators, printf/sprintf, etc.)
âĒ Others
Rubyâs Design Principles
âĒ Principle of Least Surprise (POLS), aka Law of Least Astonishment (LOLA)
âĒ Human-oriented designâĒ Orthogonality, ânaturalness,â consistencyâĒ Flexibility and dynamismâĒ TMTOWTDI â âThereâs More Than One Way To
Do ItââĒ TABWTDI â âThereâs A Better Way To Do Itâ
Disclaimer:
I am not an
expert in Perl.
How is Ruby like Perl?
âĒ Scripting language
âĒ Interpreted, not compiled
âĒ Minimalist philosophy
âĒ Good at text processing
âĒ Understands regular expressions
âĒ Powerful and versatile
âĒ Many features borrowed directly from Perl
How is Ruby different from Perl?
âĒ Radically object-oriented from the start
âĒ Extremely dynamic
âĒ Built-in threads (non-native)
âĒ True closures (?)
âĒ Exception handling
âĒ Significant syntax differences
Some Specific SimilaritiesâĶ
âĒ Most operators and precedence
âĒ Most regular expression features
âĒ Many special variables: $! $& $+ $` $â$0-$9 $/ $\ $, $. $$ $? $_
âĒ Flexible quoting of strings
âĒ Multiple assignment
âĒ __END__, taint, and other features
Some Specific DifferencesâĶ
âĒ OOP by design: No bless, tie, tied, untieâĒ No scope declarations (my, local)âĒ Prefixes indicate scope, not typeâĒ True/false testing is differentâĒ Missing special variables: $| %SIG @_ $# $=
$~ $% $: $; $[âĒ No autovivificationâĒ Better #{} supportâĒ Better support for dynamic featuresâĒ No DESTROY, __PACKAGE__, __DATA__
Enough! Letâs see some code.
The Obligatory Hello, world! Program:
puts âHello, world!âor print âHello, world!\nâ
Some Basic Syntax
# This is a comment.
str1 = âSome string.â
str2 = âSome other string.â
# Multiple assignment:
a, b, c = 3, 5, 7
# Interpolating values in strings:
puts âThe sum is #{a+b+c}â
Some More Syntax
var = 123 # Local variable
$var = 234 # Global variable
PI = 3.14159 # Constant
# Note that variables donât have types!
var = âxyzâ # redefined
# Note that constants really arenât.
PI = 3.1416 # Gives a warning
Loops
for index in 1..9 do puts âIteration #{index}âend
1.upto(9) {|index| puts index }
index = 1while index < 9 do puts index index += 1end
loop { puts âInfinite loop.â }
Conditionsif x < 5 puts âyesâ else puts ânoâ endunless x < 5 puts ânoâ else puts âyesâ end
if x < 5 then puts âyesâ else puts ânoâ endunless x < 5 then puts ânoâ else puts âyesâ end
y = if x < 5 then 23 else 45 endy = unless x < 5 then 45 else 23 endy = x < 5 ? 23 : 45
Loop and condition modifier forms
puts âError!â if x < 5
puts âError!â unless x >= 5
do_something while notFinished
do_something until finished
Syntax Sugar and More
âĒ for loop calls default iterator eachâĒ x += y is shorthand for x = x + y
âĒ Most operators are methods
âĒ Aliases or synonyms are allowed
âĒ Flexible quoting and array literals
âĒ Method suffixes (? and !)
OOP in Ruby
âĒ Everything is an object â no wrappers as in JavaâĒ Standalone functions are really methods of Object
âĒ Code can be stored as objectsâĒ Singletons are permittedâĒ MetaclassesâĒ Data hiding: public, private, protectedâĒ Etc. âĶ
A Simple Class
class Person def initialize(name, number) @name, @phone = name, number end def inspect âName=#{@name} Phone=#{@phone}â endend
# Note that ânewâ invokes âinitializeâ
a1 = Person.new(âBill Gatesâ, â1-800-666-0666â)a2 = Person.new(âJennyâ, â867-5309â)
# p is like print or puts but invokes inspect
p a2 # Prints âName=Jenny Phone=867-5309â
Defining attributes
# Adding to previous exampleâĶ
class Person attr_reader :name # Defines a ânameâ method attr_accessor :phone # Defines âphoneâ and # âphone=â methodsend
person1 = a2.name # âJennyâphone_num = a2.phone # â867-5309âa2.phone = â512 867-5309â # Value replacedâĶ
p a2 # Prints âName=Jenny Phone=512 867-5309â
Class-level entitiesclass Foobar @@count = 0 # Class variable
def initialize(str) @data = str @@count += 1 end
def Foobar.population # Class method @@count endend
a = Foobar.new(âlionsâ)b = Foobar.new(âtigersâ)c = Foobar.new(âbearsâ)
puts Foobar.population # Prints 3
Inheritance
class Student < Person def initialize(name, number, id, major) @name, @phone = name, number @id, @major = id, major end def inspect super + âID=#@id Major=#@majorâ endend
x = Student.new(âMike Nicholasâ, â555-1234â, â000-13-5031â, âphysicsâ)
puts âyesâ if x.is_a? Student # yesputs âyesâ if x.is_a? Person # yes
Singleton objects
# Assume a âCelebrityâ class
newsguy = Celebrity.new(âDan Ratherâ)popstar = Celebrity.new(âBritney Spearsâ)superman = Celebrity.new(âSupermanâ)
class << superman def fly puts âLook, Iâm flying! Woo-hoo!â endend
superman.fly # Look, Iâm flying! Woo-hoo!newsguy.fly # Error!
Garbage Collection
âĒ No need for destructors
âĒ No memory deallocation, etc.
âĒ Currently âmark and sweepâ technique
âĒ Plans for generational GC
Using method_missing
class OSwrapper
def method_missing(method, *args) system(method.to_s, *args) end
end
sys = OSwrapper.newsys.date # Sat Apr 13 16:32:00âĶsys.du â-sâ, â/tmpâ # 166749 /tmp
Modules in Ruby
âĒ Used as mixins (substitute for multiple inheritance); features are âmixed inâ to an existing class
âĒ Used for interface polymorphism; existing class defines method(s) that will be called by the module methods (and vice versa)
âĒ Used for namespace management
Modules as mixins
âĒ An example of a âpureâ mixin is the special Kernel module
âĒ Because Kernel is mixed into Object, its methods are universally available (without receivers)
âĒ In most cases, module methods call methods of the class into which they are mixed (interface polymorphism)
Modules for Interface Polymorphism
âĒ Example is Enumerable, which implements methods such as min, max, find, and select
âĒ These methods depend on the existence of the default iterator each and a method called <=> (used for comparing).
Modules for Namespace Management
âĒ An example is the Math module
âĒ It has many useful mathematical functions, but these are basically independent of any class or object
âĒ Therefore Math is really never mixed into a class
âĒ A similar example is the Process module
Module example 1
class MyCollection include Enumerable # interface polymorphism #âĶ
def <=>(other) # Compare self to other somehowâĶ # Return â1, 0, or 1 end
def each # Iterate through the collection and do # a yield on each oneâĶ end
end
Module example 2
# Namespace management
def sin puts âPride, gluttony, bad commentingâĶâend
x = Math.sin(theta) # unrelated to âourâ sin
User = Process.uid # uid of this process
Module example 3# A user-defined module
module FlyingThing def fly puts âLook, Iâm flying!â endend
class Bat < Mammal include FlyingThing # A substitute for MI? #âĶend
x = Bat.newx.is_a? Bat # truex.is_a? Mammal # truex.is_a? FlyingThing # true
Programming Paradigms
âĒ Functional Programming (FP): This is possible in a limited way in Ruby (for Haskell fans, etc.)
âĒ Aspect-Oriented Programming (AOP): A library (AspectR) exists
âĒ Design-by-Contract (DBC) as in Eiffel: An add-on library exists
âĒ Design Patterns: The Singleton, Observer, Delegator, and others are already implemented; new ones are relatively easy to implement
âĒ Extreme Programming (XP): Rubyâs flexible and dynamic nature makes it a natural for XP practices
Cool Features in Ruby
âĒ Iterators (as in CLU)âĒ A rich class setâĒ Open classesâĒ ExceptionsâĒ Easy extension in RubyâĒ Operator overloadingâĒ Reflection or dynamic featuresâĒ ThreadsâĒ The Bignum classâĒ ContinuationsâĒ Easy extension in C
A Rich Set of Classes
âĒ ArrayâĒ ExceptionâĒ FileâĒ HashâĒ IOâĒ ProcâĒ RangeâĒ RegexpâĒ StringâĒ Struct
âĒ And othersâĶ
A Closer Look at Some ClassesâĶâĒ Array instance methods:
& * + - << <=> == === [ ] [ ]= | assoc at clear collect collect! compact compact! concat delete delete_at delete_if each each_index empty? eql? fill first flatten flatten! include? index indexes indices join last length map! nitems pack pop push rassoc reject! replace reverse reverse! reverse_each rindex shift size slice slice! sort sort! to_a to_ary to_s uniq uniq! unshift
âĒ IO class and instance methodsforeach new pipe popen readlines select << binmode clone close close_read close_write closed? each each_byte each_line eof eof? fcntl fileno flush getc gets ioctl isatty lineno lineno= pid pos pos= print printf putc puts read readchar readline readlines reopen rewind seek stat sync sync= sysread syswrite tell to_i to_io tty? ungetc write
âĒ String instance methods% * + << <=> == === =~ [ ] [ ]= ~ capitalize capitalize! center chomp chomp! chop chop! concat count crypt delete delete! downcase downcase! dump each each_byte each_line empty? gsub gsub! hash hex include? index intern length ljust next next! oct replace reverse reverse! rindex rjust scan size slice slice! split squeeze squeeze! strip strip! sub sub! succ succ! sum swapcase swapcase! to_f to_i to_s to_str tr tr! tr_s tr_s! unpack upcase upcase! upto
IteratorsâĒ An iterator is a method that can take a code block
as a parameter; control is passed back and forth as though they were coroutines.
âĒ The âstandardâ iterator is called each; this can also be called implicitly through a for statement. Example: list = [1, 2, 3, 4, 5] list.each do {|x| puts x if x > 3 } # EquivalentlyâĶ for x in list puts x if x > 3 end
âĒ Many classes have other predefined iterators such as foreach, each_byte, reverse_each, and so on.
Iterators That Donât Iterate
âĒ Sometimes the term âiteratorâ is not truly accurate; it may serve to enclose a block of code and isolate its context.The canonical example:
f = File.open(âsomefileâ) # Requires a close # ButâĶ
File.open(âsomefileâ) do |f| # Process the file as needed; it will be # closed automatically at end of block end
âĒ Other examples:
mutex.synchronize do # Perform thread-sensitive operation, then # release the mutex end
Dir.chdir(â/tmpâ) do # Temporarily change current directory end
Defining Your Own Iteratorsclass Array
# Iterate only over an arrayâs even-# numbered indicesâĶ
def every_other if block_given? self.each_with_index do |x,i| yield(x) if i % 2 == 0
end
else
raise âNo block specified!â
end
end
arr = [11,23,35,47,59,61,73]
arr.every_other {|obj| puts obj }
# Prints 11 35 59 73
arr2 = []
arr.every_other {|obj| arr2 << obj }
# arr2 is now [11,35,59,73]
Interesting Example #1
âĒ In this code fragment source.each { |line| process(line) }What is source? We canât tell!
âĒ It could be anything that has an iterator each and returns a line at a time.
âĒ It could be a string with embedded newlines.
âĒ It could be a file or other IO object.
âĒ In a sense, we care less about its real âtypeâ or âclassâ than we care about the methods it implements.
Interesting Example #2
âĒ The POP3 email library defines a POPMail class that has a method called all (to process the entire contents of the message). This method acts as an iterator if it is used with a block: msg.all {|line| puts line }
âĒ Otherwise it uses the append operator (<<) on whatever object was passed to it. Thus the object can be any object that responds to the << message:
arr = [] str = ââ out = $stdout msg.all(arr) # Produce an array of lines msg.all(str) # or a string with embedded newlines msg.all(out) # Write each line to stdout
Open Classes
This means that predefined classes can beadded to or modified at will.
Example:
class String def rot13 self.tr(âA-Ma-mN-Zn-zâ,âN-Zn-zA-Ma-mâ) end end
text = âElvis is dead.â secret = text.rot13 # Ryivf vf qrnq.
Exceptions
âĒ Help obviate the need for return codes
âĒ Help eliminate spaghetti âifâ logicâĒ Example forms:
raise raise âAny error message.â raise ArgumentError raise ArgumentError, âBad data.â raise ArgumentError.new(âBad data.â) raise ArgumentError, âBad dataâ, caller[0]
Catching Exceptions, Part 1
begin
x = Math.sqrt(y/z)
# âĶ
rescue ArgumentErrorputs âError taking square root.â
rescue ZeroDivisionError
puts âTried to divide by zero.â
end
Catching Exceptions, Part 2: The General Form
begin
# âĶ
rescue SomeExceptionType
# Can attempt recovery with âretryâ
rescue SomeOtherType
# Same thing, different exceptionâĶ
else
# All other exception types
ensure
# Code here is ALWAYS executed
end
Other Forms of rescueâĒ Inside a method definition:
def mymethod # CodeâĶ rescue # Handle any exceptionsâĶ end
âĒ Capturing in a variable begin #âĶ rescue SomeType => exc puts exc.message end
âĒ As a one-liner (modifier form) x = y/z rescue puts âDivision by zero!â
Easy Extension (in Ruby)
âĒ Often we can âplayâ with new features before adding them to the core language.
âĒ Matz doesnât have to change the interpreter.
âĒ We donât have to write a C extension.
Example: Smalltalk-like inject
# A Smalltalk-like âinjectâ method for arraysclass Array def inject(initial) result = initial self.each {|x| result = yield(x, result) } result endend
nums = [1,2,3,4]sum = arr.inject(0) {|x,acc| acc+x }prod = arr.inject(1) {|x,acc| acc*x }
words = [âredâ, âgreenâ, âblueâ]list = words.inject(âWords:â) {|x,acc| acc+â â+x }# list is now: âWords: red green blueâ
Example: Invert Array to Form Hash
class Array
def invert
h={}
self.each_with_index{|x,i| h[x]=i}
h
end
end
a = %w[red green blue]
h = a.invert
# {âblueâ=>2, âgreenâ=>1, âredâ=>0}
Example: Sorting by an Arbitrary Key
# Assume class Person with name, age, and height
class Array def sort_by(sym) self.sort {|x,y| x.send(sym) <=> y.send(sym)} end end
list = [Person.new("Hansel", 35, 69), Person.new("Gretel", 32, 64), Person.new("Ted", 36, 68), Person.new("Alice", 33, 63)]
# Sorted listsâĶs1 = people.sort_by(:name)s2 = people.sort_by(:age)s3 = people.sort_by(:height)
# s1 is [Alice 33 63, Gretel 32 64, Hansel 35 69, Ted 36 68] # s2 is [Gretel 32 64, Alice 33 63, Hansel 35 69, Ted 36 68] # s3 is [Alice 33 63, Gretel 32 64, Ted 36 68, Hansel 35 69]
Example: Existential Quantifiers
module Quantifier def any? self.each { |x| return true if yield x } false end
def all? self.each { |x| return false if not yield x } true end end
class Array include Quantifierend
list = [1, 2, 3, 4, 5] flag1 = list.any? {|x| x > 5 } # false flag2 = list.any? {|x| x >= 5 } # true flag3 = list.all? {|x| x <= 10 } # true flag4 = list.all? {|x| x % 2 == 0 } # false
Example: Selective File Deletion
def delete_if(dir) Dir.chdir(dir) do Dir.foreach(â.â) do |entry| next if File.directory?(entry) # Skip dirs File.unlink(entry) if yield(entry) end endend
# Delete files over 5K in sizedelete_if(â/tmpâ) {|f| File.size(f) > 5000 }
# Delete log and tmp files delete_if(â/tmpâ) {|f| f =~ /(log|tmp)$/i }
# Delete files over 24 hours olddelete_if(â/home/billâ) {|f| (Time.now-File.mtime(f))>86400 }
Other Possible Examples(of Extending Ruby in Ruby)
âĒ Autovivification of hashes and arrays
âĒ One-based arrays
âĒ Better multidimensional array syntax
âĒ Hash-like constructs that allow duplicates
âĒ Design-by-contract features
âĒ AOP features
âĒ âĶand much more
Dynamic Features of Ruby
âĒ Dynamic code evaluation (eval, instance_eval, class_eval, and module_eval)
âĒ Queries or reflection (finding a classâs methods and so on)
âĒ Hooks (modifying âbehind the scenesâ behavior)âĒ Callbacks (finding out when something happens,
e.g., when a variable is modified)
Operator Overloading
âĒ Most operators can be redefinedâĒ Example:
# Assume a class Length with feet and inchesclass Length #âĶ def +(other) f = self.feet + other.feet i = self.inches + other.inches if i > 12 then i -= 12; f += 1 end Length.new(f,i) endend
board1 = Length.new(5,10)board2 = Length.new(8,9)total = board1 + board2
p total # 14â 7â
Operator Overloading, ex. 2
class File
def <<(args) self.print(*args) self # Return the file object!
end
end
f = $stdout
f << âThe time is â << Time.now << â currently.\nâ
The Bignum class
âĒ A Fixnum will transparently âroll overâ into a Bignum â an arbitrary-precision integer
âĒ Example: a, b, c, d, e, f = 237, 365, 451, 666, 2001, 24601
product = a*b*c*d*e*f
puts product
# Output: 1279062690897238830
square = product**2
# Output: 1636001367245285523749542918059768900
cube = product**3
# Output:
# 2092548311100316744450709557388954690847073917906387000
Threads in Ruby
âĒ Ruby threads allow platform-independent multithreading of applications
âĒ As such, they are non-native (not pthreads, for example)
âĒ They do not take advantage of multiple processorsâĒ They can be started, stopped, synchronized, and
killed by means of a number of predefined methods
âĒ For more sophisticated synchronization, there are add-on libraries available such as monitor.rb
Thread Example 1# Thinking ahead during chessâĶresponses = {} # move-response hash humans_turn = true thinking_ahead = Thread.new(board) do predictMove do |m| responses[m] = myResponse(board,m) Thread.exit if humans_turn == false end end
human_move = getHumanMove(board) humans_turn = false # Stop the thread gracefully
# Now we can access âresponsesâ which may contain # the move the person just made...
Thread Example 2
# A simple threaded serverâĶ
require "socket"
PORT = 9999
server = TCPServer.new(PORT)
while (session = server.accept)
Thread.new(session) do |my_session|
#âĶ
my_session.close
end
end
ContinuationsContinuations are similar to setjmp and longjmp in C; we can do anon-local jump to another context. Contrived example:
def mymethod(cont) puts "Line 2" cont.call # "long jump" puts "Line 3" end
callcc do |cc| # a Kernel method puts "Line 1" mymethod(cc) puts "Line 4" end
puts âLine 5â # Here's the return point
# Output: # Line 1 # Line 2 # Line 5
Extending Ruby in C
âĒ Every Ruby object is accessed as a VALUE (either an immediate value or a pointer)
âĒ The only header file needed is ruby.hâĒ Various rb_* functions correspond to Ruby
operations (rb_ary_push, rb_define_var, and so on)
âĒ C datatype wrapping is accomplished with Data_Wrap_Struct, Data_Make_Struct, and Data_Make_Struct
âĒ Rumor has it, it is much easier to extend Ruby than Perl
Rubyâs Weaknesses
âĒ âNow, the bad newsâĶââĒ Some external add-ons (libraries, tools, utilities) of
the language are immature, incomplete, or missingâĒ Many things are still documented only in JapaneseâĒ There are some âissuesâ with Windows platformsâĒ The Ruby Application Archive (RAA) is not
nearly so comprehensive as the CPAN as yetâĒ User base is limited and expertise is rareâĒ Industry acceptance is limited as yetâĒ âAnd now, back to our regularly scheduled
programâĶâ
Libraries and UtilitiesâĒ The âone true repositoryâ is the Ruby Application
Archive (RAA) accessible from www.ruby-lang.org; this includesâĶ
âĒ HTTP, CGI, XML, and related librariesâĒ Network and distributed app librariesâĒ Development tools (editors, browsers, simple
IDEs, syntax highlighting files, debuggers, etc.)âĒ Database apps and interfacesâĒ GUI, graphics, sound, multimedia in generalâĒ MS Windows-related librariesâĒ Numerical and scientific librariesâĒ Documentation
Ruby and MS Windows
âĒ The WIN32API library gives access to the entire Windows API (should you be so bold)
âĒ The WIN32OLE library provides a Ruby interface for OLE automation
âĒ ActiveScriptRuby allows Ruby to interface (for example) with the WSH
âĒ RubyCOM is like a Ruby-to-COM bridge, allowing Ruby to reference VB objects and vice versa
Whoâs Into RubyâĶ
âĒ Dave Thomas and Andy Hunt (the âPragmatic Programmersâ); authors of The Pragmatic Programmer and Programming Ruby
âĒ Ron Jeffries and Chet Hendrickson, XP gurus and co-authors of Extreme Programming Installed
âĒ Dan Sugalski, developer for Parrot (the upcoming Perl/Python/Ruby runtime environment)
âĒ âĶand a growing user community on comp.lang.ruby!
Web Resources
âĒ www.ruby-lang.org The master site for all things Ruby-related, including the RAA
âĒ www.rubycentral.com Dave and Andyâs site; very useful info and links
âĒ www.rubygarden.org A Ruby wiki and a wealth of information
âĒ www.rubyhacker.com My personal site, still under development
Print Resources
âĒ Programming Ruby, Dave Thomas and Andy Hunt, Addison-Wesley, 2000.
âĒ Ruby in a Nutshell, Yukihiro Matsumoto, OâReilly, 2001.
âĒ The Ruby Way, Sams Publishing, Hal Fulton, 2001.
âĒ The Ruby Developerâs Guide, Syngress, Michael Neumann et al., 2002.
âĒ Teach Yourself Ruby in 21 Days, Sams Publishing, Mark Slagell, 2002.
The Ruby Way Table of Contents
1. Ruby in Review2. Simple Data Tasks3. Manipulating Structured Data4. External Data Manipulation5. OOP and Dynamicity in Ruby6. Graphical Interfaces for Ruby7. Ruby Threads8. Scripting and System Administration9. Network and Web Programming
A. From Perl to RubyB. From Python to RubyC. Tools and UtilitiesD. Resources on the Web (and Elsewhere)E. Whatâs New in Ruby 1.8
More than 300 sectionsMore than 500 code fragments and full listingsMore than 10,000 lines of codeAll significant code fragments available in an archive
exit(0) # Thatâs all, folks!