= Daijobu === "Oh no! Another key-value-store wrapper!" Don't worry, Daijobu isn't about that. Rather, it wraps the serialization/deserialzation layer of accessing key-value stores, specifically Tokyo Cabinet, but I guess with some work it could work with other things. === "So how's it work?" Make a new, inappropriately-named Daijobu::Client object and give it your store (supported stores are MemCache, Rufus::Tokyo::Cabinet, and Rufus::Tokyo::Tyrant), and then the scheme or schemes you want to use for serialization. rufus = Rufus::Tokyo::Cabinet.new('casket.tch') daijobu = Daijobu::Client.new(rufus, :schemes => :json) You can now use the regular hash getter and setter methods ([] and []=) without worrying about serialization. The out-of-the-box schemes are :marshal (using Marshal), :json (using JSON from the json gem), :yaml (using YAML), :eval (using Kernel::eval), and :raw (using nothing). You can specify your own schemes by making new Daijobu::Parser objects. Just instantiate a new Parser and tell it how you want to parse and unparse. parser = Daijobu::Parser.new({ :parse => Proc.new { |str| str.deserialize }, :unparse => Proc.new { |obj| obj.serialize } }) If you don't like passing procs as keyword arguments, you can give a block and define the #parse and #unparse methods yourself. parser = Daijobu::Parser.new do def parse(str) str.deserialize_using_some_fancy_method end def unparse(obj) obj.serialize_using_some_fancy_method end end Alternately, you can make a new Parser with a delegate object, and specify which methods of the delegate should be used for parsing and unparsing. For example, the :marshal parser is this: parser = Daijobu::Parser(Marshal, :parse => :load, :unparse => :dump) Then just pass this parser object as your scheme. daijobu = Daijobu::Client.new(rufus, :schemes => parser) Because some schemes are very strict, and sometimes what gets dumped can't be parsed back (for example, unparsing an integer using JSON), you can specify a set of schemes. If one doesn't work, it'll try the next in the list until it succeeds in parsing. Daijobu::Client.new(rufus, :schemes => [:json, :yaml, :eval]) Daijobu doesn't do any real format-checking; if, say, Marshal.load throws an error, for whatever reason, it'll just rescue and move on to the next scheme. Therefore, if you define your own parser and want to use fallbacks, the #parse and #unparse methods should raise some kind of error (besides a Daijobu::Error) if they fail. You can set different read and write schemes, too. This would be useful, say, if you wanted to change the serialization format. Daijobu::Client.new(rufus, :read => :json, :write => :raw) One last cool thing that I threw in just because: the key names in a key-value store are often namespaced, so you can call these namespaces as methods on a Client object to automatically prepend that namespace to any keys asked for. daijobu.namespace['123'] # => looks for 'namespace:123' daijobu.name.space['123'] # => looks for 'name:space:123' You can set the separator (defaults to ':' because that's what I was using) on the Daijobu::Client class. Daijobu::Client.default_separator = '/' daijobu.name.space['123'] # => 'name/space/123' Or you can set it per-invocation: daijobu.name('/').space(':')['123'] # => 'name/space:123' If this is the case, it'll keep using the last separator mentioned for subsequent namespacing. daijobu.some('/').long(':').name.space['123'] # => 'some/long:name:space:123' === "Anything else I should know?" Pretty much only the getting and setting APIs are implemented for the supported adapters, so fancier stuff like iterating over keys isn't there yet. Multi-get is also kind of janky right now for MemCache, due to a flaw in the memcache-client gem that assumes Marshal.load'ing on get_multi. Keys are therefore fetched one at a time. === "What does the future hold for Daijobu?" I plan to eventually switch out my home-rolled adapters for a more complete and more-intelligently-written backend, like Moneta, but last time I checked it was broken and I needed this gem to do work right now. Until then, I'm thinking of putting in support for user-defined adapters as a stopgap, basically any object that responds to #get(key) and #set(key, value). I also plan to take a look at ActiveRecord::Base#serialize to see if I can do something with that, because reading and writing YAML is like dying every day. === "What's with the name?" It's my understanding that "daijobu" is Japanese for "I'm fine" or "It's okay". The hardest thing about making gems is deciding what to call them, and that's the first thing that popped into my head. == Copyright Copyright (c) 2009 Sander Hartlage. See LICENSE for details.