Today, I continue work on my
couch_design_docs
gem. The basic idea remains the same, a javascript file in couch/_design/lucene/transform.js
should describe a CouchDB design document:{So far, I have a
"lucene": {
"transform": <<contents of transform.js>>
}
}
Directory
class that converts the directory path, file basename and file contents into an array. Next up, I need a way to convert arrays into deep hashes:it "should convert arrays into deep hashes" doRunning the RSpec example, I get a failure:
Directory.
a_to_hash(%w{a b c d}).
should == {
'a' => {
'b' => {
'c' => 'd'
}
}
}
end
cstrom@jaynestown:~/repos/couch_design_docs$ spec ./spec/couch_design_docs_spec.rbI change the message by defining an empty
.F.
1)
NoMethodError in 'CouchDesignDocs::Directory should convert arrays into deep hashes'
undefined method `a_to_hash' for CouchDesignDocs::Directory:Class
./spec/couch_design_docs_spec.rb:17:
Finished in 0.006896 seconds
3 examples, 1 failure
a_to_hash
class method:cstrom@jaynestown:~/repos/couch_design_docs$ spec ./spec/couch_design_docs_spec.rbNo more changing the message is needed, now I can make it pass. I still rather fancy tail recursion, so I end up with something similar to the other day:
.F.
1)
'CouchDesignDocs::Directory should convert arrays into deep hashes' FAILED
expected: {"a"=>{"b"=>{"c"=>"d"}}},
got: nil (using ==)
./spec/couch_design_docs_spec.rb:25:
Finished in 0.007203 seconds
3 examples, 1 failure
def self.a_to_hash(a)With that, I am ready to assemble all javascript files into a design docs structure. First up, I make sure that I have more than one javascript file in the fixtures directory:
key = a.first
if (a.length > 2)
{ key => a_to_hash(a[1,a.length]) }
else
{ key => a.last }
end
end
cstrom@jaynestown:~/repos/couch_design_docs$ find fixtures/Then I write my example to drive things along:
fixtures/
fixtures/a
fixtures/a/b
fixtures/a/b/d.js
fixtures/a/b/c.js
it "should assemble all documents into a single docs structure" doThe code that implements this iterates over each
@it.to_hash.
should == {
'a' => {
'b' => {
'c' => 'function(doc) { return true; }',
'd' => 'function(doc) { return true; }'
}
}
}
end
.js
file in the design docs directory, using the previously built methods to build hashes to be merged together:def to_hashSimple enough, but wrong:
Dir["#{couch_view_dir}/**/*.js"].inject({}) do |memo, filename|
hash = Directory.a_to_hash(expand_file(filename))
memo.merge(hash)
end
end
cstrom@jaynestown:~/repos/couch_design_docs$ spec ./spec/couch_design_docs_spec.rbThe problem is the
...F
1)
'CouchDesignDocs::Directory a valid directory should assemble all documents into a single docs structure' FAILED
expected: {"a"=>{"b"=>{"c"=>"function(doc) { return true; }", "d"=>"function(doc) { return true; }"}}},
got: {"a"=>{"b"=>{"c"=>"function(doc) { return true; }"}}} (using ==)
./spec/couch_design_docs_spec.rb:48:
Finished in 0.008113 seconds
4 examples, 1 failure
merge
, which merges at the top level (the "a" key). I want the deepest hashes (the values of "b") to be merged together. Something like this does the trick:def deep_hash_merge(h1, h2)It works, but it is not side-effect free. I will likely retry that bit of code tomorrow. My brain is not working so well at this point, so it is a good time to call it a day. Before I quit, leave myself a note:
h2.each_key do |k|
if h1.key? k
deep_hash_merge(h1[k], h2[k])
else
h1[k] = h2[k]
end
end
h1
end
it "should assemble all documents into a single docs structure" doHopefully my tomorrow self will not be too offended.
pending "you can do a better job with deep hash merging than that"
@it.to_hash.
should == {
'a' => {
'b' => {
'c' => 'function(doc) { return true; }',
'd' => 'function(doc) { return true; }'
}
}
}
end
This is really cool territory here. Have you seen the CouchApp framework for managing files -> JSON?
ReplyDeletehttp://github.com/couchapp/couchapp
It's basically what you're building here but we've got macros and the ability to clone from a design document down to your filesystem.
Yah, I scanned through CouchApp before starting down this rabbit hole. I think the HTML in the design docs threw me. That and the Python. Well, mostly the Python ;)
ReplyDeleteI will make an effort to look through it in more depth today to see if there are some more ideas in there that I might borrow.
Thanks!