Transcript Document

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:
or
puts “Hello, world!”
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
$var = 234
PI = 3.14159
# Local variable
# Global variable
# 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 = 1
while index < 9 do
puts index
index += 1
end
loop { puts “Infinite loop.” }
Conditions
if x <
puts
else
puts
end
unless
puts
else
puts
end
5
“yes”
“no”
x < 5
“no”
“yes”
if x < 5 then puts “yes” else puts “no” end
unless x < 5 then puts “no” else puts “yes” end
y = if x < 5 then 23 else 45 end
y = unless x < 5 then 45 else 23 end
y = 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}”
end
end
# 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
attr_accessor :phone
# Defines a “name” method
# Defines “phone” and
# “phone=“ methods
end
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 entities
class Foobar
@@count = 0
# Class variable
def initialize(str)
@data = str
@@count += 1
end
def Foobar.population
@@count
end
end
# Class method
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”
end
end
x = Student.new(“Mike Nicholas”, “555-1234”,
“000-13-5031”, “physics”)
puts “yes” if x.is_a? Student
puts “yes” if x.is_a? Person
# yes
# 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!”
end
end
superman.fly
newsguy.fly
# Look, I’m flying! Woo-hoo!
# 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.new
sys.date
sys.du “-s”, “/tmp”
# Sat Apr 13 16:32:00…
# 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!”
end
end
class Bat < Mammal
include FlyingThing
#…
end
x = Bat.new
x.is_a? Bat
x.is_a? Mammal
x.is_a? FlyingThing
# A substitute for MI?
# true
# true
# 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 methods
foreach 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 Iterators
class 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 be
added 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
raise
raise
raise
raise
“Any error message.”
ArgumentError
ArgumentError, “Bad data.”
ArgumentError.new(“Bad data.”)
ArgumentError, “Bad data”, caller[0]
Catching Exceptions, Part 1
begin
x = Math.sqrt(y/z)
# …
rescue ArgumentError
puts “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 arrays
class Array
def inject(initial)
result = initial
self.each {|x| result = yield(x, result) }
result
end
end
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 Quantifier
end
list = [1, 2, 3, 4, 5]
flag1 = list.any? {|x|
flag2 = list.any? {|x|
flag3 = list.all? {|x|
flag4 = list.all? {|x|
x
x
x
x
> 5 }
>= 5 }
<= 10 }
% 2 == 0 }
#
#
#
#
false
true
true
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
end
end
# Delete files over 5K in size
delete_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 old
delete_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 inches
class 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)
end
end
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
Continuations
Continuations are similar to setjmp and longjmp in C; we can do a
non-local jump to another context. Contrived example:
def mymethod(cont)
puts "Line 2"
cont.call
# "long jump"
puts "Line 3"
end
callcc do |cc|
puts "Line 1"
mymethod(cc)
puts "Line 4"
end
# a Kernel method
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.rubylang.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 coauthors 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.
2.
3.
4.
5.
6.
7.
8.
9.
Ruby in Review
Simple Data Tasks
Manipulating Structured Data
External Data Manipulation
OOP and Dynamicity in Ruby
Graphical Interfaces for Ruby
Ruby Threads
Scripting and System Administration
Network and Web Programming
A.
B.
C.
D.
E.
From Perl to Ruby
From Python to Ruby
Tools and Utilities
Resources on the Web (and Elsewhere)
What’s New in Ruby 1.8
More than 300 sections
More than 500 code fragments and full listings
More than 10,000 lines of code
All significant code fragments available in an archive
exit(0)
# That’s all, folks!