Survey
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
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!