openlogic-couchrest_model 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +11 -0
- data/.rspec +4 -0
- data/Gemfile +4 -0
- data/LICENSE +176 -0
- data/README.md +137 -0
- data/Rakefile +38 -0
- data/THANKS.md +21 -0
- data/VERSION +1 -0
- data/benchmarks/dirty.rb +118 -0
- data/couchrest_model.gemspec +36 -0
- data/history.md +309 -0
- data/init.rb +1 -0
- data/lib/couchrest/model.rb +10 -0
- data/lib/couchrest/model/associations.rb +231 -0
- data/lib/couchrest/model/base.rb +129 -0
- data/lib/couchrest/model/callbacks.rb +28 -0
- data/lib/couchrest/model/casted_array.rb +83 -0
- data/lib/couchrest/model/casted_by.rb +33 -0
- data/lib/couchrest/model/casted_hash.rb +84 -0
- data/lib/couchrest/model/class_proxy.rb +135 -0
- data/lib/couchrest/model/collection.rb +273 -0
- data/lib/couchrest/model/configuration.rb +67 -0
- data/lib/couchrest/model/connection.rb +70 -0
- data/lib/couchrest/model/core_extensions/hash.rb +9 -0
- data/lib/couchrest/model/core_extensions/time_parsing.rb +66 -0
- data/lib/couchrest/model/design_doc.rb +128 -0
- data/lib/couchrest/model/designs.rb +91 -0
- data/lib/couchrest/model/designs/view.rb +513 -0
- data/lib/couchrest/model/dirty.rb +39 -0
- data/lib/couchrest/model/document_queries.rb +99 -0
- data/lib/couchrest/model/embeddable.rb +78 -0
- data/lib/couchrest/model/errors.rb +25 -0
- data/lib/couchrest/model/extended_attachments.rb +83 -0
- data/lib/couchrest/model/persistence.rb +178 -0
- data/lib/couchrest/model/properties.rb +228 -0
- data/lib/couchrest/model/property.rb +114 -0
- data/lib/couchrest/model/property_protection.rb +71 -0
- data/lib/couchrest/model/proxyable.rb +183 -0
- data/lib/couchrest/model/support/couchrest_database.rb +13 -0
- data/lib/couchrest/model/support/couchrest_design.rb +33 -0
- data/lib/couchrest/model/typecast.rb +154 -0
- data/lib/couchrest/model/validations.rb +80 -0
- data/lib/couchrest/model/validations/casted_model.rb +16 -0
- data/lib/couchrest/model/validations/locale/en.yml +5 -0
- data/lib/couchrest/model/validations/uniqueness.rb +69 -0
- data/lib/couchrest/model/views.rb +151 -0
- data/lib/couchrest/railtie.rb +24 -0
- data/lib/couchrest_model.rb +66 -0
- data/lib/rails/generators/couchrest_model.rb +16 -0
- data/lib/rails/generators/couchrest_model/config/config_generator.rb +18 -0
- data/lib/rails/generators/couchrest_model/config/templates/couchdb.yml +21 -0
- data/lib/rails/generators/couchrest_model/model/model_generator.rb +27 -0
- data/lib/rails/generators/couchrest_model/model/templates/model.rb +2 -0
- data/spec/.gitignore +1 -0
- data/spec/fixtures/attachments/README +3 -0
- data/spec/fixtures/attachments/couchdb.png +0 -0
- data/spec/fixtures/attachments/test.html +11 -0
- data/spec/fixtures/config/couchdb.yml +10 -0
- data/spec/fixtures/models/article.rb +36 -0
- data/spec/fixtures/models/base.rb +164 -0
- data/spec/fixtures/models/card.rb +19 -0
- data/spec/fixtures/models/cat.rb +23 -0
- data/spec/fixtures/models/client.rb +6 -0
- data/spec/fixtures/models/course.rb +27 -0
- data/spec/fixtures/models/event.rb +8 -0
- data/spec/fixtures/models/invoice.rb +14 -0
- data/spec/fixtures/models/key_chain.rb +5 -0
- data/spec/fixtures/models/membership.rb +4 -0
- data/spec/fixtures/models/person.rb +11 -0
- data/spec/fixtures/models/project.rb +6 -0
- data/spec/fixtures/models/question.rb +7 -0
- data/spec/fixtures/models/sale_entry.rb +9 -0
- data/spec/fixtures/models/sale_invoice.rb +14 -0
- data/spec/fixtures/models/service.rb +10 -0
- data/spec/fixtures/models/user.rb +22 -0
- data/spec/fixtures/views/lib.js +3 -0
- data/spec/fixtures/views/test_view/lib.js +3 -0
- data/spec/fixtures/views/test_view/only-map.js +4 -0
- data/spec/fixtures/views/test_view/test-map.js +3 -0
- data/spec/fixtures/views/test_view/test-reduce.js +3 -0
- data/spec/functional/validations_spec.rb +8 -0
- data/spec/spec_helper.rb +60 -0
- data/spec/unit/active_model_lint_spec.rb +30 -0
- data/spec/unit/assocations_spec.rb +242 -0
- data/spec/unit/attachment_spec.rb +176 -0
- data/spec/unit/base_spec.rb +537 -0
- data/spec/unit/casted_spec.rb +72 -0
- data/spec/unit/class_proxy_spec.rb +167 -0
- data/spec/unit/collection_spec.rb +86 -0
- data/spec/unit/configuration_spec.rb +77 -0
- data/spec/unit/connection_spec.rb +148 -0
- data/spec/unit/core_extensions/time_parsing.rb +77 -0
- data/spec/unit/design_doc_spec.rb +241 -0
- data/spec/unit/designs/view_spec.rb +831 -0
- data/spec/unit/designs_spec.rb +134 -0
- data/spec/unit/dirty_spec.rb +436 -0
- data/spec/unit/embeddable_spec.rb +498 -0
- data/spec/unit/inherited_spec.rb +33 -0
- data/spec/unit/persistence_spec.rb +481 -0
- data/spec/unit/property_protection_spec.rb +192 -0
- data/spec/unit/property_spec.rb +481 -0
- data/spec/unit/proxyable_spec.rb +376 -0
- data/spec/unit/subclass_spec.rb +85 -0
- data/spec/unit/typecast_spec.rb +521 -0
- data/spec/unit/validations_spec.rb +140 -0
- data/spec/unit/view_spec.rb +367 -0
- metadata +301 -0
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'question'
|
2
|
+
require 'person'
|
3
|
+
|
4
|
+
class Course < CouchRest::Model::Base
|
5
|
+
use_database TEST_SERVER.default_database
|
6
|
+
|
7
|
+
property :title, String
|
8
|
+
property :questions, [Question]
|
9
|
+
property :professor, Person
|
10
|
+
property :participants, [Object]
|
11
|
+
property :ends_at, Time
|
12
|
+
property :estimate, Float
|
13
|
+
property :hours, Integer
|
14
|
+
property :profit, BigDecimal
|
15
|
+
property :started_on, :type => Date
|
16
|
+
property :updated_at, DateTime
|
17
|
+
property :active, :type => TrueClass
|
18
|
+
property :very_active, :type => TrueClass
|
19
|
+
property :klass, :type => Class
|
20
|
+
|
21
|
+
view_by :title
|
22
|
+
view_by :title, :active
|
23
|
+
view_by :dept, :ducktype => true
|
24
|
+
|
25
|
+
view_by :active, :map => "function(d) { if (d['#{model_type_key}'] == 'Course' && d['active']) { emit(d['updated_at'], 1); }}", :reduce => "function(k,v,r) { return sum(v); }"
|
26
|
+
|
27
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
class Invoice < CouchRest::Model::Base
|
2
|
+
# Set the default database to use
|
3
|
+
use_database DB
|
4
|
+
|
5
|
+
# Official Schema
|
6
|
+
property :client_name
|
7
|
+
property :employee_name
|
8
|
+
property :location
|
9
|
+
|
10
|
+
# Validation
|
11
|
+
validates_presence_of :client_name, :employee_name
|
12
|
+
validates_presence_of :location, :message => "Hey stupid!, you forgot the location"
|
13
|
+
|
14
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'client'
|
2
|
+
require 'sale_entry'
|
3
|
+
|
4
|
+
class SaleInvoice < CouchRest::Model::Base
|
5
|
+
use_database DB
|
6
|
+
|
7
|
+
belongs_to :client
|
8
|
+
belongs_to :alternate_client, :class_name => 'Client', :foreign_key => 'alt_client_id'
|
9
|
+
|
10
|
+
collection_of :entries, :class_name => 'SaleEntry'
|
11
|
+
|
12
|
+
property :date, Date
|
13
|
+
property :price, Integer
|
14
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
class User < CouchRest::Model::Base
|
2
|
+
# Set the default database to use
|
3
|
+
use_database DB
|
4
|
+
property :name, :accessible => true
|
5
|
+
property :admin # this will be automatically protected
|
6
|
+
end
|
7
|
+
|
8
|
+
class SpecialUser < CouchRest::Model::Base
|
9
|
+
# Set the default database to use
|
10
|
+
use_database DB
|
11
|
+
property :name # this will not be protected
|
12
|
+
property :admin, :protected => true
|
13
|
+
end
|
14
|
+
|
15
|
+
# There are two modes of protection
|
16
|
+
# 1) Declare accessible poperties, assume all the rest are protected
|
17
|
+
# property :name, :accessible => true
|
18
|
+
# property :admin # this will be automatically protected
|
19
|
+
#
|
20
|
+
# 2) Declare protected properties, assume all the rest are accessible
|
21
|
+
# property :name # this will not be protected
|
22
|
+
# property :admin, :protected => true
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
2
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), "..", "lib"))
|
3
|
+
|
4
|
+
require "bundler/setup"
|
5
|
+
require "rubygems"
|
6
|
+
require "rspec"
|
7
|
+
|
8
|
+
require 'couchrest_model'
|
9
|
+
|
10
|
+
unless defined?(FIXTURE_PATH)
|
11
|
+
MODEL_PATH = File.join(File.dirname(__FILE__), "fixtures", "models")
|
12
|
+
$LOAD_PATH.unshift(MODEL_PATH)
|
13
|
+
|
14
|
+
FIXTURE_PATH = File.join(File.dirname(__FILE__), '/fixtures')
|
15
|
+
SCRATCH_PATH = File.join(File.dirname(__FILE__), '/tmp')
|
16
|
+
|
17
|
+
COUCHHOST = "http://127.0.0.1:5984"
|
18
|
+
TESTDB = 'couchrest-model-test'
|
19
|
+
TEST_SERVER = CouchRest.new COUCHHOST
|
20
|
+
TEST_SERVER.default_database = TESTDB
|
21
|
+
DB = TEST_SERVER.database(TESTDB)
|
22
|
+
end
|
23
|
+
|
24
|
+
RSpec.configure do |config|
|
25
|
+
config.before(:all) { reset_test_db! }
|
26
|
+
|
27
|
+
config.after(:all) do
|
28
|
+
cr = TEST_SERVER
|
29
|
+
test_dbs = cr.databases.select { |db| db =~ /^#{TESTDB}/ }
|
30
|
+
test_dbs.each do |db|
|
31
|
+
cr.database(db).delete! rescue nil
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# Require each of the fixture models
|
37
|
+
Dir[ File.join(MODEL_PATH, "*.rb") ].sort.each { |file| require File.basename(file) }
|
38
|
+
|
39
|
+
class Basic < CouchRest::Model::Base
|
40
|
+
use_database TEST_SERVER.default_database
|
41
|
+
end
|
42
|
+
|
43
|
+
def reset_test_db!
|
44
|
+
DB.recreate! rescue nil
|
45
|
+
# Reset the Design Cache
|
46
|
+
Thread.current[:couchrest_design_cache] = {}
|
47
|
+
DB
|
48
|
+
end
|
49
|
+
|
50
|
+
|
51
|
+
def couchdb_lucene_available?
|
52
|
+
lucene_path = "http://localhost:5985/"
|
53
|
+
url = URI.parse(lucene_path)
|
54
|
+
req = Net::HTTP::Get.new(url.path)
|
55
|
+
res = Net::HTTP.new(url.host, url.port).start { |http| http.request(req) }
|
56
|
+
true
|
57
|
+
rescue Exception => e
|
58
|
+
false
|
59
|
+
end
|
60
|
+
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'spec_helper'
|
3
|
+
require 'test/unit/assertions'
|
4
|
+
require 'active_model/lint'
|
5
|
+
|
6
|
+
class CompliantModel < CouchRest::Model::Base
|
7
|
+
end
|
8
|
+
|
9
|
+
|
10
|
+
describe CouchRest::Model::Base do
|
11
|
+
include Test::Unit::Assertions
|
12
|
+
include ActiveModel::Lint::Tests
|
13
|
+
|
14
|
+
before :each do
|
15
|
+
@model = CompliantModel.new
|
16
|
+
end
|
17
|
+
|
18
|
+
describe "active model lint tests" do
|
19
|
+
ActiveModel::Lint::Tests.public_instance_methods.map{|m| m.to_s}.grep(/^test/).each do |m|
|
20
|
+
example m.gsub('_',' ') do
|
21
|
+
send m
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def model
|
27
|
+
@model
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
@@ -0,0 +1,242 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
describe "Assocations" do
|
5
|
+
|
6
|
+
describe ".merge_belongs_to_association_options" do
|
7
|
+
before :all do
|
8
|
+
def SaleInvoice.merge_assoc_opts(*args)
|
9
|
+
merge_belongs_to_association_options(*args)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should return a default set of options" do
|
14
|
+
o = SaleInvoice.merge_assoc_opts(:cat)
|
15
|
+
o[:foreign_key].should eql('cat_id')
|
16
|
+
o[:class_name].should eql('Cat')
|
17
|
+
o[:proxy_name].should eql('cats')
|
18
|
+
o[:proxy].should eql('Cat') # same as class name
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should merge with provided options" do
|
22
|
+
o = SaleInvoice.merge_assoc_opts(:cat, :foreign_key => 'somecat_id', :proxy => 'some_cats')
|
23
|
+
o[:foreign_key].should eql('somecat_id')
|
24
|
+
o[:proxy].should eql('some_cats')
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should generate a proxy string if proxied" do
|
28
|
+
SaleInvoice.stub!(:proxy_owner_method).twice.and_return('company')
|
29
|
+
o = SaleInvoice.merge_assoc_opts(:cat)
|
30
|
+
o[:proxy].should eql('self.company.cats')
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
describe "of type belongs to" do
|
36
|
+
|
37
|
+
before :each do
|
38
|
+
@invoice = SaleInvoice.create(:price => 2000)
|
39
|
+
@client = Client.create(:name => "Sam Lown")
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should create a foreign key property with setter and getter" do
|
43
|
+
@invoice.properties.find{|p| p.name == 'client_id'}.should_not be_nil
|
44
|
+
@invoice.respond_to?(:client_id).should be_true
|
45
|
+
@invoice.respond_to?("client_id=").should be_true
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should set the property and provide object when set" do
|
49
|
+
@invoice.client = @client
|
50
|
+
@invoice.client_id.should eql(@client.id)
|
51
|
+
@invoice.client.should eql(@client)
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should set the attribute, save and return" do
|
55
|
+
@invoice.client = @client
|
56
|
+
@invoice.save
|
57
|
+
@invoice = SaleInvoice.get(@invoice.id)
|
58
|
+
@invoice.client.id.should eql(@client.id)
|
59
|
+
end
|
60
|
+
|
61
|
+
it "should remove the association if nil is provided" do
|
62
|
+
@invoice.client = @client
|
63
|
+
@invoice.client = nil
|
64
|
+
@invoice.client_id.should be_nil
|
65
|
+
end
|
66
|
+
|
67
|
+
it "should not try to search for association if foreign_key is nil" do
|
68
|
+
@invoice.client_id = nil
|
69
|
+
Client.should_not_receive(:get)
|
70
|
+
@invoice.client
|
71
|
+
end
|
72
|
+
|
73
|
+
it "should allow override of foreign key" do
|
74
|
+
@invoice.respond_to?(:alternate_client).should be_true
|
75
|
+
@invoice.respond_to?("alternate_client=").should be_true
|
76
|
+
@invoice.properties.find{|p| p.name == 'alt_client_id'}.should_not be_nil
|
77
|
+
end
|
78
|
+
|
79
|
+
it "should allow override of foreign key and save" do
|
80
|
+
@invoice.alternate_client = @client
|
81
|
+
@invoice.save
|
82
|
+
@invoice = SaleInvoice.get(@invoice.id)
|
83
|
+
@invoice.alternate_client.id.should eql(@client.id)
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
87
|
+
|
88
|
+
describe "of type collection_of" do
|
89
|
+
|
90
|
+
before(:each) do
|
91
|
+
@invoice = SaleInvoice.create(:price => 2000)
|
92
|
+
@entries = [
|
93
|
+
SaleEntry.create(:description => 'test line 1', :price => 500),
|
94
|
+
SaleEntry.create(:description => 'test line 2', :price => 500),
|
95
|
+
SaleEntry.create(:description => 'test line 3', :price => 1000)
|
96
|
+
]
|
97
|
+
end
|
98
|
+
|
99
|
+
it "should create an associated property and collection proxy" do
|
100
|
+
@invoice.respond_to?('entry_ids').should be_true
|
101
|
+
@invoice.respond_to?('entry_ids=').should be_true
|
102
|
+
@invoice.entries.class.should eql(::CouchRest::Model::CollectionOfProxy)
|
103
|
+
end
|
104
|
+
|
105
|
+
it "should allow replacement of objects" do
|
106
|
+
@invoice.entries = @entries
|
107
|
+
@invoice.entries.length.should eql(3)
|
108
|
+
@invoice.entry_ids.length.should eql(3)
|
109
|
+
@invoice.entries.first.should eql(@entries.first)
|
110
|
+
@invoice.entry_ids.first.should eql(@entries.first.id)
|
111
|
+
end
|
112
|
+
|
113
|
+
it "should allow ids to be set directly and load entries" do
|
114
|
+
@invoice.entry_ids = @entries.collect{|i| i.id}
|
115
|
+
@invoice.entries.length.should eql(3)
|
116
|
+
@invoice.entries.first.should eql(@entries.first)
|
117
|
+
end
|
118
|
+
|
119
|
+
it "should replace collection if ids replaced" do
|
120
|
+
@invoice.entry_ids = @entries.collect{|i| i.id}
|
121
|
+
@invoice.entries.length.should eql(3) # load once
|
122
|
+
@invoice.entry_ids = @entries[0..1].collect{|i| i.id}
|
123
|
+
@invoice.entries.length.should eql(2)
|
124
|
+
end
|
125
|
+
|
126
|
+
it "should allow forced collection update if ids changed" do
|
127
|
+
@invoice.entry_ids = @entries[0..1].collect{|i| i.id}
|
128
|
+
@invoice.entries.length.should eql(2) # load once
|
129
|
+
@invoice.entry_ids << @entries[2].id
|
130
|
+
@invoice.entry_ids.length.should eql(3)
|
131
|
+
@invoice.entries.length.should eql(2) # cached!
|
132
|
+
@invoice.entries(true).length.should eql(3)
|
133
|
+
end
|
134
|
+
|
135
|
+
it "should empty arrays when nil collection provided" do
|
136
|
+
@invoice.entries = @entries
|
137
|
+
@invoice.entries = nil
|
138
|
+
@invoice.entry_ids.should be_empty
|
139
|
+
@invoice.entries.should be_empty
|
140
|
+
end
|
141
|
+
|
142
|
+
it "should empty arrays when nil ids array provided" do
|
143
|
+
@invoice.entries = @entries
|
144
|
+
@invoice.entry_ids = nil
|
145
|
+
@invoice.entry_ids.should be_empty
|
146
|
+
@invoice.entries.should be_empty
|
147
|
+
end
|
148
|
+
|
149
|
+
it "should ignore nil entries" do
|
150
|
+
@invoice.entries = [ nil ]
|
151
|
+
@invoice.entry_ids.should be_empty
|
152
|
+
@invoice.entries.should be_empty
|
153
|
+
end
|
154
|
+
|
155
|
+
# Account for dirty tracking
|
156
|
+
describe "dirty tracking" do
|
157
|
+
it "should register changes on push" do
|
158
|
+
@invoice.changed?.should be_false
|
159
|
+
@invoice.entries << @entries[0]
|
160
|
+
@invoice.changed?.should be_true
|
161
|
+
end
|
162
|
+
it "should register changes on pop" do
|
163
|
+
@invoice.entries << @entries[0]
|
164
|
+
@invoice.save
|
165
|
+
@invoice.changed?.should be_false
|
166
|
+
@invoice.entries.pop
|
167
|
+
@invoice.changed?.should be_true
|
168
|
+
end
|
169
|
+
it "should register id changes on push" do
|
170
|
+
@invoice.entry_ids << @entries[0].id
|
171
|
+
@invoice.changed?.should be_true
|
172
|
+
end
|
173
|
+
it "should register id changes on pop" do
|
174
|
+
@invoice.entry_ids << @entries[0].id
|
175
|
+
@invoice.save
|
176
|
+
@invoice.changed?.should be_false
|
177
|
+
@invoice.entry_ids.pop
|
178
|
+
@invoice.changed?.should be_true
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
describe "proxy" do
|
183
|
+
|
184
|
+
it "should ensure new entries to proxy are matched" do
|
185
|
+
@invoice.entries << @entries.first
|
186
|
+
@invoice.entry_ids.first.should eql(@entries.first.id)
|
187
|
+
@invoice.entries.first.should eql(@entries.first)
|
188
|
+
@invoice.entries << @entries[1]
|
189
|
+
@invoice.entries.count.should eql(2)
|
190
|
+
@invoice.entry_ids.count.should eql(2)
|
191
|
+
@invoice.entry_ids.last.should eql(@entries[1].id)
|
192
|
+
@invoice.entries.last.should eql(@entries[1])
|
193
|
+
end
|
194
|
+
|
195
|
+
it "should support push method" do
|
196
|
+
@invoice.entries.push(@entries.first)
|
197
|
+
@invoice.entry_ids.first.should eql(@entries.first.id)
|
198
|
+
end
|
199
|
+
|
200
|
+
it "should support []= method" do
|
201
|
+
@invoice.entries[0] = @entries.first
|
202
|
+
@invoice.entry_ids.first.should eql(@entries.first.id)
|
203
|
+
end
|
204
|
+
|
205
|
+
it "should support unshift method" do
|
206
|
+
@invoice.entries.unshift(@entries.first)
|
207
|
+
@invoice.entry_ids.first.should eql(@entries.first.id)
|
208
|
+
@invoice.entries.unshift(@entries[1])
|
209
|
+
@invoice.entry_ids.first.should eql(@entries[1].id)
|
210
|
+
end
|
211
|
+
|
212
|
+
it "should support pop method" do
|
213
|
+
@invoice.entries.push(@entries.first)
|
214
|
+
@invoice.entries.pop.should eql(@entries.first)
|
215
|
+
@invoice.entries.empty?.should be_true
|
216
|
+
@invoice.entry_ids.empty?.should be_true
|
217
|
+
end
|
218
|
+
|
219
|
+
it "should support shift method" do
|
220
|
+
@invoice.entries.push(@entries[0])
|
221
|
+
@invoice.entries.push(@entries[1])
|
222
|
+
@invoice.entries.shift.should eql(@entries[0])
|
223
|
+
@invoice.entries.first.should eql(@entries[1])
|
224
|
+
@invoice.entry_ids.first.should eql(@entries[1].id)
|
225
|
+
end
|
226
|
+
|
227
|
+
it "should raise error when adding un-persisted entries" do
|
228
|
+
SaleEntry.find_by_description('test entry').should be_nil
|
229
|
+
entry = SaleEntry.new(:description => 'test entry', :price => 500)
|
230
|
+
lambda {
|
231
|
+
@invoice.entries << entry
|
232
|
+
}.should raise_error
|
233
|
+
# In the future maybe?
|
234
|
+
# @invoice.save.should be_true
|
235
|
+
# SaleEntry.find_by_description('test entry').should_not be_nil
|
236
|
+
end
|
237
|
+
|
238
|
+
end
|
239
|
+
|
240
|
+
end
|
241
|
+
|
242
|
+
end
|