Array Properties accept hash with ordered keys and raise error for anything else
This commit is contained in:
parent
dd55466764
commit
1b89f1e1df
|
@ -12,6 +12,8 @@
|
||||||
* Refactoring of properties, added read_attribute and write_attribute methods.
|
* Refactoring of properties, added read_attribute and write_attribute methods.
|
||||||
* Now possible to send anything to update_attribtues method. Invalid or readonly attributes will be ignored.
|
* Now possible to send anything to update_attribtues method. Invalid or readonly attributes will be ignored.
|
||||||
* Attributes with arrays are *always* instantiated as a CastedArray.
|
* Attributes with arrays are *always* instantiated as a CastedArray.
|
||||||
|
* Setting a property of type Array (or keyed hash) must be an array or an error will be raised.
|
||||||
|
* Now possible to set Array attribute from hash where keys determine order.
|
||||||
|
|
||||||
* Major enhancements
|
* Major enhancements
|
||||||
* Added support for anonymous CastedModels defined in Documents
|
* Added support for anonymous CastedModels defined in Documents
|
||||||
|
|
|
@ -75,6 +75,9 @@ module CouchRest
|
||||||
#
|
#
|
||||||
# Addtional options match those of the the belongs_to method.
|
# Addtional options match those of the the belongs_to method.
|
||||||
#
|
#
|
||||||
|
# NOTE: This method is *not* recommended for large collections or collections that change
|
||||||
|
# frequently! Use with prudence.
|
||||||
|
#
|
||||||
def collection_of(attrib, *options)
|
def collection_of(attrib, *options)
|
||||||
opts = {
|
opts = {
|
||||||
:foreign_key => attrib.to_s.singularize + '_ids',
|
:foreign_key => attrib.to_s.singularize + '_ids',
|
||||||
|
@ -153,7 +156,6 @@ module CouchRest
|
||||||
EOS
|
EOS
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
@ -168,9 +170,9 @@ module CouchRest
|
||||||
def initialize(array, casted_by, property)
|
def initialize(array, casted_by, property)
|
||||||
self.property = property
|
self.property = property
|
||||||
self.casted_by = casted_by
|
self.casted_by = casted_by
|
||||||
array ||= []
|
(array ||= []).compact!
|
||||||
casted_by[property.to_s] = [] # replace the original array!
|
casted_by[property.to_s] = [] # replace the original array!
|
||||||
array.each do |obj|
|
array.compact.each do |obj|
|
||||||
casted_by[property.to_s] << obj.id
|
casted_by[property.to_s] << obj.id
|
||||||
end
|
end
|
||||||
super(array)
|
super(array)
|
||||||
|
|
|
@ -28,8 +28,18 @@ module CouchRest
|
||||||
def cast(parent, value)
|
def cast(parent, value)
|
||||||
return value unless casted
|
return value unless casted
|
||||||
if type.is_a?(Array)
|
if type.is_a?(Array)
|
||||||
# Convert to array if it is not already
|
if value.nil?
|
||||||
value = [value].compact unless value.is_a?(Array)
|
value = []
|
||||||
|
elsif [Hash, HashWithIndifferentAccess].include?(value.class)
|
||||||
|
# Assume provided as a Hash where key is index!
|
||||||
|
data = value
|
||||||
|
value = [ ]
|
||||||
|
data.keys.sort.each do |k|
|
||||||
|
value << data[k]
|
||||||
|
end
|
||||||
|
elsif value.class != Array
|
||||||
|
raise "Expecting an array or keyed hash for property #{parent.class.name}##{self.name}"
|
||||||
|
end
|
||||||
arr = value.collect { |data| cast_value(parent, data) }
|
arr = value.collect { |data| cast_value(parent, data) }
|
||||||
# allow casted_by calls to be passed up chain by wrapping in CastedArray
|
# allow casted_by calls to be passed up chain by wrapping in CastedArray
|
||||||
value = type_class != String ? ::CouchRest::CastedArray.new(arr, self) : arr
|
value = type_class != String ? ::CouchRest::CastedArray.new(arr, self) : arr
|
||||||
|
|
|
@ -146,6 +146,12 @@ describe "Assocations" do
|
||||||
@invoice.entries.should be_empty
|
@invoice.entries.should be_empty
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "should ignore nil entries" do
|
||||||
|
@invoice.entries = [ nil ]
|
||||||
|
@invoice.entry_ids.should be_empty
|
||||||
|
@invoice.entries.should be_empty
|
||||||
|
end
|
||||||
|
|
||||||
describe "proxy" do
|
describe "proxy" do
|
||||||
|
|
||||||
it "should ensure new entries to proxy are matched" do
|
it "should ensure new entries to proxy are matched" do
|
||||||
|
|
|
@ -348,7 +348,7 @@ describe CouchRest::CastedModel do
|
||||||
describe "calling base_doc from a nested casted model" do
|
describe "calling base_doc from a nested casted model" do
|
||||||
before :each do
|
before :each do
|
||||||
@course = Course.new(:title => 'Science 101')
|
@course = Course.new(:title => 'Science 101')
|
||||||
@professor = Person.new(:name => 'Professor Plum')
|
@professor = Person.new(:name => ['Professor', 'Plum'])
|
||||||
@cat = Cat.new(:name => 'Scratchy')
|
@cat = Cat.new(:name => 'Scratchy')
|
||||||
@toy1 = CatToy.new
|
@toy1 = CatToy.new
|
||||||
@toy2 = CatToy.new
|
@toy2 = CatToy.new
|
||||||
|
|
|
@ -42,14 +42,15 @@ describe "ExtendedDocument properties" do
|
||||||
end
|
end
|
||||||
|
|
||||||
it "should let you use an alias for a casted attribute" do
|
it "should let you use an alias for a casted attribute" do
|
||||||
@card.cast_alias = Person.new(:name => "Aimonetti")
|
@card.cast_alias = Person.new(:name => ["Aimonetti"])
|
||||||
@card.cast_alias.name.should == ["Aimonetti"]
|
@card.cast_alias.name.should == ["Aimonetti"]
|
||||||
@card.calias.name.should == ["Aimonetti"]
|
@card.calias.name.should == ["Aimonetti"]
|
||||||
card = Card.new(:first_name => "matt", :cast_alias => {:name => "Aimonetti"})
|
card = Card.new(:first_name => "matt", :cast_alias => {:name => ["Aimonetti"]})
|
||||||
card.cast_alias.name.should == ["Aimonetti"]
|
card.cast_alias.name.should == ["Aimonetti"]
|
||||||
card.calias.name.should == ["Aimonetti"]
|
card.calias.name.should == ["Aimonetti"]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
it "should be auto timestamped" do
|
it "should be auto timestamped" do
|
||||||
@card.created_at.should be_nil
|
@card.created_at.should be_nil
|
||||||
@card.updated_at.should be_nil
|
@card.updated_at.should be_nil
|
||||||
|
@ -660,6 +661,57 @@ describe "ExtendedDocument properties" do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "properties of array of casted models" do
|
||||||
|
|
||||||
|
before(:each) do
|
||||||
|
@course = Course.new :title => 'Test Course'
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should allow attribute to be set from an array of objects" do
|
||||||
|
@course.questions = [Question.new(:q => "works?"), Question.new(:q => "Meaning of Life?")]
|
||||||
|
@course.questions.length.should eql(2)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should allow attribute to be set from an array of hashes" do
|
||||||
|
@course.questions = [{:q => "works?"}, {:q => "Meaning of Life?"}]
|
||||||
|
@course.questions.length.should eql(2)
|
||||||
|
@course.questions.last.q.should eql("Meaning of Life?")
|
||||||
|
@course.questions.last.class.should eql(Question) # typecasting
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should allow attribute to be set from hash with ordered keys and objects" do
|
||||||
|
@course.questions = { '0' => Question.new(:q => "Test1"), '1' => Question.new(:q => 'Test2') }
|
||||||
|
@course.questions.length.should eql(2)
|
||||||
|
@course.questions.last.q.should eql('Test2')
|
||||||
|
@course.questions.last.class.should eql(Question)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should allow attribute to be set from hash with ordered keys and sub-hashes" do
|
||||||
|
@course.questions = { '0' => {:q => "Test1"}, '1' => {:q => 'Test2'} }
|
||||||
|
@course.questions.length.should eql(2)
|
||||||
|
@course.questions.last.q.should eql('Test2')
|
||||||
|
@course.questions.last.class.should eql(Question)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should allow attribute to be set from hash with ordered keys and HashWithIndifferentAccess" do
|
||||||
|
# This is similar to what you'd find in an HTML POST parameters
|
||||||
|
hash = HashWithIndifferentAccess.new({ '0' => {:q => "Test1"}, '1' => {:q => 'Test2'} })
|
||||||
|
@course.questions = hash
|
||||||
|
@course.questions.length.should eql(2)
|
||||||
|
@course.questions.last.q.should eql('Test2')
|
||||||
|
@course.questions.last.class.should eql(Question)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
it "should raise an error if attempting to set single value for array type" do
|
||||||
|
lambda {
|
||||||
|
@course.questions = Question.new(:q => 'test1')
|
||||||
|
}.should raise_error
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
describe "a casted model retrieved from the database" do
|
describe "a casted model retrieved from the database" do
|
||||||
before(:each) do
|
before(:each) do
|
||||||
reset_test_db!
|
reset_test_db!
|
||||||
|
|
2
spec/fixtures/more/person.rb
vendored
2
spec/fixtures/more/person.rb
vendored
|
@ -1,7 +1,7 @@
|
||||||
class Person < Hash
|
class Person < Hash
|
||||||
include ::CouchRest::CastedModel
|
include ::CouchRest::CastedModel
|
||||||
property :pet, :cast_as => 'Cat'
|
property :pet, :cast_as => 'Cat'
|
||||||
property :name, :type => ['String']
|
property :name, [String]
|
||||||
|
|
||||||
def last_name
|
def last_name
|
||||||
name.last
|
name.last
|
||||||
|
|
Loading…
Reference in a new issue