Gray Soft

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

    JAN
    2012

    Rubies in the Rough

    [Update: the Rubies in the Rough articles were originally available by subscription, but they are now free on this blog.]

    I know this blog has been quiet for quite some time now, but I'm still writing about Ruby. In fact, I'm very excited about a new series of articles I am producing called Rubies in the Rough.

    In that series, I am working hard not to teach the language or syntax or anything else that's trivial, but the thought processes behind how I program Ruby. I think this is some of the most important work I've ever done for Ruby. Anyone can learn a few keywords, but understanding how to think about problems and the solutions we code for them is key, in my opinion.

    This new series isn't free, but it is a steal. It works out to two bucks an article and I often write close to 20 printed pages. This is some serious content.

    If you want to learn how I think about programming, do yourself a favor and subscribe to Rubies in the Rough. It can teach you to see programming challenges as I see them and loan you my confidence as you solve them.

  • 11

    JAN
    2012

    Experimenting With DATA

    In the last article, I talked about the importance of a culture that encourages experimentation. It's hard to fiddle with something and not gain a better understanding of how it works. That knowledge is valuable to us programmers. I mentioned though that the way Perl programmers experiment is not the same way us Rubyists do it. Let me show you some actual Ruby experimentation I've witnessed over the years…

    Executing Your Email

    Some of Ruby's features are fairly obscure. Even worse, some of us who use those obscure features try to bend them to even stranger purposes. This is one way Rubyists like to experiment. Ironically, the features I'm going to talk about in this article are inherited from Perl.

    Ruby can literally use your email as an executable program. Assume I have the following saved in a file called email.txt:

    Dear Nuby:
    
    I just thought you would like to know what the Hello World program looks
    like in Ruby.  Here's the code:
    
    #!/usr/bin/env ruby -w
    
    puts "Hello world!"
    
    __END__
    
    I hope the simplicity of that inspires you to learn more.
    
    May Ruby Be With You,
    Ruby Jedi
    

    Read more…

  • 1

    JAN
    2012

    Perl's Golf Culture

    I'm stealing some time to write this while on vacation. I am also under the weather. Given that, we'll make this article short and easier on me to think up. That's not always a bad thing though. There are plenty of simple concepts I would like to get across. For example, let's talk about how Perl programmers do what it is they do.

    Ruby's Sister Language

    I spent plenty of time in the Perl camps and I really learned a lot about programming there. That may shock you to hear, because Perl programmers often get a bad wrap from the rest of the programming community.

    One reason they catch a lot flak is that their language is often terse to the point of obscurity. We joke that Perl is a "write only" language or too hard for other developers to read. That would be bad enough on its own, but Perl programmers seem to intentionally make this worse.

    Perl programmers love to play the programmer's version of golf. That is writing a program with the fewest possible keystrokes. To shrink their program's size, they will resort to every dirty trick in the book, including:

    Read more…

  • 21

    DEC
    2011

    Refactoring: rcat

    I use these Rubies in the Rough articles to teach how I think about code. Well, I have a scary admission to make: I didn't really understand refactoring until I was many years into being a programmer. Sure, I knew what it meant, but I just didn't get it. I hope to save you from the same mistake.

    Refactoring is important. Very important. It may be one of the most important things we do as programmers. If I learned one thing from reading Smalltalk Best Practice Patterns, it's that code's primary purpose is to communicate with the reader. Let's face it though, when we are trying to get something working, it's often like stumbling around in the dark. We are running into all kinds of things, breaking stuff, and just trying to reach that "Holy cow it works!" moment. We're probably not thinking too long and hard about how well this mess we are making communicates and that's perfectly fine.

    Refactoring is where you get to fix that. It's about taking working code and making it sexy. Note that I said it starts with working code. Until you have that, there's nothing worth communicating to a potential reader. Make it work, then make it sexy. (I believe that saying really involves speed, but that's a very different conversation we can have at a later date.)

    Read more…

  • 11

    DEC
    2011

    Even More Eloquent Ruby

    I recently read Eloquent Ruby so we can discuss it on an upcoming Ruby Rogues episode with author Russ Olsen. In short, the book is fantastic. You should definitely read it.

    I, on the other hand, am cranky. When you have read Ruby books since the first one was published (literally!), you can always find something to complain about. There are a handful of examples in Eloquent Ruby that could be better, in my opinion. I thought I would show you some of those. If you've read the book, this should make a nice supplement. Don't worry if you haven't though, you will still be able to follow these ideas just fine. I also won't spoil the ending, but you all know that the Rubyist saves the day.

    Before I start, let me stress one more time that this is a terrific book. It has so many clear discussions of real issues Rubyists must face when writing code like class variables, the differences between lambda(), proc(), and Proc.new(), how to use blocks and modules, why people think Ruby leaks memory and how you can avoid those problems, plus more. Don't let any fun I poke at the examples below change your view of this book. If I didn't love it, I wouldn't have bothered to write this article.

    Read more…

  • 1

    DEC
    2011

    Dreamy Testing (Part 2)

    In Part 1 of this article, I began building out my ideal testing interface, or at least my best attempt at such a thing.

    In that article, I worked primarily on the "assertion" interface: a file full of calls to ok() with a block that returns true or false to pass or fail tests. I also built some standard test printers to show us familiar output.

    As I wrapped up, I was running this code in example/basic_test.rb:

    ok("Is true")  { true        }
    ok("Is false") { false       }
    ok("Is error") { fail "Oops" }
    

    and seeing these results:

    $ ruby -I lib -r ok example/basic_test.rb 
    Running tests:
    .FE
    
    0) Failure: Is false
      example/basic_test.rb:2:in `<main>'
    1) Error: Is error
      example/basic_test.rb:3:in `block in <main>'
      example/basic_test.rb:3:in `<main>'
    
    Finished tests in 0.000300s
    3 tests, 1 failure, 1 error
    

    Of course, there was still a lot missing in my code. Let's work on adding some of the other must have features and perhaps a nicety or two.

    Running Tests

    In the first article, I spent a lot of time talking about how all of the references to things other than my code in tests are a distraction. I wanted to remove as much of that as possible. We have done pretty well on that front.

    Read more…

  • 21

    NOV
    2011

    Dreamy Testing (Part 1)

    I want to take a swing at one last rule before I wrap up this Breaking All of the Rules miniseries, at least for now. I'm not the type of guy to come out full on against many things and I won't do that here. But there is one rule I think is on pretty shaky ground for how often I hear it thrown about. Let's analyze it and break it.

    Don't Reinvent the Wheel

    It should be pretty thoroughly drilled into most programmer's minds that we don't want to waste our time reinventing wheels. Well, let's try to find the why behind that before we accept it as law.

    First, what's the not-so-hidden assumption this time? It's that we are wasting our time. If we aren't, should the rule still hold?

    As always, there are good reasons that this rule exists. Here are a couple I feel are worth honoring:

    • When you are in the middle of a job and you figure out that you need something, it's usually a much better idea to go with an existing, ready-to-use solution. It would take you time to rebuild it and your version isn't likely to be as robust (just due to it being newer).
    • If there's an existing solution that is 90% of what you need, it's probably better to contribute the other 10% than to separately build a new 100% solution. Contributing should be faster for you and help others in return.

    Read more…

  • 11

    NOV
    2011

    Doing it Wrong

    Continuing with my Breaking All of the Rules series, I want to peek into several little areas where I've been caught doing the wrong thing. I'm a rule breaker and I'm determined to take someone down with me!

    My Forbidden Parser

    In one application, I work with an API that hands me very simple data like this:

    <emails>
      <email>user1@example.com</email>
      <email>user2@example.com</email>
      <email>user3@example.com</email></emails>
    

    Now I need to make a dirty confession: I parsed this with a Regular Expression.

    I know, I know. We should never parse HTML or XML with a Regular Expression. If you don't believe me, just take a moment to actually read that response. Yikes!

    Oh and you shouldn't validate emails with a Regular Expression. Oops. We're talking about at least two violations here.

    But it gets worse.

    You may be think I rolled a little parser based on Regular Expressions. That might look like this:

    #!/usr/bin/env ruby -w
    
    require "strscan"
    
    class EmailParser
      def initialize(data)
        @scanner = StringScanner.new(data)
      end
    
      def parse(&block)
        parse_emails(&block)
      end
    
      private
    
      def parse_emails(&block)
        @scanner.scan(%r{\s*<emails>\s*}) or fail "Failed to match list start"
        loop do
          parse_email(&block) or break
        end
        @scanner.scan(%r{\s*</emails>}) or fail "Failed to match list end"
      end
    
      def parse_email(&block)
        if @scanner.scan(%r{<email>\s*})
          if email = @scanner.scan_until(%r{</email>\s*})
            block[email.strip[0..-9].strip]
            return true
          else
            fail "Failed to match email end"
          end
        end
        false
      end
    end
    
    EmailParser.new(ARGF.read).parse do |email|
      puts email
    end
    

    Read more…

  • 1

    NOV
    2011

    The Wrong Tool for the Job

    I want to start our exploration of how to think about Ruby programming with a miniseries called Breaking All of the Rules. As I'm sure you know, programmers have a lot of rules. You can barely speak to a programmer for a few minutes without them quoting some axiom. We have a huge collection of advice to hand out.

    Fortunately, I'm not just a programmer. I'm also a tournament chess player. Getting good at chess has really helped my programming. That's because chess players also have a ton of rules.

    Perhaps you've seen our books of opening chess moves? They are literally hundred of pages that just list the various moves that you can "start" a chess game with. I use the word start very loosely there because some combinations can go 20 moves into the game or more. Chess games generally only average about 60 moves, so the first third of what we do is often straight out of a book. In fact, while you are playing a chess opening, we say that you are "in book." That means you are following the rules.

    Read more…

  • 10

    JAN
    2010

    Tokyo Cabinet's Key-Value Database Types

    We've taken a good look at Tokyo Cabinet's Hash Database, but there's a lot more to the library than just that. Tokyo Cabinet supports three other kinds of databases. In addition, each database type accepts various tuning parameters that can be used to change its behavior. Each database type and setting involves different tradeoffs so you really have a lot of options for turning Tokyo Cabinet into exactly what you need. Let's look into some of those options now.

    The B+Tree Database

    Tokyo Cabinet's B+Tree Database is a little slower than the Hash Database we looked at before. That's its downside. However, giving up a little speed gains you several extra features that may just allow you to work smarter instead of faster.

    The B+Tree Database is a more advanced form of the Hash Database. What that means is that all of the stuff I showed you in the last article still applies. You can set, read, and remove values by keys, iteration is supported, and you still have access to the neat options like adding to counters. With a B+Tree Database you get all of that and more.

    Read more…