Writing a Searchable Dictionary with Ruby and wxWidgets

Written By: Nathan Baker

- 29 May 2006 -

Description: For today's Ruby lesson, we will explore the creation of a simple GUI, and then create an interface allowing us to search a user-created dictionary.

  1. Introduction
  2. Getting started
  3. Gooey
  4. Making it actually do something

Part 2: Getting started

OK, before we dive into the wide world of wxWidgets, let's get the backend out of the way first. We want to take a user-supplied dictionary file, read it into memory, and provide the ability to search it. Let's go with a simple dictionary format: the word (or phrase), followed by an arbitrary number of tabs, followed by the definition. This allows the file to be nicely-formatted but still easily parsed, and tab is one of the few characters that doesn't legitimately appear in most standard text of any language.

Anyone with any familiarity with Ruby and regular expressions (or even with my previous article on Ruby) should be able to do this in their sleep, so I'll just dump the whole class here and then point out the more interesting parts before moving on.

class Dictionary
 
        def initialize(file)
                 = Hash.new
                
                File.open(file){ |f|
                        parse(f.read())
                }
        end
 
        def [](idx)
                [idx]
        end
 
        def lookup(word)
                [word]
        end
 
        def add(word, definition)
                [word] = definition
        end
 
        def each
                .each{ |k, v|
                        yield(k,v)
                }
        end
        
        def has_key?(k)
                .has_key?(k)
        end
 
private
 
        def parse(str)
                re = /(^[^\t]+)\t+(.+)/
                str.scan(re){ |key, entry|
                        [key] = entry
                }
        end
 
end

Well, that was pretty simple, no? Let's dissect this a bit before we get to the fun stuff:

First off, you'll notice that I pass a block of code to File.open (if you're new to Ruby, note now that you'll be seeing this a lot). This is similar to a using block in C#. It automatically closes the file once the end of the block is reached. This does keep the file open throughout the parsing, which could be avoided if I read the file contents into a variable and then closed the file before passing the variable to the parse method, but this is a minor detail and I wanted to illustrate this technique.

You can also see that I treat this class like a container--I implement each and the subscript operator. If you're going to be providing a wrapper for a class, you need to implement the most important functions of that class or nobody will use your wrapper. Also, Ruby (characteristically) makes it really easy to do, so why not?

Also, note that the ? is a valid character in the name of a method, and is usually used to denote a predicate, or a method that returns true or false. Ruby's LISP roots are certainly evident here.

Finally, notice that I use the extremely handy scan method to parse the file. I define a regular expression, and when I pass it to the scan method it calls the following code block on each match generated by the regular expression. Even more handy, each parameter in the lambda expression is assigned the result of one parenthesized subexpression, which makes doing things like, oh, parsing dictionary files ridiculously easy.

OK! Text parsing is some of the most boring programming imaginable, and thankfully Ruby makes it pretty painless. Even so, I almost fell asleep while writing this, so let's shake things up a bit in the next section.

<< Previous

Next >>