From 9858f85c19e804920692926d4c091aae247ba3de Mon Sep 17 00:00:00 2001 From: Chris Anderson Date: Thu, 2 Oct 2008 17:13:59 -0700 Subject: [PATCH] subobject casting --- lib/couchrest/core/model.rb | 27 +++++++++++++++++++++++++++ spec/couchrest/core/model_spec.rb | 25 +++++++++++++++++++++++-- 2 files changed, 50 insertions(+), 2 deletions(-) diff --git a/lib/couchrest/core/model.rb b/lib/couchrest/core/model.rb index 32f5133..233e5e6 100644 --- a/lib/couchrest/core/model.rb +++ b/lib/couchrest/core/model.rb @@ -54,6 +54,7 @@ module CouchRest keys.each do |k,v| self[k.to_s] = v end + cast_keys unless self['_id'] && self['_rev'] self['couchrest-type'] = self.class.to_s end @@ -81,11 +82,20 @@ module CouchRest new(doc) end + # Cast a field as another class. The class must be happy to have the + # field's primitive type as the argument to it's constucture. Classes + # which inherit from CouchRest::Model are happy to act as sub-objects + # for any fields that are stored in JSON as object (and therefore are + # parsed from the JSON as Ruby Hashes). def cast field, opts = {} @casts ||= {} @casts[field.to_s] = opts end + def casts + @casts + end + # Defines methods for reading and writing from fields in the document. # Uses key_writer and key_reader internally. def key_accessor *keys @@ -396,6 +406,23 @@ module CouchRest end end + def cast_keys + return unless self.class.casts + self.class.casts.each do |k,v| + next unless self[k] + target = v[:as] + if target.is_a?(Array) && target[0].is_a?(Class) + self[k] = self[k].collect do |value| + target[0].new(value) + end + elsif target.is_a?(Class) + self[k] = target.new(self[k]) + else + raise ArgumentError, ":as => MyClass, :as => [MyClass]" + end + end + end + include ::Extlib::Hook register_instance_hooks :save, :create, :update, :destroy diff --git a/spec/couchrest/core/model_spec.rb b/spec/couchrest/core/model_spec.rb index b9ad366..4787770 100644 --- a/spec/couchrest/core/model_spec.rb +++ b/spec/couchrest/core/model_spec.rb @@ -18,9 +18,17 @@ class Question < CouchRest::Model key_accessor :q, :a end +class Person < CouchRest::Model + key_accessor :name + def last_name + name.last + end +end + class Course < CouchRest::Model key_accessor :title cast :questions, :as => [Question] + cast :professor, :as => Person end class Article < CouchRest::Model @@ -170,8 +178,21 @@ describe CouchRest::Model do end describe "getting a model with a subobject field" do - it "should instantiate it as such" do - + before(:all) do + course_doc = { + "title" => "Metaphysics 410", + "professor" => { + "name" => ["Mark", "Hinchliff"] + } + } + r = Course.database.save course_doc + @course = Course.get r['id'] + end + it "should load the course" do + @course["professor"]["name"][1].should == "Hinchliff" + end + it "should instantiate the professor as a person" do + @course['professor'].last_name.should == "Hinchliff" end end