<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">
  <channel>
    <title>Purple Workshops News and Technical Articles</title>
    <link>http://www.purpleworkshops.com/feed</link>
    <description>Purple Workshops news and technical articles.</description>
    <geo:lat>42.03618</geo:lat><geo:long>-87.732106</geo:long><image><link>http://www.purpleworkshops.com/images/logo_medium.png</link><url>http://www.feedburner.com/fb/images/pub/fb_pwrd.gif</url><title>Purple Workshops</title></image><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" href="http://feeds.feedburner.com/purpleworkshops" type="application/rss+xml" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com" /><item>
      <title>Slides for Top 10 Things .NET Developers Should Know About Ruby</title>
      <description>&lt;p&gt;&lt;i&gt;
        Note: For best formatting, you may want to &lt;a href="http://www.purpleworkshops.com/articles/slides-top-10-things-ruby"&gt;view this article on the web&lt;/a&gt;.&lt;/i&gt;&lt;/p&gt;&lt;p&gt;Here's a link to the slides for a talk I gave on Sept 9, 2009 to the Chicago ALT.NET user group, called "Top 10+ Things Every .NET Developer Should Know About Ruby."&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.slideshare.net/jefflcohen/top-10-things-net-developers-should-know-about-ruby"&gt;Click Here for the SlideShare Deck&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It was a great group, and I had a great time.&lt;/p&gt;

&lt;p&gt;If you have questions or comments about the slides, ask me on twitter: http://www.twitter.com/home?status=@jeffcohen&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/purpleworkshops?a=Br_srZmHKLU:B0HxBEy9GRc:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/purpleworkshops?i=Br_srZmHKLU:B0HxBEy9GRc:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/purpleworkshops?a=Br_srZmHKLU:B0HxBEy9GRc:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/purpleworkshops?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/purpleworkshops?a=Br_srZmHKLU:B0HxBEy9GRc:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/purpleworkshops?i=Br_srZmHKLU:B0HxBEy9GRc:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/purpleworkshops?a=Br_srZmHKLU:B0HxBEy9GRc:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/purpleworkshops?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/purpleworkshops/~4/Br_srZmHKLU" height="1" width="1"/&gt;</description>
      <pubDate> 9 Sep 2009</pubDate>
      <link>http://feedproxy.google.com/~r/purpleworkshops/~3/Br_srZmHKLU/slides-top-10-things-ruby</link>
      <guid isPermaLink="false">http://www.purpleworkshops.com/articles/slides-top-10-things-ruby</guid>
      <dc:creator>Jeff Cohen</dc:creator>
    <feedburner:origLink>http://www.purpleworkshops.com/articles/slides-top-10-things-ruby</feedburner:origLink></item>
    <item>
      <title>Registration Now Open for Essential Javascript</title>
      <description>&lt;p&gt;&lt;i&gt;
        Note: For best formatting, you may want to &lt;a href="http://www.purpleworkshops.com/articles/essential-javascript-registration-open"&gt;view this article on the web&lt;/a&gt;.&lt;/i&gt;&lt;/p&gt;&lt;p&gt;Registration is now open for &lt;a href="http://www.purpleworkshops.com/workshops/essential-javascript"&gt;Essential Javascript with jQuery&lt;/a&gt;, a one-day fun-filled workshop for everyone that wants to learn how to integrate Javascript into their .NET, Ruby, PHP, or straight-HTML web applications.&lt;/p&gt;

&lt;p&gt;We've secured a great location right in the heart of Chicago's downtown (right across the street from the Sears Tower, in fact).&lt;/p&gt;

&lt;p&gt;If you've wanted to learn Javascript but didn't know how to get started, our friendly, inclusive workshop is the place for you.&lt;/p&gt;

&lt;p&gt;Seats are limited, so register today.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/purpleworkshops?a=-7JEAd00mig:NxllssovLUw:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/purpleworkshops?i=-7JEAd00mig:NxllssovLUw:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/purpleworkshops?a=-7JEAd00mig:NxllssovLUw:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/purpleworkshops?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/purpleworkshops?a=-7JEAd00mig:NxllssovLUw:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/purpleworkshops?i=-7JEAd00mig:NxllssovLUw:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/purpleworkshops?a=-7JEAd00mig:NxllssovLUw:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/purpleworkshops?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/purpleworkshops/~4/-7JEAd00mig" height="1" width="1"/&gt;</description>
      <pubDate>19 Aug 2009</pubDate>
      <link>http://feedproxy.google.com/~r/purpleworkshops/~3/-7JEAd00mig/essential-javascript-registration-open</link>
      <guid isPermaLink="false">http://www.purpleworkshops.com/articles/essential-javascript-registration-open</guid>
      <dc:creator>Jeff Cohen</dc:creator>
    <feedburner:origLink>http://www.purpleworkshops.com/articles/essential-javascript-registration-open</feedburner:origLink></item>
    <item>
      <title>The Learnometer</title>
      <description>&lt;p&gt;&lt;i&gt;
        Note: For best formatting, you may want to &lt;a href="http://www.purpleworkshops.com/articles/learnometer"&gt;view this article on the web&lt;/a&gt;.&lt;/i&gt;&lt;/p&gt;	&lt;p&gt;If you missed our opinion on &lt;a href="http://www.purpleworkshops.com/articles/how-to-spot-a-good-instructor"&gt;How to Spot a Good Instructor&lt;/a&gt;, we identified the critical role the instructor plays in the learning process.&lt;/p&gt;


	&lt;p&gt;In this article, we'll continue our look at the in-person experience.  But this time, we'll flip things around, and talk about how you &amp;#8211; the student/attendee &amp;#8211; can tell if the class is helping you achieve your objectives, or if it's actually a colossal waste of your time.&lt;/p&gt;


	&lt;p&gt;We don't think paying for a class should be a waste of time.  It should be a growing experience, and, dare we say, &lt;em&gt;fun&lt;/em&gt;.&lt;/p&gt;


	&lt;h2&gt;Measuring Workshop Effectiveness&lt;/h2&gt;


	&lt;p&gt;It would be great if there was a &lt;em&gt;learnometer&lt;/em&gt;.  You know: something you could stick under your tongue to measure how much you learned.&lt;/p&gt;


	&lt;p&gt;If you simply gained knowledge of new facts, &lt;strong&gt;you've thrown your money down the drain&lt;/strong&gt;.&lt;/p&gt;


	&lt;p&gt;Facts have been pretty much become a commodity.  Learning facts from a live instructor is about the most expensive way to get them.  In contrast, this is the sweet spot for blogs: as a fountain of facts. &amp;#8220;Here's how you setup a Git repository.&amp;#8221;  &amp;#8220;How to configure ActionMailer to send GMail.&amp;#8221; And so on.&lt;/p&gt;


	&lt;p&gt;Indeed, if all you want are facts, just search the web, cargo-cult what you need, and you're done.&lt;/p&gt;


	&lt;p&gt;A great workshop isn't all about facts.  At a Purple Workshop, you might actually be a little frustrated that we don't spend all our time giving out pre-made code examples that you can just copy and paste into your project.&lt;/p&gt;


	&lt;p&gt;We don't do that because it would be unfair to you, the attendee.  It really would be a colossal waste of your time.&lt;/p&gt;


	&lt;h2&gt;The Wake Behind Your Boat&lt;/h2&gt;


	&lt;p&gt;Instead, a great workshop or classroom experience is more than getting new facts.  &lt;em&gt;You've learned how to learn.&lt;/em&gt;  The best thing you can get from a class is learning how to learn more &lt;em&gt;without the class&lt;/em&gt;.&lt;/p&gt;


	&lt;p&gt;A visual analogy might help here.&lt;/p&gt;


	&lt;p&gt;You're standing at the helm of a big yacht.  It's time to leave the dock and travel to the other side of the ocean.  You know enough facts about the big steering wheel to know how to use it.  And no doubt, it's important to know how to steer a boat.&lt;/p&gt;


	&lt;p&gt;But if all you know how to do is turn the wheel this way and that, after an hour, you're still in the same place.  Stuck at the dock.&lt;/p&gt;


	&lt;p&gt;Successful boat captains know how to move the boat.  There's a direction.  Even with a beginner at the helm, we might be moving slowly, but we'd be moving forward nonetheless.  You could look back and see the wake being left behind.  And now, steering the boat becomes useful.&lt;/p&gt;


	&lt;p&gt;But classes that are primarily about acquiring facts aren't useful.  You'll get home from the workshop, start working on a project that's not exactly the same as the class example, and you'll be stuck.  Dead in the water.  And unfortunately, most people in this predicament start googling for more facts, in an attempt to solve their problems.&lt;/p&gt;


	&lt;h2&gt;Learning how to Learn&lt;/h2&gt;


	&lt;p&gt;Sometimes at a workshop, we'll start by doing things &amp;#8220;the hard way.&amp;#8221;  More precisely, we'll make sure you understand the motivation and reason behind everything we do.  So when that Rails scaffold generator doesn't generate the &lt;span class="caps"&gt;HTML&lt;/span&gt; you need, you won't be stuck, because you'll know what to do next and why.  When your migrations fail, you won't be stuck, because you'll understand the relationship between schema versions and the migration architecture so you can fix it.&lt;/p&gt;


	&lt;p&gt;Perhaps best of all, you'll be able to learn more on your own without needing a lot more workshops.  Indeed, once you get the hang of it, learning how to learn more becomes second nature.&lt;/p&gt;


	&lt;p&gt;You might even say, it becomes &lt;em&gt;fun&lt;/em&gt;.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/purpleworkshops?a=CqZAGhJk9Gk:oEsrxSZf1Bg:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/purpleworkshops?i=CqZAGhJk9Gk:oEsrxSZf1Bg:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/purpleworkshops?a=CqZAGhJk9Gk:oEsrxSZf1Bg:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/purpleworkshops?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/purpleworkshops?a=CqZAGhJk9Gk:oEsrxSZf1Bg:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/purpleworkshops?i=CqZAGhJk9Gk:oEsrxSZf1Bg:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/purpleworkshops?a=CqZAGhJk9Gk:oEsrxSZf1Bg:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/purpleworkshops?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/purpleworkshops/~4/CqZAGhJk9Gk" height="1" width="1"/&gt;</description>
      <pubDate>16 Aug 2009</pubDate>
      <link>http://feedproxy.google.com/~r/purpleworkshops/~3/CqZAGhJk9Gk/learnometer</link>
      <guid isPermaLink="false">http://www.purpleworkshops.com/articles/learnometer</guid>
      <dc:creator>Jeff Cohen</dc:creator>
    <feedburner:origLink>http://www.purpleworkshops.com/articles/learnometer</feedburner:origLink></item>
    <item>
      <title>How To Spot a Good Instructor</title>
      <description>&lt;p&gt;&lt;i&gt;
        Note: For best formatting, you may want to &lt;a href="http://www.purpleworkshops.com/articles/how-to-spot-a-good-instructor"&gt;view this article on the web&lt;/a&gt;.&lt;/i&gt;&lt;/p&gt;&lt;p&gt;Right now, today, it's easier for us to learn something &amp;#8211; anything &amp;#8211; than ever before.&lt;/p&gt;


	&lt;p&gt;Just think about it. On-demand video. Screencasts. The entire blogosphere at your fingertips. Wikipedia.  Search engines that bring a planet's worth of information to you less than a second.&lt;/p&gt;


	&lt;p&gt;Oh, and there's still the old-fashioned way: sitting in a classroom with an instructor.  This could be a typical school classroom, but it could also be a seminar at a conference, or a workshop like the ones we do here at Purple Workshops.&lt;/p&gt;


	&lt;h2&gt;What's New is Old Again&lt;/h2&gt;


	&lt;p&gt;Actually, all of these new mediums share many similarities to the old-style traditional classroom setting.&lt;/p&gt;


	&lt;ul&gt;
	&lt;li&gt;There's someone who has a certain kind of knowledge&lt;/li&gt;
		&lt;li&gt;You want to also have that knowledge&lt;/li&gt;
		&lt;li&gt;There's a communication medium for transferring that knowledge&lt;/li&gt;
	&lt;/ul&gt;


	&lt;p&gt;When you're in 4th grade trying to learn how to build your first science fair project (usually the dreaded volcano), the person with the knowledge you need is your teacher, and he or she has a variety of options for sharing that knowledge:&lt;/p&gt;


	&lt;ul&gt;
	&lt;li&gt;Verbally&lt;/li&gt;
		&lt;li&gt;Drawing on the chalkboard&lt;/li&gt;
		&lt;li&gt;Showing you a volcano another child already made&lt;/li&gt;
		&lt;li&gt;Getting their hands dirty and making it with you&lt;/li&gt;
	&lt;/ul&gt;


	&lt;p&gt;Even better, they probably use a combination of all of the above.&lt;/p&gt;


	&lt;p&gt;Suppose the 4th grade teacher said, &amp;#8220;Watch this screencast instead while I run some errands.&amp;#8221;  Would the knowledge transfer happen just as effectively?  Would you really learn the same things?  And would it be as fun?&lt;/p&gt;


	&lt;p&gt;Perhaps it would be.  One advantage of a screencast, for example, is that you could take watch the screencast as many times as you want until you feel you understood it.  You could watch it from home, instead of trying to hear the teacher in the middle of a loud, bustling 4th grade homeroom.&lt;/p&gt;


	&lt;p&gt;But with one-way mediums like screencasts and blogs, there are many shortcomings.  Perhaps the greatest of these is that you can't ask questions along the way.  If you don't understand a key concept at the start of the screencast, you might not get any value from the rest of the screencast at all.&lt;/p&gt;


	&lt;p&gt;The advantage of most blogs is your chance to leave comments and ask questions of the author, who might respond.  But it's still pretty much a one-way shot.&lt;/p&gt;


	&lt;h2&gt;Learning Modalities&lt;/h2&gt;


	&lt;p&gt;A lot of research has been done on how people learn.  You may have heard that some people are &amp;#8220;visual learners,&amp;#8221; while others learn best through an auditory experience.  Others learn best through a tactile experience.  Kids who are learning to count often don't learn by writing out equations on a blackboard.  Or even drawing pictures of apples on a blackboard.  They need to physically handle something in order to &amp;#8220;get it.&amp;#8221;  This is why a playing with beads or blocks is important for internalizing the concepts of &amp;#8220;zero&amp;#8221; and &amp;#8220;one&amp;#8221; and &amp;#8220;two&amp;#8221;.&lt;/p&gt;


	&lt;p&gt;Many adults feel they learn best by reading logical explanations of the concepts they seek to understand.  Walk into a Borders or Barnes &amp;#38; Noble &amp;#8211; their whole business is based on it.  &lt;/p&gt;

&lt;p&gt;This works because for at a certain point, we learn to think abstractly. We read the sentence, &amp;#8220;Now throw the second beanbag up in the air as you prepare to catch the first,&amp;#8221; and transform it into how we learned as child: we might feel that we can &amp;#8220;hear&amp;#8221; the voice of the words in the book, and we can visualize the action being described.&lt;/p&gt;


	&lt;p&gt;Meanwhile, others of us prefer to learn from screencasts, since the combination of video and voice (if there's a narration overdubbed onto the video) is much closer to a live, in-person experience.&lt;/p&gt;


	&lt;p&gt;But there's still no substitute from learning in a real, live, seminar or workshop setting, where a combination of visual, auditory, and tactile modes are all at work simulataneously.&lt;/p&gt;


	&lt;h2&gt;How To Spot a Great Instructor&lt;/h2&gt;


	&lt;p&gt;You've had at least one great teacher that you can remember from your days in school.  What made he or she so special?&lt;/p&gt;


	&lt;p&gt;Indeed, not all instructors are alike.  When you are paying money to take a workshop or seminar, or you're trying to decide which breakout sessions to attend at a conference, you want to be sure that you're going to learn what you need to learn before it's over.  Here are a few qualities that good instructors possess:&lt;/p&gt;


	&lt;ol&gt;
	&lt;li&gt;&lt;strong&gt;The instructor knows the material.&lt;/strong&gt;  Conference organizers should be sure to include important facts in the instructor's &amp;#8220;bio statement&amp;#8221; that gives you some guidance here.&lt;/li&gt;
		&lt;li&gt;&lt;strong&gt;The instructor uses more than one modality.&lt;/strong&gt;  Ever wonder why bullet-point Powerpoint presentations suck for learning new material?  Well, there's actually lots of reasons, but an instructor who simply reads bullet points has reduced the experience back into an abstract logical exercise, no better than if you were reading the material on your own.  &lt;/li&gt;
		&lt;li&gt;&lt;strong&gt;The instructor brings and encourages a sense of humor into the seminar.&lt;/strong&gt;  You don't want a standup comedian, but you need someone who's able to share their joy of the topic to everyone in the room.  Learning that isn't fun, isn't effective.&lt;/li&gt;
		&lt;li&gt;&lt;strong&gt;The instructor isn't worried about mistakes.&lt;/strong&gt;  Have you ever learned something by explaining something to someone else?  It happens more than you might think.  Making mistakes in front of a group is scary, but always very valuable for everyone involved.  It lets the attendees see how the instructor fixes something that's broken, which in itself is highly instructive.&lt;/li&gt;
		&lt;li&gt;&lt;strong&gt;The instructor isn't intimidating.&lt;/strong&gt;  The best way to learn is by asking questions.  Too many seminars ask people to "hold questions until the end." Or the instructor has a rockstar aura, making people feel awkward if they ask a seemingly "newbie" question.  Instructors should always have a non-threatening, everyone-can-participate approach.&lt;/li&gt;
	&lt;/ol&gt;


	&lt;h2&gt;Try It Yourself&lt;/h2&gt;


	&lt;p&gt;Some people go to conferences and workshops all the time, but don't really have the results to show for it.  If that's you, our advice is to start sharing your knowledge with others.  Start a blog.  Make a screencast. Pair with a fellow worker on a task.  When you have to explain something to someone else, chances are you'll force yourself to know the topic in a deeper way than ever have before.&lt;/p&gt;


	&lt;p&gt;Others never go to conferences, or never sign up for a workshop.  If that's you, you're missing out on an experience that can single-handedly get your career up another notch in a short amount of time.&lt;/p&gt;


	&lt;p&gt;And of course, if you're looking for somewhere to start, take a look at our &lt;a href="/public"&gt;upcoming public workshops&lt;/a&gt;.  We really think you're going to enjoy the Purple experience.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/purpleworkshops?a=fx2ROXvw5FY:EYvFD2zEEKQ:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/purpleworkshops?i=fx2ROXvw5FY:EYvFD2zEEKQ:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/purpleworkshops?a=fx2ROXvw5FY:EYvFD2zEEKQ:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/purpleworkshops?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/purpleworkshops?a=fx2ROXvw5FY:EYvFD2zEEKQ:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/purpleworkshops?i=fx2ROXvw5FY:EYvFD2zEEKQ:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/purpleworkshops?a=fx2ROXvw5FY:EYvFD2zEEKQ:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/purpleworkshops?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/purpleworkshops/~4/fx2ROXvw5FY" height="1" width="1"/&gt;</description>
      <pubDate>26 Jul 2009</pubDate>
      <link>http://feedproxy.google.com/~r/purpleworkshops/~3/fx2ROXvw5FY/how-to-spot-a-good-instructor</link>
      <guid isPermaLink="false">http://www.purpleworkshops.com/articles/how-to-spot-a-good-instructor</guid>
      <dc:creator>Jeff Cohen</dc:creator>
    <feedburner:origLink>http://www.purpleworkshops.com/articles/how-to-spot-a-good-instructor</feedburner:origLink></item>
    <item>
      <title>Join Us at Windy City Rails 2009</title>
      <description>&lt;p&gt;&lt;i&gt;
        Note: For best formatting, you may want to &lt;a href="http://www.purpleworkshops.com/articles/windy-city-rails-2009"&gt;view this article on the web&lt;/a&gt;.&lt;/i&gt;&lt;/p&gt;  &lt;p&gt;PurpleWorkshops will conduct the morning tutorial session at the upcoming &lt;a href="http://windycityrails.org"&gt;Windy City Rails Conference&lt;/a&gt;.  It's a 3-hour tutorial called &lt;a href="http://windycityrails.org/sessions"&gt;REST 101: Best Practices for Rails Developers&lt;/a&gt;.&lt;/p&gt;
  
  &lt;p&gt;The conference will be held on September 12, 2009 in downtown Chicago. If you register now, you can get the early bird rate of $99 for conference admission or &lt;a href="http://windycityrails.org/register"&gt;just $199 for the conference with one tutorial session&lt;/a&gt;.&lt;/p&gt;
  
  &lt;p&gt;&lt;strong&gt;Windy City Rails donates all profits to local charities, like the &lt;a href="http://www.chicagosfoodbank.org/"&gt;Greater Chicago Food Depository&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;
  
  &lt;p&gt;&lt;a href="http://windycityrails.org/register"&gt;Register now&lt;/a&gt; for the conference!&lt;/p&gt;
  
  &lt;p&gt;If you're getting started with Rails and ready to take the next step, sign up for our tutorial session too.  We'll have fun and learn a lot!&lt;/p&gt;
  
  &lt;p&gt;Questions? Feel free to email me directly at &lt;a  href="mailto:&amp;#105;n&amp;#102;&amp;#111;&amp;#64;&amp;#112;&amp;#117;r&amp;#112;&amp;#108;&amp;#101;w&amp;#111;&amp;#114;k&amp;#115;&amp;#104;&amp;#111;p&amp;#115;&amp;#46;&amp;#99;&amp;#111;&amp;#109;"&gt;&amp;#105;&amp;#110;fo&amp;#64;&amp;#112;&amp;#117;&amp;#114;&amp;#112;&amp;#108;&amp;#101;&amp;#119;&amp;#111;&amp;#114;&amp;#107;&amp;#115;h&amp;#111;&amp;#112;&amp;#115;&amp;#46;c&amp;#111;&amp;#109;&lt;/a&gt;
  &lt;/p&gt;
 
 &lt;p&gt;&lt;strong&gt;See you there!&lt;/strong&gt;&lt;/p&gt;

 
&lt;p&gt;&lt;em&gt;If you're not able to attend the conference, you're also in luck. The tutorial is a shortened version of &lt;a href="/workshops/rails-for-everyone"&gt;Rails for Everyone&lt;/a&gt;.  You can &lt;a href="/workshops/rails-for-everyone"&gt;sign up to get an email when registration opens&lt;/a&gt; that will also include a discount code.&lt;/em&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/purpleworkshops?a=Nimg93OMZlw:xX0f3P7LiVo:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/purpleworkshops?i=Nimg93OMZlw:xX0f3P7LiVo:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/purpleworkshops?a=Nimg93OMZlw:xX0f3P7LiVo:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/purpleworkshops?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/purpleworkshops?a=Nimg93OMZlw:xX0f3P7LiVo:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/purpleworkshops?i=Nimg93OMZlw:xX0f3P7LiVo:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/purpleworkshops?a=Nimg93OMZlw:xX0f3P7LiVo:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/purpleworkshops?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/purpleworkshops/~4/Nimg93OMZlw" height="1" width="1"/&gt;</description>
      <pubDate>24 Jun 2009</pubDate>
      <link>http://feedproxy.google.com/~r/purpleworkshops/~3/Nimg93OMZlw/windy-city-rails-2009</link>
      <guid isPermaLink="false">http://www.purpleworkshops.com/articles/windy-city-rails-2009</guid>
      <dc:creator>Jeff Cohen</dc:creator>
    <feedburner:origLink>http://www.purpleworkshops.com/articles/windy-city-rails-2009</feedburner:origLink></item>
    <item>
      <title>Rails 101: Grouping Controllers in Subdirectories</title>
      <description>&lt;p&gt;&lt;i&gt;
        Note: For best formatting, you may want to &lt;a href="http://www.purpleworkshops.com/articles/grouped-controllers"&gt;view this article on the web&lt;/a&gt;.&lt;/i&gt;&lt;/p&gt;&lt;p&gt;Every Rails application consists of many different Ruby classes.  Rails dictates where these classes go.  For example, some classes are called &lt;emph&gt;models&lt;/emph&gt;, and Rails will expect to find them in your &lt;code&gt;app/models&lt;/code&gt; directory; &lt;emph&gt;controllers&lt;/emph&gt; go in &lt;code&gt;app/controllers&lt;/code&gt;; and so on.&lt;/p&gt;

&lt;p&gt;For large applications, the list of Ruby files in a directory may grow large, and you might wish to create subdirectories to group related classes together.  Rails lets you create subdirectories for your classes, but you need to do more than simply move them into a new subdirectory before Rails can find them and use them properly.  In this article, we'll show you how to put a controller into a subdirectory and enable Rails to find it automatically.&lt;/p&gt;

&lt;h2&gt;Grouping Controllers into an Admin Folder&lt;/h2&gt;
&lt;p&gt;Even if your application isn't very large, you may still want to group controllers into a subdirectory.  It's not uncommon to have two controllers for a particular resource: one that serves public pages, and the other to provide an administrative interface.&lt;/p&gt;

&lt;p&gt;Let's pretend our application sells tickets for a large number of venues.  The public &lt;code&gt;VenuesController&lt;/code&gt; class allows users to select a venue, get directions, view a seating chart, and so on.  But our administrative staff has different needs: they want to add new venues, delete others, and change the information pertaining to a given venue.&lt;/p&gt;

&lt;p&gt;Let's put our administrative controller into a folder named &lt;code&gt;app/controllers/admin&lt;/code&gt;. We can generate our new controller with the &lt;code&gt;generate&lt;/code&gt; command:
  
&lt;pre class="session"&gt;script/generate controller admin/venues
&lt;/pre&gt;

&lt;p&gt;Now, open up the &lt;code&gt;app/controllers/admin/venues_controller.rb&lt;/code&gt; file that was generated:&lt;/p&gt;

              &lt;table class="code_listing"&gt;
                &lt;tr&gt;
                  &lt;td class="code ruby"&gt;&lt;pre&gt;&lt;notextile&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;Admin::VenuesController&lt;/span&gt; &lt;span class="punct"&gt;&amp;lt;&lt;/span&gt; &lt;span class="constant"&gt;ApplicationController&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;/notextile&gt;&lt;/pre&gt;&lt;/td&gt;
                &lt;/tr&gt;
              &lt;/table&gt;


&lt;p&gt;That looks... familiar. But what's with the strange class name?  And if we try to browse to &lt;code&gt;/admin/venues&lt;/code&gt;, we'll get an error message.  Why can't Rails find our controller class?&lt;/p&gt;

&lt;h2&gt;Grouped Controllers Need Ruby Modules&lt;/h2&gt;

&lt;p&gt;Here's the first catch: when you move a class into a subdirectory, Rails won't see it unless it is contained inside a lexical scope that corresponds to its physical directory.  Our &lt;code&gt;VenuesController&lt;/code&gt; is in a subdirectory named &lt;code&gt;Admin&lt;/code&gt;, so we must wrap it inside a corresponding Ruby module named &lt;code&gt;Admin&lt;/code&gt; as well.&lt;/p&gt;

&lt;p&gt;Why does Rails make us do this?  To prevent name collisions.  We want our public &lt;code&gt;VenuesController&lt;/code&gt; to be up in the main &lt;code&gt;app/controllers&lt;/code&gt; directory, so their needs to be a way to distinguish the two classes by something other than physical location on disk.&lt;/p&gt;

&lt;p&gt;Do do you have to configure what module name will be used in each directory?  No.  Rails conventions to the rescue. The module name is assumed to be the same as the directory name.&lt;/p&gt;

&lt;p&gt;Since our file lives in the &lt;code&gt;admin/&lt;/code&gt; subdirectory, our module name is &lt;code&gt;Admin&lt;/code&gt;.  There are a couple of ways to specify that your class lives in a directory, but one of the most common ways is to simply put the module name in front of the class name, separated by two colons.  That's how we got the class name &lt;code&gt;Admin::VenuesController&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;Grouped Controllers Need Namespaced Routes&lt;/h2&gt;

&lt;p&gt;And now for the second catch.  If we were putting our model into a subdirectory, we'd be done as soon as we used the right module and class name combination.  But since this is a controller, Rails also needs a way to route admin urls to our admin controllers.  To do that, we use the &lt;code&gt;namespace&lt;/code&gt; method in our routes file:&lt;/p&gt;

              &lt;table class="code_listing"&gt;
                &lt;tr&gt;
                  &lt;td class="code ruby"&gt;&lt;pre&gt;&lt;notextile&gt;&lt;span class="constant"&gt;ActionController&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="constant"&gt;Routing&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="constant"&gt;Routes&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;draw&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt; &lt;span class="punct"&gt;|&lt;/span&gt;&lt;span class="ident"&gt;map&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt;

  &lt;span class="comment"&gt;# Somewhere inside this block, &lt;/span&gt;
  &lt;span class="comment"&gt;# just create a namespace for the&lt;/span&gt;
  &lt;span class="comment"&gt;# admin controllers, like this:&lt;/span&gt;
  
  &lt;span class="ident"&gt;map&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;namespace&lt;/span&gt; &lt;span class="symbol"&gt;:admin&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt; &lt;span class="punct"&gt;|&lt;/span&gt;&lt;span class="ident"&gt;admin&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt;
    &lt;span class="ident"&gt;admin&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;resources&lt;/span&gt; &lt;span class="symbol"&gt;:venues&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;
  
&lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;/notextile&gt;&lt;/pre&gt;&lt;/td&gt;
                &lt;/tr&gt;
              &lt;/table&gt;


&lt;p&gt;The &lt;code&gt;namespace&lt;/code&gt; will expect a path prefix of &lt;code&gt;admin&lt;/code&gt; and also creates named routes with the same prefix.  For example, to create a link to the &lt;code&gt;Admin::VenuesController&lt;/code&gt;'s  index action, you would do something like this:&lt;/p&gt;

              &lt;table class="code_listing"&gt;
                &lt;tr&gt;
                  &lt;td class="code ruby"&gt;&lt;pre&gt;&lt;notextile&gt;&lt;span class="ident"&gt;link_to&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;View all venues&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;,&lt;/span&gt; &lt;span class="ident"&gt;admin_venues_path&lt;/span&gt;
&lt;/notextile&gt;&lt;/pre&gt;&lt;/td&gt;
                &lt;/tr&gt;
              &lt;/table&gt;


&lt;h2&gt;Summary&lt;/h2&gt;
&lt;p&gt;To group controllers into a subdirectory, you must do two things:&lt;/p&gt;

&lt;p&gt;1. &lt;strong&gt;Wrap your controller class inside a Ruby module&lt;/strong&gt;.  The name of the module should be the same as your subdirectory name.&lt;/p&gt;
&lt;p&gt;2. &lt;strong&gt;Create a routing namespace&lt;/strong&gt; with the same name as your subdirectory name, and map your controller from inside the namespace.&lt;/p&gt;  

&lt;p&gt;And presto!  You can now browse to &lt;code&gt;/admin/venues&lt;/code&gt; and use your new controller.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/purpleworkshops?a=r0xNWBwZhig:zDp5sFflIWs:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/purpleworkshops?i=r0xNWBwZhig:zDp5sFflIWs:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/purpleworkshops?a=r0xNWBwZhig:zDp5sFflIWs:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/purpleworkshops?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/purpleworkshops?a=r0xNWBwZhig:zDp5sFflIWs:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/purpleworkshops?i=r0xNWBwZhig:zDp5sFflIWs:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/purpleworkshops?a=r0xNWBwZhig:zDp5sFflIWs:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/purpleworkshops?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/purpleworkshops/~4/r0xNWBwZhig" height="1" width="1"/&gt;</description>
      <pubDate>12 Feb 2009</pubDate>
      <link>http://feedproxy.google.com/~r/purpleworkshops/~3/r0xNWBwZhig/grouped-controllers</link>
      <guid isPermaLink="false">http://www.purpleworkshops.com/articles/grouped-controllers</guid>
      <dc:creator>Jeff Cohen</dc:creator>
    <feedburner:origLink>http://www.purpleworkshops.com/articles/grouped-controllers</feedburner:origLink></item>
    <item>
      <title>Agile 101: The Simplest Thing That Could Possibly Work</title>
      <description>&lt;p&gt;&lt;i&gt;
        Note: For best formatting, you may want to &lt;a href="http://www.purpleworkshops.com/articles/simplest-thing"&gt;view this article on the web&lt;/a&gt;.&lt;/i&gt;&lt;/p&gt;	&lt;p&gt;The saying, &amp;#8220;Do the simplest thing that could possibly work,&amp;#8221; has reached legendary status in most agile circles.  When I first heard of it, I thought it was a pretty silly statement.  After all, what developer in their right mind &lt;em&gt;chooses&lt;/em&gt; to do things the hard way?  

	&lt;p&gt;A related, albeit slightly less famous agile phrase is, &amp;#8220;Solve today's problems today.&amp;#8221;  In other words, don't design a solution to a problem that doesn't really exist, based solely on a guess that it &lt;strong&gt;might&lt;/strong&gt; be a problem tomorrow.  Just solve today's problems.&lt;/p&gt;


	&lt;p&gt;It wasn't until much later that I began to understand what this simple phrase was really talking about.&lt;/p&gt;


	&lt;p&gt;If you're new to &amp;#8220;Do the simplest thing that could possibly work,&amp;#8221; and even if you &lt;em&gt;think&lt;/em&gt; your understand what it means, read on.  I'm going to show you how we implemented a feature on the PurpleWorkshops site that followed this advice to such an extreme, that you might think I'm crazy.&lt;/p&gt;


	&lt;h2&gt;The Problem&lt;/h2&gt;


	&lt;p&gt;Potential customers can get in touch with us by filling out a very simple form (&lt;a href="http://www.purpleworkshops.com/inquiries/new"&gt;you can see it here&lt;/a&gt;). Although we don't get a lot of traffic, we were getting a significant amount of spam submitted through that form before we implemented a simple Captcha system, that you now see at the bottom of the form.  Each spam submission would add rows to our database that would require cleaning out, and each would alert me - falsely - that a potential customer was contacting us.&lt;/p&gt;



	&lt;h2&gt;A Not-So-Simple Solution&lt;/h2&gt;


	&lt;p&gt;Now, I really wanted to avoid a complicated, TicketMaster-style-can-barely-see-those-stupid-letters experience that I hate so much.  But I finally couldn't avoid it any longer, and started looking into captcha strategies.&lt;/p&gt;


	&lt;p&gt;The general idea of a captcha is you present something that automated scripts probably won't understand - like a word or number sequence contained in an .png or .jpg file - and require the user to enter that word or sequence into the form.  This raises the level of confidence that whoever - or whatever - is submitting the form is a real, human person, and therefore is probably a legitimate potential customer.&lt;/p&gt;


	&lt;p&gt;There are many solutions available.  Most of them generate images on the fly, requiring you to install something like RMagick on your server. All of the solutions I looked at were fine, but&amp;#8230; complicated.  Yes, installing a plugin and following a few directions is complicated for me.  Maybe I'm just getting old.&lt;/p&gt;


	&lt;h2&gt;First Attempt At Being Simple&lt;/h2&gt;


	&lt;p&gt;Or maybe I'm just too agile.  It occurred to me, out of the blue, that I don't really need all that complexity that most captcha solutions give me.  I have a relatively low-trafic site.  The spambots are probably not going to think it worthwhile to really target my site.  So I don't need something super deluxe.  Just something to stop the simple bots.&lt;/p&gt;


	&lt;p&gt;So rather than install RMagick and generate images on the fly with some randomly-generated word pulled from a dictionary each time the page loads, maybe I could just generate a set of images and randomly present one of them using a simple image tag.&lt;/p&gt;


	&lt;p&gt;Doesn't that sounds simpler?&lt;/p&gt;


	&lt;p&gt;Wait, it gets even better.  Instead of using RMagick to generate these images, I'm just going to use (drum roll&amp;#8230;) Skitch.  Yes, I'm going to generate them by hand, say 20 of them.&lt;/p&gt;


	&lt;p&gt;I just have to give them filenames like &lt;code&gt;captcha_1.png&lt;/code&gt;, &lt;code&gt;captcha_2.png&lt;/code&gt;, and so on.  Then, to choose an image at random, I need to do something like this in my &lt;code&gt;new&lt;/code&gt; action:&lt;/p&gt;


              &lt;table class="code_listing"&gt;
                &lt;tr&gt;
                  &lt;td class="line_numbers"&gt;&lt;pre&gt;&lt;notextile&gt;1
2
3
4
5&lt;/notextile&gt;&lt;/pre&gt;&lt;/td&gt;
                  &lt;td class="code ruby"&gt;&lt;pre&gt;&lt;notextile&gt;&lt;span class="comment"&gt;# Show form to user&lt;/span&gt;
&lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;new&lt;/span&gt;
  &lt;span class="ident"&gt;random_key&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;rand&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="number"&gt;20&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt; &lt;span class="punct"&gt;+&lt;/span&gt; &lt;span class="number"&gt;1&lt;/span&gt;
  &lt;span class="attribute"&gt;@captcha_filename&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;captcha_&lt;span class="expr"&gt;#{random_key}&lt;/span&gt;.png&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt; 
&lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;/notextile&gt;&lt;/pre&gt;&lt;/td&gt;
                &lt;/tr&gt;
              &lt;/table&gt;



	&lt;p&gt;Later in the &lt;code&gt;create&lt;/code&gt; action, I can verify that the word they enter is the same as what's shown in the image.&lt;/p&gt;


	&lt;p&gt;Of course, somewhere I'm going to have to store the correct answer.  This could be kept in the session (say, as an &lt;span class="caps"&gt;MD5&lt;/span&gt; of the answer) or on the server.&lt;/p&gt;


	&lt;p&gt;Hmmm, this is starting to feel&amp;#8230; I don't know, not &lt;em&gt;complicated&lt;/em&gt; exactly, but more hassle than I wanted.&lt;/p&gt;


	&lt;p&gt;Time to simplify again.&lt;/p&gt;


	&lt;h2&gt;The Simplest Thing That Could Possibly... you know...&lt;/h2&gt;


	&lt;p&gt;This may sound absurd at first, but I thought, what would happen if I really just did the simplest thing that could possibly work.  At least as a first pass, before I go implementing the whole solution.&lt;/p&gt;


	&lt;p&gt;What would that be?  I think the simplest thing would be to have just one image that is shown every time, and one correct, hard-coded answer.&lt;/p&gt;


	&lt;p&gt;And that's exactly the solution &lt;a href="http://www.purpleworkshops.com/inquiries/new" target="new"&gt;you see now:&lt;/a&gt; the user must correctly type the word they see in the image before our Rails app will accept the inquiry.&lt;/p&gt;


	&lt;p&gt;But now you know the secret (whoa, I hope you don't program spambots for a living).&lt;/p&gt;


	&lt;h2&gt;The Benefits&lt;/h2&gt;


	&lt;p&gt;I created the image in about 3 minutes, added an image tag and a new text field to the inquiry form in about 3 minutes, added model validation (using the correct answer as a hardcoded string) in about 1 minute.  7 minutes, and two weeks later, no spam.  Zero.&lt;/p&gt;


	&lt;p&gt;I suppose one day, maybe even tomorrow, some spambot will figure out the answer, and this solution won't work anymore.  I'll have to make things a little more complex, and maybe use the 20-image solution.  When that happens, that will become the simplest thing that could possibly work.&lt;/p&gt;


	&lt;p&gt;But remember, that's &lt;em&gt;tomorrow's problem.&lt;/em&gt; We agile developers only solve today's problems today.&lt;/p&gt;


	&lt;h2&gt;Crazy?&lt;/h2&gt;


	&lt;p&gt;Does my solution sound crazy too you?  Ok, maybe you wouldn't say it's &lt;em&gt;crazy&lt;/em&gt; - but naive?  Do you think a &amp;#8220;real&amp;#8221; solution to the problem would involve a more rigorous solution?&lt;/p&gt;


	&lt;p&gt;If so, I have one question for you.&lt;/p&gt;


	&lt;p&gt;Did I mention &lt;em&gt;we haven't gotten any spam yet&lt;/em&gt;?&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/purpleworkshops?a=oq7WYkWIsCA:clWYnmJ_igg:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/purpleworkshops?i=oq7WYkWIsCA:clWYnmJ_igg:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/purpleworkshops?a=oq7WYkWIsCA:clWYnmJ_igg:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/purpleworkshops?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/purpleworkshops?a=oq7WYkWIsCA:clWYnmJ_igg:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/purpleworkshops?i=oq7WYkWIsCA:clWYnmJ_igg:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/purpleworkshops?a=oq7WYkWIsCA:clWYnmJ_igg:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/purpleworkshops?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/purpleworkshops/~4/oq7WYkWIsCA" height="1" width="1"/&gt;</description>
      <pubDate> 3 Dec 2008</pubDate>
      <link>http://feedproxy.google.com/~r/purpleworkshops/~3/oq7WYkWIsCA/simplest-thing</link>
      <guid isPermaLink="false">http://www.purpleworkshops.com/articles/simplest-thing</guid>
      <dc:creator>Jeff Cohen</dc:creator>
    <feedburner:origLink>http://www.purpleworkshops.com/articles/simplest-thing</feedburner:origLink></item>
    <item>
      <title>Rails Internals: &lt;i&gt;named_scope&lt;/i&gt; Refactored</title>
      <description>&lt;p&gt;&lt;i&gt;
        Note: For best formatting, you may want to &lt;a href="http://www.purpleworkshops.com/articles/named-scope-refactored"&gt;view this article on the web&lt;/a&gt;.&lt;/i&gt;&lt;/p&gt;&lt;p&gt;You've probably heard that reading someone else's code is one way to learn more Ruby, and it's true.  If you're a Rails developer, you already have a large quantity of reading material at your disposal: the Rails source itself. Reading the Rails source code is a great way to learn about Ruby idioms and techniques that you may not be using in your own applications.  
&lt;/p&gt;
&lt;div class="callout"&gt;&lt;img alt="Stop" src="/images/icons/stop.png?1253338587" /&gt;&lt;p&gt;
&lt;p&gt;Not familiar with &lt;code&gt;named_scope&lt;/code&gt;? Check the &lt;a href="http://api.rubyonrails.com/classes/ActiveRecord/NamedScope/ClassMethods.html#M001648"&gt;API documentation&lt;/a&gt; or read about it in the &lt;a href="http://guides.rails.info/finders.html#_named_scopes"&gt;official Rails guide&lt;/a&gt;.
&lt;/p&gt;&lt;/p&gt;&lt;/div&gt;

&lt;p&gt;Some Rails code is bread-and-butter Ruby, that most developers can readily understand.  Other parts use more advanced idioms or a more densely-packed style, which might dissuade the casual developer from being able to understand the code.  That's a shame, because valuable concepts and techniques can go unnoticed and unlearned.
&lt;/p&gt;

&lt;p&gt;We're going to take a look at the implementation of &lt;strong&gt;named_scope&lt;/strong&gt;, a very popular feature of ActiveRecord that first appeared in Rails 2.1.  
&lt;/p&gt;

&lt;h2&gt;1. What is Refactoring?&lt;/h2&gt;

&lt;p&gt;&lt;emph&gt;Refactoring&lt;/emph&gt; is an essential coding discipline for every agile developer.  Refactoring is the process of taking existing code, and morphing into new code that exhibits the exact same behavior on the outside, but is cleaner, simpler, and better designed on the inside.  
&lt;/p&gt;
&lt;p&gt;Martin Fowler, author of the well-known &lt;a href="http://www.amazon.com/exec/obidos/ASIN/0201485672"&gt;Refactoring book&lt;/a&gt;, identifies many kinds of &lt;a href="http://www.refactoring.com/catalog/index.html"&gt;refactoring patterns&lt;/a&gt;.  One of the most common techniques - &lt;a href="http://www.refactoring.com/catalog/extractMethod.html"&gt;extract method&lt;/a&gt; - can help simplify a method that's trying to do too much, or whenever the _intent_ of the code isn't clear enough.  
&lt;/p&gt;
&lt;p&gt;To demonstrate, we're going to take a look at the implementation of one of the most popular features in Rails 2.1: &lt;strong&gt;named_scope&lt;/strong&gt;.  
&lt;/p&gt;
&lt;h2&gt;2. The 10-Second Rule&lt;/h2&gt;

&lt;p&gt;No, I'm not talking about the bagel you dropped on the floor. Take a look at the following code.  It's taken directly from the Rails 2.1 source code.  Can you understand it in 10 seconds or less?
&lt;/p&gt;
              &lt;table class="code_listing"&gt;
                &lt;tr&gt;
                  &lt;td class="line_numbers"&gt;&lt;pre&gt;&lt;notextile&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19&lt;/notextile&gt;&lt;/pre&gt;&lt;/td&gt;
                  &lt;td class="code ruby"&gt;&lt;pre&gt;&lt;notextile&gt;&lt;span class="comment"&gt;# Implementation of named_scope in Rails 2.1&lt;/span&gt;
&lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;named_scope&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;name&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;options&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="punct"&gt;{},&lt;/span&gt; &lt;span class="punct"&gt;&amp;amp;&lt;/span&gt;&lt;span class="ident"&gt;block&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
  &lt;span class="ident"&gt;name&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;name&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;to_sym&lt;/span&gt;
  
  &lt;span class="ident"&gt;scopes&lt;/span&gt;&lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="ident"&gt;name&lt;/span&gt;&lt;span class="punct"&gt;]&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;lambda&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt; &lt;span class="punct"&gt;|&lt;/span&gt;&lt;span class="ident"&gt;parent_scope&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="punct"&gt;*&lt;/span&gt;&lt;span class="ident"&gt;args&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt;
    &lt;span class="constant"&gt;Scope&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;parent_scope&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="keyword"&gt;case&lt;/span&gt; &lt;span class="ident"&gt;options&lt;/span&gt;
      &lt;span class="keyword"&gt;when&lt;/span&gt; &lt;span class="constant"&gt;Hash&lt;/span&gt;
        &lt;span class="ident"&gt;options&lt;/span&gt;
      &lt;span class="keyword"&gt;when&lt;/span&gt; &lt;span class="constant"&gt;Proc&lt;/span&gt;
        &lt;span class="ident"&gt;options&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;call&lt;/span&gt;&lt;span class="punct"&gt;(*&lt;/span&gt;&lt;span class="ident"&gt;args&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
    &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="punct"&gt;&amp;amp;&lt;/span&gt;&lt;span class="ident"&gt;block&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;
  
  &lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="punct"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="constant"&gt;self&lt;/span&gt;&lt;span class="punct"&gt;;&lt;/span&gt; &lt;span class="constant"&gt;self&lt;/span&gt; &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;span class="punct"&gt;).&lt;/span&gt;&lt;span class="ident"&gt;instance_eval&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt;
    &lt;span class="ident"&gt;define_method&lt;/span&gt; &lt;span class="ident"&gt;name&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt; &lt;span class="punct"&gt;|*&lt;/span&gt;&lt;span class="ident"&gt;args&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt;
      &lt;span class="ident"&gt;scopes&lt;/span&gt;&lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="ident"&gt;name&lt;/span&gt;&lt;span class="punct"&gt;].&lt;/span&gt;&lt;span class="ident"&gt;call&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="constant"&gt;self&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="punct"&gt;*&lt;/span&gt;&lt;span class="ident"&gt;args&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
    &lt;span class="keyword"&gt;end&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;/notextile&gt;&lt;/pre&gt;&lt;/td&gt;
                &lt;/tr&gt;
              &lt;/table&gt;


&lt;p&gt;Unless you're comfortable with some advanced Ruby concepts, this code may be pretty hard to understand.  
&lt;/p&gt;
&lt;p&gt;There are several things going on here that make this code harder to read than it ought to be.  Let's walk through them one at a time.  We'll refactor as we go, leaving us with code that will behave the same, but will be make the &lt;code&gt;named_scope&lt;/code&gt; method more readable and its intent more transparent.
&lt;/p&gt;
&lt;p&gt;The method starts innocently enough, by coercing the &lt;code&gt;name&lt;/code&gt; parameter into a symbol.  
&lt;/p&gt;
&lt;p&gt;Then we go over the cliff pretty fast.  Line 5 looks like it's going to assign a key-value pair into a hash named &lt;code&gt;scopes&lt;/code&gt;.  The key for the pair is &lt;code&gt;name&lt;/code&gt;, but the value is... well, something complicated:
&lt;/p&gt;
              &lt;table class="code_listing"&gt;
                &lt;tr&gt;
                  &lt;td class="line_numbers"&gt;&lt;pre&gt;&lt;notextile&gt;5
6
7
8
9
10
11
12&lt;/notextile&gt;&lt;/pre&gt;&lt;/td&gt;
                  &lt;td class="code ruby"&gt;&lt;pre&gt;&lt;notextile&gt;&lt;span class="ident"&gt;scopes&lt;/span&gt;&lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="ident"&gt;name&lt;/span&gt;&lt;span class="punct"&gt;]&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;lambda&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt; &lt;span class="punct"&gt;|&lt;/span&gt;&lt;span class="ident"&gt;parent_scope&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="punct"&gt;*&lt;/span&gt;&lt;span class="ident"&gt;args&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt;
  &lt;span class="constant"&gt;Scope&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;parent_scope&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="keyword"&gt;case&lt;/span&gt; &lt;span class="ident"&gt;options&lt;/span&gt;
    &lt;span class="keyword"&gt;when&lt;/span&gt; &lt;span class="constant"&gt;Hash&lt;/span&gt;
      &lt;span class="ident"&gt;options&lt;/span&gt;
    &lt;span class="keyword"&gt;when&lt;/span&gt; &lt;span class="constant"&gt;Proc&lt;/span&gt;
      &lt;span class="ident"&gt;options&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;call&lt;/span&gt;&lt;span class="punct"&gt;(*&lt;/span&gt;&lt;span class="ident"&gt;args&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="punct"&gt;&amp;amp;&lt;/span&gt;&lt;span class="ident"&gt;block&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;/notextile&gt;&lt;/pre&gt;&lt;/td&gt;
                &lt;/tr&gt;
              &lt;/table&gt;


&lt;p&gt;It's a &lt;code&gt;lambda&lt;/code&gt; that takes multiple parameters, and which will return a new &lt;code&gt;Scope&lt;/code&gt; object.  We don't know yet what the &lt;code&gt;Scope&lt;/code&gt; class does, but we don't need to worry about that for now.  Furthermore, creating this &lt;code&gt;Scope&lt;/code&gt; instance seems to require three parameters, although it may not be immediately obvious.  
&lt;/p&gt;
&lt;p&gt;The first parameter is simply the &lt;code&gt;parent_scope&lt;/code&gt; value that was received by the &lt;code&gt;lambda&lt;/code&gt;. The second, however, requires a &lt;code&gt;case&lt;/code&gt; statement to determine, and the author of this code has chosen to put the &lt;code&gt;case&lt;/code&gt; statement inline with the rest of the code. The third parameter is the &lt;code&gt;&amp;block&lt;/code&gt; parameter that the &lt;code&gt;named_scope&lt;/code&gt; method originally received.  
&lt;/p&gt;
&lt;p&gt;After some digging into the &lt;code&gt;Scope&lt;/code&gt; class, and researching where the &lt;code&gt;scopes&lt;/code&gt; hash is used, I determined that the &lt;code&gt;scopes&lt;/code&gt; hash maps the name of your named scope to a &lt;code&gt;lambda&lt;/code&gt; expression that will be executed later.
&lt;/p&gt;
&lt;h2&gt;3. Refactoring, Part 1&lt;/h2&gt;

&lt;p&gt;Let's refactor this code segment out to a well-named method that more clearly describes the author's original intent.  
&lt;/p&gt;
              &lt;table class="code_listing"&gt;
                &lt;tr&gt;
                  &lt;td class="code ruby"&gt;&lt;pre&gt;&lt;notextile&gt;&lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;save_scope_definition_for_later&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;options&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="punct"&gt;&amp;amp;&lt;/span&gt;&lt;span class="ident"&gt;block&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
  &lt;span class="ident"&gt;scopes&lt;/span&gt;&lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="ident"&gt;name&lt;/span&gt;&lt;span class="punct"&gt;]&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;lambda&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt; &lt;span class="punct"&gt;|&lt;/span&gt;&lt;span class="ident"&gt;parent_scope&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="punct"&gt;*&lt;/span&gt;&lt;span class="ident"&gt;args&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt;
    &lt;span class="constant"&gt;Scope&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;parent_scope&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="keyword"&gt;case&lt;/span&gt; &lt;span class="ident"&gt;options&lt;/span&gt;
      &lt;span class="keyword"&gt;when&lt;/span&gt; &lt;span class="constant"&gt;Hash&lt;/span&gt;
        &lt;span class="ident"&gt;options&lt;/span&gt;
      &lt;span class="keyword"&gt;when&lt;/span&gt; &lt;span class="constant"&gt;Proc&lt;/span&gt;
        &lt;span class="ident"&gt;options&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;call&lt;/span&gt;&lt;span class="punct"&gt;(*&lt;/span&gt;&lt;span class="ident"&gt;args&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
    &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="punct"&gt;&amp;amp;&lt;/span&gt;&lt;span class="ident"&gt;block&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;/notextile&gt;&lt;/pre&gt;&lt;/td&gt;
                &lt;/tr&gt;
              &lt;/table&gt;


&lt;p&gt;Now we can simplify the original code a little bit:
&lt;/p&gt;
              &lt;table class="code_listing"&gt;
                &lt;tr&gt;
                  &lt;td class="line_numbers"&gt;&lt;pre&gt;&lt;notextile&gt;1
2
3
4
5
6
7
8
9
10
11
12&lt;/notextile&gt;&lt;/pre&gt;&lt;/td&gt;
                  &lt;td class="code ruby"&gt;&lt;pre&gt;&lt;notextile&gt;&lt;span class="comment"&gt;# New implementation after one round of refactoring&lt;/span&gt;
&lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;named_scope&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;name&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;options&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="punct"&gt;{},&lt;/span&gt; &lt;span class="punct"&gt;&amp;amp;&lt;/span&gt;&lt;span class="ident"&gt;block&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
  &lt;span class="ident"&gt;name&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;name&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;to_sym&lt;/span&gt;
  
  &lt;span class="ident"&gt;save_scope_definition_for_later&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;options&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="punct"&gt;&amp;amp;&lt;/span&gt;&lt;span class="ident"&gt;block&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
  
  &lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="punct"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="constant"&gt;self&lt;/span&gt;&lt;span class="punct"&gt;;&lt;/span&gt; &lt;span class="constant"&gt;self&lt;/span&gt; &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;span class="punct"&gt;).&lt;/span&gt;&lt;span class="ident"&gt;instance_eval&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt;
    &lt;span class="ident"&gt;define_method&lt;/span&gt; &lt;span class="ident"&gt;name&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt; &lt;span class="punct"&gt;|*&lt;/span&gt;&lt;span class="ident"&gt;args&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt;
      &lt;span class="ident"&gt;scopes&lt;/span&gt;&lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="ident"&gt;name&lt;/span&gt;&lt;span class="punct"&gt;].&lt;/span&gt;&lt;span class="ident"&gt;call&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="constant"&gt;self&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="punct"&gt;*&lt;/span&gt;&lt;span class="ident"&gt;args&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
    &lt;span class="keyword"&gt;end&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;/notextile&gt;&lt;/pre&gt;&lt;/td&gt;
                &lt;/tr&gt;
              &lt;/table&gt;


&lt;p&gt;Wow, that helped a lot.  Less code, more transparency.  It feels a lot better already.
&lt;/p&gt;
&lt;h2&gt;4. Refactoring, Part 2&lt;/h2&gt;

&lt;p&gt;We now have less code in the &lt;code&gt;named_scope&lt;/code&gt; method. But the code that remains still feels a bit funny. Ruby methods should contain code at the same level of abstraction.  The nice-looking call to save away the scope definition is followed several lines of very detailed-looking code.  
&lt;/p&gt;
&lt;p&gt;Let's take a closer look at the remaining code:
&lt;/p&gt;
              &lt;table class="code_listing"&gt;
                &lt;tr&gt;
                  &lt;td class="code ruby"&gt;&lt;pre&gt;&lt;notextile&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="punct"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="constant"&gt;self&lt;/span&gt;&lt;span class="punct"&gt;;&lt;/span&gt; &lt;span class="constant"&gt;self&lt;/span&gt; &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;span class="punct"&gt;).&lt;/span&gt;&lt;span class="ident"&gt;instance_eval&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt;
  &lt;span class="ident"&gt;define_method&lt;/span&gt; &lt;span class="ident"&gt;name&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt; &lt;span class="punct"&gt;|*&lt;/span&gt;&lt;span class="ident"&gt;args&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt;
    &lt;span class="ident"&gt;scopes&lt;/span&gt;&lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="ident"&gt;name&lt;/span&gt;&lt;span class="punct"&gt;].&lt;/span&gt;&lt;span class="ident"&gt;call&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="constant"&gt;self&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="punct"&gt;*&lt;/span&gt;&lt;span class="ident"&gt;args&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;/notextile&gt;&lt;/pre&gt;&lt;/td&gt;
                &lt;/tr&gt;
              &lt;/table&gt;


&lt;p&gt;There are actually two advanced Ruby idioms in use here. Suffice to say, this code will generate a new method in your model class.  The name of this new method is made to be the same as your named scope; and the implementation is actually quite simple: it first finds the appropriate scope definition that had previously been saved away, and executes it.  
&lt;/p&gt;
&lt;p&gt;Let's again factor this out to a well-named method:
&lt;/p&gt;
              &lt;table class="code_listing"&gt;
                &lt;tr&gt;
                  &lt;td class="code ruby"&gt;&lt;pre&gt;&lt;notextile&gt;&lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;create_method_with_same_name_as_scope&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;name&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
  &lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="punct"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="constant"&gt;self&lt;/span&gt;&lt;span class="punct"&gt;;&lt;/span&gt; &lt;span class="constant"&gt;self&lt;/span&gt; &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;span class="punct"&gt;).&lt;/span&gt;&lt;span class="ident"&gt;instance_eval&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt;
    &lt;span class="ident"&gt;define_method&lt;/span&gt; &lt;span class="ident"&gt;name&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt; &lt;span class="punct"&gt;|*&lt;/span&gt;&lt;span class="ident"&gt;args&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt;
      &lt;span class="ident"&gt;scopes&lt;/span&gt;&lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="ident"&gt;name&lt;/span&gt;&lt;span class="punct"&gt;].&lt;/span&gt;&lt;span class="ident"&gt;call&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="constant"&gt;self&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="punct"&gt;*&lt;/span&gt;&lt;span class="ident"&gt;args&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
    &lt;span class="keyword"&gt;end&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;/notextile&gt;&lt;/pre&gt;&lt;/td&gt;
                &lt;/tr&gt;
              &lt;/table&gt;
 

&lt;p&gt;And now, the &lt;code&gt;named_scope&lt;/code&gt; method has been reduced to this:
&lt;/p&gt;
              &lt;table class="code_listing"&gt;
                &lt;tr&gt;
                  &lt;td class="line_numbers"&gt;&lt;pre&gt;&lt;notextile&gt;1
2
3
4
5
6&lt;/notextile&gt;&lt;/pre&gt;&lt;/td&gt;
                  &lt;td class="code ruby"&gt;&lt;pre&gt;&lt;notextile&gt;&lt;span class="comment"&gt;# Clearer code&lt;/span&gt;
&lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;named_scope&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;name&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;options&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="punct"&gt;{},&lt;/span&gt; &lt;span class="punct"&gt;&amp;amp;&lt;/span&gt;&lt;span class="ident"&gt;block&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
  &lt;span class="ident"&gt;name&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;name&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;to_sym&lt;/span&gt; 
  &lt;span class="ident"&gt;save_scope_definition_for_later&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;options&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="punct"&gt;&amp;amp;&lt;/span&gt;&lt;span class="ident"&gt;block&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
  &lt;span class="ident"&gt;create_method_with_same_name_as_scope&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;name&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;/notextile&gt;&lt;/pre&gt;&lt;/td&gt;
                &lt;/tr&gt;
              &lt;/table&gt;


&lt;p&gt;We can even do away with that reassignment of the &lt;code&gt;name&lt;/code&gt; variable as well, and perform the conversion on the fly:
&lt;/p&gt;

              &lt;table class="code_listing"&gt;
                &lt;tr&gt;
                  &lt;td class="line_numbers"&gt;&lt;pre&gt;&lt;notextile&gt;1
2
3
4
5&lt;/notextile&gt;&lt;/pre&gt;&lt;/td&gt;
                  &lt;td class="code ruby"&gt;&lt;pre&gt;&lt;notextile&gt;&lt;span class="comment"&gt;# Refactored version&lt;/span&gt;
&lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;named_scope&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;name&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;options&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="punct"&gt;{},&lt;/span&gt; &lt;span class="punct"&gt;&amp;amp;&lt;/span&gt;&lt;span class="ident"&gt;block&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
  &lt;span class="ident"&gt;save_scope_definition_for_later&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;options&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="punct"&gt;&amp;amp;&lt;/span&gt;&lt;span class="ident"&gt;block&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
  &lt;span class="ident"&gt;create_method_with_same_name_as_scope&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;name&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;to_sym&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;/notextile&gt;&lt;/pre&gt;&lt;/td&gt;
                &lt;/tr&gt;
              &lt;/table&gt;


&lt;p/&gt;

&lt;h2&gt;5. What Did We Learn?&lt;/h2&gt;

&lt;p&gt;Imagine if our final version of the &lt;code&gt;named_scope&lt;/code&gt; was the _first_ version you saw.  You'd probably have a much easier time understanding how it works because there are two methods, each descriptively named, that provide insight into their intent. 
&lt;/p&gt;
&lt;p&gt;Refactoring is great way to learn code that you don't understand.  Begin slowly, and work to understand what the code does.  As you gain understanding, you may find that extracting out the more complicated segments into well-named methods will bring a level of clarity that you did not have when you started.
&lt;/p&gt;
&lt;div class="callout"&gt;&lt;img alt="Note" src="/images/icons/note.png?1253338587" /&gt;&lt;p&gt;&lt;p&gt;For a complete introduction to the practice of refactoring, we recommend Martin Fowler's seminal work, &lt;a href="http://www.amazon.com/exec/obidos/ASIN/0201485672"&gt;Refactoring: Improving the Design of Existing Code&lt;/a&gt;.&lt;/p&gt;
&lt;/p&gt;&lt;/div&gt;

&lt;!--
  
--&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/purpleworkshops?a=FwCEoCm3wrg:YGXKnxNagMI:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/purpleworkshops?i=FwCEoCm3wrg:YGXKnxNagMI:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/purpleworkshops?a=FwCEoCm3wrg:YGXKnxNagMI:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/purpleworkshops?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/purpleworkshops?a=FwCEoCm3wrg:YGXKnxNagMI:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/purpleworkshops?i=FwCEoCm3wrg:YGXKnxNagMI:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/purpleworkshops?a=FwCEoCm3wrg:YGXKnxNagMI:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/purpleworkshops?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/purpleworkshops/~4/FwCEoCm3wrg" height="1" width="1"/&gt;</description>
      <pubDate>19 Nov 2008</pubDate>
      <link>http://feedproxy.google.com/~r/purpleworkshops/~3/FwCEoCm3wrg/named-scope-refactored</link>
      <guid isPermaLink="false">http://www.purpleworkshops.com/articles/named-scope-refactored</guid>
      <dc:creator>Jeff Cohen</dc:creator>
    <feedburner:origLink>http://www.purpleworkshops.com/articles/named-scope-refactored</feedburner:origLink></item>
    <item>
      <title>Ruby 101: Method Definitions</title>
      <description>&lt;p&gt;&lt;i&gt;
        Note: For best formatting, you may want to &lt;a href="http://www.purpleworkshops.com/articles/method-definitions"&gt;view this article on the web&lt;/a&gt;.&lt;/i&gt;&lt;/p&gt;&lt;p&gt;Objects manage state, and they also exhibit behavior.  In this article, we'll be learning how to add behavior to classes that we write in Ruby.  
&lt;/p&gt;
&lt;p&gt;By "behavior" we mean, what the class, or an instance of the class, can "do."  While variables allow an object to store data, Ruby objects can define &lt;strong&gt;methods&lt;/strong&gt; that execute code.  This is an essential concept in object-oriented programming.  Objects don't just encapsulate data, they also perform actions and can have responsibilities assigned to them.
&lt;/p&gt;
&lt;h2&gt;1. The Basics&lt;/h2&gt;

&lt;p&gt;Sometimes the best way to learn is to dive right in.  Take a look at this Ruby code.
&lt;/p&gt;
              &lt;table class="code_listing"&gt;
                &lt;tr&gt;
                  &lt;td class="line_numbers"&gt;&lt;pre&gt;&lt;notextile&gt;1
2&lt;/notextile&gt;&lt;/pre&gt;&lt;/td&gt;
                  &lt;td class="code ruby"&gt;&lt;pre&gt;&lt;notextile&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;Telephone&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;/notextile&gt;&lt;/pre&gt;&lt;/td&gt;
                &lt;/tr&gt;
              &lt;/table&gt;


&lt;p&gt;This Ruby code defines our &lt;code&gt;Telephone&lt;/code&gt; class.  A class is a blueprint for how to make objects of that class.  We can create a new &lt;code&gt;Telephone&lt;/code&gt; object by calling the &lt;code&gt;new&lt;/code&gt; method on our class:
&lt;/p&gt;
              &lt;table class="code_listing"&gt;
                &lt;tr&gt;
                  &lt;td class="line_numbers"&gt;&lt;pre&gt;&lt;notextile&gt;1&lt;/notextile&gt;&lt;/pre&gt;&lt;/td&gt;
                  &lt;td class="code ruby"&gt;&lt;pre&gt;&lt;notextile&gt;&lt;span class="ident"&gt;my_phone&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Telephone&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;
&lt;/notextile&gt;&lt;/pre&gt;&lt;/td&gt;
                &lt;/tr&gt;
              &lt;/table&gt;


&lt;p&gt;&lt;code&gt;my_phone&lt;/code&gt; is now an &lt;strong&gt;instance&lt;/strong&gt; of a &lt;code&gt;Telephone&lt;/code&gt;.  What can our instance variable do that a plain &lt;code&gt;Object&lt;/code&gt; can't do? Well... nothing yet.  Let's teach a &lt;code&gt;Telephone&lt;/code&gt; how to dial a phone number:
&lt;/p&gt;
              &lt;table class="code_listing"&gt;
                &lt;tr&gt;
                  &lt;td class="line_numbers"&gt;&lt;pre&gt;&lt;notextile&gt;1
2
3
4
5
6
7
8
9
10&lt;/notextile&gt;&lt;/pre&gt;&lt;/td&gt;
                  &lt;td class="code ruby"&gt;&lt;pre&gt;&lt;notextile&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;Telephone&lt;/span&gt;

  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;dial&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;number&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
    &lt;span class="ident"&gt;puts&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;Dialing &lt;span class="expr"&gt;#{number}&lt;/span&gt;...&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;
  
&lt;span class="keyword"&gt;end&lt;/span&gt;

&lt;span class="ident"&gt;my_phone&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Telephone&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;
&lt;span class="ident"&gt;my_phone&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;dial&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;1-800-555-1212&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;
&lt;/notextile&gt;&lt;/pre&gt;&lt;/td&gt;
                &lt;/tr&gt;
              &lt;/table&gt;


&lt;p&gt;Here on line 3, we've defined an &lt;strong&gt;instance method&lt;/strong&gt; by using the &lt;strong&gt;def&lt;/strong&gt; keyword.  Save this code into a file named &lt;code&gt;phone.rb&lt;/code&gt;, and run it:
&lt;/p&gt;
&lt;pre class="session"&gt;c:\&gt; ruby phone.rb
Dialing 1-800-555-1212...
&lt;/pre&gt;

&lt;p&gt;We can define as many instance methods as we'd like.  Let's teach our object to hang up the phone.
&lt;/p&gt;
              &lt;table class="code_listing"&gt;
                &lt;tr&gt;
                  &lt;td class="line_numbers"&gt;&lt;pre&gt;&lt;notextile&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14&lt;/notextile&gt;&lt;/pre&gt;&lt;/td&gt;
                  &lt;td class="code ruby"&gt;&lt;pre&gt;&lt;notextile&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;Telephone&lt;/span&gt;

  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;dial&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;number&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
    &lt;span class="ident"&gt;puts&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;Dialing &lt;span class="expr"&gt;#{number}&lt;/span&gt;...&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;

  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;hang_up&lt;/span&gt;
    &lt;span class="ident"&gt;puts&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;Hung up.&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;

&lt;span class="ident"&gt;my_phone&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Telephone&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;
&lt;span class="ident"&gt;my_phone&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;dial&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;1-800-555-1212&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;
&lt;span class="ident"&gt;my_phone&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;hang_up&lt;/span&gt;
&lt;/notextile&gt;&lt;/pre&gt;&lt;/td&gt;
                &lt;/tr&gt;
              &lt;/table&gt;


&lt;p&gt;We'll get this:
&lt;/p&gt;
&lt;pre class="session"&gt;c:\&gt; ruby phone.rb
Dialing 1-800-555-1212...
Hung up.
&lt;/pre&gt;

&lt;p&gt;There is one special instance method you should know about, called the &lt;emph&gt;initializer&lt;/emph&gt;.  We don't have to define this method, but if we do, Ruby will call it for us automatically every time a new instance is created.  Here's an example:
&lt;/p&gt;
              &lt;table class="code_listing"&gt;
                &lt;tr&gt;
                  &lt;td class="line_numbers"&gt;&lt;pre&gt;&lt;notextile&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18&lt;/notextile&gt;&lt;/pre&gt;&lt;/td&gt;
                  &lt;td class="code ruby"&gt;&lt;pre&gt;&lt;notextile&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;Telephone&lt;/span&gt;

  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;initialize&lt;/span&gt;
    &lt;span class="ident"&gt;puts&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;New telephone created!&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;
  
  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;dial&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;number&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
    &lt;span class="ident"&gt;puts&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;Dialing &lt;span class="expr"&gt;#{number}&lt;/span&gt;...&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;

  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;hang_up&lt;/span&gt;
    &lt;span class="ident"&gt;puts&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;Hung up.&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;

&lt;span class="ident"&gt;my_phone&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Telephone&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;
&lt;span class="ident"&gt;my_phone&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;dial&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;1-800-555-1212&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;
&lt;span class="ident"&gt;my_phone&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;hang_up&lt;/span&gt;
&lt;/notextile&gt;&lt;/pre&gt;&lt;/td&gt;
                &lt;/tr&gt;
              &lt;/table&gt;


&lt;p&gt;Let's run it again:
&lt;/p&gt;
&lt;pre class="session"&gt;c:\&gt; ruby phone.rb
New telephone created!
Dialing 1-800-555-1212...
Hung up.
&lt;/pre&gt;

&lt;p&gt;Initializers can take arguments, just like our &lt;code&gt;dial&lt;/code&gt; method did.  We pass the actual argument values when we call &lt;code&gt;new&lt;/code&gt; to create instances of our object.  If we change our initializer to this:
&lt;/p&gt;
              &lt;table class="code_listing"&gt;
                &lt;tr&gt;
                  &lt;td class="code ruby"&gt;&lt;pre&gt;&lt;notextile&gt;&lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;initialize&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;home_area_code&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
  &lt;span class="ident"&gt;puts&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;New telephone created!&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;
  &lt;span class="attribute"&gt;@area_code&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;home_area_code&lt;/span&gt;
  &lt;span class="ident"&gt;puts&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;Our home area code is &lt;span class="expr"&gt;#{@area_code}&lt;/span&gt;.&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;/notextile&gt;&lt;/pre&gt;&lt;/td&gt;
                &lt;/tr&gt;
              &lt;/table&gt;


&lt;p&gt;Now we are required to provide the phone's home area code when we construct a &lt;code&gt;Telephone&lt;/code&gt; instance:
&lt;/p&gt;
              &lt;table class="code_listing"&gt;
                &lt;tr&gt;
                  &lt;td class="code ruby"&gt;&lt;pre&gt;&lt;notextile&gt;&lt;span class="ident"&gt;my_phone&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Telephone&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;&lt;span class="punct"&gt;('&lt;/span&gt;&lt;span class="string"&gt;312&lt;/span&gt;&lt;span class="punct"&gt;')&lt;/span&gt;
&lt;/notextile&gt;&lt;/pre&gt;&lt;/td&gt;
                &lt;/tr&gt;
              &lt;/table&gt;


&lt;p&gt;And now we'll get output like this:
&lt;/p&gt;
&lt;pre class="session"&gt;c:\&gt; ruby phone.rb
New telephone created!
Our home area code is 312.
Dialing 1-800-555-1212...
Hung up.
&lt;/pre&gt;

&lt;h2&gt;Class Methods vs. Instance Methods&lt;/h2&gt;

&lt;div class="callout"&gt;&lt;img alt="Note" src="/images/icons/note.png?1253338587" /&gt;&lt;p&gt;
Java and C# &lt;emph&gt;static methods&lt;/emph&gt; are the same as &lt;emph&gt;class methods&lt;/emph&gt; in Ruby.
(Switching from .NET to Rails? &lt;a href="/book"&gt;Buy the book&lt;/a&gt;).
&lt;/p&gt;&lt;/div&gt;

&lt;p&gt;So far we've learned how to create &lt;code&gt;instance methods&lt;/code&gt;.  They're called that because we have to first create an instance of our class before we can call them.
&lt;/p&gt;

&lt;p&gt;Sometimes we have functionality that seems appropriate to all telephones, regardless of _which_ telephone we might use.  We can create &lt;code&gt;class methods&lt;/code&gt; - methods that apply to the whole class, and not any specific instance.
&lt;/p&gt;

&lt;p&gt;Since all of our telephones have one thing in common - their manufacturer - we can create a class method to report the name of the manufacturer:
&lt;/p&gt;
              &lt;table class="code_listing"&gt;
                &lt;tr&gt;
                  &lt;td class="line_numbers"&gt;&lt;pre&gt;&lt;notextile&gt;1
2
3
4
5
6
7
8
9
10
11
12&lt;/notextile&gt;&lt;/pre&gt;&lt;/td&gt;
                  &lt;td class="code ruby"&gt;&lt;pre&gt;&lt;notextile&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;Telephone&lt;/span&gt;

  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;self.manufacturer&lt;/span&gt;
    &lt;span class="keyword"&gt;return&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;Purple Telco&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;
  
  &lt;span class="comment"&gt;# Rest of class definition goes here&lt;/span&gt;
  &lt;span class="comment"&gt;# ...&lt;/span&gt;
  
&lt;span class="keyword"&gt;end&lt;/span&gt;

&lt;span class="ident"&gt;puts&lt;/span&gt; &lt;span class="constant"&gt;Telephone&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;manufacturer&lt;/span&gt;
&lt;/notextile&gt;&lt;/pre&gt;&lt;/td&gt;
                &lt;/tr&gt;
              &lt;/table&gt;


&lt;p&gt;Notice how we prefix the &lt;code&gt;self&lt;/code&gt; keyword in front of the method name to indicate that it's a class method, instead of an instance method.  Let's run it:
&lt;/p&gt;
&lt;pre class="session"&gt;c:\&gt; ruby phone.rb
Purple Telco&lt;/pre&gt;

&lt;p&gt;Notice how we didn't need to create any instances first.  &lt;code&gt;manufacturer&lt;/code&gt; is a class method: all we needed was the name of the class.
&lt;/p&gt;
&lt;p&gt;Congratulations! You now know the basics of instance and class methods in Ruby.
&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/purpleworkshops?a=ikLT40Y8FhA:IOT4R7LetYM:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/purpleworkshops?i=ikLT40Y8FhA:IOT4R7LetYM:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/purpleworkshops?a=ikLT40Y8FhA:IOT4R7LetYM:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/purpleworkshops?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/purpleworkshops?a=ikLT40Y8FhA:IOT4R7LetYM:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/purpleworkshops?i=ikLT40Y8FhA:IOT4R7LetYM:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/purpleworkshops?a=ikLT40Y8FhA:IOT4R7LetYM:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/purpleworkshops?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/purpleworkshops/~4/ikLT40Y8FhA" height="1" width="1"/&gt;</description>
      <pubDate>18 Nov 2008</pubDate>
      <link>http://feedproxy.google.com/~r/purpleworkshops/~3/ikLT40Y8FhA/method-definitions</link>
      <guid isPermaLink="false">http://www.purpleworkshops.com/articles/method-definitions</guid>
      <dc:creator>Jeff Cohen</dc:creator>
    <feedburner:origLink>http://www.purpleworkshops.com/articles/method-definitions</feedburner:origLink></item>
  </channel>
</rss>
