Friday, July 31, 2009

Rolling Version 1.1 of the couch_design_docs Gem

‹prev | My Chain | next›

I left off yesterday having BDD'd my way to an updated version of the couch_design_docs gem.

As a considerate gem maintainer, I update my History.txt:
== 1.1.0 / 2009-07-31

* Add the ability to upload "normal" documents in addition to design
* CouchDesignDocs::upload_dir is aliased as
CouchDesignDocs::put_dir and is DEPRECATED.
* CouchDesignDocs::put_dir now puts both design documents
and "normal" documents onto the CouchDB database.
* CouchDesignDocs::put_design_dir has been added to put
design documents
* CouchDesignDocs::put_document_dir has been added to put
"normal" documents
Since I have changed the functionality slightly, I also update the README, specifically including modified usage instructions:

DB_URL = "http://localhost:5984/db"
DIRECTORY = "/repos/db/couchdb/"

# /repos/db/couchdb/_design/lucene/transform.js
# /repos/db/couchdb/foo.json

CouchDesignDocs.put_dir(DB_URL, DIRECTORY)

# => lucene design document with a "transform" function containing
# the contents of transform.js
# - AND -
# a document named "foo" with the JSON contents from the foo.json
# file
I started with version 1.0—partly because I extracted working code from a functioning application and partly because bones defaults to 1.0 and I am lazy. Given that some new functionality was added, I bump the VERSION up to 1.1, recording this information in the couch_design_docs.rb:
  VERSION = '1.1.0'
Before pushing to Github, I would like to make sure that it still works with my existing application.

To install from my local repository, I use Bones's built-in rake gem:install:
cstrom@jaynestown:~/repos/couch_design_docs$ rake gem:install
(in /home/cstrom/repos/couch_design_docs)
rm -r pkg
mkdir -p pkg
mkdir -p pkg/couch_design_docs-1.1.0
cd pkg/couch_design_docs-1.1.0
Successfully built RubyGem
Name: couch_design_docs
Version: 1.1.0
File: couch_design_docs-1.1.0.gem
mv couch_design_docs-1.1.0.gem ../couch_design_docs-1.1.0.gem
cd -
sudo /usr/bin/ruby1.8 -S gem install --local pkg/couch_design_docs-1.1.0
[sudo] password for cstrom:^C
I Ctrl-C out of this because I prefer installing my gems locally:
cstrom@jaynestown:~/repos/couch_design_docs$ gem install --local pkg/couch_design_docs-1.1.0
WARNING: Installing to ~/.gem since /var/lib/gems/1.8 and
/var/lib/gems/1.8/bin aren't both writable.
Successfully installed couch_design_docs-1.1.0
1 gem installed
I have a rake task in my application that lets me quickly reload my design documents:
DB = "http://localhost:5984/eee"

namespace :couchdb do
# ...
require 'couch_design_docs'

desc "Load (replacing any existing) all design documents"
task :load_design_docs do
CouchDesignDocs.upload_dir(DB, "couch")
I verify that the couch_design_docs gem still works by deleting one of my design documents manually from the CouchDB database, running rake couchdb:load_design_docs, and then reloading the view in my browser to see that the design document is back and working:

To check the new functionality of being able to upload regular documents, I implement the document that started all of this—a lookup document containing the names of our kids and the nicknames that we display on the website (yah, we're that paranoid):
// couch/kids.json
Before running the rake task, the kids document is the blank one that I manually created to allow the app to work:

Then I run the rake task:
cstrom@jaynestown:~/repos/eee-code$ rake couchdb:load_design_docs --trace
(in /home/cstrom/repos/eee-code)
** Invoke couchdb:load_design_docs (first_time)
** Execute couchdb:load_design_docs
rake aborted!
undefined method `put!' for #
/home/cstrom/.gem/ruby/1.8/gems/couch_design_docs-1.1.0/lib/couch_design_docs.rb:45:in `put_document_dir'
/home/cstrom/.gem/ruby/1.8/gems/couch_design_docs-1.1.0/lib/couch_design_docs/document_directory.rb:14:in `each_document'
/home/cstrom/.gem/ruby/1.8/gems/couch_design_docs-1.1.0/lib/couch_design_docs/document_directory.rb:12:in `each'
/home/cstrom/.gem/ruby/1.8/gems/couch_design_docs-1.1.0/lib/couch_design_docs/document_directory.rb:12:in `each_document'
/home/cstrom/.gem/ruby/1.8/gems/couch_design_docs-1.1.0/lib/couch_design_docs.rb:44:in `put_document_dir'
/home/cstrom/.gem/ruby/1.8/gems/couch_design_docs-1.1.0/lib/couch_design_docs.rb:21:in `put_dir'
/home/cstrom/.gem/ruby/1.8/gems/couch_design_docs-1.1.0/lib/couch_design_docs.rb:26:in `upload_dir'
Aw, nuts!

I BDD'd a call to an instance method that is really a class method. I update the RSpec spec to expect a call to a class method instead:
  it "should be able to load documents into CouchDB" do
store = mock("Store")

dir = mock("Document Directory")
and_yield('foo', {"foo" => "1"})


with('foo', {"foo" => "1"})

CouchDesignDocs.put_document_dir("uri", "fixtures")
Now I get the error that I should:
cstrom@jaynestown:~/repos/couch_design_docs$ spec ./spec/couch_design_docs_spec.rb 

Spec::Mocks::MockExpectationError in 'CouchDesignDocs should be able to load documents into CouchDB'
Mock 'Store' received unexpected message :put! with ("foo", {"foo"=>"1"})
/home/cstrom/repos/couch_design_docs/lib/couch_design_docs.rb:45:in `put_document_dir'
/home/cstrom/repos/couch_design_docs/lib/couch_design_docs.rb:44:in `put_document_dir'

Finished in 0.016747 seconds

16 examples, 1 failure
I can make the example pass with:
  def self.put_document_dir(db_uri, dir)
store =
dir =
dir.each_document do |name, contents|
Store.put!("#{db_uri}/#{name}", contents)
I then re-install the gem, run the rake task again, and find the document uploaded as expected:


With that, I am ready to commit my changes. I update the gemspec with the built-in Bones rake gem:spec task. Then commit my changes:
cstrom@jaynestown:~/repos/couch_design_docs$ git commit -m "Add the ability to upload documents in addition to design documents." -a
Created commit eb76354: Add the ability to upload documents in addition to design documents.
13 files changed, 169 insertions(+), 38 deletions(-)
rename fixtures/{ => _design}/a/b/c.js (100%)
rename fixtures/{ => _design}/a/b/d.js (100%)
create mode 100644 fixtures/bar.json
create mode 100644 fixtures/foo.json
rename lib/couch_design_docs/{directory.rb => design_directory.rb} (94%)
create mode 100644 lib/couch_design_docs/document_directory.rb
Before pushing to Github, I use another Bones rake task, git:create_tag, to tag this new version of the gem.

Check it out: two tags and two downloads (thanks to the tag) and some nice, well tested code:

No comments:

Post a Comment