couchrest 0.32 → 0.33

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -17,7 +17,7 @@ Note: CouchRest only support CouchDB 0.9.0 or newer.
17
17
  Alternatively, you can install from Github:
18
18
 
19
19
  $ gem sources -a http://gems.github.com (you only have to do this once)
20
- $ sudo gem install mattetti-couchrest
20
+ $ sudo gem install couchrest-couchrest
21
21
 
22
22
  ### Relax, it's RESTful
23
23
 
data/history.txt CHANGED
@@ -1,3 +1,18 @@
1
+ == 0.33
2
+
3
+ * Major enhancements
4
+
5
+ * Added a new Rack logger middleware letting you log/save requests/queries (Matt Aimonetti)
6
+
7
+ * Minor enhancements
8
+
9
+ * Added #amount_pages to a paginated result array (Matt Aimonetti)
10
+ * Ruby 1.9.2 compatible (Matt Aimonetti)
11
+ * Added a property? method for property cast as :boolean (John Wood)
12
+ * Added an option to force the deletion of a attachments (bypass 409s) (Matt Aimonetti)
13
+ * Created a new abstraction layer for the REST API (Matt Aimonetti)
14
+ * Bug fix: made ExtendedDocument#all compatible with Couch 0.10 (tc)
15
+
1
16
  == 0.32
2
17
 
3
18
  * Major enhancements
@@ -45,4 +60,4 @@
45
60
  ---
46
61
 
47
62
  Unfortunately, before 0.30 we did not keep a track of the modifications made to CouchRest.
48
- You can see the full commit history on GitHub: http://github.com/mattetti/couchrest/commits/master/
63
+ You can see the full commit history on GitHub: http://github.com/couchrest/couchrest/commits/master/
data/lib/couchrest.rb CHANGED
@@ -28,7 +28,7 @@ require 'couchrest/monkeypatches'
28
28
 
29
29
  # = CouchDB, close to the metal
30
30
  module CouchRest
31
- VERSION = '0.32' unless self.const_defined?("VERSION")
31
+ VERSION = '0.33' unless self.const_defined?("VERSION")
32
32
 
33
33
  autoload :Server, 'couchrest/core/server'
34
34
  autoload :Database, 'couchrest/core/database'
@@ -45,8 +45,13 @@ module CouchRest
45
45
  autoload :ExtendedDocument, 'couchrest/more/extended_document'
46
46
  autoload :CastedModel, 'couchrest/more/casted_model'
47
47
 
48
+ require File.join(File.dirname(__FILE__), 'couchrest', 'core', 'rest_api')
48
49
  require File.join(File.dirname(__FILE__), 'couchrest', 'core', 'http_abstraction')
49
50
  require File.join(File.dirname(__FILE__), 'couchrest', 'mixins')
51
+
52
+ # we extend CouchRest with the RestAPI module which gives us acess to
53
+ # the get, post, put, delete and copy
54
+ CouchRest.extend(::RestAPI)
50
55
 
51
56
  # The CouchRest module methods handle the basic JSON serialization
52
57
  # and deserialization, as well as query parameters. The module also includes
@@ -139,52 +144,6 @@ module CouchRest
139
144
  cr.database(parsed[:database])
140
145
  end
141
146
 
142
- def put(uri, doc = nil)
143
- payload = doc.to_json if doc
144
- begin
145
- JSON.parse(HttpAbstraction.put(uri, payload))
146
- rescue Exception => e
147
- if $DEBUG
148
- raise "Error while sending a PUT request #{uri}\npayload: #{payload.inspect}\n#{e}"
149
- else
150
- raise e
151
- end
152
- end
153
- end
154
-
155
- def get(uri)
156
- begin
157
- JSON.parse(HttpAbstraction.get(uri), :max_nesting => false)
158
- rescue => e
159
- if $DEBUG
160
- raise "Error while sending a GET request #{uri}\n: #{e}"
161
- else
162
- raise e
163
- end
164
- end
165
- end
166
-
167
- def post uri, doc = nil
168
- payload = doc.to_json if doc
169
- begin
170
- JSON.parse(HttpAbstraction.post(uri, payload))
171
- rescue Exception => e
172
- if $DEBUG
173
- raise "Error while sending a POST request #{uri}\npayload: #{payload.inspect}\n#{e}"
174
- else
175
- raise e
176
- end
177
- end
178
- end
179
-
180
- def delete uri
181
- JSON.parse(HttpAbstraction.delete(uri))
182
- end
183
-
184
- def copy uri, destination
185
- JSON.parse(HttpAbstraction.copy(uri, {'Destination' => destination}))
186
- end
187
-
188
147
  def paramify_url url, params = {}
189
148
  if params && !params.empty?
190
149
  query = params.collect do |k,v|
@@ -113,10 +113,21 @@ module CouchRest
113
113
  end
114
114
 
115
115
  # DELETE an attachment directly from CouchDB
116
- def delete_attachment doc, name
116
+ def delete_attachment(doc, name, force=false)
117
117
  uri = url_for_attachment(doc, name)
118
118
  # this needs a rev
119
- JSON.parse(HttpAbstraction.delete(uri))
119
+ begin
120
+ JSON.parse(HttpAbstraction.delete(uri))
121
+ rescue Exception => error
122
+ if force
123
+ # get over a 409
124
+ doc = get(doc['_id'])
125
+ uri = url_for_attachment(doc, name)
126
+ JSON.parse(HttpAbstraction.delete(uri))
127
+ else
128
+ error
129
+ end
130
+ end
120
131
  end
121
132
 
122
133
  # Save a document to CouchDB. This will use the <tt>_id</tt> field from
@@ -0,0 +1,49 @@
1
+ module RestAPI
2
+
3
+ def put(uri, doc = nil)
4
+ payload = doc.to_json if doc
5
+ begin
6
+ JSON.parse(HttpAbstraction.put(uri, payload))
7
+ rescue Exception => e
8
+ if $DEBUG
9
+ raise "Error while sending a PUT request #{uri}\npayload: #{payload.inspect}\n#{e}"
10
+ else
11
+ raise e
12
+ end
13
+ end
14
+ end
15
+
16
+ def get(uri)
17
+ begin
18
+ JSON.parse(HttpAbstraction.get(uri), :max_nesting => false)
19
+ rescue => e
20
+ if $DEBUG
21
+ raise "Error while sending a GET request #{uri}\n: #{e}"
22
+ else
23
+ raise e
24
+ end
25
+ end
26
+ end
27
+
28
+ def post(uri, doc = nil)
29
+ payload = doc.to_json if doc
30
+ begin
31
+ JSON.parse(HttpAbstraction.post(uri, payload))
32
+ rescue Exception => e
33
+ if $DEBUG
34
+ raise "Error while sending a POST request #{uri}\npayload: #{payload.inspect}\n#{e}"
35
+ else
36
+ raise e
37
+ end
38
+ end
39
+ end
40
+
41
+ def delete(uri)
42
+ JSON.parse(HttpAbstraction.delete(uri))
43
+ end
44
+
45
+ def copy(uri, destination)
46
+ JSON.parse(HttpAbstraction.copy(uri, {'Destination' => destination}))
47
+ end
48
+
49
+ end
@@ -0,0 +1,263 @@
1
+ ####################################
2
+ # USAGE
3
+ #
4
+ # in your rack.rb file
5
+ # require this file and then:
6
+ #
7
+ # couch = CouchRest.new
8
+ # LOG_DB = couch.database!('couchrest-logger')
9
+ # use CouchRest::Logger, LOG_DB
10
+ #
11
+ # Note:
12
+ # to require just this middleware, if you have the gem installed do:
13
+ # require 'couchrest/middlewares/logger'
14
+ #
15
+ # For log processing examples, see examples at the bottom of this file
16
+
17
+ module CouchRest
18
+ class Logger
19
+
20
+ def self.log
21
+ Thread.current["couchrest.logger"] ||= {:queries => []}
22
+ end
23
+
24
+ def initialize(app, db=nil)
25
+ @app = app
26
+ @db = db
27
+ end
28
+
29
+ def self.record(log_info)
30
+ log[:queries] << log_info
31
+ end
32
+
33
+ def log
34
+ Thread.current["couchrest.logger"] ||= {:queries => []}
35
+ end
36
+
37
+ def reset_log
38
+ Thread.current["couchrest.logger"] = nil
39
+ end
40
+
41
+ def call(env)
42
+ reset_log
43
+ log['started_at'] = Time.now
44
+ log['env'] = env
45
+ log['url'] = 'http://' + env['HTTP_HOST'] + env['REQUEST_URI']
46
+ response = @app.call(env)
47
+ log['ended_at'] = Time.now
48
+ log['duration'] = log['ended_at'] - log['started_at']
49
+ # let's report the log in a different thread so we don't slow down the app
50
+ @db ? Thread.new(@db, log){|db, rlog| db.save_doc(rlog);} : p(log.inspect)
51
+ response
52
+ end
53
+ end
54
+ end
55
+
56
+ # inject our logger into CouchRest HTTP abstraction layer
57
+ module HttpAbstraction
58
+
59
+ def self.get(uri, headers=nil)
60
+ start_query = Time.now
61
+ log = {:method => :get, :uri => uri, :headers => headers}
62
+ response = super(uri, headers=nil)
63
+ end_query = Time.now
64
+ log[:duration] = (end_query - start_query)
65
+ CouchRest::Logger.record(log)
66
+ response
67
+ end
68
+
69
+ def self.post(uri, payload, headers=nil)
70
+ start_query = Time.now
71
+ log = {:method => :post, :uri => uri, :payload => (payload ? (JSON.load(payload) rescue 'parsing error') : nil), :headers => headers}
72
+ response = super(uri, payload, headers=nil)
73
+ end_query = Time.now
74
+ log[:duration] = (end_query - start_query)
75
+ CouchRest::Logger.record(log)
76
+ response
77
+ end
78
+
79
+ def self.put(uri, payload, headers=nil)
80
+ start_query = Time.now
81
+ log = {:method => :put, :uri => uri, :payload => (payload ? (JSON.load(payload) rescue 'parsing error') : nil), :headers => headers}
82
+ response = super(uri, payload, headers=nil)
83
+ end_query = Time.now
84
+ log[:duration] = (end_query - start_query)
85
+ CouchRest::Logger.record(log)
86
+ response
87
+ end
88
+
89
+ def self.delete(uri, headers=nil)
90
+ start_query = Time.now
91
+ log = {:method => :delete, :uri => uri, :headers => headers}
92
+ response = super(uri, headers=nil)
93
+ end_query = Time.now
94
+ log[:duration] = (end_query - start_query)
95
+ CouchRest::Logger.record(log)
96
+ response
97
+ end
98
+
99
+ end
100
+
101
+
102
+ # Advanced usage example
103
+ #
104
+ #
105
+ # # DB VIEWS
106
+ # by_url = {
107
+ # :map =>
108
+ # "function(doc) {
109
+ # if(doc['url']){ emit(doc['url'], 1) };
110
+ # }",
111
+ # :reduce =>
112
+ # 'function (key, values, rereduce) {
113
+ # return(sum(values));
114
+ # };'
115
+ # }
116
+ # req_duration = {
117
+ # :map =>
118
+ # "function(doc) {
119
+ # if(doc['duration']){ emit(doc['url'], doc['duration']) };
120
+ # }",
121
+ # :reduce =>
122
+ # 'function (key, values, rereduce) {
123
+ # return(sum(values)/values.length);
124
+ # };'
125
+ # }
126
+ #
127
+ # query_duration = {
128
+ # :map =>
129
+ # "function(doc) {
130
+ # if(doc['queries']){
131
+ # doc.queries.forEach(function(query){
132
+ # if(query['duration'] && query['method']){
133
+ # emit(query['method'], query['duration'])
134
+ # }
135
+ # });
136
+ # };
137
+ # }" ,
138
+ # :reduce =>
139
+ # 'function (key, values, rereduce) {
140
+ # return(sum(values)/values.length);
141
+ # };'
142
+ # }
143
+ #
144
+ # action_queries = {
145
+ # :map =>
146
+ # "function(doc) {
147
+ # if(doc['queries']){
148
+ # emit(doc['url'], doc['queries'].length)
149
+ # };
150
+ # }",
151
+ # :reduce =>
152
+ # 'function (key, values, rereduce) {
153
+ # return(sum(values)/values.length);
154
+ # };'
155
+ # }
156
+ #
157
+ # action_time_spent_in_db = {
158
+ # :map =>
159
+ # "function(doc) {
160
+ # if(doc['queries']){
161
+ # var totalDuration = 0;
162
+ # doc.queries.forEach(function(query){
163
+ # totalDuration += query['duration']
164
+ # })
165
+ # emit(doc['url'], totalDuration)
166
+ # };
167
+ # }",
168
+ # :reduce =>
169
+ # 'function (key, values, rereduce) {
170
+ # return(sum(values)/values.length);
171
+ # };'
172
+ # }
173
+ #
174
+ # show_queries = %Q~function(doc, req) {
175
+ # var body = ""
176
+ # body += "<h1>" + doc['url'] + "</h1>"
177
+ # body += "<h2>Request duration in seconds: " + doc['duration'] + "</h2>"
178
+ # body += "<h3>" + doc['queries'].length + " queries</h3><ul>"
179
+ # if (doc.queries){
180
+ # doc.queries.forEach(function(query){
181
+ # body += "<li>"+ query['uri'] +"</li>"
182
+ # });
183
+ # };
184
+ # body += "</ul>"
185
+ # if(doc){ return { body: body} }
186
+ # }~
187
+ #
188
+ #
189
+ # couch = CouchRest.new
190
+ # LOG_DB = couch.database!('couchrest-logger')
191
+ # design_doc = LOG_DB.get("_design/stats") rescue nil
192
+ # LOG_DB.delete_doc design_doc rescue nil
193
+ # LOG_DB.save_doc({
194
+ # "_id" => "_design/stats",
195
+ # :views => {
196
+ # :by_url => by_url,
197
+ # :request_duration => req_duration,
198
+ # :query_duration => query_duration,
199
+ # :action_queries => action_queries,
200
+ # :action_time_spent_in_db => action_time_spent_in_db
201
+ # },
202
+ # :shows => {
203
+ # :queries => show_queries
204
+ # }
205
+ # })
206
+ #
207
+ # module CouchRest
208
+ # class Logger
209
+ #
210
+ # def self.roundup(value)
211
+ # begin
212
+ # value = Float(value)
213
+ # (value * 100).round.to_f / 100
214
+ # rescue
215
+ # value
216
+ # end
217
+ # end
218
+ #
219
+ # # Usage example:
220
+ # # CouchRest::Logger.average_request_duration(LOG_DB)['rows'].first['value']
221
+ # def self.average_request_duration(db)
222
+ # raw = db.view('stats/request_duration', :reduce => true)
223
+ # (raw.has_key?('rows') && !raw['rows'].empty?) ? roundup(raw['rows'].first['value']) : 'not available yet'
224
+ # end
225
+ #
226
+ # def self.average_query_duration(db)
227
+ # raw = db.view('stats/query_duration', :reduce => true)
228
+ # (raw.has_key?('rows') && !raw['rows'].empty?) ? roundup(raw['rows'].first['value']) : 'not available yet'
229
+ # end
230
+ #
231
+ # def self.average_get_query_duration(db)
232
+ # raw = db.view('stats/query_duration', :key => 'get', :reduce => true)
233
+ # (raw.has_key?('rows') && !raw['rows'].empty?) ? roundup(raw['rows'].first['value']) : 'not available yet'
234
+ # end
235
+ #
236
+ # def self.average_post_query_duration(db)
237
+ # raw = db.view('stats/query_duration', :key => 'post', :reduce => true)
238
+ # (raw.has_key?('rows') && !raw['rows'].empty?) ? roundup(raw['rows'].first['value']) : 'not available yet'
239
+ # end
240
+ #
241
+ # def self.average_queries_per_action(db)
242
+ # raw = db.view('stats/action_queries', :reduce => true)
243
+ # (raw.has_key?('rows') && !raw['rows'].empty?) ? roundup(raw['rows'].first['value']) : 'not available yet'
244
+ # end
245
+ #
246
+ # def self.average_db_time_per_action(db)
247
+ # raw = db.view('stats/action_time_spent_in_db', :reduce => true)
248
+ # (raw.has_key?('rows') && !raw['rows'].empty?) ? roundup(raw['rows'].first['value']) : 'not available yet'
249
+ # end
250
+ #
251
+ # def self.stats(db)
252
+ # Thread.new(db){|db|
253
+ # puts "=== STATS ===\n"
254
+ # puts "average request duration: #{average_request_duration(db)}\n"
255
+ # puts "average query duration: #{average_query_duration(db)}\n"
256
+ # puts "average queries per action : #{average_queries_per_action(db)}\n"
257
+ # puts "average time spent in DB (per action): #{average_db_time_per_action(db)}\n"
258
+ # puts "===============\n"
259
+ # }
260
+ # end
261
+ #
262
+ # end
263
+ # end
@@ -19,9 +19,9 @@ module CouchRest
19
19
  end
20
20
 
21
21
  # deletes an attachment directly from couchdb
22
- def delete_attachment(name)
22
+ def delete_attachment(name, force=false)
23
23
  raise ArgumentError, "doc.database required to delete_attachment" unless database
24
- result = database.delete_attachment(self, name)
24
+ result = database.delete_attachment(self, name, force)
25
25
  self['_rev'] = result['rev']
26
26
  result['ok']
27
27
  end
@@ -1,5 +1,14 @@
1
1
  module CouchRest
2
2
  module Mixins
3
+ module PaginatedResults
4
+ def amount_pages
5
+ @amount_pages ||= 0
6
+ end
7
+ def amount_pages=(value)
8
+ @amount_pages = value
9
+ end
10
+ end
11
+
3
12
  module Collection
4
13
 
5
14
  def self.included(base)
@@ -115,7 +124,10 @@ module CouchRest
115
124
  results = @database.view(@view_name, pagination_options(page, per_page))
116
125
  @amount_pages ||= (results['total_rows'].to_f / per_page.to_f).ceil
117
126
  remember_where_we_left_off(results, page)
118
- convert_to_container_array(results)
127
+ results = convert_to_container_array(results)
128
+ results.extend(PaginatedResults)
129
+ results.amount_pages = @amount_pages
130
+ results
119
131
  end
120
132
 
121
133
  # See Collection.paginated_each
@@ -181,7 +193,7 @@ module CouchRest
181
193
  @target.inspect
182
194
  end
183
195
 
184
- def convert_to_container_array(results)
196
+ def convert_to_container_array(results)
185
197
  if @container_class.nil?
186
198
  results
187
199
  else
@@ -12,7 +12,7 @@ module CouchRest
12
12
  # name of the current class. Take the standard set of
13
13
  # CouchRest::Database#view options.
14
14
  def all(opts = {}, &block)
15
- view(:all, {:reduce => false}.merge(opts), &block)
15
+ view(:all, opts, &block)
16
16
  end
17
17
 
18
18
  # Returns the number of documents that have the "couchrest-type" field
@@ -77,6 +77,9 @@ module CouchRest
77
77
  # Float instances don't get initialized with #new
78
78
  elsif ((property.init_method == 'new') && target == 'Float')
79
79
  cast_float(self[key])
80
+ # 'boolean' type is simply used to generate a property? accessor method
81
+ elsif ((property.init_method == 'new') && target == 'boolean')
82
+ self[key]
80
83
  else
81
84
  # Let people use :send as a Time parse arg
82
85
  klass = ::CouchRest.constantize(target)
@@ -128,6 +131,18 @@ module CouchRest
128
131
  end
129
132
  EOS
130
133
 
134
+ if property.type == 'boolean'
135
+ class_eval <<-EOS, __FILE__, __LINE__
136
+ def #{property.name}?
137
+ if self['#{property.name}'].nil? || self['#{property.name}'] == false || self['#{property.name}'].to_s.downcase == 'false'
138
+ false
139
+ else
140
+ true
141
+ end
142
+ end
143
+ EOS
144
+ end
145
+
131
146
  if property.alias
132
147
  class_eval <<-EOS, __FILE__, __LINE__
133
148
  alias #{property.alias.to_sym} #{property.name.to_sym}
@@ -1,10 +1,11 @@
1
- require File.join(File.dirname(__FILE__), '..', 'mixins', 'properties')
1
+ require File.expand_path('../../mixins/properties', __FILE__)
2
+
2
3
 
3
4
  module CouchRest
4
5
  module CastedModel
5
6
 
6
7
  def self.included(base)
7
- base.send(:include, CouchRest::Mixins::Properties)
8
+ base.send(:include, ::CouchRest::Mixins::Properties)
8
9
  base.send(:attr_accessor, :casted_by)
9
10
  end
10
11
 
@@ -1,4 +1,4 @@
1
- require File.dirname(__FILE__) + '/../../spec_helper'
1
+ require File.expand_path("../../../spec_helper", __FILE__)
2
2
 
3
3
  describe CouchRest do
4
4
 
@@ -1,4 +1,4 @@
1
- require File.dirname(__FILE__) + '/../../spec_helper'
1
+ require File.expand_path("../../../spec_helper", __FILE__)
2
2
 
3
3
  describe CouchRest::Database do
4
4
  before(:each) do
@@ -263,7 +263,11 @@ describe CouchRest::Database do
263
263
  r['ok'].should == true
264
264
  doc = @db.get("attach-this")
265
265
  attachment = @db.fetch_attachment(doc,"couchdb.png")
266
- attachment.should == image
266
+ if attachment.respond_to?(:net_http_res)
267
+ attachment.net_http_res.body.should == image
268
+ else
269
+ attachment.should == image
270
+ end
267
271
  end
268
272
  end
269
273
 
@@ -368,8 +372,18 @@ describe CouchRest::Database do
368
372
  end
369
373
  it "should delete the attachment" do
370
374
  lambda { @db.fetch_attachment(@doc,'test.html') }.should_not raise_error
371
- @db.delete_attachment(@doc, "test.html")
372
- lambda { @db.fetch_attachment(@doc,'test.html') }.should raise_error(RestClient::ResourceNotFound)
375
+ @db.delete_attachment(@doc, "test.html")
376
+ @doc = @db.get('mydocwithattachment') # avoid getting a 409
377
+ lambda{ @db.fetch_attachment(@doc,'test.html')}.should raise_error
378
+ end
379
+
380
+ it "should force a delete even if we get a 409" do
381
+ @doc['new_attribute'] = 'something new'
382
+ @db.put_attachment(@doc, 'test', File.open(File.join(File.dirname(__FILE__), '..', '..', 'fixtures', 'attachments', 'test.html')).read)
383
+ # at this point the revision number changed, if we try to save doc one more time
384
+ # we would get a 409.
385
+ lambda{ @db.save_doc(@doc) }.should raise_error
386
+ lambda{ @db.delete_attachment(@doc, "test", true) }.should_not raise_error
373
387
  end
374
388
  end
375
389
 
@@ -1,4 +1,4 @@
1
- require File.dirname(__FILE__) + '/../../spec_helper'
1
+ require File.expand_path("../../../spec_helper", __FILE__)
2
2
 
3
3
  describe CouchRest::Design do
4
4
 
@@ -1,4 +1,4 @@
1
- require File.dirname(__FILE__) + '/../../spec_helper'
1
+ require File.expand_path("../../../spec_helper", __FILE__)
2
2
 
3
3
  class Video < CouchRest::Document; end
4
4
 
@@ -1,4 +1,4 @@
1
- require File.dirname(__FILE__) + '/../../spec_helper'
1
+ require File.expand_path("../../../spec_helper", __FILE__)
2
2
 
3
3
  describe CouchRest::Server do
4
4
 
@@ -1,4 +1,4 @@
1
- require File.dirname(__FILE__) + '/../../spec_helper'
1
+ require File.expand_path("../../../spec_helper", __FILE__)
2
2
 
3
3
  describe CouchRest::Pager do
4
4
  before(:all) do
@@ -1,4 +1,4 @@
1
- require File.dirname(__FILE__) + '/../../spec_helper'
1
+ require File.expand_path("../../../spec_helper", __FILE__)
2
2
 
3
3
  describe CouchRest::Streamer do
4
4
  before(:all) do
@@ -1,4 +1,4 @@
1
- require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper')
1
+ require File.expand_path('../../../spec_helper', __FILE__)
2
2
  require File.join(FIXTURE_PATH, 'more', 'card')
3
3
 
4
4
  class Car < CouchRest::ExtendedDocument
@@ -1,6 +1,6 @@
1
1
  # encoding: utf-8
2
2
 
3
- require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper')
3
+ require File.expand_path('../../../spec_helper', __FILE__)
4
4
  require File.join(FIXTURE_PATH, 'more', 'card')
5
5
  require File.join(FIXTURE_PATH, 'more', 'cat')
6
6
  require File.join(FIXTURE_PATH, 'more', 'person')
@@ -1,4 +1,4 @@
1
- require File.dirname(__FILE__) + '/../../spec_helper'
1
+ require File.expand_path('../../../spec_helper', __FILE__)
2
2
 
3
3
  describe "ExtendedDocument attachments" do
4
4
 
@@ -1,4 +1,4 @@
1
- require File.dirname(__FILE__) + '/../../spec_helper'
1
+ require File.expand_path("../../../spec_helper", __FILE__)
2
2
  require File.join(FIXTURE_PATH, 'more', 'article')
3
3
  require File.join(FIXTURE_PATH, 'more', 'course')
4
4
 
@@ -1,4 +1,4 @@
1
- require File.dirname(__FILE__) + '/../../spec_helper'
1
+ require File.expand_path("../../../spec_helper", __FILE__)
2
2
  require File.join(FIXTURE_PATH, 'more', 'card')
3
3
  require File.join(FIXTURE_PATH, 'more', 'course')
4
4
 
@@ -1,4 +1,4 @@
1
- require File.dirname(__FILE__) + '/../../spec_helper'
1
+ require File.expand_path("../../../spec_helper", __FILE__)
2
2
  require File.join(FIXTURE_PATH, 'more', 'article')
3
3
  require File.join(FIXTURE_PATH, 'more', 'course')
4
4
 
@@ -354,7 +354,8 @@ describe "ExtendedDocument views" do
354
354
  a = Article.new(:title => title, :date => Date.today)
355
355
  a.save
356
356
  end
357
- end
357
+ end
358
+ require 'date'
358
359
  it "should return a proxy that looks like an array of 7 Article objects" do
359
360
  articles = Article.by_date :key => Date.today
360
361
  articles.class.should == Array
@@ -374,8 +375,7 @@ describe "ExtendedDocument views" do
374
375
  end
375
376
  it "should have the amount of paginated pages" do
376
377
  articles = Article.by_date :key => Date.today
377
- articles.paginate(:per_page => 3)
378
- articles.amount_pages.should == 3
378
+ articles.paginate(:per_page => 3).amount_pages.should == 3
379
379
  end
380
380
  it "should provide a class method to access the collection directly" do
381
381
  articles = Article.collection_proxy_for('Article', 'by_date', :descending => true,
@@ -1,4 +1,4 @@
1
- require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper')
1
+ require File.expand_path('../../../spec_helper', __FILE__)
2
2
  require File.join(FIXTURE_PATH, 'more', 'person')
3
3
  require File.join(FIXTURE_PATH, 'more', 'card')
4
4
  require File.join(FIXTURE_PATH, 'more', 'invoice')
@@ -161,9 +161,35 @@ describe "ExtendedDocument properties" do
161
161
  it "should work fine when a float is being passed" do
162
162
  RootBeerFloat.new(:price => 9.99).price.should == 9.99
163
163
  end
164
-
165
164
  end
166
165
 
166
+ describe "casting to a boolean value" do
167
+ class RootBeerFloat < CouchRest::ExtendedDocument
168
+ use_database DB
169
+ property :tasty, :cast_as => :boolean
170
+ end
171
+
172
+ it "should add an accessor with a '?' for boolean attributes that returns true or false" do
173
+ RootBeerFloat.new(:tasty => true).tasty?.should == true
174
+ RootBeerFloat.new(:tasty => 'you bet').tasty?.should == true
175
+ RootBeerFloat.new(:tasty => 123).tasty?.should == true
176
+
177
+ RootBeerFloat.new(:tasty => false).tasty?.should == false
178
+ RootBeerFloat.new(:tasty => 'false').tasty?.should == false
179
+ RootBeerFloat.new(:tasty => 'FaLsE').tasty?.should == false
180
+ RootBeerFloat.new(:tasty => nil).tasty?.should == false
181
+ end
182
+
183
+ it "should return the real value when the default accessor is used" do
184
+ RootBeerFloat.new(:tasty => true).tasty.should == true
185
+ RootBeerFloat.new(:tasty => 'you bet').tasty.should == 'you bet'
186
+ RootBeerFloat.new(:tasty => 123).tasty.should == 123
187
+ RootBeerFloat.new(:tasty => 'false').tasty.should == 'false'
188
+ RootBeerFloat.new(:tasty => false).tasty.should == false
189
+ RootBeerFloat.new(:tasty => nil).tasty.should == nil
190
+ end
191
+ end
192
+
167
193
  end
168
194
 
169
195
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: couchrest
3
3
  version: !ruby/object:Gem::Version
4
- version: "0.32"
4
+ version: "0.33"
5
5
  platform: ruby
6
6
  authors:
7
7
  - J. Chris Anderson
@@ -68,11 +68,13 @@ files:
68
68
  - lib/couchrest/core/document.rb
69
69
  - lib/couchrest/core/http_abstraction.rb
70
70
  - lib/couchrest/core/response.rb
71
+ - lib/couchrest/core/rest_api.rb
71
72
  - lib/couchrest/core/server.rb
72
73
  - lib/couchrest/core/view.rb
73
74
  - lib/couchrest/helper/pager.rb
74
75
  - lib/couchrest/helper/streamer.rb
75
76
  - lib/couchrest/helper/upgrade.rb
77
+ - lib/couchrest/middlewares/logger.rb
76
78
  - lib/couchrest/mixins/attachments.rb
77
79
  - lib/couchrest/mixins/callbacks.rb
78
80
  - lib/couchrest/mixins/class_proxy.rb