TE
TechEcho
Home24h TopNewestBestAskShowJobs
GitHubTwitter
Home

TechEcho

A tech news platform built with Next.js, providing global tech news and discussions.

GitHubTwitter

Home

HomeNewestBestAskShowJobs

Resources

HackerNews APIOriginal HackerNewsNext.js

© 2025 TechEcho. All rights reserved.

Metaprogramming in Ruby: It’s All About the Self

61 pointsby iveyover 15 years ago

3 comments

patio11over 15 years ago
I often feel, when reading articles like this about programming, that they would be significantly enhanced by telling me why I should care about metaprogramming.<p>It is not obvious to me that there is any value in being able to declare a method on an object via metaprogramming versus just writing the method into the class. If you, like me, have to see obvious value to change your programming practices, let me provide you with a bit of motivation:<p>Metaprogramming allows you to cut down on boilerplate code, making your programs shorter, easier to write, easier to read, and easier to test. Also, it reduces the impact of changes.<p>For example, metaprogramming is used internally to provide a lot of the "magic" that people associate with Rails. You never have to define a find_by_email method in ActiveRecord because just putting an email column on the table causes that method to be automatically generated for you. That saves you perhaps three lines of code in the instant case, but when you start to compound that over several dozen columns on 10 different tables, you're talking about hundreds of lines of negacode.<p>Yeah, great for library writers, right? How do you use this in actual application code? Well, to pick one example from my application: a stupendous portion of the "business logic" involved in my app is creating print jobs. Print jobs have a grab bag of properties associated with them and, every time I implement a new feature, that means they typically get another property (or several). If I had implemented that via adding a new column every time I added a new feature, I'd have to add a new column to my table every week, and it would get progressively harder and harder to manage.<p>Instead, I have a column called options in the table which is just a JSON grab bag. My model class has a hash called default options, which has a bunch of keys representing virtual properties and a bunch of values for what they should take if the user hasn't specified anything. A quick little metaprogramming loop goes over the default options hash and adds getters and setters for those properties, so that they work transparently from the object. (For example, print_job.name = "foo" sets print_job[:options][:name] = "foo".) Another line of code sets the default values at initialization time.<p>This means that adding another property to my print jobs requires adding one entry to that hash, rather than writing a bunch of getters, setters, and dealing with migrating the 100,000 print jobs in the database which don't have a value for it yet. This is <i>extraordinarily</i> powerful in reducing the impact of changes.<p>For example, I recently added color support to my application. This required adding five properties to my print jobs. I just checked in SVN for how much of an impact this had on the printing class -- <i>nine</i> lines. The 35 lines of boilerplate getters/setters I didn't have to add contained exactly no typos, required no test cases, and caused no bugs. The data migration I didn't write caused no downtime. The special cases that don't exist for jobs without color information caused no subtle bugs two weeks later when they fell out of the cache and then got regenerated.<p>[Edited to add: It occurs to me that I have a contrasting example, too. I do Big Freaking Java Enterprise Web Apps at the day job.<p>Recently, we had to add the JSON grab bag approach to our internal framework, because it would allow us to customize what data we associate with e.g. students on a per-university basis without requiring code changes, separate schema, and a redeployment.<p>This took a lot of blood, sweat, and tears from our best engineer, myself, and one contractor -- probably about 2.5 man months, total. We did it with 100% plain ol' Java, rather than metaprogramming.<p>It will save us literally hundreds of thousands of dollars, so that isn't a terrible tradeoff, but if I had been using Ruby, I could have done it by myself in two to three days.]
评论 #943878 未加载
评论 #943911 未加载
评论 #944110 未加载
jamesbrittover 15 years ago
Everyone interested in this topic should watch this talk:<p><a href="http://mtnwestrubyconf2008.confreaks.com/11farley.html" rel="nofollow">http://mtnwestrubyconf2008.confreaks.com/11farley.html</a><p>Ruby Internals - Patrick Farley
评论 #943954 未加载
评论 #943767 未加载
Jim_Neathover 15 years ago
I highly recommend reading the Metaprogramming Ruby book from pragprog for people who wish to learn more.<p>Read the entire book in a couple of days and it really opened my eyes to new ways of doing things.<p><a href="http://www.pragprog.com/titles/ppmetr/metaprogramming-ruby" rel="nofollow">http://www.pragprog.com/titles/ppmetr/metaprogramming-ruby</a>