couchrest_model 1.0.0.beta7 → 1.0.0.beta8

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -13,7 +13,24 @@ CouchRest Model only supports CouchDB 0.10.0 or newer.
13
13
 
14
14
  ## Install
15
15
 
16
- $ sudo gem install couchrest_model
16
+ ### From Gem
17
+
18
+ CouchRest Model depends on Rails 3's ActiveModel which has not yet been released. You'll need to add
19
+ `--pre` to the end of the gem install until the dependencies are stable:
20
+
21
+ $ sudo gem install couchrest_model --pre
22
+
23
+ ### Bundler
24
+
25
+ If you're using bundler, just define a line similar to the following in your project's Gemfile:
26
+
27
+ gem 'couchrest_model'
28
+
29
+ You might also consider using the latest git repository. All tests should pass in the master code branch
30
+ but no guarantees!
31
+
32
+ gem 'couchrest_model', :git => 'git://github.com/couchrest/couchrest_model.git'
33
+
17
34
 
18
35
  ## General Usage
19
36
 
@@ -57,7 +74,7 @@ with a property, but a property may not have any attributes associated if none h
57
74
 
58
75
  In its simplest form, a property
59
76
  will only create a getter and setter passing all attribute data directly to the database. Assuming the attribute
60
- provided responds to +to_json+, there will not be any problems saving it, but when loading the
77
+ provided responds to `to_json`, there will not be any problems saving it, but when loading the
61
78
  data back it will either be a string, number, array, or hash:
62
79
 
63
80
  class Cat < CouchRest::Model::Base
@@ -110,7 +127,7 @@ Adding the +:default+ option will ensure the attribute always has a value.
110
127
 
111
128
  Defining a property as read-only will mean that its value is set only when read from the
112
129
  database and that it will not have a setter method. You can however update a read-only
113
- attribute using the +write_attribute+ method:
130
+ attribute using the `write_attribute` method:
114
131
 
115
132
  class Cat < CouchRest::Model::Base
116
133
  property :name, String
@@ -145,7 +162,7 @@ By default, the array will be ready to use from the moment the object as been in
145
162
  @cat.nicknames == ['Buffy']
146
163
 
147
164
  When anything other than a string is set as the class of a property, the array will be converted
148
- into special wrapper called a CastedArray. If the child objects respond to the 'casted_by' method
165
+ into special wrapper called a CastedArray. If the child objects respond to the `casted_by` method
149
166
  (such as those created with CastedModel, below) it will contain a reference to the parent.
150
167
 
151
168
  ## Casted Models
@@ -214,7 +231,7 @@ TODO: Document properly!
214
231
  CouchRest Model automatically includes the new ActiveModel validations, so they should work just as the traditional Rails
215
232
  validations. For more details, please see the ActiveModel::Validations documentation.
216
233
 
217
- CouchRest Model adds the possibility to check the uniqueness of attributes using the @validates_uniqueness_of@ class method, for example:
234
+ CouchRest Model adds the possibility to check the uniqueness of attributes using the `validates_uniqueness_of` class method, for example:
218
235
 
219
236
  class Person < CouchRest::Model::Base
220
237
  property :title, String
@@ -223,7 +240,7 @@ CouchRest Model adds the possibility to check the uniqueness of attributes using
223
240
  end
224
241
 
225
242
  The uniqueness validation creates a new view for the attribute or uses one that already exists. You can
226
- specify a different view using the +:view+ option, useful for when the @unique_id@ is specified and
243
+ specify a different view using the `:view` option, useful for when the `unique_id` is specified and
227
244
  you'd like to avoid the typical RestClient Conflict error:
228
245
 
229
246
  unique_id :code
@@ -307,12 +324,12 @@ CouchRest install, from the project root directory run `rake`, or `autotest`
307
324
 
308
325
  API: [http://rdoc.info/projects/couchrest/couchrest_model](http://rdoc.info/projects/couchrest/couchrest_model)
309
326
 
310
- Check the wiki for documentation and examples [http://wiki.github.com/couchrest/couchrest](http://wiki.github.com/couchrest/couchrest)
327
+ Check the wiki for documentation and examples [http://wiki.github.com/couchrest/couchrest_model](http://wiki.github.com/couchrest/couchrest_model)
311
328
 
312
329
 
313
330
  ## Contact
314
331
 
315
- Please post bugs, suggestions and patches to the bug tracker at [http://github.com/couchrest/couchrest/issues](http://github.com/couchrest/couchrest/issues).
332
+ Please post bugs, suggestions and patches to the bug tracker at [http://github.com/couchrest/couchrest_model/issues](http://github.com/couchrest/couchrest_model/issues).
316
333
 
317
334
  Follow us on Twitter: [http://twitter.com/couchrest](http://twitter.com/couchrest)
318
335
 
data/Rakefile CHANGED
@@ -24,14 +24,15 @@ begin
24
24
  gemspec.homepage = "http://github.com/couchrest/couchrest_model"
25
25
  gemspec.authors = ["J. Chris Anderson", "Matt Aimonetti", "Marcos Tapajos", "Will Leinweber", "Sam Lown"]
26
26
  gemspec.extra_rdoc_files = %w( README.md LICENSE THANKS.md )
27
- gemspec.files = %w( LICENSE README.md Rakefile THANKS.md history.txt couchrest.gemspec) + Dir["{examples,lib,spec,utils}/**/*"] - Dir["spec/tmp"]
27
+ gemspec.files = %w( LICENSE README.md Rakefile THANKS.md history.txt couchrest.gemspec) + Dir["{examples,lib,spec}/**/*"] - Dir["spec/tmp"]
28
28
  gemspec.has_rdoc = true
29
- gemspec.add_dependency("couchrest", ">= 1.0.0.beta")
30
- gemspec.add_dependency("mime-types", ">= 1.15")
31
- gemspec.add_dependency("activesupport", ">= 2.3.5")
32
- gemspec.add_dependency("activemodel", ">= 3.0.0.beta4")
29
+ gemspec.add_dependency("couchrest", "~> 1.0.0")
30
+ gemspec.add_dependency("mime-types", "~> 1.15")
31
+ gemspec.add_dependency("activesupport", "~> 2.3.5")
32
+ gemspec.add_dependency("activemodel", "~> 3.0.0.beta4")
33
+ gemspec.add_dependency("tzinfo", "~> 0.3.22")
33
34
  gemspec.version = CouchRest::Model::VERSION
34
- gemspec.date = "2008-11-22"
35
+ gemspec.date = Time.now.strftime("%Y-%m-%d")
35
36
  gemspec.require_path = "lib"
36
37
  end
37
38
  rescue LoadError
data/THANKS.md CHANGED
@@ -13,6 +13,8 @@ changes. A list of these people is included below.
13
13
  * [Matt Lyon](http://mattly.tumblr.com/)
14
14
  * Simon Rozet (simon /at/ rozet /dot/ name)
15
15
  * [Marcos Tapajós](http://tapajos.me)
16
+ * [Sam Lown](http://github.com/samlown)
17
+ * [Will Leinweber](http://github.com/will)
16
18
 
17
19
  Patches are welcome. The primary source for this software project is [on Github](http://github.com/couchrest/couchrest)
18
20
 
data/history.txt CHANGED
@@ -3,12 +3,14 @@
3
3
  * Major enhancements
4
4
 
5
5
  * Minor enhancements
6
+ * Raise error on adding objects to "collection_of" without an id
7
+ * Allow mixing of protected and accessible properties. Any unspecified properties are now assumed to be protected by default
6
8
 
7
9
  == CouchRest Model 1.0.0.beta7
8
10
 
9
11
  * Major enhancements
10
12
  * Renamed ExtendedDocument to CouchRest::Model
11
- * Added initial support for simple belongs_to associations
13
+ * Added initial support for simple belongs_to associations
12
14
  * Added support for basic collection_of association (unique to document databases!)
13
15
  * Moved Validation to ActiveModel
14
16
  * Moved Callbacks to ActiveModel
@@ -16,6 +18,9 @@
16
18
  * Validation always included
17
19
  * Uniqueness validation now available
18
20
 
21
+ * Minor enhancements
22
+ * Removed support for auto_validate! and :length on properties
23
+
19
24
 
20
25
  == 1.0.0.beta6
21
26
 
@@ -70,7 +75,7 @@
70
75
  * Adds support for continuous replication (sauy7)
71
76
  * Automatic Type Casting (Alexander Uvarov, Sam Lown, Tim Heighes, Will Leinweber)
72
77
  * Added a search method to CouchRest:Database to search the documents in a given database. (Dave Farkas, Arnaud Berthomier, John Wood)
73
-
78
+
74
79
  * Minor enhancements
75
80
  * Provide a description of the timeout error (John Wood)
76
81
 
@@ -99,9 +104,9 @@
99
104
  * Adds attribute protection to properties. (Will Leinweber)
100
105
  * Improved CouchRest::Database#save_doc, added "batch" mode to significantly speed up saves at cost of lower durability gurantees. (Igal Koshevoy)
101
106
  * Added CouchRest::Database#bulk_save_doc and #batch_save_doc as human-friendlier wrappers around #save_doc. (Igal Koshevoy)
102
-
103
- * Minor enhancements
104
-
107
+
108
+ * Minor enhancements
109
+
105
110
  * Fix content_type handling for attachments
106
111
  * Fixed a bug in the pagination code that caused it to paginate over records outside of the scope of the view parameters.(John Wood)
107
112
  * Removed amount_pages calculation for the pagination collection, since it cannot be reliably calculated without a view.(John Wood)
@@ -120,9 +125,9 @@
120
125
  * Major enhancements
121
126
 
122
127
  * Added a new Rack logger middleware letting you log/save requests/queries (Matt Aimonetti)
123
-
124
- * Minor enhancements
125
-
128
+
129
+ * Minor enhancements
130
+
126
131
  * Added #amount_pages to a paginated result array (Matt Aimonetti)
127
132
  * Ruby 1.9.2 compatible (Matt Aimonetti)
128
133
  * Added a property? method for property cast as :boolean (John Wood)
@@ -131,14 +136,14 @@
131
136
  * Bug fix: made ExtendedDocument#all compatible with Couch 0.10 (tc)
132
137
 
133
138
  == 0.32
134
-
139
+
135
140
  * Major enhancements
136
141
 
137
142
  * ExtendedDocument.get doesn't raise an exception anymore. If no documents are found nil is returned.
138
143
  * ExtendedDocument.get! works the say #get used to work and will raise an exception if a document isn't found.
139
-
140
- * Minor enhancements
141
-
144
+
145
+ * Minor enhancements
146
+
142
147
  * Bug fix: Model.all(:keys => [1,2]) was not working (Matt Aimonetti)
143
148
  * Added ValidationErrors#count in order to play nicely with Rails (Peter Wagenet)
144
149
  * Bug fix: class proxy design doc refresh (Daniel Kirsh)
@@ -151,29 +156,29 @@
151
156
 
152
157
  * Created an abstraction HTTP layer to support different http adapters (Matt Aimonetti)
153
158
  * Added ExtendedDocument.create({}) and #create!({}) so you don't have to do Model.new.create (Matt Aimonetti)
154
-
159
+
155
160
  * Minor enhancements
156
-
161
+
157
162
  * Added an init.rb file for easy usage as a Rails plugin (Aaron Quint)
158
163
  * Bug fix: pagination shouldn't die on empty results (Arnaud Berthomier)
159
164
  * Optimized ExtendedDocument.count to run about 3x faster (Matt Aimonetti)
160
165
  * Added Float casting (Ryan Felton & Matt Aimonetti)
161
166
 
162
167
  == 0.30
163
-
168
+
164
169
  * Major enhancements
165
-
170
+
166
171
  * Added support for pagination (John Wood)
167
172
  * Improved performance when initializing documents with timestamps (Matt Aimonetti)
168
-
173
+
169
174
  * Minor enhancements
170
-
175
+
171
176
  * Extended the API to retrieve an attachment URI (Matt Aimonetti)
172
177
  * Bug fix: default value should be able to be set as false (Alexander Uvarov)
173
178
  * Bug fix: validates_is_numeric should be able to properly validate a Float instance (Rob Kaufman)
174
179
  * Bug fix: fixed the Timeout implementation (Seth Falcon)
175
-
176
-
180
+
181
+
177
182
  ---
178
183
 
179
184
  Unfortunately, before 0.30 we did not keep a track of the modifications made to CouchRest.
@@ -39,7 +39,7 @@ module CouchRest
39
39
  attr_accessor :casted_by
40
40
 
41
41
 
42
- # Instantiate a new ExtendedDocument by preparing all properties
42
+ # Instantiate a new CouchRest::Model::Base by preparing all properties
43
43
  # using the provided document hash.
44
44
  #
45
45
  # Options supported:
@@ -7,11 +7,15 @@ module CouchRest
7
7
  def create_attachment(args={})
8
8
  raise ArgumentError unless args[:file] && args[:name]
9
9
  return if has_attachment?(args[:name])
10
- self['_attachments'] ||= {}
11
10
  set_attachment_attr(args)
12
11
  rescue ArgumentError => e
13
12
  raise ArgumentError, 'You must specify :file and :name'
14
13
  end
14
+
15
+ # return all attachments
16
+ def attachments
17
+ self['_attachments'] ||= {}
18
+ end
15
19
 
16
20
  # reads the data from an attachment
17
21
  def read_attachment(attachment_name)
@@ -30,13 +34,13 @@ module CouchRest
30
34
 
31
35
  # deletes a file attachment from the current doc
32
36
  def delete_attachment(attachment_name)
33
- return unless self['_attachments']
34
- self['_attachments'].delete attachment_name
37
+ return unless attachments
38
+ attachments.delete attachment_name
35
39
  end
36
40
 
37
41
  # returns true if attachment_name exists
38
42
  def has_attachment?(attachment_name)
39
- !!(self['_attachments'] && self['_attachments'][attachment_name] && !self['_attachments'][attachment_name].empty?)
43
+ !!(attachments && attachments[attachment_name] && !attachments[attachment_name].empty?)
40
44
  end
41
45
 
42
46
  # returns URL to fetch the attachment from
@@ -62,7 +66,7 @@ module CouchRest
62
66
  def set_attachment_attr(args)
63
67
  content_type = args[:content_type] ? args[:content_type] : get_mime_type(args[:file].path)
64
68
  content_type ||= (get_mime_type(args[:name]) || 'text/plain')
65
- self['_attachments'][args[:name]] = {
69
+ attachments[args[:name]] = {
66
70
  'content_type' => content_type,
67
71
  'data' => args[:file].read
68
72
  }
@@ -1,4 +1,4 @@
1
- # encoding: urf-8
1
+ # encoding: utf-8
2
2
 
3
3
  module CouchRest
4
4
  module Model
@@ -16,15 +16,14 @@ module CouchRest
16
16
 
17
17
  def validate_each(document, attribute, value)
18
18
  view_name = options[:view].nil? ? "by_#{attribute}" : options[:view]
19
+ # Determine the base of the search
20
+ base = options[:proxy].nil? ? @klass : document.instance_eval(options[:proxy])
19
21
 
20
- unless @klass.has_view?(view_name)
22
+ if base.respond_to?(:has_view?) && !base.has_view?(view_name)
21
23
  raise "View #{document.class.name}.#{options[:view]} does not exist!" unless options[:view].nil?
22
24
  @klass.view_by attribute
23
25
  end
24
26
 
25
- # Determine the base of the search
26
- base = options[:proxy].nil? ? @klass : document.instance_eval(options[:proxy])
27
-
28
27
  docs = base.view(view_name, :key => value, :limit => 2, :include_docs => false)['rows']
29
28
  return if docs.empty?
30
29
 
@@ -127,18 +127,11 @@ module CouchRest
127
127
  if raw || (opts.has_key?(:include_docs) && opts[:include_docs] == false)
128
128
  fetch_view(db, name, opts, &block)
129
129
  else
130
- begin
131
- if block.nil?
132
- collection_proxy_for(design_doc, name, opts.merge({:include_docs => true}))
133
- else
134
- view = fetch_view db, name, opts.merge({:include_docs => true}), &block
135
- view['rows'].collect{|r|create_from_database(r['doc'])} if view['rows']
136
- end
137
- rescue
138
- # fallback for old versions of couchdb that don't
139
- # have include_docs support
140
- view = fetch_view(db, name, opts, &block)
141
- view['rows'].collect{|r|create_from_database(db.get(r['id']))} if view['rows']
130
+ if block.nil?
131
+ collection_proxy_for(design_doc, name, opts.merge({:database => db, :include_docs => true}))
132
+ else
133
+ view = fetch_view db, name, opts.merge({:include_docs => true}), &block
134
+ view['rows'].collect{|r|create_from_database(r['doc'])} if view['rows']
142
135
  end
143
136
  end
144
137
  end
@@ -3,7 +3,7 @@ module CouchRest
3
3
 
4
4
  module Model
5
5
 
6
- VERSION = "1.0.0.beta7"
6
+ VERSION = "1.0.0.beta8"
7
7
 
8
8
  end
9
9
 
@@ -0,0 +1,11 @@
1
+ require "rails"
2
+ require "active_model/railtie"
3
+
4
+ module CouchrestModel
5
+ # = Active Record Railtie
6
+ class Railtie < Rails::Railtie
7
+ config.generators.orm :couchrest
8
+ end
9
+
10
+ end
11
+
@@ -1,12 +1,13 @@
1
-
2
- # require File.join(File.dirname(__FILE__), "couchrest", "extended_document")
3
-
4
- gem 'couchrest'
5
-
1
+ gem 'couchrest', ">= 1.0.0.beta"
6
2
  require 'couchrest'
7
3
 
4
+ gem "tzinfo", ">= 0.3.22"
5
+
6
+ gem "activesupport", ">= 2.3.5"
8
7
  require 'active_support/core_ext'
9
8
  require 'active_support/json'
9
+
10
+ gem "activemodel", ">= 3.0.0.beta4"
10
11
  require 'active_model'
11
12
  require "active_model/callbacks"
12
13
  require "active_model/conversion"
@@ -17,6 +18,8 @@ require "active_model/serialization"
17
18
  require "active_model/translation"
18
19
  require "active_model/validator"
19
20
  require "active_model/validations"
21
+
22
+ gem "mime-types", ">= 1.15"
20
23
  require 'mime/types'
21
24
  require "enumerator"
22
25
  require "time"
@@ -54,3 +57,5 @@ require "couchrest/model/base"
54
57
 
55
58
  # Add rails support *after* everything has loaded
56
59
 
60
+ require "couchrest/railtie"
61
+
@@ -0,0 +1,26 @@
1
+ require 'rails/generators/couchrest_model'
2
+
3
+ module CouchrestModel
4
+ module Generators
5
+ class ModelGenerator < Base
6
+
7
+ check_class_collision
8
+
9
+ def create_model_file
10
+ template 'model.rb', File.join('app/models', class_path, "#{file_name}.rb")
11
+ end
12
+
13
+ def create_module_file
14
+ return if class_path.empty?
15
+ template 'module.rb', File.join('app/models', "#{class_path.join('/')}.rb") if behavior == :invoke
16
+ end
17
+
18
+ protected
19
+
20
+ def parent_class_name
21
+ "CouchRest::Model::Base"
22
+ end
23
+
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,2 @@
1
+ class <%= class_name %> < <%= parent_class_name.classify %>
2
+ end
@@ -0,0 +1,16 @@
1
+ require 'rails/generators/named_base'
2
+ require 'rails/generators/active_model'
3
+ require 'couchrest_model'
4
+
5
+ module CouchrestModel
6
+ module Generators
7
+ class Base < Rails::Generators::NamedBase #:nodoc:
8
+
9
+ # Set the current directory as base for the inherited generators.
10
+ def self.base_root
11
+ File.dirname(__FILE__)
12
+ end
13
+
14
+ end
15
+ end
16
+ end
@@ -1,31 +1,6 @@
1
1
  # encoding: utf-8
2
2
  require File.expand_path('../../spec_helper', __FILE__)
3
-
4
- class Client < CouchRest::Model::Base
5
- use_database DB
6
-
7
- property :name
8
- property :tax_code
9
- end
10
-
11
- class SaleEntry < CouchRest::Model::Base
12
- use_database DB
13
-
14
- property :description
15
- property :price
16
- end
17
-
18
- class SaleInvoice < CouchRest::Model::Base
19
- use_database DB
20
-
21
- belongs_to :client
22
- belongs_to :alternate_client, :class_name => 'Client', :foreign_key => 'alt_client_id'
23
-
24
- collection_of :entries, :class_name => 'SaleEntry'
25
-
26
- property :date, Date
27
- property :price, Integer
28
- end
3
+ require File.join(FIXTURE_PATH, 'more', 'sale_invoice')
29
4
 
30
5
 
31
6
  describe "Assocations" do
@@ -33,7 +8,7 @@ describe "Assocations" do
33
8
  describe "of type belongs to" do
34
9
 
35
10
  before :each do
36
- @invoice = SaleInvoice.create(:price => "sam", :price => 2000)
11
+ @invoice = SaleInvoice.create(:price => 2000)
37
12
  @client = Client.create(:name => "Sam Lown")
38
13
  end
39
14
 
@@ -94,7 +69,7 @@ describe "Assocations" do
94
69
  describe "of type collection_of" do
95
70
 
96
71
  before(:each) do
97
- @invoice = SaleInvoice.create(:price => "sam", :price => 2000)
72
+ @invoice = SaleInvoice.create(:price => 2000)
98
73
  @entries = [
99
74
  SaleEntry.create(:description => 'test line 1', :price => 500),
100
75
  SaleEntry.create(:description => 'test line 2', :price => 500),
@@ -121,7 +96,7 @@ describe "Assocations" do
121
96
  @invoice.entries.length.should eql(3)
122
97
  @invoice.entries.first.should eql(@entries.first)
123
98
  end
124
-
99
+
125
100
  it "should replace collection if ids replaced" do
126
101
  @invoice.entry_ids = @entries.collect{|i| i.id}
127
102
  @invoice.entries.length.should eql(3) # load once
@@ -135,7 +110,7 @@ describe "Assocations" do
135
110
  @invoice.entry_ids << @entries[2].id
136
111
  @invoice.entry_ids.length.should eql(3)
137
112
  @invoice.entries.length.should eql(2) # cached!
138
- @invoice.entries(true).length.should eql(3)
113
+ @invoice.entries(true).length.should eql(3)
139
114
  end
140
115
 
141
116
  it "should empty arrays when nil collection provided" do
@@ -203,11 +178,19 @@ describe "Assocations" do
203
178
  @invoice.entry_ids.first.should eql(@entries[1].id)
204
179
  end
205
180
 
181
+ it "should raise error when adding un-persisted entries" do
182
+ SaleEntry.find_by_description('test entry').should be_nil
183
+ entry = SaleEntry.new(:description => 'test entry', :price => 500)
184
+ lambda {
185
+ @invoice.entries << entry
186
+ }.should raise_error
187
+ # In the future maybe?
188
+ # @invoice.save.should be_true
189
+ # SaleEntry.find_by_description('test entry').should_not be_nil
190
+ end
206
191
 
207
192
  end
208
-
209
193
 
210
194
  end
211
195
 
212
196
  end
213
-
@@ -30,6 +30,13 @@ describe "Model attachments" do
30
30
  @obj.delete_attachment(@attachment_name)
31
31
  @obj.has_attachment?(@attachment_name).should be_false
32
32
  end
33
+
34
+ it 'should return false if an attachment has been removed and reloaded' do
35
+ @obj.delete_attachment(@attachment_name)
36
+ reloaded_obj = Basic.get(@obj.id)
37
+ reloaded_obj.has_attachment?(@attachment_name).should be_false
38
+ end
39
+
33
40
  end
34
41
 
35
42
  describe "creating an attachment" do
@@ -46,14 +53,14 @@ describe "Model attachments" do
46
53
  @obj.create_attachment(:file => @file_ext, :name => @attachment_name)
47
54
  @obj.save.should be_true
48
55
  reloaded_obj = Basic.get(@obj.id)
49
- reloaded_obj['_attachments'][@attachment_name].should_not be_nil
56
+ reloaded_obj.attachments[@attachment_name].should_not be_nil
50
57
  end
51
58
 
52
59
  it "should create an attachment from file without an extension" do
53
60
  @obj.create_attachment(:file => @file_no_ext, :name => @attachment_name)
54
61
  @obj.save.should be_true
55
62
  reloaded_obj = Basic.get(@obj.id)
56
- reloaded_obj['_attachments'][@attachment_name].should_not be_nil
63
+ reloaded_obj.attachments[@attachment_name].should_not be_nil
57
64
  end
58
65
 
59
66
  it 'should raise ArgumentError if :file is missing' do
@@ -66,19 +73,19 @@ describe "Model attachments" do
66
73
 
67
74
  it 'should set the content-type if passed' do
68
75
  @obj.create_attachment(:file => @file_ext, :name => @attachment_name, :content_type => @content_type)
69
- @obj['_attachments'][@attachment_name]['content_type'].should == @content_type
76
+ @obj.attachments[@attachment_name]['content_type'].should == @content_type
70
77
  end
71
78
 
72
79
  it "should detect the content-type automatically" do
73
80
  @obj.create_attachment(:file => File.open(FIXTURE_PATH + '/attachments/couchdb.png'), :name => "couchdb.png")
74
- @obj['_attachments']['couchdb.png']['content_type'].should == "image/png"
81
+ @obj.attachments['couchdb.png']['content_type'].should == "image/png"
75
82
  end
76
83
 
77
84
  it "should use name to detect the content-type automatically if no file" do
78
85
  file = File.open(FIXTURE_PATH + '/attachments/couchdb.png')
79
86
  file.stub!(:path).and_return("badfilname")
80
87
  @obj.create_attachment(:file => File.open(FIXTURE_PATH + '/attachments/couchdb.png'), :name => "couchdb.png")
81
- @obj['_attachments']['couchdb.png']['content_type'].should == "image/png"
88
+ @obj.attachments['couchdb.png']['content_type'].should == "image/png"
82
89
  end
83
90
 
84
91
  end
@@ -113,7 +120,7 @@ describe "Model attachments" do
113
120
  file = File.open(FIXTURE_PATH + '/attachments/README')
114
121
  @file.should_not == file
115
122
  @obj.update_attachment(:file => file, :name => @attachment_name, :content_type => @content_type)
116
- @obj['_attachments'][@attachment_name]['content_type'].should == @content_type
123
+ @obj.attachments[@attachment_name]['content_type'].should == @content_type
117
124
  end
118
125
 
119
126
  it 'should delete an attachment that exists' do
@@ -143,6 +150,27 @@ describe "Model attachments" do
143
150
  it 'should return the attachment URI' do
144
151
  @obj.attachment_uri(@attachment_name).should == "#{Basic.database.uri}/#{@obj.id}/#{@attachment_name}"
145
152
  end
146
-
153
+ end
154
+
155
+ describe "#attachments" do
156
+ before(:each) do
157
+ @obj = Basic.new
158
+ @file = File.open(FIXTURE_PATH + '/attachments/test.html')
159
+ @attachment_name = 'my_attachment'
160
+ @obj.create_attachment(:file => @file, :name => @attachment_name)
161
+ @obj.save.should be_true
162
+ end
163
+
164
+ it 'should return an empty Hash when document does not have any attachment' do
165
+ new_obj = Basic.new
166
+ new_obj.save.should be_true
167
+ new_obj.attachments.should == {}
168
+ end
169
+
170
+ it 'should return a Hash with all attachments' do
171
+ @file.rewind
172
+ @obj.attachments.should == { @attachment_name =>{ "data" => "PCFET0NUWVBFIGh0bWw+CjxodG1sPgogIDxoZWFkPgogICAgPHRpdGxlPlRlc3Q8L3RpdGxlPgogIDwvaGVhZD4KICA8Ym9keT4KICAgIDxwPgogICAgICBUZXN0CiAgICA8L3A+CiAgPC9ib2R5Pgo8L2h0bWw+Cg==", "content_type" => "text/html"}}
173
+ end
174
+
147
175
  end
148
176
  end