The errata list is a list of errors and their corrections that were found after the product was released.
The following errata were submitted by our customers and have not yet been approved or disproved by the author or editor. They solely represent the opinion of the customer.
Version |
Location |
Description |
Submitted by |
Date submitted |
ePub |
Chapter 7. 1st and 4th paragraph. |
There are a couple links in the 1st and 4th paragraph to rubycentral.com in this chapter that aren’t resolving: https://www.safaribooksonline.com/library/view/ruby-cookbook/0596523696/pr03s07.html
|
Anonymous |
May 11, 2017 |
Printed |
Page 1.18
mgsub |
mgsub doesn't seem like grouping with ():
ex.
"red white blue".gsub(/(white)/,'x\1x')
=> red xwhitex blue
"red white blue".mgsub([[/(white)/,'x\1x']])
=> red x\\1x blue
|
Anonymous |
Jun 05, 2008 |
Printed |
Page 7,8,9
.each_simultaneously do |e| |
sleep(5)
print "Completed operation for #{e}!
"
end.each { |t| t.join } # THIS IS THE CHANGED LINE
...[rest of code excerpt]...
|
Anonymous |
|
Printed |
Page 7,8,9
.each_simultaneously do |e| |
sleep(5)
print "Completed operation for #{e}!
"
end.each { |t| t.join } # THIS IS THE CHANGED LINE
...[rest of code excerpt]...
|
Anonymous |
|
Printed |
Page 10
line immediately above "Discussion" |
There should be a space between "wrong" and the period that follows it
s.split(//).reverse!.join(' ') # => "These words are in the wrong . order"
|
Anonymous |
|
Printed |
Page 10
line immediately above "Discussion" |
There should be a space between "wrong" and the period that follows it
s.split(//).reverse!.join(' ') # => "These words are in the wrong . order"
|
Anonymous |
|
Printed |
Page 18
2nd code example under Discussion heading |
For the example describing a pattern match for anything that isn't whitespace. It should be a lowercase 's'. So the example should read:
/[^s]+/
The capital 'S' which the book uses results in only whitespace since you're negating the 'S' match. A simpler alternative would be:
/S+/
|
Anonymous |
|
Printed |
Page 18
2nd code example under Discussion heading |
For the example describing a pattern match for anything that isn't whitespace. It should be a lowercase 's'. So the example should read:
/[^s]+/
The capital 'S' which the book uses results in only whitespace since you're negating the 'S' match. A simpler alternative would be:
/S+/
|
Anonymous |
|
Printed |
Page 25
first paragraph under heading See Also |
Paragraph refers to chapter 11.2 for details on the use of the iconv library.
Nevertheless iconv is not mentioned in chapter 11.2.
|
Anonymous |
|
Printed |
Page 25
first paragraph under heading See Also |
Paragraph refers to chapter 11.2 for details on the use of the iconv library.
Nevertheless iconv is not mentioned in chapter 11.2.
|
Anonymous |
|
Printed |
Page 32-33
Recipe 1.18 mgsub |
mgsub doesn't seem like grouping with ():
ex.
"red white blue".gsub(/(white)/,'x1x')
=> red xwhitex blue
"red white blue".mgsub([[/(white)/,'x1x']])
=> red x\1x blue
|
Anonymous |
|
PDF |
Page 42
4th line |
Change
:to_f => /([+-]?([0-9]*\.)?[0-9]+(e[+-]?[0-9]+)?)/i,
to
:to_f => /([+-]?(?:[0-9]*\.)?[0-9]+(?:e[+-]?[0-9]+)?)/i,
The addition of the ?: in the second and third group prevents them from being capture groups so repeating the body of the regular expression multiple times such as
/([+-]?(?:[0-9]*\.)?[0-9]+(?:e[+-]?[0-9]+)?) ([+-]?(?:[0-9]*\.)?[0-9]+(?:e[+-]?[0-9]+)?)/i
to parse two floating point numbers will return the float strings in $1 and $2 as expected, otherwise without the ?: will return the floats in $1 and $3 - much less intuitive.
|
Anonymous |
Nov 05, 2008 |
ePub |
Page 52
Top of page |
Code should read:
def random_word
letters = { ?v => 'aeiou',
?c => 'bcdfghjklmnprstvwyz' }
word = ''
'cvcvcvc'.each_char do |x|
source = letters[x]
word << source[rand(source.length)].chr
end
return word
end
puts random_word # => "josuyip"
puts random_word # => "haramic"
|
Anonymous |
Nov 27, 2013 |
Printed |
Page 53
end of Solution |
In the book, the formula to convert a logarithm from base b1 to base b2 looks like this:
log_b1(x) = log_b2(x) / log_b2(k)
however, the 'k' should be 'b1' as in
log_b1(x) = log_b2(x) / log_b2(b1)
See also http://en.wikipedia.org/wiki/Logarithm#Change_of_base
|
Anonymous |
|
Printed |
Page 53
Discussion, line 2-4 |
The sentence reads:
"That is, Math.log10(1000)==3.0 because 10 cubed is 1000.Math.log(Math::E)==1 because e to the first power is e."
A space between '1000.' and 'Math.log(Math::E)' is missing - the above are actually two sentences.
|
Anonymous |
|
Printed |
Page 53
end of Solution |
In the book, the formula to convert a logarithm from base b1 to base b2 looks like this:
log_b1(x) = log_b2(x) / log_b2(k)
however, the 'k' should be 'b1' as in
log_b1(x) = log_b2(x) / log_b2(b1)
See also http://en.wikipedia.org/wiki/Logarithm#Change_of_base
|
Anonymous |
|
Printed |
Page 53
Discussion, line 2-4 |
The sentence reads:
"That is, Math.log10(1000)==3.0 because 10 cubed is 1000.Math.log(Math::E)==1 because e to the first power is e."
A space between '1000.' and 'Math.log(Math::E)' is missing - the above are actually two sentences.
|
Anonymous |
|
Printed |
Page 53
Sentence "To calculated a logarithm...", under "Solution" |
Argument of divisor should be "b1" ("b sub 1"), not "k". Should read:
log x = log x / log b1
b b b
1 2 2
|
Cary Swoveland |
Jul 22, 2010 |
Printed |
Page 55
2.8 first code example |
(Note: Since I'm reading the book via the Safari bookshelf, I have no idea which page it is; but it is anyway chapater 2.8, titled
"Recipe 2.8. Finding Mean, Median, and Mode"
The code example
def mean(array)
array.inject(array.inject(0) { |sum, x| sum += x } / array.size.to_f
end
has two problems, one a typo (which you likely have already noticed), and a more subtle pedagogic one:
The correct way to write the function would be IMO
def mean(array)
array.inject(0) { |sum,x| sum+x } / array.size.to_f
end
Apart from the obvious correction of the typo at the beginning of
the statement, note that I changed sum+=x to sum+x. While both
expressions would work here, sum+=x silently implies that the
incject function *should* modify the running variable (here: sum).
This is not true. Changing sum within the block has no effect
outside. Array#incject only takes the return value of the block.
In this case, sum+x and sum+=x yield the same return value, but
sum+x communicates this fact in a clearer way.
|
Anonymous |
|
Printed |
Page 55
2.8 first code example |
(Note: Since I'm reading the book via the Safari bookshelf, I have no idea which page it is; but it is anyway chapater 2.8, titled
"Recipe 2.8. Finding Mean, Median, and Mode"
The code example
def mean(array)
array.inject(array.inject(0) { |sum, x| sum += x } / array.size.to_f
end
has two problems, one a typo (which you likely have already noticed), and a more subtle pedagogic one:
The correct way to write the function would be IMO
def mean(array)
array.inject(0) { |sum,x| sum+x } / array.size.to_f
end
Apart from the obvious correction of the typo at the beginning of
the statement, note that I changed sum+=x to sum+x. While both
expressions would work here, sum+=x silently implies that the
incject function *should* modify the running variable (here: sum).
This is not true. Changing sum within the block has no effect
outside. Array#incject only takes the return value of the block.
In this case, sum+x and sum+=x yield the same return value, but
sum+x communicates this fact in a clearer way.
|
Anonymous |
|
Printed |
Page 91
class Date def Date.now... |
class Date
def Date.now
return Date.jd(Datetime.now.jd)
end
end
puts Date.now
does not work. It generates the following error message:
`now': stack level too deep (SystemStackError)
Remedy: change to
class Date
def Date.new
Date.jd(DateTime.now.jd)
end
end
puts Date.new
|
Anonymous |
|
Printed |
Page 91
class Date def Date.now... |
class Date
def Date.now
return Date.jd(Datetime.now.jd)
end
end
puts Date.now
does not work. It generates the following error message:
`now': stack level too deep (SystemStackError)
Remedy: change to
class Date
def Date.new
Date.jd(DateTime.now.jd)
end
end
puts Date.new
|
Anonymous |
|
Printed |
Page 111
Bottom code fragment |
to_local_time is incorrect, and will return a date several years off.
Original:
def to_local_time
to_time(new_offset(DateTime.now.offset-offset), :local)
end
Counter-example:
Consider the call DateTime.now.to_local_time, for any time zone, such as PST.
This results in
to_time(new_offset(0), :local)
which invokes Time.local with offset(0) H:M:S.
This should be:
def to_local_time
to_time(new_offset(DateTime.now.offset), :local)
end
|
Anonymous |
|
Printed |
Page 111
Bottom code fragment |
to_local_time is incorrect, and will return a date several years off.
Original:
def to_local_time
to_time(new_offset(DateTime.now.offset-offset), :local)
end
Counter-example:
Consider the call DateTime.now.to_local_time, for any time zone, such as PST.
This results in
to_time(new_offset(0), :local)
which invokes Time.local with offset(0) H:M:S.
This should be:
def to_local_time
to_time(new_offset(DateTime.now.offset), :local)
end
|
Anonymous |
|
Printed |
Page 112
code at bottom of page in normalize_time_types(array) |
On the next to last line on the page, in the line of code that's part of the rescue statement
convert_to = DateTime
is superfluous. The variable convert_to is never referenced.
|
Anonymous |
|
Printed |
Page 112
code at bottom of page in normalize_time_types(array) |
On the next to last line on the page, in the line of code that's part of the rescue statement
convert_to = DateTime
is superfluous. The variable convert_to is never referenced.
|
Anonymous |
|
Printed |
Page 138
code related to the else clauses in the revised class []= for SortedArray |
The following code in the two "else" clauses that contain the comment "# Not supported. Delegate to superclass; will probably give an error." is incorrect:
else
# Not supported...
super
sort!(&sort_by)
end
else
# Not supported...
super
sort!(&sort_by)
end
should be:
else
# Not supported...
super
sort!(&@sort_by)
end
else
# Not supported...
super
sort!(&@sort_by)
end
This is no big deal since the code should never execute.
|
Anonymous |
|
Printed |
Page 138
code related to the else clauses in the revised class []= for SortedArray |
The following code in the two "else" clauses that contain the comment "# Not supported. Delegate to superclass; will probably give an error." is incorrect:
else
# Not supported...
super
sort!(&sort_by)
end
else
# Not supported...
super
sort!(&sort_by)
end
should be:
else
# Not supported...
super
sort!(&@sort_by)
end
else
# Not supported...
super
sort!(&@sort_by)
end
This is no big deal since the code should never execute.
|
Anonymous |
|
Printed |
Page 139
line 6 from bottom of page 139 |
stripes = SortedArray.new(["aardwolf", "zebrafish"])
should be
stripes = FrozenCopySortedArray.new(["aardwolf", "zebrafish"])
then if you ran
stripes[1].upcase!
you will get the following error message:
`upcase!': can't modify frozen string (TypeError)
|
Anonymous |
|
Printed |
Page 139
line 6 from bottom of page 139 |
stripes = SortedArray.new(["aardwolf", "zebrafish"])
should be
stripes = FrozenCopySortedArray.new(["aardwolf", "zebrafish"])
then if you ran
stripes[1].upcase!
you will get the following error message:
`upcase!': can't modify frozen string (TypeError)
|
Anonymous |
|
Printed |
Page 141
1st paragraph under "Discussion" |
The author refers to a variable, total, in the example above. However,
the example uses the variable sum. Also, the first sentence of the
paragraph reads:
"...we didn't need to define the variable total variable outside the scope of
iteration."
One of the instances of the word variable needs to be removed, and the
sentence should be adjusted, depending on which instance is removed.
|
Anonymous |
|
Printed |
Page 141
1st paragraph under "Discussion" |
The author refers to a variable, total, in the example above. However,
the example uses the variable sum. Also, the first sentence of the
paragraph reads:
"...we didn't need to define the variable total variable outside the scope of
iteration."
One of the instances of the word variable needs to be removed, and the
sentence should be adjusted, depending on which instance is removed.
|
Anonymous |
|
Printed |
Page 144
Discussion section |
The Array#shuffle! method implements the Fisher-Yates shuffle algorithm (Knuth _The Art of Computer Programming_ vol. 2 pg. 145). The implementation works, yet it has a small superfluous step. Namely, we do not need to iterate over "each" index. Once j is equal to the final value (n-1) there is only 1 array element left, and there is no point swapping it with itself.
Here is a version that closely follows Knuth's description (although applied to 0-based indexing):
class Array
def shuffle!
(length-1).downto(1) do |i|
j = rand(i + 1)
self[j], self[i] = self[i], self[j]
end
self
end
end
And here is a slight variant that avoids unnecessary swaps:
class Array
def shuffle!
(length-1).downto(1) do |i|
j = rand(i + 1)
self[j], self[i] = self[i], self[j] unless i == j
end
self
end
end
|
David Sletten |
Jul 04, 2010 |
Printed |
Page 146
line 5 and 6 from bottom of page 146 |
The SortedList class from Recipe 4.7 is used for this task. The
min_n method below create a SortedList "stable" that .....
The "SortedList" of lines 5 and 6 should be "SortedArray".
If you look at Recipe 4.7 and source code of page 147, there is a
"SortedArray" class instead of "SortedList" class.
|
Anonymous |
|
Printed |
Page 146
line 5 and 6 from bottom of page 146 |
The SortedList class from Recipe 4.7 is used for this task. The
min_n method below create a SortedList "stable" that .....
The "SortedList" of lines 5 and 6 should be "SortedArray".
If you look at Recipe 4.7 and source code of page 147, there is a
"SortedArray" class instead of "SortedList" class.
|
Anonymous |
|
Printed |
Page 148
Comment line describing result after running hash.update (8th line from bottom of page) |
# => {5=>"five", 1=>"ontwo", 2=>"two", 3=>"three", 4=>"four"}
should be
# => {5=>"five", 1=>"one", 2=>"two", 3=>"three", 4=>"four"}
NOTE: "ontwo" after 1=> is a typo
|
Anonymous |
|
Printed |
Page 148
Comment line describing result after running hash.update (8th line from bottom of page) |
# => {5=>"five", 1=>"ontwo", 2=>"two", 3=>"three", 4=>"four"}
should be
# => {5=>"five", 1=>"one", 2=>"two", 3=>"three", 4=>"four"}
NOTE: "ontwo" after 1=> is a typo
|
Anonymous |
|
Printed |
Page 151
middle of the pages |
"then use use Array#compress! to remove them."
has too many uses.
|
Anonymous |
|
Printed |
Page 151
last paragraph (before code) |
There's no method called Array#compress!. The correct method for removing nil values is Array#compact!
|
Anonymous |
|
Printed |
Page 151
code at bottom of page defining strip_values_at! |
There's a misplaced "end"
The code in the book is:
class Array
def strip_values_at!(*args)
# For each mentioned index, replace its value with a dummy object
values = []
dummy = Object.new
args.each do | i |
if i < size
values << self[i]
self[i] = dummy
end
#Strip out the dummy objects
delete(dummy)
return values
end
end
end
Correct code should be:
class Array
def strip_values_at!(*args)
# For each mentioned index, replace its value with a dummy object
values = []
dummy = Object.new
args.each do | i |
if i < size
values << self[i]
self[i] = dummy
end
end
# Strip out the dummy objects
delete(dummy)
return values
end
end
|
Anonymous |
|
Printed |
Page 151
middle of the pages |
"then use use Array#compress! to remove them."
has too many uses.
|
Anonymous |
|
Printed |
Page 151
last paragraph (before code) |
There's no method called Array#compress!. The correct method for removing nil values is Array#compact!
|
Anonymous |
|
Printed |
Page 151
code at bottom of page defining strip_values_at! |
There's a misplaced "end"
The code in the book is:
class Array
def strip_values_at!(*args)
# For each mentioned index, replace its value with a dummy object
values = []
dummy = Object.new
args.each do | i |
if i < size
values << self[i]
self[i] = dummy
end
#Strip out the dummy objects
delete(dummy)
return values
end
end
end
Correct code should be:
class Array
def strip_values_at!(*args)
# For each mentioned index, replace its value with a dummy object
values = []
dummy = Object.new
args.each do | i |
if i < size
values << self[i]
self[i] = dummy
end
end
# Strip out the dummy objects
delete(dummy)
return values
end
end
|
Anonymous |
|
Printed |
Page 153
3rd set of code (from either the top or the bottom of the page) |
The following code is incorrect:
array = [1, 2, 3]
set = [3, 4, 5].to_s
array & set
set & array
It should be the following:
array = [1, 2, 3]
set = [3, 4, 5].to_set
array & set
set & array
NOTE: to_s should be to_set
|
Anonymous |
|
Printed |
Page 153
3rd set of code (from either the top or the bottom of the page) |
The following code is incorrect:
array = [1, 2, 3]
set = [3, 4, 5].to_s
array & set
set & array
It should be the following:
array = [1, 2, 3]
set = [3, 4, 5].to_set
array & set
set & array
NOTE: to_s should be to_set
|
Anonymous |
|
Printed |
Page 155
4th to last line of code on the page (a comment) |
The comment is missing a closing quotation mark for "String"
The text should be:
# Divide the set into the "String" subset, the "Fixnum" subset, and
# the "Float" subset
|
Anonymous |
|
Printed |
Page 155
4th to last line of code on the page (a comment) |
The comment is missing a closing quotation mark for "String"
The text should be:
# Divide the set into the "String" subset, the "Fixnum" subset, and
# the "Float" subset
|
Anonymous |
|
Printed |
Page 156
2nd section of code above Discussion |
The result for the operation to divide the set into sets of adjacent numbers is wrong. There was no element "-3" in Set s. There was a "-2".
The incorrect results in the book are:
#<Set: {#<Set: {1, 2, 3}>,
#<Set: {-1}>,
#<Set: {-4, -3}>}>
The correct results should be:
#<Set: {#<Set: {1, 2, 3}>,
#<Set: {-4}>,
#<Set: {-2, -1}>}>
|
Anonymous |
|
Printed |
Page 156
section of code immediate preceding Discussion |
The following assignment statement should precede the code that uses Set#classify;
s = Set.new([1, 2, 3, 'a', 'b', 'c', -1.0, -2.0, -3.0])
|
Anonymous |
|
Printed |
Page 156
2nd section of code above Discussion |
The result for the operation to divide the set into sets of adjacent numbers is wrong. There was no element "-3" in Set s. There was a "-2".
The incorrect results in the book are:
#<Set: {#<Set: {1, 2, 3}>,
#<Set: {-1}>,
#<Set: {-4, -3}>}>
The correct results should be:
#<Set: {#<Set: {1, 2, 3}>,
#<Set: {-4}>,
#<Set: {-2, -1}>}>
|
Anonymous |
|
Printed |
Page 156
section of code immediate preceding Discussion |
The following assignment statement should precede the code that uses Set#classify;
s = Set.new([1, 2, 3, 'a', 'b', 'c', -1.0, -2.0, -3.0])
|
Anonymous |
|
Printed |
Page 160
Last code example on page |
The following has an error (missing colons in key labels):
h = { :one_squared => 1, two_squared => 4, three_squared => 9,
:four_squared => 16 }
The corrected code should be:
h = { :one_squared => 1, :two_squared => 4, :three_squared => 9,
:four_squared => 16 }
|
Anonymous |
|
Printed |
Page 160
Last code example on page |
The following has an error (missing colons in key labels):
h = { :one_squared => 1, two_squared => 4, three_squared => 9,
:four_squared => 16 }
The corrected code should be:
h = { :one_squared => 1, :two_squared => 4, :three_squared => 9,
:four_squared => 16 }
|
Anonymous |
|
Printed |
Page 165
2nd section of code up from the bottom of the page |
The example in the book is:
squares = [1, 1, 2, 3, 4, 9]
results = {}
squares.into_hash(results) # => {1=>1, 2=>3, 4=>9}
It would seem that this is a typo and that the correct version should be:
squares = [1, 1, 2, 4, 3, 9]
results = {}
squares.into_hash(results) # => {1=>1, 2=>4, 3=>9}
|
Anonymous |
|
Printed |
Page 165
Last section of code on page |
The values used for the hash named cubes causes confusion.
cubes = { 3 => 27, 4 => 256, 5 => 3125 }
I recommend using one of the following instead:
cubes = { 3 => 27, 4 => 64, 5 => 125 }
cubes = { 3 => 3 ** 3, 4 => 4 ** 3, 5 => 5 ** 3 }
|
Anonymous |
|
Printed |
Page 165
2nd section of code up from the bottom of the page |
The example in the book is:
squares = [1, 1, 2, 3, 4, 9]
results = {}
squares.into_hash(results) # => {1=>1, 2=>3, 4=>9}
It would seem that this is a typo and that the correct version should be:
squares = [1, 1, 2, 4, 3, 9]
results = {}
squares.into_hash(results) # => {1=>1, 2=>4, 3=>9}
|
Anonymous |
|
Printed |
Page 165
Last section of code on page |
The values used for the hash named cubes causes confusion.
cubes = { 3 => 27, 4 => 256, 5 => 3125 }
I recommend using one of the following instead:
cubes = { 3 => 27, 4 => 64, 5 => 125 }
cubes = { 3 => 3 ** 3, 4 => 4 ** 3, 5 => 5 ** 3 }
|
Anonymous |
|
Printed |
Page 165
class Array...end |
The into_hash method seems like an
'anti recipe' because one can just use
results = Hash[*squares]
To convert an array with key-value pairs into a hash
|
David Ongaro |
Mar 01, 2009 |
Printed |
Page 167
1st section of code on page |
There is no value shown for the 8th line of code:
h.delete(5)
The actual value returned is nil:
h.delete(5) # => nil
|
Anonymous |
|
Printed |
Page 167
1st section of code on page |
There is no value shown for the 8th line of code:
h.delete(5)
The actual value returned is nil:
h.delete(5) # => nil
|
Anonymous |
|
Printed |
Page 199
Next to last line of code on page |
d.reject { |f| f[0] == '.' } generates the following output:
[".", "..", ".hidden_file", "ruby_script.rb", "subdirectory", "text_file"]
The problem is that f[0] returns a Fixnum, not a string.
Any of the following will work properly:
d.reject { |f| f[0] == ?. }
d.reject { |f| f[0..0] == '.' }
d.reject { |f| f[/^./] == '.' }
d.reject { |f| f =~ [/^./ }
|
Anonymous |
|
Printed |
Page 199
Next to last line of code on page |
d.reject { |f| f[0] == '.' } generates the following output:
[".", "..", ".hidden_file", "ruby_script.rb", "subdirectory", "text_file"]
The problem is that f[0] returns a Fixnum, not a string.
Any of the following will work properly:
d.reject { |f| f[0] == ?. }
d.reject { |f| f[0..0] == '.' }
d.reject { |f| f[/^./] == '.' }
d.reject { |f| f =~ [/^./ }
|
Anonymous |
|
Printed |
Page 206
The last two lines of code at top of page (just above "See Also") |
First, IO.sync, as it appears in the code, is invoking a class method. IO#sync is an instance method.
Second, in order for the output to go straight into the OS buffer, you'd want to set IO#sync = true (not false).
Either of the following corrects what's in the book:
file = open('output', 'w')
file.sync = true
file << 'This is going straight into the OS buffer.'
file.close
open('output', 'w') do | f |
f.sync = true
f << 'This is going straight into the OS buffer.'
end
|
Anonymous |
|
Printed |
Page 206
The last two lines of code at top of page (just above "See Also") |
First, IO.sync, as it appears in the code, is invoking a class method. IO#sync is an instance method.
Second, in order for the output to go straight into the OS buffer, you'd want to set IO#sync = true (not false).
Either of the following corrects what's in the book:
file = open('output', 'w')
file.sync = true
file << 'This is going straight into the OS buffer.'
file.close
open('output', 'w') do | f |
f.sync = true
f << 'This is going straight into the OS buffer.'
end
|
Anonymous |
|
Printed |
Page 217
section 6.13 |
Here's the offending recipe:
#
# original recipe
#
open( 'output', 'w' ) do |f|
flock(f, File::LOCK_EX) do |f|
f << "Kiss me, I've got a write lock on a file!"
end
end
The recipe truncates the file before obtaining the lock. Some other process could have LOCK_EX and be writing into
the file. If the reader realizes this can happen, he'll wonder if the any of the recipe is correct.
I solve this problem by creating a zero-length companion file which takes such rough treatment without ill effect:
#
# suggested changed recipe
#
open( 'output.lck', 'a' ) do |f|
flock( f, File::LOCK_EX)
open( 'output', 'w' ) do |g|
g << "Kiss me, I've got the write lock for this file!"
end
end
How this works:
1. Open an append-write handle on the companion, which creates the companion if it does not already exist.
Derive companion name from the file you really want to write.
2. Request and wait for an exclusive lock on the companion
3. Open a write handle on the actual file.
4. Write to the actual file
5. Close the write handle on the actual file
6. Close the append handle on the companion file. This releases the lock.
General comments:
1. I like cookbook recipes which don't strain credulity. Using the same block variable |f| in two nested
blocks works, but distracts the reader.
2. open(...) do |h| ... end passes the handle created by open() into the block. This is idiosyncratic to Ruby and should be noted.
3. The fact that leaving the block closes the handle is idiosyncratic to Ruby and should be noted.
4. It is not widely appreciated that closing a handle on a file terminates any flock lock you may have on the file through that handle. This is a feature of the OS and not Ruby. But if we note this, reader will completely understand how this recipe works and believe it. He will appreciate a bit of how Ruby is set up for brevity.
|
Anonymous |
|
PDF |
Page 217
6.11 Choosing Randomly from a Weighted List, Solution paragraph |
The choose_weighted() function has an off-by-one error that renders the results incorrect. For small integer weights, the values are egregiously wrong.
The line:
return item if target <= weight
Should instead read:
return item if target < weight
Using less-than-or-equal-to instead of strictly less-than creates an off-by-one error since rand() produces outputs that are zero-indexed.
For example, if you call choose_weighted() with argument {'A' => 1, 'B' => 1} you would expect it to return 'A' and 'B' each half the time. What actually occurs is that it returns 'A' uniformly and never returns 'B'.
This is because the sum of the weights is 2, so rand(2) returns either 0 or 1. Both 0 and 1 are <= the weight 1, so the function always returns 'A'. This is incorrect.
The problem is less severe but still present in the floating point version of the function, which is unlikely to encounter the boundary case because the space of floating point numbers is so large.
|
Andy Brody |
Apr 25, 2018 |
Printed |
Page 227
top line in the set of code at the bottom of the page |
Throughout the examples in 6.17, you add "b" to the file mode which is needed when you open a binary file on Windows. In the first set line of code after Discussion, you omit this.
Change
f = open('binary')
to
f = open('binary', 'rb')
|
Anonymous |
|
Printed |
Page 227
top line in the set of code at the bottom of the page |
Throughout the examples in 6.17, you add "b" to the file mode which is needed when you open a binary file on Windows. In the first set line of code after Discussion, you omit this.
Change
f = open('binary')
to
f = open('binary', 'rb')
|
Anonymous |
|
Printed |
Page 231
1st line of code in 6.18 |
The first line of code looks like Java code instead of Ruby code
The following line of code
import 'fileutils'
should be changed to
require 'fileutils'
|
Anonymous |
|
Printed |
Page 231
1st line of code in 6.18 |
The first line of code looks like Java code instead of Ruby code
The following line of code
import 'fileutils'
should be changed to
require 'fileutils'
|
Anonymous |
|
Printed |
Page 232
Last two sections of code on the page |
The following code:
open(filename, File::TRUNC) do | f |
generates the following error
in `initialize': Invalid argument - truncate.txt (Errno::EINVAL)
The same open statement appears twice in the text.
Note: The value of the constatn File::TRUNC is 512.
|
Anonymous |
|
Printed |
Page 232
Last two sections of code on the page |
The following code:
open(filename, File::TRUNC) do | f |
generates the following error
in `initialize': Invalid argument - truncate.txt (Errno::EINVAL)
The same open statement appears twice in the text.
Note: The value of the constatn File::TRUNC is 512.
|
Anonymous |
|
Printed |
Page 245
Code at bottom of page |
If you want to pick numbers between min and max, inclusive, then you should change
limit.times { yield min+rand(max+1) }
to
limit.times { yield min+rand(max) }
The implementation defined in the book chooses numbers between 1 and 50 (rand(49) returns a value between 0 and 48)
The code still has the problem that it can pick the same number more than once.
|
Anonymous |
|
Printed |
Page 245
Code at bottom of page |
If you want to pick numbers between min and max, inclusive, then you should change
limit.times { yield min+rand(max+1) }
to
limit.times { yield min+rand(max) }
The implementation defined in the book chooses numbers between 1 and 50 (rand(49) returns a value between 0 and 48)
The code still has the problem that it can pick the same number more than once.
|
Anonymous |
|
Printed |
Page 249
1st sample code block |
When the each method recurses with the line "child.each { |e| yield e }" it is wrapping the original block with multiple successive blocks as it recurses deeper into the tree. This seems very inefficient. This can easily be seen by putting a print statement into the block so that the printed output clearly shows this wrapping...
child_node.each { |e| puts "yield #{e}"; yield e }
I believe a better version of the each method would use a named block thusly...
def each(&block)
block.call(@value)
@children.each do |child_node|
child_node.each(&block)
end
end
The evolution of this solution was very instructive for me and might be worth discussing in the next version of the cook book as a way of reinforcing how yield and blocks/closures work.
|
Anonymous |
|
Printed |
Page 249
1st sample code block |
When the each method recurses with the line "child.each { |e| yield e }" it is wrapping the original block with multiple successive blocks as it recurses deeper into the tree. This seems very inefficient. This can easily be seen by putting a print statement into the block so that the printed output clearly shows this wrapping...
child_node.each { |e| puts "yield #{e}"; yield e }
I believe a better version of the each method would use a named block thusly...
def each(&block)
block.call(@value)
@children.each do |child_node|
child_node.each(&block)
end
end
The evolution of this solution was very instructive for me and might be worth discussing in the next version of the cook book as a way of reinforcing how yield and blocks/closures work.
|
Anonymous |
|
Printed |
Page 251
The heading reads Discussion, but probably should be Solution. |
|
Anonymous |
|
Printed |
Page 271
3rd paragraph |
The book says:
"Calling attr_accessor :instance_variable generates both the getter method
speaks_english and the setter method speaks_english="
I believe it should say:
"Calling attr_accessor :speaks_english generates both the getter method
speaks_english and the setter method speaks_english="
|
Anonymous |
|
Printed |
Page 271
3rd paragraph |
The book says:
"Calling attr_accessor :instance_variable generates both the getter method
speaks_english and the setter method speaks_english="
I believe it should say:
"Calling attr_accessor :speaks_english generates both the getter method
speaks_english and the setter method speaks_english="
|
Anonymous |
|
Printed |
Page 279
Second paragraph under "Solution" |
"...by passing the coordinates of its top-left and bottom-left corners..."
should be
"...by passing the coordinates of its top-left and bottom-right corners..."
|
Anonymous |
|
Printed |
Page 279
Second paragraph under "Solution" |
"...by passing the coordinates of its top-left and bottom-left corners..."
should be
"...by passing the coordinates of its top-left and bottom-right corners..."
|
Anonymous |
|
Printed |
Page 281
2nd paragraph after Solution |
ArgumentException should be ArgumentError (or ArgumentError exception)
|
Anonymous |
|
Printed |
Page 281
2nd paragraph after Solution |
ArgumentException should be ArgumentError (or ArgumentError exception)
|
Anonymous |
|
Printed |
Page 285
2nd paragraph |
The text refers to a class called CardinalNumber. The code defines a class called OrdinalNumber. The text should change CardinalNumber to OrdinalNumber (occurs 3 times).
The comment at the beginning of the code states:
# An integer represented as an ordinal number (1st, 2nd, 3rd...), as
# opposed to an ordinal number (1, 2, 3...)
It should be changed to:
# An integer represented as an ordinal number (1st, 2nd, 3rd...), as
# opposed to an cardinal number (1, 2, 3...)
|
Anonymous |
|
Printed |
Page 285
code |
There are two problems with the code:
1. The line below check = abs should be changed from:
if to_check == 11 or to_check == 12
to
if check == 11 or check == 12 or check == 13
2. There's a line missing from the case expression.
Change from:
case check % 10
when 1 then suffix = "st"
when 2 then suffix = "nd"
else suffix = "th"
end
to:
case check % 10
when 1 then suffix = "st"
when 2 then suffix = "nd"
when 3 then suffix = "rd"
else suffix = "th"
end
You might also want to add to the bottom of the code:
OrdinalNumber.new(3).to_s # => "3rd"
OrdinalNumber.new(13).to_s # => "13th"
OrdinalNumber.new(123).to_s # => "123rd"
|
Anonymous |
|
Printed |
Page 285
2nd paragraph |
The text refers to a class called CardinalNumber. The code defines a class called OrdinalNumber. The text should change CardinalNumber to OrdinalNumber (occurs 3 times).
The comment at the beginning of the code states:
# An integer represented as an ordinal number (1st, 2nd, 3rd...), as
# opposed to an ordinal number (1, 2, 3...)
It should be changed to:
# An integer represented as an ordinal number (1st, 2nd, 3rd...), as
# opposed to an cardinal number (1, 2, 3...)
|
Anonymous |
|
Printed |
Page 285
code |
There are two problems with the code:
1. The line below check = abs should be changed from:
if to_check == 11 or to_check == 12
to
if check == 11 or check == 12 or check == 13
2. There's a line missing from the case expression.
Change from:
case check % 10
when 1 then suffix = "st"
when 2 then suffix = "nd"
else suffix = "th"
end
to:
case check % 10
when 1 then suffix = "st"
when 2 then suffix = "nd"
when 3 then suffix = "rd"
else suffix = "th"
end
You might also want to add to the bottom of the code:
OrdinalNumber.new(3).to_s # => "3rd"
OrdinalNumber.new(13).to_s # => "13th"
OrdinalNumber.new(123).to_s # => "123rd"
|
Anonymous |
|
Printed |
Page 286
code in the center of the page |
change
a = AppendOnlyArray
to
a = AppendOnlyArray.new
|
Anonymous |
|
Printed |
Page 286
code in the center of the page |
change
a = AppendOnlyArray
to
a = AppendOnlyArray.new
|
Anonymous |
|
Printed |
Page 287
Under See Also |
Change CardinalNumber to OrdinalNumber
|
Anonymous |
|
Printed |
Page 287
Under See Also |
Change CardinalNumber to OrdinalNumber
|
Anonymous |
|
Printed |
Page 303
Recipe 8.15 |
5th coding example reads
API_KEY = "100f7vo4gg".freeze
API_KEY[0] = 4
# TypeError: can't modify frozen string
API_KEY = "400f7vo4gg"
# warning: already initialized constant API_KEY
From the text, the reader is lead to conclude that the warning "already initialized constant" results from the fact that API_KEY has been frozen in the first line.
This is not correct (at least not in Ruby 1.8.6). The warning would be issued even if API_KEY would not have been assigned a frozen string before. It comes from the fact that the variable name starts with an uppercase letter (and hence designates what Ruby calls a "constant"). Indeed, if we would have used variables starting with a lower case letter, i.e.
api_key="....".freeze
api_key[0]=4
api_key="...."
We would not get any warning (although of course, we would still get the type error in the second line).
|
Anonymous |
|
PDF |
Page 322
Bottom of page |
String does not include Enumerable as the book claims it does.
[29] pry(main)> "asdf".is_a? Enumerable
=> false
[30] pry(main)> String.is_a? Enumerable
=> false
|
Rylee Fowler |
May 13, 2014 |
Printed |
Page 326
code above "See Also" |
The last line of code before the final end is:
RubyString.new("This is a built-in string, not a StringTheory2::String")
This code should be moved below the end, and changed to:
StringTheory2::RubyString.new("This is a built-in string, not a StringTheory2::String")
The full example is:
module StringTheory2
RubyString = String
class String
def initialize(length=1.0e-33)
@length = length
end
end
end
StringTheory2::RubyString.new("This is a built-in string, not a StringTheory2::String")
#=>"This is a built-in string, not a StringTheory2::String"
|
Anonymous |
|
Printed |
Page 326
code above "See Also" |
The last line of code before the final end is:
RubyString.new("This is a built-in string, not a StringTheory2::String")
This code should be moved below the end, and changed to:
StringTheory2::RubyString.new("This is a built-in string, not a StringTheory2::String")
The full example is:
module StringTheory2
RubyString = String
class String
def initialize(length=1.0e-33)
@length = length
end
end
end
StringTheory2::RubyString.new("This is a built-in string, not a StringTheory2::String")
#=>"This is a built-in string, not a StringTheory2::String"
|
Anonymous |
|
Printed |
Page 339
Text under Problem |
There's a word missing.
change "You want to the name of a method..."
to "You want to put the name of a method..."
|
Anonymous |
|
Printed |
Page 339
Text under Problem |
There's a word missing.
change "You want to the name of a method..."
to "You want to put the name of a method..."
|
Anonymous |
|
Printed |
Page 339
Last paragraph |
The last paragraph on the page describes the Method#arity method, but the example that follows does not illustrate it.
|
Celso Frazao |
Mar 10, 2009 |
Printed |
Page 339
Last paragraph |
The last paragraph on the page describes the Method#arity method, but the example that follows does not illustrate it.
|
Celso Frazao |
Mar 10, 2009 |
Printed |
Page 341
code at the top of the page |
Although it doesn't change anything, I think the 5th line of code at the top of the page should be changed from:
Welcomer.method("an_instance_method")
to
Welcomer.method("an_instance_method").call
|
Anonymous |
|
Printed |
Page 341
code at the top of the page |
Although it doesn't change anything, I think the 5th line of code at the top of the page should be changed from:
Welcomer.method("an_instance_method")
to
Welcomer.method("an_instance_method").call
|
Anonymous |
|
Printed |
Page 351
code appearing inside the Problem section |
The following code:
class RGBColor(red=0, green=0, blue=0)
@red = red
@green = green
@blue = blue
end
generates the following syntax errors:
syntax error, unexpected '
', expecting tCOLON2 or '[' or '.'
syntax error, unexpected kEND, expecting $end
I believe the correct syntax for the above code is the following:
class RGBColor
def initialize(red=0, green=0, blue=0)
@red = red
@green = green
@blue = blue
end
end
|
Anonymous |
|
Printed |
Page 351
code appearing inside the Problem section |
The following code:
class RGBColor(red=0, green=0, blue=0)
@red = red
@green = green
@blue = blue
end
generates the following syntax errors:
syntax error, unexpected '
', expecting tCOLON2 or '[' or '.'
syntax error, unexpected kEND, expecting $end
I believe the correct syntax for the above code is the following:
class RGBColor
def initialize(red=0, green=0, blue=0)
@red = red
@green = green
@blue = blue
end
end
|
Anonymous |
|
Printed |
Page 368
5th line from the top of the page |
There's a blank space missing between the word "must" and "satisfy".
change at the end of the 5th line of code
".... '#{method}' must" +
to
".... '#{method}' must " +
|
Anonymous |
|
Printed |
Page 368
5th line from the top of the page |
There's a blank space missing between the word "must" and "satisfy".
change at the end of the 5th line of code
".... '#{method}' must" +
to
".... '#{method}' must " +
|
Anonymous |
|
Printed |
Page 373
Code at the bottom of the page |
The following is wrong:
invalid_xml = %{
<groceries>
<bread>Wheat
}
(valid_xml?(invalid_xml) == nil)
According to the book, the above is supposed to return
# => false, # That is, it is "valid"
That is wrong. The valid_xml?(invalid_xml) returns nil.
As such, the following statement does not work:
REXML::Document.new(invalid_xml).write
However, the following does work
REXML::Document.new(good_xml).write
|
Anonymous |
|
Printed |
Page 373
Code at the bottom of the page |
The following is wrong:
invalid_xml = %{
<groceries>
<bread>Wheat
}
(valid_xml?(invalid_xml) == nil)
According to the book, the above is supposed to return
# => false, # That is, it is "valid"
That is wrong. The valid_xml?(invalid_xml) returns nil.
As such, the following statement does not work:
REXML::Document.new(invalid_xml).write
However, the following does work
REXML::Document.new(good_xml).write
|
Anonymous |
|
Printed |
Page 379
1st line of code under Discussion |
The following code is incorrect:
red_fish = doc.children[0].children[3].children[1].children[1]
The correct code is the following:
red_fish = doc.children[1].children[3].children[1].children[1]
Note: doc.children[0] refers to the text '
' (i.e., the newline between "%{" and "<acquarium>" specified in the assignment to the variable xml on the top of page 378)
|
Anonymous |
|
Printed |
Page 379
1st line of code under Discussion |
The following code is incorrect:
red_fish = doc.children[0].children[3].children[1].children[1]
The correct code is the following:
red_fish = doc.children[1].children[3].children[1].children[1]
Note: doc.children[0] refers to the text '
' (i.e., the newline between "%{" and "<acquarium>" specified in the assignment to the variable xml on the top of page 378)
|
Anonymous |
|
Printed |
Page 380
3rd line of code from top of page |
doc.children[0] is wrong
doc.children[1] is correct
doc.children[0] returns => "
"
doc.children[1] returns => <acquarium> ... </>
|
Anonymous |
|
Printed |
Page 380
3rd line of code from top of page |
doc.children[0] is wrong
doc.children[1] is correct
doc.children[0] returns => "
"
doc.children[1] returns => <acquarium> ... </>
|
Anonymous |
|
Printed |
Page 391
Second line |
second line:
require
causes exception;
ArgumentError: wrong number of arguments (0 for 1)
Probably a misprint - should be eliminated????
|
Anonymous |
|
Printed |
Page 391
Second line |
second line:
require
causes exception;
ArgumentError: wrong number of arguments (0 for 1)
Probably a misprint - should be eliminated????
|
Anonymous |
|
Printed |
Page 450
Last paragraph of the introduction of chapter 13 (URL/references) |
The 2nd URL seems to be:
http://wiki.rubyonrails.org/rails/pages/ActiveRecord
instead of:
http://wiki.rubyonrails.org/show/ActiveRecord
9460) Heading reads Discussion, but probably should be Solution.
|
Anonymous |
|
Printed |
Page 508
2nd paragraph (code listing) |
The code gives an example how one could run many DNS queires in parallel. Unfortunately this code doesn't close the connection. This is now Problem in the example, but could lead to serious problems, if run for more then the 26 queries in the example.
|
Anonymous |
|
Printed |
Page 508
2nd paragraph (code listing) |
The code gives an example how one could run many DNS queires in parallel. Unfortunately this code doesn't close the connection. This is now Problem in the example, but could lead to serious problems, if run for more then the 26 queries in the example.
|
Anonymous |
|
Printed |
Page 558
Invocation line after $ cd status |
Invocation "./script/generate controller status index" should be
"ruby script/generate controller status index"
Similar error on p.559 where "./script/server" should be
"ruby script/server"
|
Anonymous |
|
Printed |
Page 558
Invocation line after $ cd status |
Invocation "./script/generate controller status index" should be
"ruby script/generate controller status index"
Similar error on p.559 where "./script/server" should be
"ruby script/server"
|
Anonymous |
|
Printed |
Page 575
4th paragraph (code) |
In the last code of recipe 15.7, "require 'active_support/core_ext'" should be replaced by "require 'active_support'".
If "core_ext" is directly loaded, the search path will not be correctly set and "xml_simple" will not be found. Actually "active_support" will automatically load "active_support/core_ext".
So the correct requires are:
require 'rubygems'
require 'active_support'
|
Anonymous |
|
Printed |
Page 575
4th paragraph (code) |
In the last code of recipe 15.7, "require 'active_support/core_ext'" should be replaced by "require 'active_support'".
If "core_ext" is directly loaded, the search path will not be correctly set and "xml_simple" will not be found. Actually "active_support" will automatically load "active_support/core_ext".
So the correct requires are:
require 'rubygems'
require 'active_support'
|
Anonymous |
|
Printed |
Page 577
Third block of code on the page (creation of the view for user/login). |
Note, I am Using Ruby 1.9.1 with Rails 2.3.4. This was tested and verified on Mac OS X Snow Leopard (I also tried the Apple provided Ruby 1.8.7) and Fedora 11 using both the Mongrel and WEBrick servers. The project has the complete code from recipes 15.6 and 15.8.
First Bug;
Near the bottom of the page where the reader is creating the view for mywebapp/user/login, "flash" is incorrectly printed as "@flash" four times. This results in Ruby recognizing flash (in the view) as a variable and not a method of ActionController. Since there is no defined variable @flash this error results in an unexpected nil object error for the login action. The correction is simple, remove the '@' before each "flash" and the project runs as expected, or it would if not for a second bug...
The actual code is as follows:
<% if @flash[:message] %><div><%= @flash[:message] %></div><% end %>
<% if @flash[:error] %><div><%= @flash[:error] %></div><% end %>
The code should read:
<% if flash[:message] %><div><%= flash[:message] %></div><% end %>
<% if flash[:error] %><div><%= flash[:error] %></div><% end %>
This also invalidates the explanation paragraph directly below as it is incorrect in referring to the "instance variable" @flash as a "hashlike object" which does not actually exist as we never declared an "@flash" rather, the "flash" method of ActionController is a "hashlike object"...
Second Bug:
After performing the corrections in the first bug, Ruby also chokes on the lines "<%= form_tag :action => 'process_login' %>" and "<% end_form_tag %>". For both lines, you no longer need the equals sign after the opening eRB tag. "end_form_tag" was removed in Rails 2, "end" is simply used. You also need a "do" after the form tag declaration.
The code is as follows:
<%= form_tag :action => 'process_login' %>
Username: <%= text_field "user", "username" %>

Password: <%= text_field "user", "password" %>

<%= submit_tag %>
<%= end_form_tag %>
The code should read:
<% form_tag :action => 'process_login' do %>
Username: <%= text_field "user", "username" %>

Password: <%= text_field "user", "password" %>

<%= submit_tag %>
<% end %>
Ruby 1.9.1, after fixing both errors, will still give the error "undefined method `^' for "?":String" (note it will not be a question mark but a letter). This is a Ruby 1.9.1 incompatibility issue. It has to do with Ruby now returning a character instead of the character code for string[index]. After a little exploration I came up with a simple fix. On a Mac and Linux system with an unmodified install prefix (assumes a source compile) the path to culprit file is "/usr/local/lib/ruby/gems/1.9.1/gems/activesupport-2.3.4/lib/active_support/message_verifier.rb". Modify line 46 to read "result |= a[i].ord ^ b[i].ord" and everything will work fine.
|
MasterStarman |
Nov 02, 2009 |
Printed |
Page 579
Last code block. |
It should be mentioned that if using Ruby 1.9 you need to require "digest/sha1" instead of just "sha1".
|
MasterStarman |
Nov 02, 2009 |
Printed |
Page 595,596,597
all code containing 'form_tag' and 'form_for' |
form_tag and form_for always go inside "<% %>" tags AFAIK. They used to go
into "<%= %>" tags, tho I don't remember when this change took place (somewhere
between AWDR v. 1 and v.2)
|
Anonymous |
|
Printed |
Page 595,596,597
all code containing 'form_tag' and 'form_for' |
form_tag and form_for always go inside "<% %>" tags AFAIK. They used to go
into "<%= %>" tags, tho I don't remember when this change took place (somewhere
between AWDR v. 1 and v.2)
|
Anonymous |
|
Printed |
Page 616
Recipe 14.5 |
Recipe 14.5 doesn't work. Executing puts SimpleMailer.create_simple_message('lucas@example.com') returns
undefined method 'create_simple_message'
|
Enrique Condes |
Mar 29, 2013 |
Printed |
Page 630
Recipe 16.7. Using a WSDL File to Make SOAP Calls Easier |
I got this book to help with SOAP/WSDL issues in Ruby, and Recipe 16.7 is great,
but Google is no longer issuing keys for this API, so I can't try it out to try
to figure out why it is working and my code isn't.
Is an update to this recipe going to be posted using some other web service?
(e.g. Amazon)
|
Anonymous |
|
Printed |
Page 630
Recipe 16.7. Using a WSDL File to Make SOAP Calls Easier |
I got this book to help with SOAP/WSDL issues in Ruby, and Recipe 16.7 is great,
but Google is no longer issuing keys for this API, so I can't try it out to try
to figure out why it is working and my code isn't.
Is an update to this recipe going to be posted using some other web service?
(e.g. Amazon)
|
Anonymous |
|
Printed |
Page 637
2nd complete code block |
On site 637 th following code is printed:
"DRb.start_service('druby://127.0.0.1:61676', Threadsafe.new)
But on site 636 the class is defined as ThreadsafeHash
|
Anonymous |
|
Printed |
Page 637
2nd complete code block |
On site 637 th following code is printed:
"DRb.start_service('druby://127.0.0.1:61676', Threadsafe.new)
But on site 636 the class is defined as ThreadsafeHash
|
Anonymous |
|
Printed |
Page 662
Solution |
During the third run of the divide.rb script, the error output says the script
that errored was 'divide_buggy.rb' in three spots of the exception.
In effect, the calling script and erroring script should be the same. Like such:
$ ruby -d divide.rb
Dividing 53 by 0
Exception `ZeroDivisionError' at divide.rb:6 - divided by 0
divide.rb:6:in `/': divided by 0 (ZeroDivisionError)
from divide.rb:6
|
Anonymous |
|
Printed |
Page 662
Solution |
In order to get the results described by --debug switch, the user must pass the
switch to Ruby and not the script.
All instances that look like '$ ./divide.rb --debug' should be
'$ ruby --debug divide.rb' otherwise the interpreter never enters the debug state.
|
Anonymous |
|
Printed |
Page 662
Solution |
During the third run of the divide.rb script, the error output says the script
that errored was 'divide_buggy.rb' in three spots of the exception.
In effect, the calling script and erroring script should be the same. Like such:
$ ruby -d divide.rb
Dividing 53 by 0
Exception `ZeroDivisionError' at divide.rb:6 - divided by 0
divide.rb:6:in `/': divided by 0 (ZeroDivisionError)
from divide.rb:6
|
Anonymous |
|
Printed |
Page 662
Solution |
In order to get the results described by --debug switch, the user must pass the
switch to Ruby and not the script.
All instances that look like '$ ./divide.rb --debug' should be
'$ ruby --debug divide.rb' otherwise the interpreter never enters the debug state.
|
Anonymous |
|
Printed |
Page 760
Second code excerpt in the Solution |
The code given completes straightaway, not after 5 seconds as described in the
text and simulated output.
Either change the described output to fit the code, or change the code to fit the
output -- perhaps like this:
start_time = Time.now
|
Anonymous |
|
Printed |
Page 760
Second code excerpt in the Solution |
The code given completes straightaway, not after 5 seconds as described in the
text and simulated output.
Either change the described output to fit the code, or change the code to fit the
output -- perhaps like this:
start_time = Time.now
|
Anonymous |
|
Printed |
Page 763-4
all sample code for recipe 20.7 |
The code for recipe 20.7 does not run as intended when using Ruby 1.9+. It throws no exceptions, but also give no output. It runs well under 1.8.7. I have attempted to debug, but cannot determine what changes, if any, are needed to successfully run under 1.9.1.
|
Joshua Smith |
Sep 02, 2011 |
Printed |
Page 764
2nd code block (line 54 in source file) |
The code runs as presented, but if you run the block over 5 times - like this:
1.upto(8) do |i| # <-- changed from 5
pool.dispatch(i) do |i|
print "Job #{i} started.
"
sleep(5-i) # <-- the bug
print "Job #{i} complete.
"
end
end
You get something like:
johnperkins:compare_files jperkins$ ruby thread_test.rb
Job 1 started.
Job 2 started.
Job 3 started.
Pool is full; waiting to run 4...
Pool is full; waiting to run 5...
Pool is full; waiting to run 6...
Pool is full; waiting to run 7...
Pool is full; waiting to run 8...
Job 3 complete.
Job 4 started.
Job 2 complete.
Job 5 started.
Job 5 complete.
Job 4 complete.
Job 7 started.
Exception `ArgumentError' at thread_test.rb:54 - time interval must be positive
Exception in thread #<ThreadPool:0x262b4>: time interval must be positive
Job 6 started.
Exception `ArgumentError' at thread_test.rb:54 - time interval must be positive
Exception in thread #<ThreadPool:0x262b4>: time interval must be positive
Job 8 started.
Exception `ArgumentError' at thread_test.rb:54 - time interval must be positive
Exception in thread #<ThreadPool:0x262b4>: time interval must be positive
Job 1 complete.
johnperkins:compare_files jperkins$
Apparently time travel is an ArgumentError.
|
Anonymous |
|
Printed |
Page 764
2nd code block (line 54 in source file) |
The code runs as presented, but if you run the block over 5 times - like this:
1.upto(8) do |i| # <-- changed from 5
pool.dispatch(i) do |i|
print "Job #{i} started.\n"
sleep(5-i) # <-- the bug
print "Job #{i} complete.\n"
end
end
You get something like:
johnperkins:compare_files jperkins$ ruby thread_test.rb
Job 1 started.
Job 2 started.
Job 3 started.
Pool is full; waiting to run 4...
Pool is full; waiting to run 5...
Pool is full; waiting to run 6...
Pool is full; waiting to run 7...
Pool is full; waiting to run 8...
Job 3 complete.
Job 4 started.
Job 2 complete.
Job 5 started.
Job 5 complete.
Job 4 complete.
Job 7 started.
Exception `ArgumentError' at thread_test.rb:54 - time interval must be positive
Exception in thread #<ThreadPool:0x262b4>: time interval must be positive
Job 6 started.
Exception `ArgumentError' at thread_test.rb:54 - time interval must be positive
Exception in thread #<ThreadPool:0x262b4>: time interval must be positive
Job 8 started.
Exception `ArgumentError' at thread_test.rb:54 - time interval must be positive
Exception in thread #<ThreadPool:0x262b4>: time interval must be positive
Job 1 complete.
johnperkins:compare_files jperkins$
Apparently time travel is an ArgumentError.
|
Anonymous |
May 15, 2008 |