peterpunk-couchrest 0.23.1 → 0.33

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. data/README.md +80 -10
  2. data/Rakefile +2 -2
  3. data/history.txt +63 -0
  4. data/lib/couchrest/core/adapters/restclient.rb +35 -0
  5. data/lib/couchrest/core/database.rb +54 -29
  6. data/lib/couchrest/core/document.rb +1 -5
  7. data/lib/couchrest/core/http_abstraction.rb +48 -0
  8. data/lib/couchrest/core/response.rb +1 -5
  9. data/lib/couchrest/core/rest_api.rb +49 -0
  10. data/lib/couchrest/middlewares/logger.rb +263 -0
  11. data/lib/couchrest/mixins/attachments.rb +2 -2
  12. data/lib/couchrest/mixins/class_proxy.rb +9 -1
  13. data/lib/couchrest/mixins/collection.rb +241 -0
  14. data/lib/couchrest/mixins/design_doc.rb +21 -8
  15. data/lib/couchrest/mixins/document_queries.rb +41 -1
  16. data/lib/couchrest/mixins/extended_attachments.rb +7 -1
  17. data/lib/couchrest/mixins/extended_document_mixins.rb +1 -0
  18. data/lib/couchrest/mixins/properties.rb +84 -18
  19. data/lib/couchrest/mixins/validation.rb +30 -2
  20. data/lib/couchrest/mixins/views.rb +29 -21
  21. data/lib/couchrest/monkeypatches.rb +61 -61
  22. data/lib/couchrest/more/casted_model.rb +9 -5
  23. data/lib/couchrest/more/extended_document.rb +37 -6
  24. data/lib/couchrest/more/property.rb +2 -2
  25. data/lib/couchrest/support/rails.rb +35 -0
  26. data/lib/couchrest/validation/auto_validate.rb +0 -2
  27. data/lib/couchrest/validation/validation_errors.rb +7 -0
  28. data/lib/couchrest/validation/validators/numeric_validator.rb +1 -1
  29. data/lib/couchrest/validation/validators/uniqueness_validator.rb +15 -2
  30. data/lib/couchrest.rb +16 -56
  31. data/spec/couchrest/core/couchrest_spec.rb +2 -2
  32. data/spec/couchrest/core/database_spec.rb +26 -20
  33. data/spec/couchrest/core/design_spec.rb +1 -1
  34. data/spec/couchrest/core/document_spec.rb +1 -1
  35. data/spec/couchrest/core/server_spec.rb +1 -1
  36. data/spec/couchrest/helpers/pager_spec.rb +1 -1
  37. data/spec/couchrest/helpers/streamer_spec.rb +1 -1
  38. data/spec/couchrest/more/casted_extended_doc_spec.rb +43 -8
  39. data/spec/couchrest/more/casted_model_spec.rb +81 -2
  40. data/spec/couchrest/more/extended_doc_attachment_spec.rb +8 -3
  41. data/spec/couchrest/more/extended_doc_spec.rb +110 -21
  42. data/spec/couchrest/more/extended_doc_subclass_spec.rb +1 -1
  43. data/spec/couchrest/more/extended_doc_view_spec.rb +104 -33
  44. data/spec/couchrest/more/property_spec.rb +199 -15
  45. data/spec/fixtures/more/article.rb +1 -1
  46. data/spec/fixtures/more/card.rb +3 -1
  47. data/spec/fixtures/more/cat.rb +18 -0
  48. data/spec/fixtures/more/invoice.rb +1 -1
  49. data/spec/fixtures/more/location.rb +1 -1
  50. data/spec/fixtures/more/service.rb +1 -1
  51. data/spec/spec_helper.rb +15 -4
  52. metadata +15 -15
data/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # CouchRest: CouchDB, close to the metal
2
2
 
3
3
  CouchRest is based on [CouchDB's couch.js test
4
- library](http://svn.apache.org/repos/asf/incubator/couchdb/trunk/share/www/script/couch.js),
4
+ library](http://svn.apache.org/repos/asf/couchdb/trunk/share/www/script/couch.js),
5
5
  which I find to be concise, clear, and well designed. CouchRest lightly wraps
6
6
  CouchDB's HTTP API, managing JSON serialization, and remembering the URI-paths
7
7
  to CouchDB's API endpoints so you don't have to.
@@ -12,14 +12,17 @@ Note: CouchRest only support CouchDB 0.9.0 or newer.
12
12
 
13
13
  ## Easy Install
14
14
 
15
- Easy Install is moving to RubyForge, heads up for the gem.
15
+ $ sudo gem install couchrest
16
+
17
+ Alternatively, you can install from Github:
18
+
19
+ $ gem sources -a http://gems.github.com (you only have to do this once)
20
+ $ sudo gem install couchrest-couchrest
16
21
 
17
22
  ### Relax, it's RESTful
18
23
 
19
- The core of Couchrest is Heroku’s excellent REST Client Ruby HTTP wrapper.
20
- REST Client takes all the nastyness of Net::HTTP and gives is a pretty face,
21
- while still giving you more control than Open-URI. I recommend it anytime
22
- you’re interfacing with a well-defined web service.
24
+ CouchRest rests on top of a HTTP abstraction layer using by default Heroku’s excellent REST Client Ruby HTTP wrapper.
25
+ Other adapters can be added to support more http libraries.
23
26
 
24
27
  ### Running the Specs
25
28
 
@@ -27,7 +30,7 @@ The most complete documentation is the spec/ directory. To validate your
27
30
  CouchRest install, from the project root directory run `rake`, or `autotest`
28
31
  (requires RSpec and optionally ZenTest for autotest support).
29
32
 
30
- ## Examples
33
+ ## Examples (CouchRest Core)
31
34
 
32
35
  Quick Start:
33
36
 
@@ -59,12 +62,50 @@ Creating and Querying Views:
59
62
  })
60
63
  puts @db.view('first/test')['rows'].inspect
61
64
 
62
- ## CouchRest::Model
63
65
 
64
- CouchRest::Model has been deprecated and replaced by CouchRest::ExtendedDocument
66
+ ## CouchRest::ExtendedDocument
67
+
68
+ CouchRest::ExtendedDocument is a DSL/ORM for CouchDB. Basically, ExtendedDocument seats on top of CouchRest Core to add the concept of Model.
69
+ ExtendedDocument offers a lot of the usual ORM tools such as optional yet defined schema, validation, callbacks, pagination, casting and much more.
70
+
71
+ ### Model example
72
+
73
+ Check spec/couchrest/more and spec/fixtures/more for more examples
74
+
75
+ class Article < CouchRest::ExtendedDocument
76
+ use_database DB
77
+ unique_id :slug
65
78
 
79
+ view_by :date, :descending => true
80
+ view_by :user_id, :date
66
81
 
67
- ## CouchRest::ExtendedDocument
82
+ view_by :tags,
83
+ :map =>
84
+ "function(doc) {
85
+ if (doc['couchrest-type'] == 'Article' && doc.tags) {
86
+ doc.tags.forEach(function(tag){
87
+ emit(tag, 1);
88
+ });
89
+ }
90
+ }",
91
+ :reduce =>
92
+ "function(keys, values, rereduce) {
93
+ return sum(values);
94
+ }"
95
+
96
+ property :date
97
+ property :slug, :read_only => true
98
+ property :title
99
+ property :tags, :cast_as => ['String']
100
+
101
+ timestamps!
102
+
103
+ save_callback :before, :generate_slug_from_title
104
+
105
+ def generate_slug_from_title
106
+ self['slug'] = title.downcase.gsub(/[^a-z0-9]/,'-').squeeze('-').gsub(/^\-|\-$/,'') if new_document?
107
+ end
108
+ end
68
109
 
69
110
  ### Callbacks
70
111
 
@@ -93,3 +134,32 @@ you can define some casting rules.
93
134
 
94
135
  If you want to cast an array of instances from a specific Class, use the trick shown above ["ClassName"]
95
136
 
137
+ ### Pagination
138
+
139
+ Pagination is available in any ExtendedDocument classes. Here are some usage examples:
140
+
141
+ basic usage:
142
+
143
+ Article.all.paginate(:page => 1, :per_page => 5)
144
+
145
+ note: the above query will look like: `GET /db/_design/Article/_view/all?include_docs=true&skip=0&limit=5&reduce=false` and only fetch 5 documents.
146
+
147
+ Slightly more advance usage:
148
+
149
+ Article.by_name(:startkey => 'a', :endkey => {}).paginate(:page => 1, :per_page => 5)
150
+
151
+ note: the above query will look like: `GET /db/_design/Article/_view/by_name?startkey=%22a%22&limit=5&skip=0&endkey=%7B%7D&include_docs=true`
152
+ Basically, you can paginate through the articles starting by the letter a, 5 articles at a time.
153
+
154
+
155
+ Low level usage:
156
+
157
+ Article.paginate(:design_doc => 'Article', :view_name => 'by_date',
158
+ :per_page => 3, :page => 2, :descending => true, :key => Date.today, :include_docs => true)
159
+
160
+
161
+ ## Ruby on Rails
162
+
163
+ CouchRest is compatible with rails and can even be used a Rails plugin.
164
+ However, you might be interested in the CouchRest companion rails project:
165
+ [http://github.com/hpoydar/couchrest-rails](http://github.com/hpoydar/couchrest-rails)
data/Rakefile CHANGED
@@ -24,12 +24,11 @@ spec = Gem::Specification.new do |s|
24
24
  s.description = "CouchRest provides a simple interface on top of CouchDB's RESTful HTTP API, as well as including some utility scripts for managing views and attachments."
25
25
  s.has_rdoc = true
26
26
  s.authors = ["J. Chris Anderson", "Matt Aimonetti"]
27
- s.files = %w( LICENSE README.md Rakefile THANKS.md ) +
27
+ s.files = %w( LICENSE README.md Rakefile THANKS.md history.txt) +
28
28
  Dir["{examples,lib,spec,utils}/**/*"] -
29
29
  Dir["spec/tmp"]
30
30
  s.extra_rdoc_files = %w( README.md LICENSE THANKS.md )
31
31
  s.require_path = "lib"
32
- s.add_dependency("json", ">= 1.1.2")
33
32
  s.add_dependency("rest-client", ">= 0.5")
34
33
  s.add_dependency("mime-types", ">= 1.15")
35
34
  end
@@ -54,6 +53,7 @@ end
54
53
 
55
54
  desc "Run all specs"
56
55
  Spec::Rake::SpecTask.new('spec') do |t|
56
+ t.spec_opts = ["--color"]
57
57
  t.spec_files = FileList['spec/**/*_spec.rb']
58
58
  end
59
59
 
data/history.txt ADDED
@@ -0,0 +1,63 @@
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
+
16
+ == 0.32
17
+
18
+ * Major enhancements
19
+
20
+ * ExtendedDocument.get doesn't raise an exception anymore. If no documents are found nil is returned.
21
+ * ExtendedDocument.get! works the say #get used to work and will raise an exception if a document isn't found.
22
+
23
+ * Minor enhancements
24
+
25
+ * Bug fix: Model.all(:keys => [1,2]) was not working (Matt Aimonetti)
26
+ * Added ValidationErrors#count in order to play nicely with Rails (Peter Wagenet)
27
+ * Bug fix: class proxy design doc refresh (Daniel Kirsh)
28
+ * Bug fix: the count method on the proxy collection was missing (Daniel Kirsch)
29
+ * Added #amount_pages to a paginated collection. (Matt Aimonetti)
30
+
31
+ == 0.31
32
+
33
+ * Major enhancements
34
+
35
+ * Created an abstraction HTTP layer to support different http adapters (Matt Aimonetti)
36
+ * Added ExtendedDocument.create({}) and #create!({}) so you don't have to do Model.new.create (Matt Aimonetti)
37
+
38
+ * Minor enhancements
39
+
40
+ * Added an init.rb file for easy usage as a Rails plugin (Aaron Quint)
41
+ * Bug fix: pagination shouldn't die on empty results (Arnaud Berthomier)
42
+ * Optimized ExtendedDocument.count to run about 3x faster (Matt Aimonetti)
43
+ * Added Float casting (Ryan Felton & Matt Aimonetti)
44
+
45
+ == 0.30
46
+
47
+ * Major enhancements
48
+
49
+ * Added support for pagination (John Wood)
50
+ * Improved performance when initializing documents with timestamps (Matt Aimonetti)
51
+
52
+ * Minor enhancements
53
+
54
+ * Extended the API to retrieve an attachment URI (Matt Aimonetti)
55
+ * Bug fix: default value should be able to be set as false (Alexander Uvarov)
56
+ * Bug fix: validates_is_numeric should be able to properly validate a Float instance (Rob Kaufman)
57
+ * Bug fix: fixed the Timeout implementation (Seth Falcon)
58
+
59
+
60
+ ---
61
+
62
+ Unfortunately, before 0.30 we did not keep a track of the modifications made to CouchRest.
63
+ You can see the full commit history on GitHub: http://github.com/couchrest/couchrest/commits/master/
@@ -0,0 +1,35 @@
1
+ module RestClientAdapter
2
+
3
+ module API
4
+ def proxy=(url)
5
+ RestClient.proxy = url
6
+ end
7
+
8
+ def proxy
9
+ RestClient.proxy
10
+ end
11
+
12
+ def get(uri, headers={})
13
+ RestClient.get(uri, headers)
14
+ end
15
+
16
+ def post(uri, payload, headers={})
17
+ RestClient.post(uri, payload, headers)
18
+ end
19
+
20
+ def put(uri, payload, headers={})
21
+ RestClient.put(uri, payload, headers)
22
+ end
23
+
24
+ def delete(uri, headers={})
25
+ RestClient.delete(uri, headers)
26
+ end
27
+
28
+ def copy(uri, headers)
29
+ RestClient::Request.execute( :method => :copy,
30
+ :url => uri,
31
+ :headers => headers)
32
+ end
33
+ end
34
+
35
+ end
@@ -17,7 +17,8 @@ module CouchRest
17
17
  @name = name
18
18
  @server = server
19
19
  @host = server.uri
20
- @uri = @root = "#{host}/#{name.gsub('/','%2F')}"
20
+ @uri = "/#{name.gsub('/','%2F')}"
21
+ @root = host + uri
21
22
  @streamer = Streamer.new(self)
22
23
  @bulk_save_cache = []
23
24
  @bulk_save_cache_limit = 500 # must be smaller than the uuid count
@@ -25,18 +26,18 @@ module CouchRest
25
26
 
26
27
  # returns the database's uri
27
28
  def to_s
28
- @uri
29
+ @root
29
30
  end
30
31
 
31
32
  # GET the database info from CouchDB
32
33
  def info
33
- CouchRest.get @uri
34
+ CouchRest.get @root
34
35
  end
35
36
 
36
37
  # Query the <tt>_all_docs</tt> view. Accepts all the same arguments as view.
37
38
  def documents(params = {})
38
39
  keys = params.delete(:keys)
39
- url = CouchRest.paramify_url "#{@uri}/_all_docs", params
40
+ url = CouchRest.paramify_url "#{@root}/_all_docs", params
40
41
  if keys
41
42
  CouchRest.post(url, {:keys => keys})
42
43
  else
@@ -48,6 +49,7 @@ module CouchRest
48
49
  def get_bulk(ids)
49
50
  documents(:keys => ids, :include_docs => true)
50
51
  end
52
+ alias :bulk_load :get_bulk
51
53
 
52
54
  # POST a temporary view function to CouchDB for querying. This is not
53
55
  # recommended, as you don't get any performance benefit from CouchDB's
@@ -55,8 +57,8 @@ module CouchRest
55
57
  def slow_view(funcs, params = {})
56
58
  keys = params.delete(:keys)
57
59
  funcs = funcs.merge({:keys => keys}) if keys
58
- url = CouchRest.paramify_url "#{@uri}/_temp_view", params
59
- JSON.parse(RestClient.post(url, funcs.to_json, {"Content-Type" => 'application/json'}))
60
+ url = CouchRest.paramify_url "#{@root}/_temp_view", params
61
+ JSON.parse(HttpAbstraction.post(url, funcs.to_json, {"Content-Type" => 'application/json'}))
60
62
  end
61
63
 
62
64
  # backwards compatibility is a plus
@@ -69,7 +71,7 @@ module CouchRest
69
71
  name = name.split('/') # I think this will always be length == 2, but maybe not...
70
72
  dname = name.shift
71
73
  vname = name.join('/')
72
- url = CouchRest.paramify_url "#{@uri}/_design/#{dname}/_view/#{vname}", params
74
+ url = CouchRest.paramify_url "#{@root}/_design/#{dname}/_view/#{vname}", params
73
75
  if keys
74
76
  CouchRest.post(url, {:keys => keys})
75
77
  else
@@ -84,7 +86,7 @@ module CouchRest
84
86
  # GET a document from CouchDB, by id. Returns a Ruby Hash.
85
87
  def get(id, params = {})
86
88
  slug = escape_docid(id)
87
- url = CouchRest.paramify_url("#{@uri}/#{slug}", params)
89
+ url = CouchRest.paramify_url("#{@root}/#{slug}", params)
88
90
  result = CouchRest.get(url)
89
91
  return result unless result.is_a?(Hash)
90
92
  doc = if /^_design/ =~ result["_id"]
@@ -98,26 +100,34 @@ module CouchRest
98
100
 
99
101
  # GET an attachment directly from CouchDB
100
102
  def fetch_attachment(doc, name)
101
- # slug = escape_docid(docid)
102
- # name = CGI.escape(name)
103
- uri = uri_for_attachment(doc, name)
104
- RestClient.get uri
105
- # "#{@uri}/#{slug}/#{name}"
103
+ uri = url_for_attachment(doc, name)
104
+ HttpAbstraction.get uri
106
105
  end
107
106
 
108
107
  # PUT an attachment directly to CouchDB
109
108
  def put_attachment(doc, name, file, options = {})
110
109
  docid = escape_docid(doc['_id'])
111
110
  name = CGI.escape(name)
112
- uri = uri_for_attachment(doc, name)
113
- JSON.parse(RestClient.put(uri, file, options))
111
+ uri = url_for_attachment(doc, name)
112
+ JSON.parse(HttpAbstraction.put(uri, file, options))
114
113
  end
115
114
 
116
115
  # DELETE an attachment directly from CouchDB
117
- def delete_attachment doc, name
118
- uri = uri_for_attachment(doc, name)
116
+ def delete_attachment(doc, name, force=false)
117
+ uri = url_for_attachment(doc, name)
119
118
  # this needs a rev
120
- JSON.parse(RestClient.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
121
131
  end
122
132
 
123
133
  # Save a document to CouchDB. This will use the <tt>_id</tt> field from
@@ -141,14 +151,20 @@ module CouchRest
141
151
  bulk_save
142
152
  end
143
153
  result = if doc['_id']
144
- slug = escape_docid(doc['_id'])
145
- CouchRest.put "#{@uri}/#{slug}", doc
154
+ slug = escape_docid(doc['_id'])
155
+ begin
156
+ CouchRest.put "#{@root}/#{slug}", doc
157
+ rescue HttpAbstraction::ResourceNotFound
158
+ p "resource not found when saving even tho an id was passed"
159
+ slug = doc['_id'] = @server.next_uuid
160
+ CouchRest.put "#{@root}/#{slug}", doc
161
+ end
146
162
  else
147
163
  begin
148
164
  slug = doc['_id'] = @server.next_uuid
149
- CouchRest.put "#{@uri}/#{slug}", doc
165
+ CouchRest.put "#{@root}/#{slug}", doc
150
166
  rescue #old version of couchdb
151
- CouchRest.post @uri, doc
167
+ CouchRest.post @root, doc
152
168
  end
153
169
  end
154
170
  if result['ok']
@@ -183,7 +199,7 @@ module CouchRest
183
199
  doc['_id'] = nextid if nextid
184
200
  end
185
201
  end
186
- CouchRest.post "#{@uri}/_bulk_docs", {:docs => docs}
202
+ CouchRest.post "#{@root}/_bulk_docs", {:docs => docs}
187
203
  end
188
204
  alias :bulk_delete :bulk_save
189
205
 
@@ -200,7 +216,7 @@ module CouchRest
200
216
  return { "ok" => true } # Mimic the non-deferred version
201
217
  end
202
218
  slug = escape_docid(doc['_id'])
203
- CouchRest.delete "#{@uri}/#{slug}?rev=#{doc['_rev']}"
219
+ CouchRest.delete "#{@root}/#{slug}?rev=#{doc['_rev']}"
204
220
  end
205
221
 
206
222
  ### DEPRECATION NOTICE
@@ -220,7 +236,7 @@ module CouchRest
220
236
  else
221
237
  dest
222
238
  end
223
- CouchRest.copy "#{@uri}/#{slug}", destination
239
+ CouchRest.copy "#{@root}/#{slug}", destination
224
240
  end
225
241
 
226
242
  ### DEPRECATION NOTICE
@@ -231,7 +247,7 @@ module CouchRest
231
247
 
232
248
  # Compact the database, removing old document revisions and optimizing space use.
233
249
  def compact!
234
- CouchRest.post "#{@uri}/_compact"
250
+ CouchRest.post "#{@root}/_compact"
235
251
  end
236
252
 
237
253
  # Create the database
@@ -244,7 +260,7 @@ module CouchRest
244
260
  def recreate!
245
261
  delete!
246
262
  create!
247
- rescue RestClient::ResourceNotFound
263
+ rescue HttpAbstraction::ResourceNotFound
248
264
  ensure
249
265
  create!
250
266
  end
@@ -264,11 +280,16 @@ module CouchRest
264
280
  # DELETE the database itself. This is not undoable and could be rather
265
281
  # catastrophic. Use with care!
266
282
  def delete!
267
- CouchRest.delete @uri
283
+ clear_extended_doc_fresh_cache
284
+ CouchRest.delete @root
268
285
  end
269
286
 
270
287
  private
271
288
 
289
+ def clear_extended_doc_fresh_cache
290
+ ::CouchRest::ExtendedDocument.subclasses.each{|klass| klass.design_doc_fresh = false if klass.respond_to?(:design_doc_fresh=) }
291
+ end
292
+
272
293
  def uri_for_attachment(doc, name)
273
294
  if doc.is_a?(String)
274
295
  puts "CouchRest::Database#fetch_attachment will eventually require a doc as the first argument, not a doc.id"
@@ -281,7 +302,11 @@ module CouchRest
281
302
  docid = escape_docid(docid)
282
303
  name = CGI.escape(name)
283
304
  rev = "?rev=#{doc['_rev']}" if rev
284
- "#{@root}/#{docid}/#{name}#{rev}"
305
+ "/#{docid}/#{name}#{rev}"
306
+ end
307
+
308
+ def url_for_attachment(doc, name)
309
+ @root + uri_for_attachment(doc, name)
285
310
  end
286
311
 
287
312
  def escape_docid id
@@ -3,10 +3,6 @@ require 'delegate'
3
3
  module CouchRest
4
4
  class Document < Response
5
5
  include CouchRest::Mixins::Attachments
6
-
7
- # def self.inherited(subklass)
8
- # subklass.send(:extlib_inheritable_accessor, :database)
9
- # end
10
6
 
11
7
  extlib_inheritable_accessor :database
12
8
  attr_accessor :database
@@ -68,7 +64,7 @@ module CouchRest
68
64
  # Returns the CouchDB uri for the document
69
65
  def uri(append_rev = false)
70
66
  return nil if new_document?
71
- couch_uri = "http://#{database.uri}/#{CGI.escape(id)}"
67
+ couch_uri = "http://#{database.root}/#{CGI.escape(id)}"
72
68
  if append_rev == true
73
69
  couch_uri << "?rev=#{rev}"
74
70
  elsif append_rev.kind_of?(Integer)
@@ -0,0 +1,48 @@
1
+ require 'couchrest/core/adapters/restclient'
2
+
3
+ # Abstraction layet for HTTP communications.
4
+ #
5
+ # By defining a basic API that CouchRest is relying on,
6
+ # it allows for easy experimentations and implementations of various libraries.
7
+ #
8
+ # Most of the API is based on the RestClient API that was used in the early version of CouchRest.
9
+ #
10
+ module HttpAbstraction
11
+
12
+ # here is the list of exception expected by CouchRest
13
+ # please convert the underlying errors in this set of known
14
+ # exceptions.
15
+ class ResourceNotFound < StandardError; end
16
+ class RequestFailed < StandardError; end
17
+ class RequestTimeout < StandardError; end
18
+ class ServerBrokeConnection < StandardError; end
19
+ class Conflict < StandardError; end
20
+
21
+
22
+ # # Here is the API you need to implement if you want to write a new adapter
23
+ # # See adapters/restclient.rb for more information.
24
+ #
25
+ # def self.proxy=(url)
26
+ # end
27
+ #
28
+ # def self.proxy
29
+ # end
30
+ #
31
+ # def self.get(uri, headers=nil)
32
+ # end
33
+ #
34
+ # def self.post(uri, payload, headers=nil)
35
+ # end
36
+ #
37
+ # def self.put(uri, payload, headers=nil)
38
+ # end
39
+ #
40
+ # def self.delete(uri, headers=nil)
41
+ # end
42
+ #
43
+ # def self.copy(uri, headers)
44
+ # end
45
+
46
+ end
47
+
48
+ HttpAbstraction.extend(RestClientAdapter::API)
@@ -3,11 +3,7 @@ module CouchRest
3
3
  def initialize(pkeys = {})
4
4
  pkeys ||= {}
5
5
  pkeys.each do |k,v|
6
- if self.respond_to?("#{k}=")
7
- self.send("#{k}=",v)
8
- else
9
- self[k.to_s] = v
10
- end
6
+ self[k.to_s] = v
11
7
  end
12
8
  end
13
9
  def []=(key, value)
@@ -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