30
JUL2006
PStore Meets YAML
I love the PStore standard library. It's a very graceful interface to get some fairly robust serialized mini-database handling in just a few lines. With it you get:
- Transactions with commit and rollbacks (automatic on exception).
- File locking, shared and exclusive.
- Multiprocessing safety.
PStore does even more, including some file mode checking and MD5 hashing to avoid unneeded writes, but the above are the major selling points for me.
Now, if I had to level any one complaint at PStore, it would be that because it uses Marshal under the hood it doesn't create files you can easily browse or tweak by hand. (Marshal is a feature, don't get me wrong. It's fast, which is very helpful.) Sometimes though I want PStore protection with the YAML file format.
I'm embarrassed to admit that I use to use a hack for this:
require "pstore"
require "yaml"
class PStore; Marshal = YAML; end
That just redefines the Marshal constant in a scope that should only alter PStore. The library only uses dump() and load() and those methods work the same with Marshal and YAML.
Ready for the punch-line?
I learned today that my fragile hack has been in vain, no matter how clever it may be. YAML ships with a file that will load and modify PStore for you. Usage is as simple as:
require "yaml/store"
From there just replace your PStore.new() calls with YAML::Store.new() and you're in business. YAML::Store is a subclass of PStore, so you won't need to change one bit of the API to get PStore robustness with YAML output.
Comments (2)
-
rahul benegal February 15th, 2007 Reply LinkDear James,
I have been using ruby for some time and had something to say about
PStoreandYAML. But first a question:-
I am using
YAMLfiles for configuration of applications (key-value pairs).However, just as in our Unix config files we may first mention a variable such as
GEM_HOMEand then use that later (e.g.$GEM_HOME/bin), I was wanting a user to be able to define a minimum number of settings in the config file. The rest maybe derived from the above.However, there doesn't seem to be any
YAMLsyntax for that. Is there some standard solution for the problem, or is my approach of using hashes wrong? -
The second point I might mention is that I tried using
YAMLto store data structures that contain HTML data. However, the loads would fail because the HTML would have:and many other such characters thatYAMLcould not take care of. (I had tried EscapeHTML but that also did not solve my issue.)Then I discovered
PStoreand used it to store the structures, and all is fine. Of course, that means that I cannot view or hand-edit thePStorefile. (XML if I recall, has something like CDATA or some syntax for specifying that the following is not to be interpreted until some set of closing characters come.)
Thanks a lot. It seems you have been very busy for a longtime. Your blog is a great inspiration for us. Please keep blogging.
-

I think
Hashes are a fine choice. One way to handle this would be to merge the user settings with an existing defaultsHash:>> DEFAULT = {:one => "default one", :two => "default two"} => {:one=>"default one", :two=>"default two"} >> user = {:two => "override two"} => {:two=>"override two"} >> settings = DEFAULT.merge(user) => {:one=>"default one", :two=>"override two"}
As for
YAMLgenerating content it cannot parse, the best thing to do would be to reduce it to a minimal case where it fails and report it as a bug on the Ruby Core mailing list.Hope that helps.
-