Ruby Tutorials

Tutorials on Ruby specific concepts.
  • 5

    SEP
    2009

    eval() Isn't Quite Pure Evil

    I was explaining method lookup to the Lone Star Ruby Conference attendees and needed to show some trivial code like this:

    module B
      def call
        puts "B"
        super
      end
    end
    
    module C
      def call
        puts "C"
        super
      end
    end
    
    module D
      def call
        puts "D"
        super
      end
    end
    

    Unfortunately, my space was limited due to the code being on slides and me needing to show more than just what you see above. I cracked under the pressure and committed two major programming sins. First, I collapsed the code with eval():

    %w[B C D].each do |name|
      eval <<-END_RUBY
      module #{name}
        def call
          puts "#{name}"
          super
        end
      end
      END_RUBY
    end
    

    Then I really blew it when I jokingly apologized to the audience for using eval().

    I got the first email with corrected code before I even finished the speech. OK, the email was from a friend and he wasn't mean, but he still instantly needed to set me straight. I had clearly turned from the light.

    Only, his corrected code didn't quite work. It got close, but it had bugs. Still the approach was sound and it could be made to work. Let me fix the bugs and show you what was recommended:

    Read more…

  • 21

    APR
    2006

    Unit Testers Get More Chicks

    Just recently, a developer I respect very much was caught uttering the this surprising statement: "Unit tests just really aren't my thing." Now, I still respect this developer very much and I can tell you that the person single-handedly created one of my very favorite pieces of software. However, I do think the developer is dead wrong on this point. This is my attempt to change the mind of everyone that thinks similar things about unit testing.

    My belief is that unit testing is for everyone and, in fact, I'll go so far as to say that I believe becoming a test-driven developer is the single best change a programmer can make in their day to day routine. Here are just some of the reasons why:

    • Though counterintuitive, I swear that it makes you code faster. No one tends to believe me on this, but most test-driven developers come to this realization eventually. The reason is simple: you spend much less time debugging the 935 errors from your two hour code sprees.
    • The tests are my memory. My head is too full of all the languages, frameworks, APIs, and family birthdays I am expected to know to remember everything I've ever done on top of that. This week at work I've touched three separate projects all with over 1,000 lines of code. I'm sure I had good ideas when I wrote those lines, but now I doubt I can tell you what they are. My tests can though. They remember so I don't have to. If I go into the code and change something I don't remember was needed or why, my tests will remind me immediately.
    • In team development, my test powered memory even travels to the machines of the other developers! How cool is that? When someone goes into the code and says, "Why on Earth did James do this? We don't need this. I'm going to change that…" my tests will look after my interests for me.
    • I'm a lot more confident in my software. I use to say things like, "I just finished this, so it hasn't been used much yet and probably still has plenty of issues." Now by the time I finish something my tests have been using the heck out of it. I won't kid you and tell you that my software now springs fully formed from the head of my tests, but it definitely comes out farther along the track.
    • Environment changes seldom surprise me anymore. When I move my software to a different box and it can't cope for whatever reason, I not only know the first time I run the tests, I have an excellent idea of exactly where the problem is.

    Read more…

  • 22

    FEB
    2006

    Class Level Mix-ins

    A question that comes up pretty often in Ruby circles was posed again today, by Xavier Noria:

    #
    # Is there standard idiom to add module methods to classes that mix them in?
    #
    # That is, I would like class C to croak:
    #
    
    module M
      def self.croak
        puts "Croak!"
      end
    end
    
    class C
      include M
      croak  # doesn't work
    end
    

    This brings up a couple of interesting points about mix-ins. Obviously, class methods are not easily added to things, but we generally want class methods so we can call them directly from the module. Here's how I deal with this issue.

    First, instance methods are the way to go for anything you will be mixing in, period. With instance methods, you can inject them into a class or object. With anything else you have to start hacking. That gives us our first change:

    module M
      def croak
        puts "Croak!"
      end
    end
    

    Now, we really wanted a module method, so I've made things worse. However, as I've said, we have all the choices with this setup. Let's just mix the module into it's own class!

    Read more…

  • 5

    JAN
    2006

    Code as a Data Type

    Introduction

    This is the first of a series of articles where I will try to demystify some Ruby idioms for the people who come to Ruby through Rails and find themselves wanting to learn a little more about the language under the hood.

    Strings, Arrays, ... and Code?

    You don't have to code for long in any language before you get intimately familiar with some standard data types. We all have a fair grasp of Ruby's String and Array, because every language has something similar. Ruby has an unusual data type though, which can trip up newcomers. That type is Ruby code itself.

    Allow me to explain what I mean, through an example. First, let's create a little in-memory database to work with:

    class ClientDB
      Record = Struct.new(:client_name, :location, :projects)
    
      def initialize
        @records = [ Record.new( "Gray Soft", "Oklahoma",
                                 ["Ruby Quiz", "Rails Extensions"] ),
                     Record.new( "Serenity Crew", "Deep Space",
                                 ["Ship Enhancements"] ),
                     Record.new( "Neo", "Hollywood", 
                                 ["Rails interface for the Matrix"] ) ]
      end
    end
    

    Read more…