Gray Soft

The programming blog of James Edward Gray II (JEG2).
  • 1

    MAR
    2008

    Design Patterns in Ruby

    I've been lucky enough to read a string of good Ruby books lately and the latest in that line is Design Patterns in Ruby. This book attempts to modernize the software design patterns by showing how these patterns can be applied in a language as dynamic as Ruby. Despite a couple of minor missteps along the way, the book definitely delivers on this goal.

    Design Patterns in Ruby begins with a couple of introductory chapters introducing both the concepts behind reusable software patterns and the Ruby programming language. After that, the main section of the book has 13 chapters that walk through 14 of the patterns first introduced in the famous "Gang of Four" book that began the design patterns movement. The author then introduces three new patterns he feels have grown out of day to day Ruby usage. Finally the book closes with a short conclusion and two appendices on installing Ruby and other sources of information.

    Most of that content is exactly what I wanted to find in this book, but you're going to have to tolerate a diversion about a pet peeve of mine that is strangely common in Ruby books. This is really, really important, so listen up: you can't teach Ruby in 30 pages. Period. I can hear all on the "But…" replies forming out there now… No buts. You can't. Trust me. Not even if the person is already an experienced programmer. It just can't be done. Authors and publishers need to come to terms with that and move on. Its just fine to say, "This is not a beginning Ruby book." We even prefer that, because we know when we are ready to read it and we don't have to skip that useless 30 page chapter when we do. Please, stop including introductory Ruby chapters in every book.

    Read more…

  • 29

    FEB
    2008

    A Bug, Today Only

    I had to debug some tests that just started failing first thing this morning. I guess I should have procrastinated though, because they would have magically fixed themselves tomorrow morning. The cause of the one day only bug: Leap Year Day, of course.

    If you run the following code on a day like today, February 29th 2008, Date will choke on your invalid date:

    require "date"  
    
    class Date
      # Returns a Date in the past +year_offset+ years ago.
      def self.years_ago(year_offset)
        now = today
        Date.civil(now.year - year_offset, now.month, now.day)
      end
    end
    
    puts Date.years_ago(1)
    

    I came up with the following fix, which is accurate enough for my purposes:

    require "date"
    
    class Date   # Returns a Date in the past +year_offset+ years ago.
      def self.years_ago(year_offset)
        today - 365 * year_offset
      end
    end
    
    puts Date.years_ago(1)
    

    I'm not 100% sure that covers all cases though, so use with caution. Date's are tricky business!

  • 28

    JAN
    2008

    Practical Ruby Projects

    Practical Ruby Projects is a pretty poorly named title, but, luckily, that doesn't stop it from being a very strong book. The book actually turns out to be an exploring-the-Ruby-programming-language-by-example book. These aren't your trivial beginners-only tasks though. There's enough meat in these pages for the intermediate crowd to really get into.

    Let me start by clarifying my earlier comment about the title. It's clear this book is named after the series it appears in, instead of the actual content it holds. There are lots of projects in the book and they are definitely written in Ruby, but Practical is not the word I would use to describe them. Fun, on the other hand, would be a great word. Beyond that, the code and concepts used in these projects is well worth studying. Just don't expect to find the typical (for Ruby) collection of Web programming tips inside. To me, that was a big plus. The title just misrepresents what's inside.

    The projects you will find in the book include: MIDI music generation, SVG graphic building, pocket change simulations, a turn-based strategy game, a Mac OS X GUI, a genetic algorithms framework, as well as both a parser and interpreter for the Lisp programming language. While these projects obviously tackle subsets of each problem space, they go deep enough to serve as a solid introduction in each area. The author is also good at focusing on the more interesting aspects of each challenge and throwing in a few twists to keep your interests high.

    Read more…

  • 24

    JAN
    2008

    From Bash to Z Shell

    I work on multiple Unix platforms all day long. I had never really taken the time to learn about the shells, but I had picked up the basics over time. I knew how to run commands, string them together with pipes, and redirect their output into files. So when I tell you that I started learning new things in the first chapter of From Bash to Z Shell, you will know the coverage is in depth. If you are a casual shell user, or even less experienced, this book has a lot to offer you.

    From Bash to Z Shell is organized into three parts. Part one is an introduction to shell basics. It focuses on typical interactions with a shell including all of the things I mentioned knowing before reading this book. There is surprisingly good depth even here though and I doubt that anyone short of a power user could make it through this section without picking up a new trick or two. I learned multiple things from each chapter in this section.

    In part two, each chapter takes a single aspect of the shells and really focuses in on just that. You will find chapters about the startup files each shell invokes as well as shell command histories. This is comprehensive coverage that really gets you to understand how things work as well as how to tune them to your personal tastes. You are even less likely to not pickup great tips in here.

    Read more…

  • 4

    JAN
    2008

    Dave Thomas is Definitely the Sammy Sosa of Programming

    There is a debate raging in the Ruby community that I don't want any part of. I'm not going to engage in any of the mud slinging and there will be no debate here. Commenters have been warned. What I do want to do is to share some simple uncontested facts about a man I am lucky enough to know.

    Sammy Sosa is famous for one thing: hitting home runs. In the entire history of the game of baseball five players have managed to hit over 600 home runs and Sammy is one of them. If that wasn't amazing enough, he has hit at least one home run against every single Major League team and in 44 Major League ballparks. Baseball fans everywhere love to watch Sammy Sosa at bat.

    Now if I had to name five programmers who get me as excited about programming as Sammy Sosa does about baseball, Dave Thomas would definitely make the list. Dave does exactly what Sammy always does: continually preforms the hardest tasks of his profession while making it look easy to the fans. Allow me to give a few examples.

    Read more…

  • 2

    JAN
    2008

    Getting FasterCSV Ready for Ruby 1.9

    The call came down from on high just before the Ruby 1.9 release: replace the standard csv.rb library with faster_csv.rb. With only hours to make the change it was a little harder than I expected. The FasterCSV code base was pretty vanilla Ruby, but it required more work than I would have guessed to get running on Ruby 1.9. Let me share a few of the tips I learned while doctoring the code in the hope that it will help others get their code ready for Ruby 1.9.

    Ruby's String Class Grows Up

    One of the biggest changes in Ruby 1.9 is the addition of m17n (multilingualization). This means that Ruby's Strings are now encoding aware and we must clarify in our code if we are working with bytes, characters, or lines.

    This is a good change, but the odds are that most of us have lazily used the old way to our advantage in the past. If you've ever written code like:

    lines = str.to_a
    

    you have bad habits to break. I sure did. Under Ruby 1.9 that code would translate to:

    lines = str.lines.to_a
    

    Read more…

  • 18

    NOV
    2007

    Ghost Wheel Example

    There has been a fair bit of buzz around the Treetop parser in the Ruby community lately. Part of that is fueled by the nice screencast that shows off how to use the parser generator.

    It doesn't get talked about as much, but I wrote a parser generator too, called Ghost Wheel. Probably the main reason Ghost Wheel doesn't receive much attention yet is that I have been slow in getting the documentation written. Given that, I thought I would show how the code built in the Treetop screencast translates to Ghost Wheel:

    #!/usr/bin/env ruby -wKU
    
    require "rubygems"
    require "ghost_wheel"
    
    # define a parser using Ghost Wheel's Ruby DSL
    RubyParser    = GhostWheel.build_parser do
      rule( :additive,
            alt( seq( :multiplicative,
                      :space,
                      :additive_op,
                      :space,
                      :additive ) { |add| add[0].send(add[2], add[-1])},
                 :multiplicative ) )
      rule(:additive_op, alt("+", "-"))
    
      rule( :multiplicative,
            alt( seq( :primary,
                      :space,
                      :multiplicative_op,
                      :space,
                      :multiplicative ) { |mul| mul[0].send(mul[2], mul[-1])},
                 :primary ) )
      rule(:multiplicative_op, alt("*", "/"))
    
      rule(:primary, alt(:parenthized_additive, :number))
      rule( :parenthized_additive,
            seq("(", :space, :additive, :space, ")") { |par| par[2] } )
      rule(:number, /[1-9][0-9]*|0/) { |n| Integer(n) }
    
      rule(:space, /\s*/)
      parser(:exp, seq(:additive, eof) { |e| e[0] })
    end
    
    # define a parser using Ghost Wheel's grammar syntax
    GrammarParser = GhostWheel.build_parser %q{
      additive             =  multiplicative space additive_op space additive
                              { ast[0].send(ast[2], ast[-1]) }
                           |  multiplicative
      additive_op          =  "+" | "-"
    
      multiplicative       =  primary space multiplicative_op space multiplicative
                              { ast[0].send(ast[2], ast[-1])}
                           |  primary
      multiplicative_op    =  "*" | "/"
    
      primary              = parenthized_additive | number
      parenthized_additive =  "(" space additive space ")" { ast[2] }
      number               =  /[1-9][0-9]*|0/ { Integer(ast) }
    
      space                =  /\s*/
      exp                  := additive EOF { ast[0] }
    }
    
    if __FILE__ == $PROGRAM_NAME
      require "test/unit"
    
      class TestArithmetic < Test::Unit::TestCase
        def test_paring_numbers
          assert_parses         "0"
          assert_parses         "1"
          assert_parses         "123"
          assert_does_not_parse "01"
        end
    
        def test_parsing_multiplicative
          assert_parses "1*2"
          assert_parses "1 * 2"
          assert_parses "1/2"
          assert_parses "1 / 2"
        end
    
        def test_parsing_additive
          assert_parses "1+2"
          assert_parses "1 + 2"
          assert_parses "1-2"
          assert_parses "1 - 2"
    
          assert_parses "1*2 + 3 * 4"
        end
    
        def test_parsing_parenthized_expressions
          assert_parses "1 * (2 + 3) * 4"
        end
    
        def test_parse_results
          assert_correct_result "0"
          assert_correct_result "1"
          assert_correct_result "123"
    
          assert_correct_result "1*2"
          assert_correct_result "1 * 2"
          assert_correct_result "1/2"
          assert_correct_result "1 / 2"
    
          assert_correct_result "1+2"
          assert_correct_result "1 + 2"
          assert_correct_result "1-2"
          assert_correct_result "1 - 2"
    
          assert_correct_result "1*2 + 3 * 4"
          assert_correct_result "1 * (2 + 3) * 4"
        end
    
        private
    
        PARSERS = [RubyParser, GrammarParser]
    
        def assert_parses(input)
          PARSERS.each do |parser|
            assert_nothing_raised(GhostWheel::FailedParseError) do
              parser.parse(input)
            end
          end
        end
    
        def assert_does_not_parse(input)
          PARSERS.each do |parser|
            assert_raises(GhostWheel::FailedParseError) { parser.parse(input) }
          end
        end
    
        def assert_correct_result(input)
          PARSERS.each { |parser| assert_equal(eval(input), parser.parse(input)) }
        end
      end
    end
    

    Read more…

  • 10

    SEP
    2007

    I Enjoy the Regional Conferences

    I have to say that the Lone Star Rubyconf was just great. I'm hoping that's representative of the other regional Ruby conferences as well and from what I've heard it is.

    I was at the official Rubyconf last year and I'm comfortable saying that the Lone Star Rubyconf competed well on content. We had great keynotes from Charles Nutter and Zed Shaw (though he's wrong about that don't love your language point); we had presentations from icons of the community, like Hal Fulton; we had popular topics covered by the experts, like the RSpec presentation from Mr. RSpec, David Chelimsky; and we had the wonderfully practical technical talks, like Evan Short's smooth coverage of Domain Specific Languages.

    While you do have to consider it a small minus to miss seeing Matz and a few other key Rubyists, the conference countered with a terrific small community feel. Everyone was open and friendly. You could easily approach anyone and chat them up about nearly any topic. Several people approached me and I loved it.

    Read more…

  • 8

    SEP
    2007

    I Got Booed at the LSRC!

    At the Lone Star Rubyconf, only a single speech coaxed a "Boo!" out crowd. Of course, it was mine.

    On a slide where I was trying to counter the expert warnings against using glue code features in Ruby, I told people not to lose a lot of sleep about external dependencies. When I added the comment, "That's your SysAdmin problem anyway," one audience member growled a complaint.

    The complainer later apologized to me for the outburst, but his point was valid that I didn't say what I intended to say.

    What I was trying to get across is that any external dependency I add to an application is going to become a line item in my SysAdmin's build script. After that, neither of us will lose any more sleep over it. He does his job so well that it makes mine easy. So, what came off as an insult, was intended as a compliment. I apologize.

    To rebalance the global karma pool, do me a favor and hug your SysAdmin today.

  • 7

    SEP
    2007

    Marcel at Play

    At the preconference charity event for the first Lone Star Rubyconf, Marcel Molina, Jr gave one of the best talks I've ever heard at a conference. The entire talk was Marcel showing examples of pathological (his word, not mine) Ruby code. Not only did he show all these examples to a room full of people new to language at an event titled Intro to Ruby, but he actually made a case for these examples being proof positive Ruby is a reliable language.

    This was a very unique approach to speeches in that we literally saw a Ruby master at play. While most speakers try to put our best foot forward, Marcel embraced the craziness and just had some fun. His attitude was infectious and really drove his point home.

    We should all try to have more fun with our speeches. It's so enlightening to watch, for any audience. I hope I have the courage to try a similar talk in the future.

    In: My Heroes | Tags: For Fun | 3 Comments