We try to keep our books accurate, but sometimes mistakes creep
in. This page lists the errors submitted by our astute readers.
If you've found a new error, please
submit it.
The latest version of the book is P4.0,
released 6 months ago.
If you've bought a PDF of the book and would like to upgrade
it to this version (for free), visit your
home page.
| PDF |
Paper |
Description |
Found in |
Fixed in |
| 1 |
|
#45084: From Kado: a comment about "private" on the book:
there is one exception: it's "setter" method.
"setter" always need "self" as literal.
def setter=(val)
p val
end
private :Setter=
def getter
p 123
end
private :getter
self.setter=(123) # => 123
self.getter # => NoMethodError--Paolo Perrotta #45084: From Kado: a comment about "private" on the book:
there is one exception: it's "setter" method.
"setter" always need "self" as literal.
...more...
|
P2.0
17-Sep-10
|
|
| 1 |
|
#49692: Mention (from the BasicObject documentation):
"BasicObject does not include Kernel (for methods like puts) and BasicObject is outside of the namespace of the standard library so common classes will not be found without a using a full class path. ... Access to classes and modules from the Ruby standard library can be obtained in a BasicObject subclass by referencing the desired constant from the root like ::File or ::Enumerator."--Paolo Perrotta #49692: Mention (from the BasicObject documentation):
"BasicObject does not include Kernel (for methods like puts) and BasicObject is outside of the ...more...
|
P3.0
15-Aug-12
|
|
|
1 |
#46235: One reader complained that the ToC is useless. Any ways to make it more informative?--Paolo Perrotta
|
P2.0
14-Jan-11
|
|
| 1 |
|
#48047: (from @jonclaus) The methods/dynamic_definition.rb code example in Chapter 5 didn't convey define_method's power or a reason to use it over the def built-in.--Paolo Perrotta #48047: (from @jonclaus) The methods/dynamic_definition.rb code example in Chapter 5 didn't convey define_method's power or a reason to use it over th ...more...
|
P3.0
26-Nov-11
|
|
| 1 |
|
#47041: Rewrite the Methods chapter to talk about the trade-offs of Ghost Methods vs. Dynamic Methods. Show the two main Ghost Method spells (the "difficult" case of Dynamic Proxy and a new spell, maybe named Convenience Ghost, for cases when you use method_missing() for convenience reasons). End by picking Dynamic Methods in the main example over Ghost Methods.--Paolo Perrotta #47041: Rewrite the Methods chapter to talk about the trade-offs of Ghost Methods vs. Dynamic Methods. Show the two main Ghost Method spells (the "dif ...more...
|
P2.0
10-May-11
|
|
|
41 |
#44209: It might be useful to discuss the way that Dynamic Dispatch relates to Second-order predicates in mathematical logic.--Rich Morin
Paolo Perrotta says: (UPDATE: I decided to skip this.)
I considered this for the second edition. However, athough the discussion would be interesting, I don't want to add to this already long chapter. Same reason why I didn't really discuss all the interesting stuff about functional programming in the Blocks chapter. Thanks for the suggestion anyway, Rich.
|
P1.0
21-Jul-10
|
|
|
47 |
#46467: "Note that define_method() is executed inside the definition of Computer..."
As the author noted, that should be:
"Note that define_component() is executed inside the definition of Computer.."
...which refers to the last three lines of the class--the lines where define_component() is called--not the definition of define_component().
However, why is that class method approach even taken? Why not simplify the example and call define_component() from inside initialize()? Inside initialize() self is the object, and if you called define_component() inside initialize(), then define_component() could be defined as a regular instance method.
Regressing for a moment, what the text fails to mention is that Module#define_method() is a *private* method. As the text explained earlier, private methods cannot be called explicitly by an object--private methods have to be called without a "receiver". And when a private method is called, the receiver becomes whatever self is at that moment.
Now, because the goal is to define regular instance methods inside the Computer class using define_method(), when we call define_method(), at that instant self must be Computer. If self isn't Computer, then define_method() won't create instance methods in the Computer class.
When is self equal to Computer? Inside a class method! When a class is used to call a method, inside the method self is the class. That is exactly analogous to when you call an instance method with an instance/object of the class--inside the method, self is the instance/object.
As a result, if you create a wrapper method around define_method() and you make the wrapper method a class method, then the receiver for define_method() will be Computer, and Computer will be populated with regular instance methods.--7stud #46467: "Note that define_method() is executed inside the definition of Computer..."
As the author noted, that should be:
"Note that define_comp ...more...
Paolo Perrotta says: It might be worth it to streamline the example as you suggest, but I still like the "inside definition" approach of the example. I'll think harder about this in a possible next edition. Thanks!
|
P1.0
24-Feb-11
|
|
| 48 |
|
#50375: In the last paragraph, last sentence, you have an extra "-" between "get" and "ListUser()" in the Flickr#tags_getListUser() method reference.--Kim Shrier
Paolo Perrotta says: Fixed. Thanks.
|
P4.0
13-Dec-12
|
|
| 56 |
|
#41959: Hi Paola, I am learning a lot from the book! Great content! A suggestion for the "The Top Level" sidebar: I would extend this a bit to mention irb subsessions which allow you to change the value of self used by the interpreter. You might also mention that this is a convenient technique for exercising private methods:
irb(main):007:0> s = "abc"
=> "abc"
irb(main):008:0> s.private_methods
=> ["rand", ... ]
irb(main):009:0> s.rand
NoMethodError: private method `rand' called for "abc":String
from (irb):9
from :0
irb(main):010:0> irb s
irb#1(abc):001:0> rand
=> 0.181140548984387
--Greg Krimer #41959: Hi Paola, I am learning a lot from the book! Great content! A suggestion for the "The Top Level" sidebar: I would extend this a bit to mention ...more...
Paolo Perrotta says: Thanks for the suggestion, Greg. I considered this for the second edition, but I decided that it would end up adding more text to an already long section.
|
B1.5
31-Dec-09
|
|
|
65 |
#50164: When the ^__ methods get added to the regex in more_blank.rb, the regex gets a little looser in other respects. The resultant regex does match respond_to?, but only because it matches the respond_t part (since the ? isn't escaped). Also, the anchors got stripped from the final two method names.
I would probably use something like /^(?:__.*|method_missing|respond_to\?)$/. Others might use /^__|^method_missing$|^respond_to\?$/ or /^__|^(?:method_missing|respond_to\?)$/. My preference is for the first alternative since I find it the most explicit. The .* makes it clear that I mean __ followed by anything, I have one ^ and one $ at their respective ends of the regex and they are always used so I don't have to waste cycles figuring out if I'm missing them somewhere or if they were omitted from one of the alternatives on purpose.
--Toby Ovod-Everett
toby@ovod-everett.org--Toby Ovod-Everett #50164: When the ^__ methods get added to the regex in more_blank.rb, the regex gets a little looser in other respects. The resultant regex does matc ...more...
|
P3.0
15-Nov-12
|
|
| 73 |
|
#51433: In the method_missing definition, args[0] is being passed in the @data_source.send call. However, the various methods being called actually need the @id (as seen in previous pages/revs). Is there something I'm missing here? This implementation seems to imply that one must call my_computer.cpu 42 in order to get the cpu info for computer 42. But, the example farther down the page does not show an id being passed in the my_computer.cpu call. #51433: In the method_missing definition, args[0] is being passed in the @data_source.send call. However, the various methods being called actually n ...more...
|
P4.0
01-May-13
|
|
| 89 |
|
#50506: in the redflag.rb:
Dir.glob('*events.rb').each do |file|
load file
each_event do |name, event|
the line above should be:
each_event do |event|
since the define_method :each_event above specifies only 1 block paramater. --thomas winn #50506: in the redflag.rb:
Dir.glob('*events.rb').each do |file|
load file
each_event do |name, event|
the line above should be:
each_ ...more...
Paolo Perrotta says: Those are the arguments to the block, not define_method. The block gets passed on and is ultimately called here, with two arguments:
events.each_pair do |name, event|
block.call name, event
end
So it must be a block that takes two arguments.
|
P4.0
22-Jan-13
|
|
| 90 |
|
#50131: the switch from "info = @data_source.send("get_#{name}_info", @id)" to "info = @data_source.send("get_#{name}_info", args[0])" in chapter Methods is a bit confusing. Kado suggested changing everything to the @id form, which I did - but as a result, the *args argument of method_missing() is never really used. I should find a way to make this less confusing in the next edition.
--Paolo Perrotta #50131: the switch from "info = @data_source.send("get_#{name}_info", @id)" to "info = @data_source.send("get_#{name}_info", args[0])" in chapter Meth ...more...
|
P3.0
04-Nov-12
|
|
|
96 |
#48358: At the beginning of section 3.7, the boss writes a `test_events.rb` file that includes two events, both of which get triggered. The example would be more complete if it also had an event that did not get triggered, e.g.
event "Everything is OK!" do
@sky_height > @mountain_height
end
--Katrina Owen #48358: At the beginning of section 3.7, the boss writes a `test_events.rb` file that includes two events, both of which get triggered. The example wo ...more...
|
P2.0
18-Dec-11
|
|
|
98 |
#43087: The 'lambda.call' solution does not seem to clear the setups and events variables for each new events file, whereas the previous solution on page 97 did. #43087: The 'lambda.call' solution does not seem to clear the setups and events variables for each new events file, whereas the previous solution on p ...more...
Paolo Perrotta says: I think that the lambda example gets its point across (you can have a shared local scope in lambda), even if it's not isofunctional to the previous example. However, you're right that this difference in behavior should be stressed. At this point I'd rather reconsider the entire example, though - piling up more notes and distinctions on it would just make it more confusing. I'll save your (very good) suggestion for the next edition of the book.
|
P1.0
04-May-10
|
|
|
98 |
#48359: "[setups and events are] evaluated in the context of an `Object` that acts as a _Clean Room_".
It would be very helpful if the example on page 96 failed if you don't use a Clean Room. In the current version, it works if you use `block.call` for both setups and events.
Blocks are somewhat mind-bending, so it would be extremely useful to have an extensive failing test suite to force the reader to understand the subtleties and implications.--Katrina Owen #48359: "[setups and events are] evaluated in the context of an `Object` that acts as a _Clean Room_".
It would be very helpful if the example on p ...more...
|
P2.0
18-Dec-11
|
|
| 120 |
|
#41771: The test cases for the redflag example are too simple to preclude a number of more simplistic solutions to the problem. In particular there's nothing that requires the "clean room" approach, e.g.., nothing in those test cases fails if you just put everything at the top level scope:
@events = Hash.new
@setups = []
def event(name, &block)
@events[name] = block
# puts "ALERT: #{name}" if yield
end
def setup(&block)
@setups << block
end
Dir.glob('*events.rb').each do |file|
load file
@events.each do |name, event|
@setups.each { |setup| setup.call }
if event.call
puts "ALERT: #{name}"
end
end
end
I realize that you've just discussed things like clean room and instance_eval, so the reader might be inclined to use them, but it would be nice if the tests pushed the reader in that direction.--Nic McPhee #41771: The test cases for the redflag example are too simple to preclude a number of more simplistic solutions to the problem. In particular there's ...more...
|
B1.5
10-Dec-09
|
|
| 123 |
|
#42023: I like your example answer ( blocks/monitor_framework/redflag.rb ) but I see some issues ... I'm sorry if I'm wrong in my assumptions.
- The event names could collide, silently. I know this is just a sample ( that you quickly replace but it was the first thing that popped into my head and distracted me from the following code for a while ).
- All of the setup blocks are iterated for each event in cleanroom objects, it really doesn't just remove the "global" nature of the @variables in the setup blocks, it removes their shared nature between events.--Jeff Wood #42023: I like your example answer ( blocks/monitor_framework/redflag.rb ) but I see some issues ... I'm sorry if I'm wrong in my assumptions.
- Th ...more...
Paolo Perrotta says: Jeff, your assumptions are definitely valid. See erratum #43087 - if I ever write a second edition of the book, I'll reconsider the entire example. At the current stage, I'd rather keep it as it is, with dark corners and everything, than pile up more notes on it.
|
B1.5
08-Jan-10
|
|
|
126 |
#45413: In the GUT, rule 6 needs a little hint that the class of a class object will be class Class at the top of the eigenclass chain. Seeing figure 4.6 made rule 6 clear. The placement of the object Class isn't mentioned until figure 4.6, which is a page too late (in v1.0). --Fred Nixon #45413: In the GUT, rule 6 needs a little hint that the class of a class object will be class Class at the top of the eigenclass chain. Seeing figure ...more...
Paolo Perrotta says: This would be best fixed by adding Class in figure 4.5. Re-doing a picture is a pretty big change, outside the scope of a reprint - so it'll have to wait until a second edition. Thank you for telling me.
|
P1.0
20-Oct-10
|
|
|
135 |
#44211: A third problem with the Around Alias is that it pollutes the name space and might clash with an existing or future name.
Why not present the alternative formulation which captures a reference to the old method in a variable and uses that in the wrapped call?--Rich Morin #44211: A third problem with the Around Alias is that it pollutes the name space and might clash with an existing or future name.
Why not present t ...more...
Paolo Perrotta says: Good point, Rich. This will come useful in the second edition.
|
P1.0
21-Jul-10
|
|
| 147 |
|
#50386: In the paragraph right after the code fragment for mere_cache/merb_ext/controller.rb, second sentence, there is a "-" between "Class" and "Methods" that shouldn't be there.--Kim Shrier #50386: In the paragraph right after the code fragment for mere_cache/merb_ext/controller.rb, second sentence, there is a "-" between "Class" and "Met ...more...
Paolo Perrotta says: Fixed. Thanks.
|
P4.0
16-Dec-12
|
|
|
148 |
#47913: From pwim on Twitter: "4.5 Quiz: Module Trouble seems to fall outside of The Great Unified Theory. Is including modules not part of the object model?". Good point, the "theory" list needs to talk about module inclusion.--Paolo Perrotta #47913: From pwim on Twitter: "4.5 Quiz: Module Trouble seems to fall outside of The Great Unified Theory. Is including modules not part of the object ...more...
|
P3.0
07-Nov-11
|
|
|
149 |
#43256: The author suggests that you can't support methods that accept blocks, such as Array#find, with dynamic dispatch, and thus you'll need to resort to eval(). I don't agree; I've only been reading up on Ruby for a month so maybe I'm missing something? Surely the ability to convert a block into a Proc by having a third argument to a method with a preceding '&', and then from this Proc to the block required by find() etc with another, allows this?
def explore_array(method,*args,&block)
['a','b','c'].send(method,*args,&block)
end
a = explore_array(:find,[]) do |x|
x == 'b'
end
p (a == 'b' ? "Book wrong - you can" : "Book right - you can't") + " support blocks without eval" # => Book wrong - you can support blocks without eval
Fantastic book either way, it's almost brought me to an understanding of eigenclases, I've got that good brain ache feeling :)
Cheers,
Tim Ruffles--Tim Ruffles #43256: The author suggests that you can't support methods that accept blocks, such as Array#find, with dynamic dispatch, and thus you'll need to reso ...more...
Paolo Perrotta says: Thank you for your comments Tim. :) About the item you reported, I wasn't clear enough in the book. This example assumes that somebody is putting the method name, arguments and (eventually) the block on a web page. If you don't care about blocks, then your user can just insert the name of a method and the values of arguments - but if you want to also allow your user to input a block, then you can only capture the content of the block as a string. If you do that, then you have to use eval() to pass that string on to the Array method. A tad confusing in hindsight. I'll probably find a clearer way to express it in a next edition of the book.
|
P1.0
15-May-10
|
|
|
152 |
#49936: In the proc{ ... }.call, the $SAFE works differently from normal global variable. I wrote a simple test like this:
$ABC = 'abc'
puts $ABC # abc
proc {
$ABC = 'cde'
puts $ABC # cde
}.call
puts $ABC # cde
Why is $SAFE different? I hope you can talk about it in the book.
I would appreciate if you can tell me why.
My email is: yzhang.wa@gmail.com
Thanks,
Yi Zhang--Yi Zhang #49936: In the proc{ ... }.call, the $SAFE works differently from normal global variable. I wrote a simple test like this:
$ABC = 'abc'
puts $ ...more...
Paolo Perrotta says: Thanks for the question, Yi Zhang - the answer is: I don't know. :) This seems to be an additional topic worth considering in the next edition. Thank you!
|
P2.0
09-Oct-12
|
|
| 175 |
|
#42010: The text says, "It [erb] ... also creates a Clean Room (109) to execute the code in a separate scope." P. 109 shows how to create a clean room by calling instance_eval on an object; p. 122 uses that technique again. I don't see that happening in the ERB snippet at the top of p. 175. Is this code using a different method of making a clean room? Is the instance of ERB the clean room?
--Wayne Conrad #42010: The text says, "It [erb] ... also creates a Clean Room (109) to execute the code in a separate scope." P. 109 shows how to create a clean roo ...more...
|
B1.5
05-Jan-10
|
|
| 184 |
|
#43561: Similar to comment #41674, I'm confused about all this extra machinery. I don't see why module/mixin authors must go through such ridiculous contortions to make mixins. Ruby provides both include(foo) and extend(foo), and it seems silly to me that the whole point of all the included() hooks is just to turn around and call extend. The thing being extended is calling include! So why doesn't the API author just say "please call 'extend BlubberMixin' to get access to Blubber"?--Seth Arnold #43561: Similar to comment #41674, I'm confused about all this extra machinery. I don't see why module/mixin authors must go through such ridiculous c ...more...
Paolo Perrotta says: The reason is that this is actually a common pattern in the wild - in particular, Rails usues it a lot. I'm not very enthusiastic about all of this complication either, and apparently neither are the Rails authors, because they changed it in Rails 3. However, the book heavily uses Rails 2 as an example in the second part, so it has to explain what's going on. I'll consider removing this description in a second edition of the book. [Update: I'm working on the second edition, and removing this spell is on the to-do list]
|
B1.5
05-Jun-10
|
|
| 243 |
|
#50218: `a ||= []` is not equivalent to `a || (a = [])`
`a || (a = [])` will throw a "undefined local variable or method 'a'"
The correct equivalent is `a = (a || [])`
--Dean Holdren #50218: `a ||= []` is not equivalent to `a || (a = [])`
`a || (a = [])` will throw a "undefined local variable or method 'a'"
The correct equivale ...more...
Paolo Perrotta says: Not only did I get this wrong, but the following snippet is wrong as well as a result. I fixed the snippet you refer to, and I replaced the following one with:
if defined?(a) && a
a = a
else
a = []
end
Surprising that nobody had noticed this problem yet. Thank you very much for pointing this out.
|
P3.0
29-Nov-12
|
|
| 243 |
|
#42849: Nill Guards do not work well with booleans.
a = false # a gets initialized
....
a ||= true # initialization gets overwritten
Effectively, it guards both against nil and false.
A pitfall that cost me quit some time, once....
Should be explained more clearly, I think.--Martijn Bak #42849: Nill Guards do not work well with booleans.
a = false # a gets initialized
....
a ||= true # initialization gets overwritten
Effecti ...more...
Paolo Perrotta says: This would make a nice additional sidebar. I'll wait for this kind of large changes until the second edition of the book.
|
P1.0
20-Apr-10
|
|