Gray Soft

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


    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:
    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


    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


    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:


    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 =
      def parse(&block)
      def parse_emails(&block)
        @scanner.scan(%r{\s*<emails>\s*}) or fail "Failed to match list start"
        loop do
          parse_email(&block) or break
        @scanner.scan(%r{\s*</emails>}) or fail "Failed to match list end"
      def parse_email(&block)
        if @scanner.scan(%r{<email>\s*})
          if email = @scanner.scan_until(%r{</email>\s*})
            return true
            fail "Failed to match email end"
    end do |email|
      puts email

    Read more…

  • 1


    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


    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…

  • 1


    Tokyo Cabinet as a Key-Value Store

    Like most key-value stores, Tokyo Cabinet has a very Hash-like interface from Ruby (assuming you use Oklahoma Mixer). You can almost think of a Tokyo Cabinet database as a Hash that just happens to be stored in a file instead of memory. The advantage of that is that your data doesn't have to fit into memory. Luckily, you don't have to pay a big speed penalty to get this disk-backed storage. Tokyo Cabinet is pretty darn fast.

    Getting and Setting Keys

    Let's have a look at the normal Hash-like methods as well as the file storage aspect:

    #!/usr/bin/env ruby -KU
    require "oklahoma_mixer""data.tch") do |db|
        puts "Loading the database.  Rerun to read back the data."
        db[:one] = 1
        db[:two] = 2
        db.update(:three => 3, :four => 4)
        db["users:1"] = "James"
        db["users:2"] = "Ruby"
        puts "Reading data."
        %w[ db[:one]
            db.keys(:prefix\ =>\ "users:")
            db.keys(:limit\ =>\ 2)
            db.values_at(:one,\ :two) ].each do |command|
          puts(command == "-" ? "" : "#{command} = %p" % [eval(command)])

    Read more…

  • 17


    Where Redis is a Good Fit

    Like any system, Redis has strengths and weaknesses. Some of the biggest positives with Redis are:

    • It's wicked fast. In fact, it may just be the fastest key-value store.
    • The collection types and the atomic operations that work on them allow you to model some moderately complex data scenarios. This makes Redis fit some higher order problems where a simple key-value store wouldn't quite be enough.
    • The snapshot data dumping model can be an asset. You get persistence with Redis, but you pay a minimal penalty for it.

    Of course, there are always some minuses. These are the two I consider the most important:

    • Redis is an in-memory data store, first and foremost. That means your entire dataset must fit completely in RAM and leave enough breathing room for anything else the server must do.
    • Snapshot backups are not perfect. If Redis fails between snapshots, you can lose data. You need to make sure that's acceptable for any application you use it in.

    It may seem weird to call snapshots both a pro and a con, but it does work for you in some ways and against you in others. You have to decide where the trade-off is worth it.

    Read more…

  • 16


    Lists and Sets in Redis

    [Update: though all of the techniques I show here still apply, many methods of the Redis gem have changed names to match the actual Redis commands they call. There are also easier and more powerful ways to do some of what I show in here, thanks to additions to Redis.]

    Redis adds one huge twist to traditional key-value storage: collections. Supporting both lists and sets through some very powerful atomic operations allows for advanced key-value usage.


    Redis allows a single key to hold a list of values. This is your typical ordered list with the operations you would expect: appending, indexed access, and access to a range of values.

    This has many potential uses. I'll cover two that I think will be very common. First, if you are going to use Redis as a full database, you store things that are naturally a list of items, like comments, in a real list. Let's look at some code:

    #!/usr/bin/env ruby -wKU
    require "redis"
    CLEAR = `clear`
    # create an article to comment on
    db                =
    article_id        = db.incr("global:next_article_id")
    article           = "article:#{article_id}"
    class << article
      def method_missing(field, *args, &blk)
        return super unless field.to_s !~ /[!?=]\z/ && args.empty? && blk.nil?
    db[article.title] = "My Favorite Language"
    db[article.body]  = "I love Ruby!"
    # initialize some session details
    comments_per_page = 2
    comment_page      = 1
    login             = ARGV.shift || "JEG2"
    loop do
      # show article
      print CLEAR
      puts "#{db[article.title]}:"
      puts "  #{db[article.body]}"
      # paginate comments
      start      =  comments_per_page * (comment_page - 1)
      finish     =  start + comments_per_page - 1
      comments   =  db.list_range(article.comments, start, finish)
      pagination =  Array( ? nil : "(p)revious")
      pagination << "(n)ext" if db.list_length(article.comments) - 1 > finish
      # show comments
      comments.each do |comment|
        posted, user, body = comment.split("|", 3)
        puts "----"
        puts "  #{body}"
        puts "  posted by #{user} on #{posted}"
      # handle commands
      print "Command? [#{(%w[(c)omment (q)uit] + pagination).join(', ')}]  "
      case (command = gets)
      when /\Ac(?:omment)?\Z/i  # add a comment
        print "Your comment?  "
        comment = gets or break
        posted  ='%m/%d/%Y at %H:%M:%S')
        db.push_tail(article.comments, "#{posted}|#{login}|#{comment.strip}")
      when /\Ap(?:revious)?\Z/i  # view previous page of comments
        if pagination.first =~ /\A\(p\)/
          comment_page -= 1
          puts "You are on the first page of comments."
          gets or break
      when /\An(?:ext)?\Z/i  # view next page of comments
        if pagination.last =~ /\A\(n\)/
          comment_page += 1
          puts "You are on the last page of comments."
          gets or break
      when /\Aq(?:uit)?\Z/i, nil  # exit program

    Read more…

  • 15


    Using Redis as a Key-Value Store

    [Update: though all of the techniques I show here still apply, many methods of the Redis gem have changed names to match the actual Redis commands they call.]

    Redis is a first and foremost a server providing key-value storage. As such, the primary features of any client library are for connecting to the server and manipulating those key-value pairs.

    Connecting to the Server

    Connecting to the Redis server can be as simple as, thanks to some defaults in both the server and Ezra's Ruby client library for talking to that server. I won't pass any options to the constructor calls below, but you can use any of the following as needed:

    • :host if you need to connect to an external host instead of the default
    • :port if you need to use something other than the default port of 6379
    • :password if you configured Redis to require a password on connection
    • :db if you want to select one of the multiple configured databases, other than the default of 0 (databases are identified by a zero-based index)
    • :timeoeut if you want a different timeout for Redis communication than the default of 5 seconds
    • :logger if you want the library to log activity as it works

    Read more…

  • 14


    Setting up the Redis Server

    Before we can play with Redis, you will need to get the server running locally. Luckily, that's very easy.

    Installing Redis

    Building Redis is a simple matter of grabbing the code and compiling it. Once built, you can place the executables in a convenient location in your PATH. On my box, I can do all of that with these commands:

    curl -O
    tar xzvf redis-1.0.tar.gz 
    cd redis-1.0
    sudo cp redis-server redis-cli redis-benchmark /usr/local/bin

    Those commands build version 1.0 of the server, which is the current stable release as of this writing. You may need to adjust the version numbers down the road to get the latest releases though.

    I also copied the executables to where I prefer to have them: /usr/local/bin. Feel free to change that directory in the last command to whatever you prefer.

    If you will be talking to Redis from Ruby, as I will show in all of my examples, you are going to need a client library. I recommend Ezra Zygmuntowicz's redis-rb. You can install that gem with:

    Read more…