1 / 32

A quick Ruby Tutorial, Part 4

A quick Ruby Tutorial, Part 4. COMP313 Source: Programming Ruby, The Pragmatic Programmers’ Guide by Dave Thomas, Chad Fowler, and Andy Hunt. 2 forms of assignment. hard coded to variables and constants: instrument = "piano" MIDDLE_A = 440

sibyl
Télécharger la présentation

A quick Ruby Tutorial, Part 4

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. A quick Ruby Tutorial, Part 4 COMP313 Source: Programming Ruby, The Pragmatic Programmers’ Guide by Dave Thomas, Chad Fowler, and Andy Hunt

  2. 2 forms of assignment hard coded to variables and constants: instrument = "piano" MIDDLE_A = 440 user defined for object attributes and other element references: song.duration = 234 instrument["ano"] = "ccolo"

  3. problems class BrokenAmplifier attr_accessor :left_channel, :right_channel def volume=(vol) left_channel = self.right_channel = vol end end ba = BrokenAmplifier.new ba.left_channel = ba.right_channel = 99 ba.volume = 5 ba.left_channel → 99 ba.right_channel → 5

  4. Parallel assignment a = [1, 2, 3, 4] b, c = a → b == 1, c == 2 b, *c = a → b == 1, c == [2, 3, 4] b, c = 99, a → b == 99, c == [1, 2, 3, 4] b, *c = 99, a → b == 99, c == [[1, 2, 3, 4]] b, c = 99, *a → b == 99, c == 1 b, *c = 99, *ab == 99, c == [1, 2, 3, 4]

  5. Nested assignment b, (c, d), e = 1,2,3,4 → b == 1, c == 2, d == nil, e == 3 b, (c, d), e = [1,2,3,4] → b == 1, c == 2, d == nil, e == 3 b, (c, d), e = 1,[2,3],4 → b == 1, c == 2, d == 3, e == 4 b, (c, d), e = 1,[2,3,4],5 → b == 1, c == 2, d == 3, e == 5 b, (c,*d), e = 1,[2,3,4],5 → b == 1, c == 2, d == [3, 4], e == 5

  6. Overwriting operators like + class Bowdlerize def initialize(string) @value = string.gsub(/[aeiou]/, '*') end def +(other) Bowdlerize.new(self.to_s + other.to_s) end def to_s @value end end a = Bowdlerize.new("damn ") → d*mn a += "shame" → d*mn sh*m*

  7. defined? operator defined? 1 → "expression" defined? dummy → nil defined? printf → "method" defined? String → "constant" defined? $_ → "global-variable" defined? Math::PI → "constant" defined? a = 1 → "assignment" defined? 42.abs → "method” defined? yield → ”yield” or nil

  8. Case expressions leap = case when year % 400 == 0: true when year % 100 == 0: false else year % 4 == 0 end case input_line when "debug" dump_debug_info dump_symbols when /p\s+(\w+)/ dump_variable($1) when "quit", "exit" exit else print "Illegal command: #{input_line}" end

  9. another case examples kind = case year when 1850..1889 then "Blues" when 1890..1909 then "Ragtime" when 1910..1929 then "New Orleans Jazz" when 1930..1939 then "Swing" when 1940..1950 then "Bebop" else "Jazz" end

  10. case as instanceof test case shape when Square, Rectangle # ... when Circle # ... when Triangle # ... else # ... end

  11. For .. in .. looping based on each => works for all classes defining each class Periods def each yield "Classical" yield "Jazz" yield "Rock" end end periods = Periods.new for genre in periods print genre, " " end produces:Classical Jazz Rock

  12. break, redo, next, retry while line = gets next if line =~ /^\s*#/ # skip comments break if line =~ /^END/ # stop at end # substitute stuff in backticks and try again redo if line.gsub!(/`(.*?)`/) { eval($1) } # process line ... end for i in 1..100 print "Now at #{i}. Restart? " retry if gets =~ /^y/ end

  13. Loops, blocks, and scope of variables while/until/for do NOT create a new scope (!= java), but explicit code blocks can: [ 1, 2, 3 ].each { |x| y = x + 1 } [ x, y ] --> error, but x=nil y=nil [ 1, 2, 3 ].each { |x| y = x + 1 } [ x, y ] --> [3,4]

  14. Exceptions op_file = File.open(opfile_name, "w") begin # Exceptions raised by this code will # be caught by the following rescue clause while data = socket.read(512) op_file.write(data) end rescue SystemCallError $stderr.print "IO failed: " + $! op_file.close File.delete(opfile_name) raise end

  15. more on Exceptions begin eval string rescue SyntaxError, NameError => boom print "String doesn't compile: " + boom rescue StandardError => bang print "Error running script: " + bang end empty rescue catches StandardError instances, may also use expression returning an Exception class

  16. ensure (cf. Java’s finally) f = File.open("testfile") begin # .. process rescue # .. handle error ensure f.close unless f.nil? end

  17. retry @esmtp = true begin # First try an extended login. If it fails because the # server doesn't support it, fall back to a normal login if @esmtp then @command.ehlo(helodom) else @command.helo(helodom) end rescue ProtocolError if @esmtp then @esmtp = false retry else raise end end

  18. Raising exceptions raise raise "bad mp3 encoding" raise InterfaceException, "Keyboard failure", caller raise "Missing name" if name.nil? if i >= names.size raise IndexError, "#{i} >= size (#{names.size})" end raise ArgumentError, "Name too big", caller[1..-1]

  19. Retry example class RetryException < RuntimeError attr :ok_to_retry def initialize(ok_to_retry) @ok_to_retry = ok_to_retry end end def read_data(socket) data = socket.read(512) raise RetryException.new(true), "transient read error” if data.nil? # .. normal processing end

  20. Retry example cont. begin stuff = read_data(socket) # .. process stuff rescue RetryException => detail retry if detail.ok_to_retry raise end

  21. Modules • provide namespace against clashes • implement mixin facility module Trig PI = 3.141592654 def Trig.sin(x) # .. end end require 'trig' y = Trig.sin(Trig::PI/4)

  22. Module mixin • Modules are not classes, cannot have instances module Debug def who_am_i? "#{self.class.name} (\##{self.object_id}): #{self.to_s}" end end class Phonograph include Debug # ... end ph = Phonograph.new("West End Blues") ph.who_am_i? → "Phonograph (#937328): West End Blues"

  23. Mixin interaction class Song include Comparable def initialize(duration) @duration = duration end def <=>(other) self.duration <=> other.duration end end song1, song2 = Song.new(225), Song.new(260) song1 <=> song2 → -1 song1 < song2 → true song1 == song1 → true song1 > song2 → false

  24. Resolving name clashes methods: immediate class, then local mixins last one first, then superclass, it’s mixins, etc … variable before method name: a = 1 def a 2 end a -> 1 a() -> 2

  25. 2 ways of IO utility methods: gets, open, print, printf, puts, putc, readline, readlines, test proper classes: IO, File, BasicSocket, … endl = ”\n" STDOUT << 99 << " red balloons" << endl

  26. File IO examples File.open("testfile") do |file| file.each_byte {|ch| putc ch; print "." } end IO.foreach("testfile") {|line| puts line } # read whole file into one string str = IO.read("testfile") str.length → 66 str[0, 30] → "This is line one\nThis is line " # read all lines into an array arr = IO.readlines("testfile") arr.length → 4 arr[0] → "This is line one\n"

  27. StringIO require 'stringio' ip = StringIO.new("now is\nthe time\nto learn\nRuby!") op = StringIO.new("", "w") ip.each_line do |line| op.puts line.reverse end op.string →”\nsi won\n\nemit eht\n\nnrael ot\n!ybuR\n"

  28. Profiler require 'profile' count = 0 words = File.open("/usr/share/dict/words") while word = words.gets word = word.chomp! if word.length == 12 count += 1 end end puts "#{count} twelve-character words”

  29. Profiler output % cumulative self self total time seconds seconds calls ms/call ms/call name 7.70 8.60 8.60 234938 0.04 0.04 IO#gets 7.65 17.14 8.54 234937 0.04 0.04 Fixnum#== 7.43 25.43 8.29 234937 0.04 0.04 String#length 7.18 33.45 8.02 234937 0.03 0.03 String#chomp! 0.70 34.23 0.78 20460 0.04 0.04 Fixnum#+ 0.00 34.23 0.00 1 0.00 0.00 Fixnum#to_s 0.00 34.23 0.00 1 0.00 0.00 Kernel.puts 0.00 34.23 0.00 1 0.00 0.00 File#initialize 0.00 34.23 0.00 2 0.00 0.00 Kernel.respond_to? 0.00 34.23 0.00 1 0.00 0.00 File#open 0.00 34.23 0.00 2 0.00 0.00 IO#write 0.00 34.23 0.00 1 0.00 0.00 Profiler__.start_profile 0.00 34.23 0.00 1 0.00 111640.00 #toplevel

  30. Faster solution require 'profile' words = File.read("/usr/share/dict/words") count = words.scan(/^.........…\n/).size puts "#{count} twelve-character words" 20460 twelve-character words % cumulative self self total time seconds seconds calls ms/call ms/call name 95.24 0.20 0.20 1 200.00 200.00 String#scan 4.76 0.21 0.01 1 10.00 10.00 File#read 0.00 0.21 0.00 2 0.00 0.00 IO#write

  31. Duck typing If it walks and talks like a duck, treat it like one (laissez-faire) def append_song(result, song) result << song.title << " (" << song.artist << ")" end ###### when checking, check for capability instead of class: def append_song(result, song) unless result.respond_to?(:<<) fail TypeError.new("'result' needs `<<' capability") end unless song.respond_to?(:artist) && song.respond_to?(:title) fail TypeError.new("'song' needs 'artist' and 'title'") end result << song.title << " (" << song.artist << ")” end

  32. other ruby stuff • threads and processes • GUI: Tk library • JavaDoc like Rdoc • Package management: RubyGems • Web stuff (including Ruby on Rails) • JRuby • Extending using host language (C/Java)

More Related