Subscribe to RSS

Writing A Web Application In Merb Part I

Testing different web frameworks is a great way to not only gain knowledge about that particular framework, but to quickly (as most of the Ruby web frameworks are focused on rapid development) implement ideas you’ve had kicking around for a while. This is what I’ll be doing over the next couple weeks, with the latest version of Merb, and a dumb little project I’ve been thinking about for a while. I’ll try to keep as close to BDD principles as I can, but I can’t make any guarantees.

The Idea

You may or may not be familiar with the Geek Code. Essentially, it is a tounge-in-cheek way of presenting personality attributes that are influential in determining the overall geekiness of a person. It is an interesting idea by itself, but as the original specification aged without being updated (and a decent amount of its criteria becoming obsolete), a few other people have built and expanded upon the idea. Whereas the original geek code specification resembled a PGP key block, newer versions of the code have been streamlined. One version in particular that strikes me as interesting is the Hacker Key, which attempts to fix several of the purported problems of the original Geek Code. What does all this have to do with web applications, however? Well, it’s very obvious there are a near infinite number of possible Hacker Keys or Geek Codes, and while each individual key can be represented by its individual values, it would be much more interesting if each Key was considered a sort of denominiation—one particular key represents the entire sect of people who assert that key’s preferences. The Hacker Keys become Hacker Cults!

So, we write a web application, choose your Hacker Key preferences, get your key, and if you’re the first person to come up with that distinct set of preferences, you get that cult named after you. There will be some dictionary of cultish prefixes and suffixes (”Seventh-Day”, “Orthodox”, that sort of thing), that will be randomly applied to your cult name. Then you can parade your new cult around in signatures and that sort of thing.

First Steps

One of the first things we want to do is be able to model a Hacker Key in a way that will not only allow us to easily store them in databases, but maintain their flexibility. We’re going to have to do a lot of testing to ensure we have an accurate model, because Hacker Keys have all kinds of interesting edge cases.

  • All categories have some kind of identifing symbol, be it one or two letters. In the case of the Hacker Key, these are always lowercase.
  • Then each category is usually—but not always—followed by a numerical suffix that indicates one’s prediliction for that category, with descriptions of each level of involvement that add ‘flavor’ to the code.
  • Following that numerical suffix, there is usually—but not always—a set of additional, stackable suffixes that are used to indicate a particular preference for a subset of the all-encompassing original category. For instance, the ‘b’ category is for books, and contains suffixes like ‘A’ for Isaac Asimov, ‘H’ for The Hitchhiker’s Guide to the Galaxy, and so on.
  • There are additional suffixes. For example, if a particular category is utilized by a hacker to earn a living, a dollar sign can be appended to the end of a category.
  • There are additional prefixes. For example, if a hacker refuses to address a category, they can prepend an exclamation point to that category’s symbol.

These are a lot of rules, and our model will have to deal with all of them. Not only will we have to ensure each individual category in a code is validly specified, but we will have to ensure each total Hacker Key is validly specified.

We’ll generate our application code…

$ merb HackerSchism
$ cd HackerSchism

…and we’ll set up our dependencies file to use the ORM and testing scheme we want, as well as Haml, because Haml is pretty :-)

config/dependencies.rb

# ...
use_orm  :datamapper
use_test :rspec
 
dependency "haml"
# ...

And to finish up our quick setup, we’ll generate our first model, and edit our database configuration file to point to databases you should create.

$ script/generate model HackerKeyCategory

So let’s take a look at an initial test.

spec/models/hacker_key_category_spec.rb

require File.join( File.dirname(__FILE__), "..", "spec_helper" )
 
describe HackerKeyCategory do
 
  it "should validate 'sw9'" do
    sw9 = HackerKeyCategory.new 'sw9'
    sw9.category.should == 'sw'
    sw9.category_description.should == 'Software Hacking'
    sw9.rating.should == 9
    sw9.rating_description.should == "I'm Bill Joy, Eric Raymond or JWZ."
  end
 
  it "should validate 'hw5'"
 
end

Note that rspec will ignore use cases that do not have a block, and simply mark them as ‘pending’. Our test will fail, and we’ll write some basic code to accomplish what we want, remembering to encapsulate.

app/models/hacker_key_category.rb

class HackerKeyCategory < DataMapper::Base
 
  attr_reader :category, :category_description
  attr_reader :rating,   :rating_description
 
  def self.categories
    {
      'sw' => 'Software Hacking',
      'hw' => 'Hardware Hacking'
    }
  end
 
  def self.ratings
    {
      'sw' => [
        nil, # level 0
        "I'm a manager and/or work at IBM",
        "I'm not even a programmer, much less a hacker!",
        "I don't hack software at all. I'm a structured programmer!",
        "I've hacked code once or twice, software isn't my thing.",
        "Average, I've made a few software hacks in my day.",
        "There is nothing better than an elegant hack.",
        "Live to Hack, Hack to Live!",
        "I am an uberhacker; I wrote my shell/debugger/editor/compiler in 30 lines of code. Other people use and love my hacks.",
        "I'm Bill Joy, Eric Raymond or JWZ."
        ]
    }
  end
 
  def initialize(string)
    parts = string.slice(/([a-z]+)(\d+)/)
    if parts
      @category = $~[1]
      @category_description = HackerKeyCategory.categories[$~[1]]
      @rating = $~[2].to_i
      @rating_description = HackerKeyCategory.ratings[$~[1]][self.rating]
    else
      raise ArgumentError, "incompatible rating supplied"
    end
  end
 
end

And our first test will pass! Note, our data is all in the class right now. That might be a problem as we keep adding more and more arrays and hashes of the Hacker Key information. We might want to load it from a file, we might want to store it in another ruby library, or we might want to load it from the database.

But this is a good place to stop for now. I will pick this up later.

Post a Comment

Your email is never published nor shared. Required fields are marked *

*
*