Prepared exclusively for Ron Brown What Readers Are Saying About Metaprogramming Ruby Reading this book was like diving into a new world of thinking. I tried a mix of Java and JRuby metaprogramming on a recent project. Using Java alone would now feel like entering a sword fight carrying only a banana, when my opponent is wielding a one-meter-long Samurai blade. Sebastian Hennebrüder Java Consultant and Trainer, laliluna.de This Ruby book fills a gap between language reference manuals and programming cookbooks. Not only does it explain various meta- programming facilities, but it also shows a pragmatic way of making software smaller and better. There’s a caveat, though; when the new knowledge sinks in, programming in more mainstream languages will start feeling like a chore. Jurek Husakowski Software Designer, Philips Applied Technologies Before this book, I’d never found a clear organization and explanation of concepts like the Ruby object model, closures, DSLs definition, and eigenclasses all spiced with real-life examples taken from the gems we usually use every day. This book is definitely worth reading. Carlo Pecchia Software Engineer I’ve had a lot of trouble finding a good way to pick up these meta- programming techniques, and this book is bar none the best way to do it. Paolo Perrotta makes it painless to learn Ruby’s most complex secrets and use them in practical applications. Chris Bunch Software Engineer Prepared exclusively for Ron Brown Metaprogramming Ruby Program Like the Ruby Pros Paolo Perrotta The Pragmatic Bookshelf Raleigh, North Carolina Dallas, Texas Prepared exclusively for Ron Brown Many of the designations used by manufacturers and sellers t o distinguish their prod- ucts are claimed as trademarks. Where those designations appear in this book, and The Pragmatic Programmers, LLC was aware of a trademark claim, the designations have been printed in initial capi tal letters or in all capitals. The Pragmatic Starter Kit, The Pragmatic Programmer, Pragmatic Programming, Pragmat ic Bookshelf and the linking g device are trademarks of The Pragmatic Programmers, LLC. Every precaution was taken in the preparation of this book. However, the publisher assumes no responsibility for errors or omissions, or for damages that may result from the use of infor mat ion (including program listings) contained herein. Our Pragmatic courses, workshops, and other products can help you and your team create better software and have more fun. For more information, as well as the latest Pragmatic titles, please visit us at http://www.pragprog.com Copyright © 2010 Paolo Perrotta. All rights reserved. No part of this publication may be reproduced, stored in a retrieval system, or transmit- ted, in any form, or by any means, electronic, mechanical, photocopying, recording, or otherwise, without the prior consent of the publisher. Printed in the United States of America. ISBN-10: 1-934356-47-6 ISBN-13: 978-1-934356-47-0 Printed on acid-free paper. P1.0 printing, January 2010 Version: 2010-1-29 Prepared exclusively for Ron Brown To Carlo. Prepared exclusively for Ron Brown Prepared exclusively for Ron Brown Contents Foreword 10 Acknowledgments 11 Introduction 13 The “M” Word . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14 About This Book . . . . . . . . . . . . . . . . . . . . . . . . . . 21 About You . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24 I Metaprogramming Ruby 26 1 Monday: The Object Model 27 1.1 Monday with Bill . . . . . . . . . . . . . . . . . . . . . . 27 1.2 Open Classes . . . . . . . . . . . . . . . . . . . . . . . . 28 1.3 The Truth About Classes . . . . . . . . . . . . . . . . . . 33 1.4 Quiz: Missing Lines . . . . . . . . . . . . . . . . . . . . . 45 1.5 What Happens When You Call a Method? . . . . . . . . 46 1.6 Quiz: Tangle of Modules . . . . . . . . . . . . . . . . . . 56 1.7 Object Model Wrap-Up . . . . . . . . . . . . . . . . . . . 59 2 Tuesday: Methods 60 2.1 A Duplication Problem . . . . . . . . . . . . . . . . . . . 61 2.2 Dynamic Methods . . . . . . . . . . . . . . . . . . . . . . 63 2.3 method_missing() . . . . . . . . . . . . . . . . . . . . . . 71 2.4 Quiz: Bug Hunt . . . . . . . . . . . . . . . . . . . . . . . 82 2.5 More method_missing() . . . . . . . . . . . . . . . . . . . 84 3 Wednesday: Blocks 91 3.1 How to Handle Hump Day . . . . . . . . . . . . . . . . . 92 3.2 Quiz: Ruby# . . . . . . . . . . . . . . . . . . . . . . . . . 93 3.3 Closures . . . . . . . . . . . . . . . . . . . . . . . . . . . 96 3.4 instance_eval() . . . . . . . . . . . . . . . . . . . . . . . . 105 Prepared exclusively for Ron Brown CONTENTS 8 3.5 Callable Objects . . . . . . . . . . . . . . . . . . . . . . . 108 3.6 Writing a Domain-Specific Language . . . . . . . . . . . 116 3.7 Quiz: A Better DSL . . . . . . . . . . . . . . . . . . . . . 118 4 Thursday: Class Definitions 122 4.1 Class Definitions Demystified . . . . . . . . . . . . . . . 123 4.2 Quiz: Class Taboo . . . . . . . . . . . . . . . . . . . . . . 130 4.3 Singleton Methods . . . . . . . . . . . . . . . . . . . . . 132 4.4 Eigenclasses . . . . . . . . . . . . . . . . . . . . . . . . . 137 4.5 Quiz: Module Trouble . . . . . . . . . . . . . . . . . . . 150 4.6 Aliases . . . . . . . . . . . . . . . . . . . . . . . . . . . . 152 4.7 Quiz: Broken Math . . . . . . . . . . . . . . . . . . . . . 157 5 Friday: Code That Writes Code 160 5.1 Leading the Way . . . . . . . . . . . . . . . . . . . . . . . 160 5.2 Kernel#eval . . . . . . . . . . . . . . . . . . . . . . . . . 163 5.3 Quiz: Checked Attributes (Step 1) . . . . . . . . . . . . 173 5.4 Quiz: Checked Attributes (Step 2) . . . . . . . . . . . . 176 5.5 Quiz: Checked Attributes (Step 3) . . . . . . . . . . . . 178 5.6 Quiz: Checked Attributes (Step 4) . . . . . . . . . . . . 179 5.7 Hook Methods . . . . . . . . . . . . . . . . . . . . . . . . 180 5.8 Quiz: Checked Attributes (Step 5) . . . . . . . . . . . . 186 6 Epilogue 188 II Metaprogramming in Rails 189 7 The Design of ActiveRecord 190 7.1 Preparing for the Tour . . . . . . . . . . . . . . . . . . . 191 7.2 The Design of ActiveRecord . . . . . . . . . . . . . . . . 193 7.3 Lessons Learned . . . . . . . . . . . . . . . . . . . . . . 202 8 Inside ActiveRecord 206 8.1 Dynamic Attributes . . . . . . . . . . . . . . . . . . . . . 206 8.2 Dynamic Finders . . . . . . . . . . . . . . . . . . . . . . 214 8.3 Lessons Learned . . . . . . . . . . . . . . . . . . . . . . 219 9 Metaprogramming Safely 224 9.1 Testing Metaprogramming . . . . . . . . . . . . . . . . . 224 9.2 Defusing Monkeypatches . . . . . . . . . . . . . . . . . 232 9.3 Lessons Learned . . . . . . . . . . . . . . . . . . . . . . 237 Report erratum this copy is (P1.0 printing, January 2010) Prepared exclusively for Ron Brown CONTENTS 9 III Appendixes 239 A Common Idioms 240 A.1 Mimic Methods . . . . . . . . . . . . . . . . . . . . . . . 240 A.2 Nil Guards . . . . . . . . . . . . . . . . . . . . . . . . . . 243 A.3 Tricks with Method Arguments . . . . . . . . . . . . . . 244 A.4 Self Yield . . . . . . . . . . . . . . . . . . . . . . . . . . . 248 A.5 Symbol#to_proc() . . . . . . . . . . . . . . . . . . . . . . 249 B Domain-Specific Languages 252 B.1 The Case for Domain-Specific Languages . . . . . . . . 252 B.2 Internal and Extern al DSLs . . . . . . . . . . . . . . . . 254 B.3 DSLs and Metaprogramming . . . . . . . . . . . . . . . 255 C Spell Book 256 C.1 The Spells . . . . . . . . . . . . . . . . . . . . . . . . . . 256 D Bibliography 268 Index 269 Report erratum this copy is (P1.0 printing, January 2010) Prepared exclusively for Ron Brown For ewo rd Ruby inherits characteristics from various languages — Lisp, Small- talk, C, and Perl, to name a few. Metaprogramming comes from Lisp (and Smalltalk). It’s a bit like magic, which makes something astonish- ing possible. There are two kinds of magic: white magic, which does good things, and black magic, which can do nasty things. Likewise, there are two aspects to metaprogramming. If you discipline yourself, you can do good things, such as enhancing the language without tweaking its syntax by macros or enabling internal domain-specific languages. But you can fall into the dark side of metaprogramming. Metaprogramming can confuse easily. Ruby trusts you. Ruby treats you as a grown-up programmer. It gives you great power such as metaprogramming. But you need to remember that with great power comes great responsibility. Enjoy programming in Ruby. matz October 2009 Prepared exclusively for Ron Brown [...]... a Ruby program and say, “This part here is metaprogramming, while this other part is not.” In a sense, metaprogramming is a routine part of every Ruby programmer’s job To be clear, metaprogramming isn’t an obscure art reserved for Ruby gurus, and it’s also not a bolt-on power feature that’s useful only for building something as sophisticated as ActiveRecord If you want to take the path to advanced Ruby. .. enough Ruby to follow the ensuing text If you thought about the for keyword, then 4 5 6 http://www .ruby- lang.org http://jruby.codehaus.org http://www.ironruby.net Report erratum Prepared exclusively for Ron Brown this copy is (P1.0 printing, January 2010) 24 A BOUT Y OU you’re probably new to Ruby In the second case, you can still embark on this metaprogramming adventure—just take an introductory Ruby. .. that those tests distracted from the metaprogramming techniques that are the meat of the book—so the tests fell on the cutting-room floor This doesn’t mean you shouldn’t write tests for your own metaprogramming endeavors! In fact, you’ll find specific advice on testing metaprogramming code in Chapter 9, Metaprogramming Safely, on page 224 Ruby Versions One of the joys of Ruby is that it’s continuously changing... rules, and get answers to your nagging questions Now that you know what metaprogramming is about, you’re ready to dive in this book About This Book Part I, Metaprogramming Ruby, is the core of the book It tells the story of your week in the office, paired with Bill, an experienced Ruby coder: • Ruby s object model is the land in which metaprogramming lives Chapter 1, Monday: The Object Model, on page 27... coding, you’ll find metaprogramming at every step Even if you’re happy with the amount of Ruby you already know and use, you’re still likely to stumble on metaprogramming in your coding travels: in the source of popular frameworks, in your favorite library, and even in small examples from random blogs Until you master metaprogramming, you won’t be able to tap into the full power of the Ruby language There... common, but it can happen with metaprogramming, which pushes Ruby to its limits As I write this text, the latest stable release of Ruby is 1.9.1 and is labeled a “developer” version Developer versions are meant as test beds for new language features, but Ruby 1.9 is generally considered stable enough for real production work—so I used it to write this book You can stick with Ruby 1.8 if you prefer Throughout... the two versions of Ruby The next production version of Ruby is going to be Ruby 2.0, which will likely introduce some big changes At the time of writing this book, this version is still too far away to either worry or rejoice about Once 2.0 comes out, I’ll update the text When I talk about Ruby versions, I’m talking about the “official” interpreter (sometimes called MRI for Matz’s Ruby Interpreter 4... the things you can do with metaprogramming in the Ruby language: • Say you want to write a Ruby program that connects to an external system—maybe a web service or a Java program With metaprogramming, you can write a wrapper that takes any method call and routes it to the external system If somebody adds methods to the external system later, you don’t have to change your Ruby wrapper; the wrapper will... book You can also find an excellent interactive introduction in the Try Ruby! tutorial on http://tryruby.sophrinix.com 7 Report erratum Prepared exclusively for Ron Brown this copy is (P1.0 printing, January 2010) 25 Part I Metaprogramming Ruby Prepared exclusively for Ron Brown Chapter 1 Monday: The Object Model Just glance at any Ruby program, and you’ll see objects everywhere Do a double take, and... two "title" string constants You can solve this problem with way less code if you sprinkle some metaprogramming magic over it.” Enter Metaprogramming At the suggestion of his expert-coder friend, Bob looks for a metaprogramming- based solution He finds that very thing in the ActiveRecord library, a popular Ruby library that maps objects to database tables.2 After a short tutorial, Bob is able to write . fall into the dark side of metaprogramming. Metaprogramming can confuse easily. Ruby trusts you. Ruby treats you as a grown-up programmer. It gives you great power such as metaprogramming. But you. painless to learn Ruby s most complex secrets and use them in practical applications. Chris Bunch Software Engineer Prepared exclusively for Ron Brown Metaprogramming Ruby Program Like the Ruby Pros Paolo. Ron Brown What Readers Are Saying About Metaprogramming Ruby Reading this book was like diving into a new world of thinking. I tried a mix of Java and JRuby metaprogramming on a recent project.