Sunday, March 28, 2010

Small couch_docs Updates

‹prev | My Chain | next›

After updating couch-replicate yesterday, I take a look at my couch_docs gem tonight. I received a patch a while back suggesting that watch mode should not update all documents when any update is made. That seem reasonable, so...

When I first start watching a directory, all documents should be pushed to the CouchDB server. Afterwards, if the updates are design documents, only the design documents should be updated. If the updates are normal documents, then the individual, updated documents should be updated. Sounds like a bunch of predicate methods to me.

First up, an RSpec example describing initial directory parsing:
    it "should be an initial add if everything is an add" do
args = [mock(:type => :added),
mock(:type => :added)]
CommandLine.should be_initial_add(args)
end
This dumps me into change-the-message of:
1)
NoMethodError in 'CouchDocs::CommandLine an instance that dumps a CouchDB database should be an initial add if everything is an add'
undefined method `initial_add?' for CouchDocs::CommandLine:Class
./spec/couch_docs_spec.rb:471:
I eventually get this passing with:
  def initial_add?(args)
args.all? { |f| f.type == :added }
end
I add a few more predicate methods, and then I am ready to refactor my directory watcher update block:
        dw.add_observer do |*args|
puts "Updating documents on CouchDB Server..."
CouchDocs.put_dir(@options[:couchdb_url],
@options[:target_dir])
end
First up, I pull the put_dir call out into a new (testable) directory_watcher_update method:
#...
dw.add_observer do |*args|
puts "Updating documents on CouchDB Server..."
directory_watcher_update(args)
end
#...

def directory_watcher_update(args)
CouchDocs.put_dir(@options[:couchdb_url],
@options[:target_dir])
end
I run all of my specs to ensure nothing has broken (it has not) before describing in more detail what should happen with directory watcher updates. First up, it should update both design document and normal documents when first starting up (which is what put_dir does):
      it "should only update design docs if only local design docs have changed" do
CouchDocs.
should_receive(:put_dir)

@it.stub!(:initial_add?).and_return(true)
@it.directory_watcher_update(@args)
end
That example passes without any changes (because that is the current behavior of the method). The trick will be to retain this behavior going forward.

I drive this method to be able to handle design document updates as well before needing to call it a night:
  def directory_watcher_update(args)
if initial_add? args
CouchDocs.put_dir(@options[:couchdb_url],
@options[:target_dir])
else
if design_doc_update? args
CouchDocs.put_design_dir(@options[:couchdb_url],
"#{@options[:target_dir]}/_design")
end
end
end
The call to update normal (non-design) documents may require some refactoring before it can be used in here. I will pick up with that (and hopefully finish) tomorrow.

Day #56

No comments:

Post a Comment