Merge branch 'master' of github.com:couchrest/couchrest_model

This commit is contained in:
Sam Lown 2011-06-05 11:21:12 +02:00
commit 634fdf8b2f
11 changed files with 119 additions and 11 deletions

View file

@ -2,9 +2,13 @@
## 1.1.0 - 2011-05-XX ## 1.1.0 - 2011-05-XX
* New Features
* Properties with a nil value are now no longer sent to the database.
* Now possible to build new objects via CastedArray#build
* Implement #get! and #find! class methods
* Minor fixes * Minor fixes
* #as_json now correctly uses ActiveSupports methods. * #as_json now correctly uses ActiveSupports methods.
* nil properties are now no longer sent in the document body.
* Rails 3.1 support (Peter Williams) * Rails 3.1 support (Peter Williams)
* Initialization blocks when creating new models (Peter Williams) * Initialization blocks when creating new models (Peter Williams)
* Removed railties dependency (DAddYE) * Removed railties dependency (DAddYE)

View file

@ -50,6 +50,12 @@ module CouchRest::Model
super super
end end
def build(*args)
obj = casted_by_property.build(*args)
self.push(obj)
obj
end
protected protected
def instantiate_and_cast(obj, change = true) def instantiate_and_cast(obj, change = true)

View file

@ -88,6 +88,13 @@ module CouchRest
end end
alias :find :get alias :find :get
def get!(id)
doc = @klass.get!(id, @database)
doc.database = @database if doc && doc.respond_to?(:database)
doc
end
alias :find! :get!
# Views # Views
def has_view?(view) def has_view?(view)

View file

@ -86,9 +86,12 @@ module CouchRest
# id<String, Integer>:: Document ID # id<String, Integer>:: Document ID
# db<Database>:: optional option to pass a custom database to use # db<Database>:: optional option to pass a custom database to use
def get!(id, db = database) def get!(id, db = database)
raise "Missing or empty document ID" if id.to_s.empty? raise CouchRest::Model::DocumentNotFound if id.blank?
doc = db.get id doc = db.get id
build_from_database(doc) build_from_database(doc)
rescue RestClient::ResourceNotFound
raise CouchRest::Model::DocumentNotFound
end end
alias :find! :get! alias :find! :get!

View file

@ -19,5 +19,7 @@ module CouchRest
end end
end end
end end
class DocumentNotFound < Errors::CouchRestModelError; end
end end
end end

View file

@ -21,8 +21,8 @@ module CouchRest
# Creates the document in the db. Raises an exception # Creates the document in the db. Raises an exception
# if the document is not created properly. # if the document is not created properly.
def create! def create!(options = {})
self.class.fail_validate!(self) unless self.create self.class.fail_validate!(self) unless self.create(options)
end end
# Trigger the callbacks (before, after, around) # Trigger the callbacks (before, after, around)
@ -120,8 +120,8 @@ module CouchRest
# #
# ==== Returns # ==== Returns
# returns the reloaded document # returns the reloaded document
def create(attributes = {}) def create(attributes = {}, &block)
instance = new(attributes) instance = new(attributes, &block)
instance.create instance.create
instance instance
end end
@ -130,8 +130,8 @@ module CouchRest
# #
# ==== Returns # ==== Returns
# returns the reloaded document or raises an exception # returns the reloaded document or raises an exception
def create!(attributes = {}) def create!(attributes = {}, &block)
instance = new(attributes) instance = new(attributes, &block)
instance.create! instance.create!
instance instance
end end

View file

@ -64,6 +64,18 @@ module CouchRest::Model
end end
end end
# Initialize a new instance of a property's type ready to be
# used. If a proc is defined for the init method, it will be used instead of
# a normal call to the class.
def build(*args)
raise StandardError, "Cannot build property without a class" if @type_class.nil?
if @init_method.is_a?(Proc)
@init_method.call(*args)
else
@type_class.send(@init_method, *args)
end
end
private private
def associate_casted_value_to_parent(parent, value) def associate_casted_value_to_parent(parent, value)

View file

@ -14,8 +14,7 @@ module CouchRest
elsif [String, TrueClass, Integer, Float, BigDecimal, DateTime, Time, Date, Class].include?(klass) elsif [String, TrueClass, Integer, Float, BigDecimal, DateTime, Time, Date, Class].include?(klass)
send('typecast_to_'+klass.to_s.downcase, value) send('typecast_to_'+klass.to_s.downcase, value)
else else
# Allow the init_method to be defined as a Proc for advanced conversion property.build(value)
property.init_method.is_a?(Proc) ? property.init_method.call(value) : klass.send(property.init_method, value)
end end
end end

View file

@ -123,6 +123,35 @@ describe "Proxy Class" do
u.respond_to?(:database).should be_false u.respond_to?(:database).should be_false
end end
end end
describe "#get!" do
it "raises exception when passed a nil" do
expect { @us.get!(nil)}.to raise_error(CouchRest::Model::DocumentNotFound)
end
it "raises exception when passed an empty string " do
expect { @us.get!("")}.to raise_error(CouchRest::Model::DocumentNotFound)
end
it "raises exception when document with provided id does not exist" do
expect { @us.get!("thisisnotreallyadocumentid")}.to raise_error(CouchRest::Model::DocumentNotFound)
end
end
describe "#find!" do
it "raises exception when passed a nil" do
expect { @us.find!(nil)}.to raise_error(CouchRest::Model::DocumentNotFound)
end
it "raises exception when passed an empty string " do
expect { @us.find!("")}.to raise_error(CouchRest::Model::DocumentNotFound)
end
it "raises exception when document with provided id does not exist" do
expect { @us.find!("thisisnotreallyadocumentid")}.to raise_error(CouchRest::Model::DocumentNotFound)
end
end
# Sam Lown 2010-04-07 # Sam Lown 2010-04-07
# Removed as unclear why this should happen as before my changes # Removed as unclear why this should happen as before my changes
# this happend by accident, not explicitly. # this happend by accident, not explicitly.

View file

@ -82,6 +82,18 @@ describe "Model Persistence" do
article.should_not be_new article.should_not be_new
end end
it "yields new instance to block before saving (#create)" do
article = Article.create{|a| a.title = 'my create init block test'}
article.title.should == 'my create init block test'
article.should_not be_new
end
it "yields new instance to block before saving (#create!)" do
article = Article.create{|a| a.title = 'my create bang init block test'}
article.title.should == 'my create bang init block test'
article.should_not be_new
end
it "should trigger the create callbacks" do it "should trigger the create callbacks" do
doc = WithCallBacks.create(:name => 'my other test') doc = WithCallBacks.create(:name => 'my other test')
doc.run_before_create.should be_true doc.run_before_create.should be_true

View file

@ -358,6 +358,28 @@ describe "Property Class" do
property.init_method.should eql('parse') property.init_method.should eql('parse')
end end
describe "#build" do
it "should allow instantiation of new object" do
property = CouchRest::Model::Property.new(:test, Date)
obj = property.build(2011, 05, 21)
obj.should eql(Date.new(2011, 05, 21))
end
it "should use init_method if provided" do
property = CouchRest::Model::Property.new(:test, Date, :init_method => 'parse')
obj = property.build("2011-05-21")
obj.should eql(Date.new(2011, 05, 21))
end
it "should use init_method Proc if provided" do
property = CouchRest::Model::Property.new(:test, Date, :init_method => Proc.new{|v| Date.parse(v)})
obj = property.build("2011-05-21")
obj.should eql(Date.new(2011, 05, 21))
end
it "should raise error if no class" do
property = CouchRest::Model::Property.new(:test)
lambda { property.build }.should raise_error(StandardError, /Cannot build/)
end
end
## Property Casting method. More thoroughly tested in typecast_spec. ## Property Casting method. More thoroughly tested in typecast_spec.
describe "casting" do describe "casting" do
@ -386,6 +408,18 @@ describe "Property Class" do
property.cast(parent, ["2010-06-01", "2010-06-02"]).class.should eql(CouchRest::Model::CastedArray) property.cast(parent, ["2010-06-01", "2010-06-02"]).class.should eql(CouchRest::Model::CastedArray)
end end
it "should allow instantion of model via CastedArray#build" do
property = CouchRest::Model::Property.new(:dates, [Date])
parent = Article.new
ary = property.cast(parent, [])
obj = ary.build(2011, 05, 21)
ary.length.should eql(1)
ary.first.should eql(Date.new(2011, 05, 21))
obj = ary.build(2011, 05, 22)
ary.length.should eql(2)
ary.last.should eql(Date.new(2011, 05, 22))
end
it "should raise and error if value is array when type is not" do it "should raise and error if value is array when type is not" do
property = CouchRest::Model::Property.new(:test, Date) property = CouchRest::Model::Property.new(:test, Date)
parent = mock("FooClass") parent = mock("FooClass")