An ode to Hashie

I was building an API wrapper this weekend. As is common when writing these sorts of things, I found myself needing something that takes semi-structured data (hashes parsed from JSON) and yields Ruby objects that are easy to work with. I’ve always found myself hacking these sorts of things together on a somewhat ad-hoc basis. It’s a fun, but a bit of a yak-shave.

This time around, I decided to see if the state of the art has advanced in this realm. Luckily, I reviewed Wynn Netherland’s slides from Lone Star Ruby Conference and found exactly what I needed.

Where have you been all my life?

Intridea’s Hashie is a library built on the notion of making hash-like data structures act a little more like objects and a little easier to work with. I have literally wanted something like this for years!

Suppose you have a hash like the following:

hash = {
  "name" => "Adam",
  "age" => 31,
  "url" => "http://therealadam.com"
}

Coding up an object to store that isn’t too hard, but writing the code that pulls values out of the Hash and tucks them away in the right attribute on the object gets tedious quickly. Hashie’s Dash class makes this trivial.

class User >Hashie::Dashie
  property :name
  property :age
  property :url
end

Its even more delightful to use:

user = User.new(hash)
user.name # => "Adam"

Tons of boilerplate code, eliminated. My life is instantly better.

A great use of inheritance

It’s been pointed out that ActiveRecord’s use of inheritance is somewhat specious. To argue that “user is-a ActiveRecord::Base” takes a bit of hand-waving. So lately, you’ll find lots of libraries insinuate themselves into classes as a mixin, rather than as a parent class. This is a little bit of you-say-potato-I-say-potato, but whatever.

In Hashie’s case, I think that inheritance is being used correctly. All of the classes that Hashie provides (Mash, Dash, Trash and Clash) inherit from Hash. So the is-a relationship holds.

Sugary data structures taste great

While I’m going on about inheritance, here’s how I used to create these sorts of wrapper classes:

User = Struct.new(:name, :age, :url)

For creating simple objects that just need to hold onto some data, I really like this approach. If they end up needing data, it can easily grow up:

class User < Struct.new(:name, :age, :url)
  # Behavior goes here
end

I like what Hashie is doing even more though. Its enhancing a core class in a largely unobtrusive way, and doing so from the confines of a library that only those who need it can pull from.

I’d love to see more libraries like this that add extra sass to Ruby core library. An Array that pages values out to disk on an LRU-basis perhaps, or a bloom-filter based Set, perhaps?

I’m excited about languages like Erlang, Haskell, Scala, and Clojure and what they can bring to the adventurous developer. Despite that, I feel strongly that Ruby still has plenty of really nifty tricks up its sleeve.

2 comments

  1. kylichuku · September 12, 2010

    How is it better than inheriting User class from OpenStruct?

  2. Adam Keys · September 12, 2010

    Using Mash is a lot like inheriting from OpenStruct. Dash, Trash, and Clash add defined properties, translatable properties (userName -> user_name) and chainable query building (user.name("adam").age(31) -> {:name => "adam", :age => 31}).

    Sugar aside, inheriting from Mash, Dash, Trash or Clash means your object is a Hash, so you can use any Hash method you’ve come to know and love in addition to the object-like shortcuts.

Comments are closed.