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 Link
Dear James,
I have been using ruby for some time and had something to say about
PStore
andYAML
. But first a question:-
I am using
YAML
files for configuration of applications (key-value pairs).However, just as in our Unix config files we may first mention a variable such as
GEM_HOME
and 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
YAML
syntax 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
YAML
to store data structures that contain HTML data. However, the loads would fail because the HTML would have:
and many other such characters thatYAML
could not take care of. (I had tried EscapeHTML but that also did not solve my issue.)Then I discovered
PStore
and used it to store the structures, and all is fine. Of course, that means that I cannot view or hand-edit thePStore
file. (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
Hash
es 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
YAML
generating 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.
-