Metaprogramming Ruby 84
scottl writes "Metaprogramming Ruby is the first book to give an in-depth and readable explanation of how dynamic programming works in Ruby. It is both readable and accurate and will be a valuable resource to intermediate and probably advanced Ruby programmers for some time to come." Keep reading for the rest of scottl's review.
Metaprogramming Ruby is not a book for programmers new to Ruby, but would make an excellent follow on book to either Programming Ruby by Dave Thomas, Chad Fowler, and Andy Hunt or The Ruby Way by Hal Fulton. Both of the above books have chapters on or at least mention metaprogramming, but this is the first full length exposition of it. The book itself is broken into two sections and four appendices. In the first section, you (the reader) is paired with a more experienced programmer for a week, a chapter for each day, and as the week progresses you cover different topics in metaprogramming after being given tasks by your boss. The second section has two chapters on the design and implementation of ActiveRecord from Rails as well as a chapter on safe metaprogramming. Finally, there are three very useful appendices and a bibliography. One other note is that the book has the concept of "spells". Each concept as it is discussed in the book will have a spell associated with it. There will be a note in the sidebar with the name of the spell and the third appendix has the spells listed in alphabetical order, a short example of the spell, and a page number linking back to the extended discussion of the spell.Metaprogramming Ruby | |
author | Paolo Perrotta |
pages | 261 |
publisher | Pragmatic Bookshelf |
rating | 9 |
reviewer | scottl |
ISBN | 978-1-93435-647-0 |
summary | Metaprogramming Ruby is an excellent introduction to dynamic and metaprogramming using Ruby. It will be useful to intermediate and advanced users of Ruby and potentially even to beginners with some programming experience. |
The first chapters are an informal introduction to metaprogramming where the reader, just starting a new job, is paired with Bill, an experienced developer, for a week. Each day is a chapter and each chapter covers a specific topic. The topics, as might be expected, increase in complexity as the week goes on. This more informal style actually works quite well. I had expected to be a bit irritated with the "schtick", but it turns out that Perrotta does not use it to excess. The topics covered here are Monday: The Object Model, Tuesday: Methods, Wednesday: Blocks, Thursday: Class Definitions, and Friday: Code That Writes Code.
Chapter 1 on Monday starts out with you meeting Bill, your experienced pair programmer, on a Monday morning and then goes straight into the Ruby object model. It discusses reopening classes to add additional methods including predefined Ruby classes such as String. It follows up with Monkey Patching (opening an existing class and redefining an existing method) and the pitfalls therein.
In Chapter 2, methods are examined. Perrotta goes over a problem with duplicated code and how to reduce this code by generating and calling code dynamically. He then moves to showing the same example using method_missing(), followed by adding a change to respond_to? to make sure the methods show up.
Wednesday's topic in Chapter 3 covers blocks, lambdas, and procs all of which are really just "callable objects". The chapter starts with a review of blocks. This is followed by a discussion of scopes and how to carry variables through scopes using blocks as closures. Perratto shows how to use instance_eval() to receive blocks and then use them to manipulate scopes. Next, converting blocks into "callable objects", lambdas and Procs, and then calling them later is covered. Finally, there's a short introduction to domain specific languages (DSL) using the the techniques from this chapter.
Chapter 4 or Thursday covers class definitions. A discussion of self and the current class open the chapter. There's also a section on singleton methods and eigenclasses. There are class instance variables, variables that belong to the class and not to a particular object. Examples of class macros, such as attr_reader, attr_writer, and attr_accessor, and how to write them are shown. Finally he covers around aliases where method names can be renamed and then redefined but the original is still available.
The final day of the week, Friday, Chapter 5, goes deep into Ruby metaprogramming with code that writes code. In this chapter, Perrotta shows how to implement an "attr_checked" attribute in a few different ways starting with a kernel method using eval and moving on to passing the validation attributes in a block. Then this gets moved to a class macro (from Chapter 4), and finally moving on to using a module with hooks. This last is a pattern that's seen in many Ruby projects including Rails and two I'm familiar with, Sequel and Ramaze.
The second section, Metaprogramming in Rails, consists of two chapters on ActiveRecord and a final chapter on metaprogramming safely. In the first two chapters, Perrotta takes a tour through
ActiveRecord, the Rails object relational mapper (ORM) and shows how ActiveRecord uses the tips and techniques from the previous chapters. The final chapter on safe metaprogramming discusses how to test metaprogramming and working around and with to make sure that monkey patching doesn't cause problems.
Finally, there are three appendices. The first shows common Ruby idioms that are seen pretty much in all Ruby code. They provide a good review, but I'm not sure how useful they really are for the audience that this book is aimed at. The second appendix is one DSLs. This is also a nice to have, but there's probably not enough to let you program a DSL if you don't have additional help from somewhere. The final appendix really is almost worth the price of the book. It contains a list of metaprogramming "spells". Each of the spells contains a short programming example as well as the page number with the longer explanation. This is incredibly useful when looking at code from any of the major frameworks (some mentioned above) and you don't understand a piece of it. Just by scanning through the spells you can often find a simple version of what you're looking at and then read a longer explanation.
All in all, this is one of the better, more readable programming books that I've read in a long while. Perrotta keeps it to around 250 pages including the appendices and it's packed full of useful information. As I noted above, this book is highly recommended as a second Ruby book. The presentation of metaprogramming is both enjoyable and useful and the book itself is well written.
You can purchase Metaprogramming Ruby from amazon.com. Slashdot welcomes readers' book reviews -- to see your own review here, read the book review guidelines, then visit the submission page.
Hmm (Score:1, Informative)
I don't think most people give a crap about Ruby in general. Why not just use a programming language that does it right?
Not dynamic programming... (Score:4, Informative)
The summary mentions dynamic programming; but this book contains nothing about dynamic programming. (A particular method suitable to problems with optimal substructure that can be used in a subset of cases where recursion can be used and typically generates results very quickly.)
The author, who I've seen speak, instead writes about "metaprogramming" which in my personal opinion is a silly catch phrase to sell talks and books when actually he's just talking about using some of the advanced functionality present in Ruby (and also JavaScript) to do things that would be done with macros or can't be done at all in traditional object oriented and procedural languages.
If you're buying this book thinking it contains some new breakthrough paradigm, and you're already familiar with the ins and outs of Ruby prepare to be disappointed. If your background is Java or C++ and you've just learned enough to get by until now it'll probably be an eye-opener.
Re:Not dynamic programming... (Score:4, Informative)
When the author said dynamic, he was using it to refer to the dynamic language [wikipedia.org] features of Ruby, not dynamic programming.
Re:know your audience (Score:1, Informative)
Its performance is similar to that of python or perl, and it outperforms these similar languages in some benchmarks.
I have put the key word of your quote, benchmarks, in bold.
Whatever benchmarks you've seen, they're probably useless. They don't apply to the real world even in the slightest.
We had to endure the same crap with Java years back. Java advocates would bring out some microbenchmarks showing "huge" performance wins over C and C++. Then we'd deploy some real world Java applications, and they'd be as slow as molasses, and require significant hardware upgrades just to run sort of shitty, rather than full-out complete shitty.
Now we see the Ruby community doing the same thing. Instead of just admitting that their platform is slow, they try to play these mind games with those of us who have real work to get done.
The only thing slower that Java and slower than Ruby is JRuby, which combines the slowness and overhead of both platforms into one of the worst programming environments I've dealt with in years (including far too many years writing COBOL, FORTRAN and PL/1 code).
Re:These techniques are horrid for maintainability (Score:4, Informative)
class Product < ActiveRecord::Base
end
Instantiates a class called 'product' which is a subclass of ActiveRecord::Base (AR::Base). As soon as the <i>act</i> of subclassing AR::Base, occurs, AR::Base has code that infers the name of the database table (in this case 'products') as the singular, lower case version of the subclass' name (Product). Then, it reads the table 'products' from the database, and dynamically adds getters and setters for the name, description, and price attributes.
In addition, AR::Base knows how to respond to a lot of methods whose names aren't known until runtime. Product.find_by_name("Table") will internally invoke "SELECT * FROM PRODUCTS WHERE name = 'Table'" and fetch a Product whose name, description, and price are reflected in the output of that SQL query.
Hence, you can do this on the Ruby console:
>> product = Product.find_by_name("Table")
>> puts product.name
"Table"
>> puts product.description
"This is a table (my description was living inside the database)"
>> puts product.price
$4.29
It's greatly simplified, but metaprogramming allows you to construct classes and objects who <i>present</i> behavior based on run time state.
You really have to dig in and use a language like Ruby for a while to see how powerful this is. If you're worried about the lack of maintainability, then write good tests
Re:Not dynamic programming... (Score:2, Informative)
"dynamic programming" is an overloaded term in the English language. All natural languages have many such terms. Sometimes the meanings are related, sometimes they are completely different. When you have learned a meaning of a term, do not assume that is the sole correct meaning. You risk sounding like a pedant or a fool as a result.