The Ruby Programming Language by David Flanagan, Yukihiro Matsumoto This is a list of the corrections made in the 4/08 reprint. Here's a key to the markup: [page-number]: serious technical mistake {page-number}: minor technical mistake : important language/formatting problem (page-number): language change or minor formatting problem ?page-number?: reader question or request for clarification This page was updated April 15, 2008. Corrected errors: ---------------------------------------------------------------------- (5): Change: "%d %s" % [3, "rubies"] # => "3 Rubies": Python-style, printf formatting To: "%d %s" % [3, "rubies"] # => "3 rubies": Python-style, printf formatting ---------------------------------------------------------------------- (11) Bottom of the page: Change "there is one alternative implementation relased at a 1.0 level (JRuby)" to "there is one alternative implementation (JRuby) released" ---------------------------------------------------------------------- (12) Top of page: Change "JRuby 1.0" to "JRuby 1.1" ---------------------------------------------------------------------- (42) Cut "(standard library)" from the figure in 3 boxes ---------------------------------------------------------------------- <43> top Change the first paragraph on the page to: The Complex class represents complex numbers, of course. BigDecimal represents real numbers with arbitrary precision, using a decimal representation rather than a binary representation. And Rational represents rational numbers: one integer divided by another. In Ruby 1.8 these classes are in the standard library. In Ruby 1.9, Complex and Rational are built-in. ---------------------------------------------------------------------- <44> middle of the page Change this: The division operator depends on the class of the operands. If both operands are integers, then the operation performed is truncating-integer division. If either operand is a Float, then floating-point division is performed: x = 5/2 # result is 2 y = 5.0/2 # result is 2.5 z = 5/2.0 # result is 2.5 To: The division operator depends on the class of the operands: if both operands are integers, then truncating integer division is performed. If either operand is a Float, then floating-point division is performed. There are also three division methods: div performs integer division, fdiv performs floating-point division, and quo returns a Rational when possible, and otherwise returns a Float (this requires the 'rational' module in Ruby 1.8). [5/2, 5.0/2, 5/2.0] # => [2, 2.5, 2.5] [5.0.div(2), 5.0.fdiv(2), 5.quo(2)] # => [2, 2.5, Rational(5,2)] ---------------------------------------------------------------------- <44> Before the box Change this: The modulo (%) operator computes remainder-after-integer division: x = 5%2 # result is 1 The % operator can also be used with Float operands, although this is less common: x = 1.5%0.4 # result is 0.3 To this: The modulo (%) operator (and the synonymous modulo method) compute the remainder after integer division. They can also be used with Float and Rational operands. The divmod returns both quotient and modulo: x = 5%2 # => 1: quotient is 2, with 1 left over q,r = 10.divmod 3 # => [3,1]: quotient is 3, remainder is 1 ---------------------------------------------------------------------- (44-45) The text on these pages has been shorted in several places without changing its meaning, and the box about "Division, Modulo and Negative Numbers" has been moved from the middle of 3.1.3 to the end of the section. These are non-technical changes required to fit the previous technical changes on the page. ---------------------------------------------------------------------- <59> Section 3.2.6.1 Change the second paragraph and the block of code that follows it to read: If a string contains multibyte characters, then the number of bytes does not correspond to the number of characters. In Ruby 1.9, the length and size methods return the number of characters in a string, and the new bytesize method returns the number of bytes. The [] and []= operators allow you to query and set the characters of a string, and the new methods getbyte and setbyte allow you to query and set individual bytes (though you should not often need to do this): # -*- coding: utf-8 -*- # Specify Unicode UTF-8 characters # This is a string literal containing a multibyte multiplication character s = "2√ó2=4" # The string contains 6 bytes which encode 5 characters s.bytesize # => 6 s.bytesize.times {|i| print s.getbyte(i), " "} # Prints "50 195 151 50 61 52" s.length # => 5 s.length.times { |i| print s[i], " "} # Prints "2 √ó 2 = 4" s.setbyte(5, s.getbyte(5)+1); # s is now "2√ó2=5" ---------------------------------------------------------------------- <60> top of page Change "When you use the [] operator to access" to "When you use the [] operator, as we did in the code above, to access". ---------------------------------------------------------------------- <60> Code in the middle of the page: Change this line: t.encoding # => To: t.encoding # => ---------------------------------------------------------------------- <60> In 2nd paragraph of the box Delete this text: Because the "BINARY" encoding really means "unencoded bytes," you can also specify this encoding by passing nil instead of an encoding name or Encoding object. Add this sentence at the end of the 3rd paragraph: The encoding name "ASCII" is an alias for "US-ASCII". ---------------------------------------------------------------------- <62> Just before 3.2.6.2. Change "raises an exception;" to "raises an exception:" Change the two lines of code that follow to: "\u20AC".encode("iso-8859-1") # No euro sign in Latin-1, so raise exception Then add this new paragraph: encode and encode! accept a hash of transcoding options as their final argument. At the time of this writing, the only defined option name is :invalid, and the only defined value for that key is :ignore. "ri String.encode" will give details when more options are implemented. ---------------------------------------------------------------------- <63> In the first paragraph, delete: but these are dynamically loaded as needed rather than built-in, and constants do not exist for these encodings until they are used. Change the 4th paragraph on the page from: If you want a list of available encodings, call Encoding.list, which returns an array of Encoding objects. The Encoding.list method only lists built-in encodings and any encodings that have already been dynamically loaded. Calling Encoding.find can cause new encodings to be loaded. These new encodings will be listed by subsequent calls to Encoding.list. To: Encoding.list returns an array of all available encoding objects. Encoding.name_list returns an array of the names (as strings) of all available encodings. Many encodings have more than one name in common use, and Encoding.aliases returns a hash that maps encoding aliases to the official encoding names for which they are synonyms. The array returned by Encoding.name_list includes the aliases in the Encoding.aliases hash. In the 6th paragraph, cut: will also accept nil as a synonym for Encoding::BINARY (i.e., unencoded bytes). Most methods In the same paragraph change "an encoding name" to "a case-insensitive encoding name" Finally, delete the entire last paragraph of Section 3.2.6.2. ---------------------------------------------------------------------- {65} Change this line: a[-9] = 81 # Error: can't assign before the start of an array To this: a[-10] = 100 # Error: can't assign before the start of an array ---------------------------------------------------------------------- <66> Change this sentence (in the middle of the page): Use << to append elements to the end of an existing array: So that it reads: Use << to append an element to the end of an existing array, and use concat to append the elements of an array: Then, at the end of the code block that follows, add this line: a.concat [7,8] # a is [1, 2, 3, [4, 5, 6], 7, 8] Line up the # mark with the ones above it, of course. Also, move the paragraph that begins "The - operator subtracts" and the one line of code that follows it, so that it comes after this discussion of << and concat (and before the paragraph that begins "Like the String class..." ---------------------------------------------------------------------- (75) 2nd code block; Change: o.class == String # true if is o a String To: o.class == String # true if o is a String ---------------------------------------------------------------------- <80> 1st para of 3.8.7.1 Add this sentence to the end of the paragraph: Ruby 1.9 adds to_c and to_r methods to convert to Complex and Rational. ---------------------------------------------------------------------- (83) 3rd line: Change "one internal state" to "internal state" ---------------------------------------------------------------------- [99] 1st full paragraph. Change this paragraph: In Ruby 1.8, array, range, and hash rvalues can be splatted. In Ruby 1.9, array, range, and enumerator (see 5.3.4) rvalues can be splatted. If you apply a splat to a value of some other class, that value simply expands to itself. You can define your own splattable classes. In Ruby 1.8, define a to_ary method that returns an array of values. In Ruby 1.9, name the method to_splat instead. Please replace it with: Array, range and hash rvalues can be splatted. In general, any rvalue that defines a to_a method can be prefixed with a splat. Any Enumerable object, including enumerators (see 5.3.4) can be splatted, for example. When a splat is applied to an object that does not define a to_a method, no expansion is performed and the splat evaluates to the object itself. ---------------------------------------------------------------------- (127) last line of section 5.2 Change "documented in later" to "documented later" ---------------------------------------------------------------------- <130> Iterators box Change "(in Ruby 1.9)" to "(in Ruby 1.9 and 1.8.7)" ---------------------------------------------------------------------- <135> 1st paragraph of 5.3.4 Change the 3rd and 4th sentences of this paragraph to read: In Ruby 1.9 (and also 1.8.7), enumerators are built-in and no require is necessary. (As we'll see later, the built-in enumerators have substantially more functionality than that provided by the enumerator library.) ---------------------------------------------------------------------- <136> 2nd paragraph: Change "In Ruby 1.9" to "In Ruby 1.9 (and 1.8.7)" ---------------------------------------------------------------------- <136> footnote: Remove the footnote on this page ---------------------------------------------------------------------- <137> Section 5.3.5 In the 2nd sentence of this section, change "In Ruby 1.9" to "In Ruby 1.9 (and 1.8.7, though the implementation is not as efficient)" ---------------------------------------------------------------------- (139) Change the last word before Example 5-1 from "enumerators" to "Ruby 1.9". ---------------------------------------------------------------------- {142} 2nd paragraph; Change this line: words.sort! {|x,y| y <=> x } To: words.sort! {|x,y| y.length <=> x.length} ---------------------------------------------------------------------- (144) 2nd paragraph from bottom Change "we might expect be able" to "we might expect to be able" ---------------------------------------------------------------------- <159> 2nd from last paragraph; Change "Expression class" to "Exception class" ---------------------------------------------------------------------- (161) 3rd line Change: puts risky # Try to invoke print the return value. To puts risky # Try to invoke and print the return value. ---------------------------------------------------------------------- (186) 1st paragraph: Change "and can be referred to instance variables" to "and can refer to instance variables" ---------------------------------------------------------------------- (188) 3rd paragraph of Section 6.4.3; Clarify this sentence: Suppose we have a method that is declared with o ordinary parameters, d parameters with default values, and one array parameter prefixed with *. By adding this at the end: , and that these parameters appear in some arbitrary order. ---------------------------------------------------------------------- (192) sect. 6.5.1, 1st line: Change "crfate" to "create" ---------------------------------------------------------------------- <196> Right before 6.5.3 Add this new paragraph and code at the end of section 6.5.2 Ruby 1.9 adds a curry method to the Proc class. Calling this method returns a curried version of a proc or lambda. When a curried proc or lambda is invoked with insufficient arguments it returns a new Proc object (also curried) with the given arguments applied. Currying is a common technique in the functional programming paradigm: product = ->(x,y){ x*y } # Define a lambda triple = product.curry[3] # Curry it, then specify the first argument [triple[10],triple[20]] # => [30,60]: lambda {|w,x,y,z| w+x+y+z}.curry[1][2,3][4] # => 10 ---------------------------------------------------------------------- (202) last sentence before 6.6.2: Change "and use a loop variables" to "and use loop variables". ---------------------------------------------------------------------- <207> last paragraph: Insert the following right before "For example:" This is similar to, but not quite the same as currying with the Proc.curry method. ---------------------------------------------------------------------- (218) Last paragraph: Change "invoke these method" to "invoke these methods". Also, insert the following sentence before "Thus": (The infrequently-used attr_writer creates setter methods only.) ---------------------------------------------------------------------- {222} 4th line from the bottom: Change: elsif # If o is not a Point To: else # If o is not a Point ---------------------------------------------------------------------- {223} 2nd line from bottom: Change "elsif" to "else" ---------------------------------------------------------------------- (233) 2nd paragraph, 3rd line: Change "refers to class" to "refers to the class" ---------------------------------------------------------------------- <235> Box about BasicObject Add a new sentence at the end of this box: Methods such as ==, equal?, instance_eval, and __send__, are normally considered to be Object methods even though they are actually defined by BasicObject. ---------------------------------------------------------------------- {251} 6th line Change "instanceof?" to "instance_of?" ---------------------------------------------------------------------- {251} 4th line of 7.5.3: Change: include 'Math' # The Math namespace can be included To: include Math # The Math namespace can be included ---------------------------------------------------------------------- <253> Top of the page Insert a new paragraph right before "Despite these overall": Ruby 1.9 also defines a require_relative method. It works like require, except that it ignores the load path and searches relative to the directory from which the invoking code was loaded. ---------------------------------------------------------------------- <255> Change these lines of code: # Add the installation directory for the current program to # the beginning of the load path To: # Add the installation directory for the current program to # the beginning of the load path instead of using require_relative ---------------------------------------------------------------------- (267) Last sentence before 8.1.1 Change "Passes" to "Pass" ---------------------------------------------------------------------- (267) In the large block of code in 8.1.1 Change this line: Integer true: integers are comparable To add a space: Integer < Comparable # => true: integers are comparable ---------------------------------------------------------------------- {271} Last paragraph before 8.3.1 In the first sentence of the paragraph, insert "local_variables," after "global_variables,". Then delete the second sentence ---------------------------------------------------------------------- {304} 4th line from bottom: Change the line: s.insert(5, " there") # Same as s[5] = " there". Alters s. Returns new s. So that it reads: s.insert(5, " there") # Same as s[5,0] = " there". Alters s. Returns new s. ---------------------------------------------------------------------- {305} top: Change these lines: s.length # => 5: counts characters in 1.9, bytes in 1.8 s.size # => 5: size is a synonym s.bytesize # => 5: length in bytes; Ruby 1.9 only To: s.length # => 11: counts characters in 1.9, bytes in 1.8 s.size # => 11: size is a synonym s.bytesize # => 11: length in bytes; Ruby 1.9 only ---------------------------------------------------------------------- (305) near middle of the page Change this line: s.start_with? "hell" # => true. Note singular "start" not "starts" To this: s.start_with? "hell" # => true. Note start_with not starts_with ---------------------------------------------------------------------- <305> bottom Add these two lines of code at the bottom of the page # In Ruby 1.9, you can specify a hash to map matches to replacements s.gsub(/[aeiou]/,"a"=>0, "e"=>1, "i"=>2) # => "h1ll" ---------------------------------------------------------------------- <311> last paragraph Change "Ruby 1.9" to "Ruby 1.9 (and 1.8.7)" ---------------------------------------------------------------------- <319> Section 9.2.4.3 In the block of code in the middle of the page, change: phone.gsub!(/\D/, "") # Remove anything other than digits To: phone.gsub!(/\D/,' '=>'-') # 1.9: remove non-digits but map space to hyphen Insert the following after the first sentence of the last paragraph on the page: (Replacement strings specified in a hash must be ordinary strings, however.) ---------------------------------------------------------------------- {321} near middle of the page: Change these lines: 1.scalar? # => false: not a complex number. Ruby 1.9. 1.0.scalar? # => false: not a complex number. Ruby 1.9. Complex(1,2).scalar? # => true: a complex number. requires 'complex'. So they read: 1.scalar? # => true: not a complex number. Ruby 1.9. 1.0.scalar? # => true: not a complex number. Ruby 1.9. Complex(1,2).scalar? # => false: a complex number. require 'complex' in 1.8 ---------------------------------------------------------------------- <322> in section 9.3.1: Change the sentence at the top of the page to: Numeric and its subclasses define various methods for rounding numbers: After the code block, change "Float also defines a few other" to "Here are a few other numeric" Then replace the final block of code in 9.3.1 with this: # For any Numeric value n, in Ruby 1.9 [n.abs, n<=>0] # Absolute value and sign [n.abs, n.angle] # Magnitude and angle (or use n.polar) [n.numerator, n.denominator] # Numerator and denominator [n.real, n.imag] # Real and imaginary parts # Floating point constants: may be implementation dependent [Float::MAX, Float::MIN] # => [1.79769313486232e+308,2.2250738585072e-308] Float::EPSILON # => 2.22044604925031e-16: difference between adjacent floats ---------------------------------------------------------------------- <322> in 9.3.2 Insert this line: Math.cbrt(27.0) # => 3.0: cube root; Ruby 1.9 and later After this line: Math.sqrt(25.0) # => 5.0: square root ---------------------------------------------------------------------- (322) in 9.3.2 Delete the quotation mark from this line: Math.exp(2) # => 7.38905609893065": same as Math::E**2 ---------------------------------------------------------------------- <323> top Change the following lines: # Decompose float x into fraction f and exponent e, such that x = f*2**e f,e = frexp(1024.0) # => [0.5, 11] x = ldexp(f, e) # => 1024: compute x = f*2**e # Error function erf(0.0) # => 0.0: error function erfc(0.0) # => 1.0: 1-erf(x): complementary error function To read: # Miscellaneous Functions f,e = frexp(1024.0) # => [0.5, 11]: decompose x into [f,e], x = f*2**e x = ldexp(f, e) # => 1024: compute x = f*2**e erf(0.0) # => 0.0: error function erfc(0.0) # => 1.0: 1-erf(x): complementary error function gamma(5) # => 24.0: floating-point factorial function lgamma(100) # => [359.134205369575, 1]: logarithmic gamma ---------------------------------------------------------------------- <323> bottom Change the first paragraph of 9.3.4 to read: The Complex class represents complex numbers. It is a core class in 1.9 and part of the standard library in 1.8. Requiring the 'complex' module (in either 1.8 or 1.9) redefines the methods of the Math module so that they can accept and return complex numbers. In Ruby 1.9 you can instead require 'cmath' to define a CMath module that defines complex-enabled versions of the Math methods. Examples: ---------------------------------------------------------------------- <324> top Change the lines of code at the top of the page to the following: require "complex" # Ruby 1.8 and for complex Math methods in 1.9 c = Complex(0.5,-0.2) # => .5-.2i. Complex.polar(1,Math::PI/2) # => Complex(0.0,1.0): create with polar coords i = 1.im # => Complex(0,1): convert to imaginary number (2.re - 3.5.im).to_s # => "2.5-3.5i": re method in Ruby 1.9 only r,i = c.real, c.imag # => [0.5,-0.2]: Real part, imaginary part m,a = c.polar # => [magnitude, angle]: Same as [c.abs,c.angle] d = c.conj # => .5+.2i: change sign of imaginary part z = "0+0i".to_c # String-to-Complex conversion function: 1.9 only 10.times { z = z*z + c } # Arithmetic operators work on Complex numbers 1.im**2 # => Complex(-1,0): i*i == -1 x = Math.sin(z) # 'complex' module redefines Math functions require 'cmath' # Ruby 1.9: Define CMath module for complex math CMath.sqrt(-1)==Complex::I # => true ---------------------------------------------------------------------- <324> 9.3.5 Change this section to the following: The Rational class represents rational numbers (the quotient of two integers). Rational is built-in to Ruby 1.9 and is part of the standard library in Ruby 1.8. Division with the quo method returns a Rational value if both arguments are integers. Some examples: require "rational" # Only necessary in Ruby 1.8 penny = Rational(1, 100) # A penny is 1/100th nickel = "5/100".to_r # String-to-Rational conversion: Ruby 1.9 only dime = 10.quo 100 # => Rational(1,10) change = 2*dime + 3*penny # => Rational(23,100) change.numerator # => 23: top of the fraction change.denominator # => 100: bottom of the fraction change.to_f # => 0.23: convert to Float (nickel * dime).to_s # => "1/200": to_s returns fractions ---------------------------------------------------------------------- <325> end of section 9.3.7 Insert this paragraph: For cryptographically secure random numbers, use the SecureRandom module, which is part of the standard library in Ruby 1.9 and 1.8.7. ---------------------------------------------------------------------- <329> 2nd paragraph: Change "in Ruby 1.9" to "in Ruby 1.9 (and 1.8.7)". ---------------------------------------------------------------------- <329> middle of the page In the paragraph about the zip method, delete this text: in Ruby 1.8 or an enumerator object in Ruby 1.9 (calling to_a on the enumerator object generates the array of arrays that would have been returned in 1.8) Then add the following two lines of code to the code that follows that paragraph: p (1..3).zip('a'..'z') # Prints [[1,"a"],[2,"b"],[3,"c"]] p (1..3).zip('a'..'b') # Prints [[1,"a"],[2,"b"],[3,nil]] ---------------------------------------------------------------------- <330> first paragraph Change "Ruby 1.9" to "Ruby 1.9 (and 1.8.7)" ---------------------------------------------------------------------- [330] last para before 9.5.1.3 Replace the last paragraph before 9.5.1.3 with the following: Finally, note that enumerators, like all Enumerable objects, are splattable: you can prefix an enumerator with an asterisk to expand it into individual values for method invocation or parallel assignment. ---------------------------------------------------------------------- <331> middle of page Change the paragraph that begin "In Ruby 1.9" to read: The find_index method (new in Ruby 1.9) is like the index method of Array: it returns the index of a specific element or of the first element that matches a block: Then add this line of code before the two following lines: data.find_index [0,1] # => 1: the second element matches ---------------------------------------------------------------------- <333> top of page Insert a new paragraph right before 9.5.1.6: The Array class defines its own efficient versions of these taking and dropping methods that do not require arrays to be iterated with each. ---------------------------------------------------------------------- <335> 9.5.2.2 Change: [1,2,3].nitems {|x| x>2} # => 1: # of elts matching block (Ruby 1.9) To: [1,2,3].nitems {|x| x>2} # => 1: # of elts matching block (Ruby 1.9 + 1.8.7) ---------------------------------------------------------------------- {335} in the code of 9.5.2.2 Please change this line: a[-a.size-1] # => 'a': first element to read: a[-a.size] # => 'a': first element ---------------------------------------------------------------------- <337> 9.5.2.4 Add this sentence at the end of the first paragraph In Ruby 1.9 and 1.8.7, array iterators return an enumerator when invoked without a block: ---------------------------------------------------------------------- <338> code near top of page Change these lines: a.index {|c| c =~ /[aeiou]/} # => 1: index of first vowel. Ruby 1.9. a.rindex {|c| c =~ /[aeiou]/} # => 4: index of last vowel. Ruby 1.9. To: a.index {|c| c =~ /[aeiou]/} # => 1: index of 1st vowel. 1.9 and 1.8.7 a.rindex {|c| c =~ /[aeiou]/} # => 4: index of last vowel. 1.9 and 1.8.7 ---------------------------------------------------------------------- {342} In section 9.5.3.3 Change this line: h.replace({1=>:a, 2=>;b} # h is now equal to the argument hash To: h.replace({1=>:a, 2=>:b}) # h is now equal to the argument hash ---------------------------------------------------------------------- <345> 2nd paragraph from the bottom Delete the second paragraph from the bottom. Matz says that the compare_by_identity method will likely be removed ---------------------------------------------------------------------- <355> Middle of the page: Insert the following before "To change the name of a file": To copy a file, use File.copy_stream, specifying filenames as the source and destination: File.copy_stream("test", "test.backup") ---------------------------------------------------------------------- <361> Section 9.7.3.2 At the end of the first paragraph, replace this sentence: None of these class methods requires you to instantiate an IO object: With this: In Ruby 1.9, you can pass a hash to these methods to specify the mode string and/or encoding of the file being read. After the first line of code in the section insert these two lines: data = IO.read("data", mode:"rb") # Open with mode string "rb" data = IO.read("data", encoding:"binary") # Read unencoded bytes Insert the following before the paragraph that begins "Although" In Ruby 1.9 you can use IO.copy_stream to read a file (or a portion) and write its content to a stream: IO.copy_stream("/usr/share/dict/words", STDOUT) # Print the dictionary IO.copy_stream("/usr/share/dict/words", STDOUT, 10, 100) # Print bytes 100-109 At the end of the next paragraph, change "and File.foreach" to "File.foreach, and File.copy_stream" ---------------------------------------------------------------------- <362> 3rd paragraph from bottom: Replace these lines: Another way to read the bytes of a stream is with the each_byte iterator. This method passes each byte of a stream to the associated block: f.each_byte {|b| ... } # Iterate through remaining bytes f.bytes # An enumerator for each_byte: Ruby 1.9 With these: You can also iterate and enumerate the characters and bytes of a stream: f.each_byte {|b| ... } # Iterate through remaining bytes f.bytes # An enumerator for each_byte: Ruby 1.9 f.each_char {|c} ...} # Iterate characters: Ruby 1.9 f.chars # An enumerator for each_char: Ruby 1.9 ---------------------------------------------------------------------- <390> last paragraph Change "-r, and -K options" to "-r, -K, -E, and -T" options. Change "on the command line" to "on the command line, unless the command line includes --disable-rubyopt ---------------------------------------------------------------------- (398) first line of section 10.2.3.3: Change "and variable" to "and variables" ----------------------------------------------------------------------