couchrest 1.1.2 → 1.1.3

Sign up to get free protection for your applications and to get access to all the features.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.1.2
1
+ 1.1.3
data/couchrest.gemspec CHANGED
@@ -28,7 +28,7 @@ Gem::Specification.new do |s|
28
28
 
29
29
  s.add_dependency(%q<rest-client>, ["~> 1.6.1"])
30
30
  s.add_dependency(%q<mime-types>, ["~> 1.15"])
31
- s.add_dependency(%q<multi_json>, ["~> 1.0.0"])
31
+ s.add_dependency(%q<multi_json>, ["~> 1.0"])
32
32
  s.add_development_dependency(%q<json>, ["~> 1.5.1"])
33
33
  s.add_development_dependency(%q<rspec>, "~> 2.6.0")
34
34
  end
@@ -28,7 +28,7 @@ books.keys.each do |book|
28
28
  while line = file.gets
29
29
  lines << line
30
30
  if lines.length > 10
31
- db.save({
31
+ db.save_doc({
32
32
  :title => title,
33
33
  :chunk => chunk,
34
34
  :text => lines.join('')
@@ -16,9 +16,9 @@ word_count = {
16
16
  }'
17
17
  }
18
18
 
19
- db.delete db.get("_design/word_count") rescue nil
19
+ db.delete_doc db.get("_design/word_count") rescue nil
20
20
 
21
- db.save({
21
+ db.save_doc({
22
22
  "_id" => "_design/word_count",
23
23
  :views => {
24
24
  :words => word_count
data/history.txt CHANGED
@@ -1,3 +1,15 @@
1
+ == 1.1.3 - 2012-07-31
2
+
3
+ * Minor changes
4
+ * Add support for HTTP HEAD requests (Tim Anglade)
5
+ * Make CouchRest#database! check if a db exists before creating it (Tim Anglade)
6
+ * Use _doc suffix in examples for delete and save (Mickael Riga)
7
+ * Database#view should not modify the params (@krishan)
8
+ * Fix replication with couchdb >= 1.1.0 (@erickt)
9
+ * Streamer protection against bad responses improved (@erickt)
10
+ * Support atomic bulk save requests with all_or_nothing CouchDB parameter (@matthiasjakel)
11
+ * Update multi_json dependency so we can use any 1.x version (@dgraham)
12
+
1
13
  == 1.1.2 - 2011-07-18
2
14
 
3
15
  * Minor changes
@@ -163,7 +163,7 @@ module CouchRest
163
163
  # missing ids, supply one from the uuid cache.
164
164
  #
165
165
  # If called with no arguments, bulk saves the cache of documents to be bulk saved.
166
- def bulk_save(docs = nil, use_uuids = true)
166
+ def bulk_save(docs = nil, use_uuids = true, all_or_nothing = false)
167
167
  if docs.nil?
168
168
  docs = @bulk_save_cache
169
169
  @bulk_save_cache = []
@@ -176,7 +176,11 @@ module CouchRest
176
176
  doc['_id'] = nextid if nextid
177
177
  end
178
178
  end
179
- CouchRest.post "#{@root}/_bulk_docs", {:docs => docs}
179
+ request_body = {:docs => docs}
180
+ if all_or_nothing
181
+ request_body[:all_or_nothing] = true
182
+ end
183
+ CouchRest.post "#{@root}/_bulk_docs", request_body
180
184
  end
181
185
  alias :bulk_delete :bulk_save
182
186
 
@@ -243,6 +247,7 @@ module CouchRest
243
247
  # Query a CouchDB view as defined by a <tt>_design</tt> document. Accepts
244
248
  # paramaters as described in http://wiki.apache.org/couchdb/HttpViewApi
245
249
  def view(name, params = {}, payload = {}, &block)
250
+ params = params.dup
246
251
  payload['keys'] = params.delete(:keys) if params[:keys]
247
252
  # Try recognising the name, otherwise assume already prepared
248
253
  view_path = name_to_view_path(name)
@@ -341,6 +346,7 @@ module CouchRest
341
346
  def replicate(other_db, continuous, options)
342
347
  raise ArgumentError, "must provide a CouchReset::Database" unless other_db.kind_of?(CouchRest::Database)
343
348
  raise ArgumentError, "must provide a target or source option" unless (options.key?(:target) || options.key?(:source))
349
+ doc_ids = options.delete(:doc_ids)
344
350
  payload = options
345
351
  if options.has_key?(:target)
346
352
  payload['source'] = other_db.root
@@ -348,7 +354,7 @@ module CouchRest
348
354
  payload['target'] = other_db.root
349
355
  end
350
356
  payload['continuous'] = continuous
351
- payload['doc_ids'] = options[:doc_ids] if options[:doc_ids]
357
+ payload['doc_ids'] = doc_ids if doc_ids
352
358
  CouchRest.post "#{@host}/_replicate", payload
353
359
  end
354
360
 
@@ -27,14 +27,19 @@ module CouchRest
27
27
 
28
28
  def open_pipe(cmd, &block)
29
29
  first = nil
30
+ prev = nil
30
31
  IO.popen(cmd) do |f|
31
32
  first = f.gets # discard header
32
33
  while line = f.gets
33
34
  row = parse_line(line)
34
35
  block.call row unless row.nil? # last line "}]" discarded
36
+ prev = line
35
37
  end
36
38
  end
37
- parse_first(first)
39
+
40
+ raise RestClient::ServerBrokeConnection if $? && $?.exitstatus != 0
41
+
42
+ parse_first(first, prev)
38
43
  end
39
44
 
40
45
  def parse_line line
@@ -44,14 +49,11 @@ module CouchRest
44
49
  end
45
50
  end
46
51
 
47
- def parse_first first
52
+ def parse_first first, last
48
53
  return nil unless first
49
- parts = first.split(',')
50
- parts.pop
51
- line = parts.join(',')
52
- MultiJson.decode("#{line}}")
53
- rescue
54
- nil
54
+ header = MultiJson.decode(last ? first + last : first)
55
+ header.delete("rows")
56
+ header
55
57
  end
56
58
 
57
59
  end
@@ -5,7 +5,7 @@ module CouchRest
5
5
  # The basic low-level interface for all REST requests to the database. Everything must pass
6
6
  # through here before it is sent to the server.
7
7
  #
8
- # Five types of REST requests are supported: get, put, post, delete, and copy.
8
+ # Six types of REST requests are supported: get, put, post, delete, copy and head.
9
9
  #
10
10
  # Requests that do not have a payload, get, delete and copy, accept the URI and options parameters,
11
11
  # where as put and post both expect a document as the second parameter.
@@ -69,6 +69,11 @@ module CouchRest
69
69
  execute(uri, :copy, opts)
70
70
  end
71
71
 
72
+ # Send a HEAD request.
73
+ def head(uri, options = {})
74
+ execute(uri, :head, options)
75
+ end
76
+
72
77
  # The default RestClient headers used in each request.
73
78
  def default_headers
74
79
  {
@@ -108,7 +113,8 @@ module CouchRest
108
113
  :headers => default_headers.merge(options[:headers] || {})
109
114
  }
110
115
  parser = {
111
- :raw => false
116
+ :raw => false,
117
+ :head => (method == :head)
112
118
  }
113
119
  # Split the options
114
120
  (options || {}).each do |k,v|
@@ -141,7 +147,7 @@ module CouchRest
141
147
 
142
148
  # Parse the response provided.
143
149
  def parse_response(result, opts = {})
144
- opts.delete(:raw) ? result : MultiJson.decode(result, opts.update(:max_nesting => false))
150
+ (opts.delete(:raw) || opts.delete(:head)) ? result : MultiJson.decode(result, opts.update(:max_nesting => false))
145
151
  end
146
152
 
147
153
  # An array of all the options that should be passed through to restclient.
@@ -55,8 +55,10 @@ module CouchRest
55
55
 
56
56
  # Creates the database if it doesn't exist
57
57
  def database!(name)
58
- create_db(name) rescue nil
58
+ CouchRest.head "#{@uri}/#{name}" # Check if the URL is valid
59
59
  database(name)
60
+ rescue RestClient::ResourceNotFound # Thrown if the HTTP HEAD fails
61
+ create_db(name)
60
62
  end
61
63
 
62
64
  # GET the welcome message
@@ -137,6 +137,12 @@ describe CouchRest::Database do
137
137
  rs = @db.view('first/test', :keys => ["another", "wild"])
138
138
  rs['rows'].length.should == 2
139
139
  end
140
+ it "should not modify given params" do
141
+ original_params = {:keys => ["another", "wild"]}
142
+ params = original_params.dup
143
+ rs = @db.view('first/test', params)
144
+ params.should == original_params
145
+ end
140
146
  it "should accept a block" do
141
147
  rows = []
142
148
  rs = @db.view('first/test', :include_docs => true) do |row|
@@ -246,6 +252,13 @@ describe CouchRest::Database do
246
252
  @db.bulk_save
247
253
  @db.get("bulk_cache_1")["val"].should == "test"
248
254
  end
255
+
256
+ it "should make an atomic write when all_or_nothing is set" do
257
+ docs = [{"_id" => "oneB", "wild" => "and random"}, {"_id" => "twoB", "mild" => "yet local"}]
258
+ CouchRest.should_receive(:post).with("#{COUCHHOST}/couchrest-test/_bulk_docs", {:all_or_nothing => true, :docs => docs})
259
+
260
+ @db.bulk_save(docs, false, true)
261
+ end
249
262
 
250
263
  it "should raise an error that is useful for recovery" do
251
264
  @r = @db.save_doc({"_id" => "taken", "field" => "stuff"})
@@ -25,18 +25,93 @@ describe CouchRest::Streamer do
25
25
 
26
26
  it "should GET each row in a view" do
27
27
  count = 0
28
- @streamer.get("#{@db.root}/_all_docs") do |row|
28
+ header = @streamer.get("#{@db.root}/_all_docs") do |row|
29
29
  count += 1
30
30
  end
31
31
  count.should == 1001
32
+ header.should == {"total_rows" => 1001, "offset" => 0}
32
33
  end
33
34
 
34
35
  it "should GET each row in a view with params" do
35
36
  count = 0
36
- @streamer.get("#{@db.root}/_all_docs?include_docs=true&limit=5") do |row|
37
+ header = @streamer.get("#{@db.root}/_all_docs?include_docs=true&limit=5") do |row|
37
38
  count += 1
38
39
  end
39
40
  count.should == 5
41
+ header.should == {"total_rows" => 1001, "offset" => 0}
42
+ end
43
+
44
+ it "should GET no rows in a view with limit=0" do
45
+ count = 0
46
+ header = @streamer.get("#{@db.root}/_all_docs?include_docs=true&limit=0") do |row|
47
+ count += 1
48
+ end
49
+ count.should == 0
50
+ header.should == {"total_rows" => 1001, "offset" => 0}
51
+ end
52
+
53
+ it "should raise an exception receives malformed data" do
54
+ IO.stub(:popen) do |cmd, block|
55
+ class F
56
+ def initialize
57
+ @lines = [
58
+ '{"total_rows": 123, "offset": "0", "rows": [',
59
+ '{"foo": 1},',
60
+ '{"foo": 2},',
61
+ ]
62
+ end
63
+
64
+ def gets
65
+ @lines.shift
66
+ end
67
+ end
68
+
69
+ f = F.new
70
+ block.call f
71
+
72
+ IO.unstub(:popen)
73
+ IO.popen 'true' do; end
74
+ end
75
+
76
+ count = 0
77
+ expect do
78
+ @streamer.get("#{@db.root}/_all_docs?include_docs=true&limit=0") do |row|
79
+ count += 1
80
+ end
81
+ end.should raise_error(MultiJson::DecodeError)
82
+ end
83
+
84
+ it "should raise an exception if the couch connection fails" do
85
+ IO.stub(:popen) do |cmd, block|
86
+ class F
87
+ def initialize
88
+ @lines = [
89
+ '{"total_rows": 123, "offset": "0", "rows": [',
90
+ '{"foo": 1},',
91
+ '{"foo": 2},',
92
+ ]
93
+ end
94
+
95
+ def gets
96
+ @lines.shift
97
+ end
98
+ end
99
+
100
+ block.call F.new
101
+
102
+ IO.unstub(:popen)
103
+ IO.popen 'false' do; end
104
+ end
105
+
106
+ count = 0
107
+
108
+ expect do
109
+ @streamer.get("#{@db.root}/_all_docs?include_docs=true&limit=0") do |row|
110
+ count += 1
111
+ end
112
+ end.should raise_error(RestClient::ServerBrokeConnection)
113
+
114
+ count.should == 2
40
115
  end
41
116
 
42
117
  it "should POST for each row in a view" do
@@ -17,6 +17,7 @@ describe CouchRest::RestAPI do
17
17
  should respond_to :post
18
18
  should respond_to :copy
19
19
  should respond_to :delete
20
+ should respond_to :head
20
21
  end
21
22
 
22
23
  it "should provide default headers" do
@@ -206,6 +207,13 @@ describe CouchRest::RestAPI do
206
207
 
207
208
  end
208
209
 
210
+ describe :head do
211
+ it "should send basic request" do
212
+ req = {:url => 'foo', :method => :head, :headers => CouchRest.default_headers}
213
+ request.should_receive(:execute).with(req).and_return(simple_response)
214
+ CouchRest.head('foo')
215
+ end
216
+ end
209
217
 
210
218
  end
211
219
 
metadata CHANGED
@@ -1,15 +1,10 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: couchrest
3
- version: !ruby/object:Gem::Version
4
- hash: 23
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.1.3
5
5
  prerelease:
6
- segments:
7
- - 1
8
- - 1
9
- - 2
10
- version: 1.1.2
11
6
  platform: ruby
12
- authors:
7
+ authors:
13
8
  - J. Chris Anderson
14
9
  - Matt Aimonetti
15
10
  - Marcos Tapajos
@@ -18,100 +13,98 @@ authors:
18
13
  autorequire:
19
14
  bindir: bin
20
15
  cert_chain: []
21
-
22
- date: 2011-07-23 00:00:00 +02:00
23
- default_executable:
24
- dependencies:
25
- - !ruby/object:Gem::Dependency
16
+ date: 2012-07-31 00:00:00.000000000 Z
17
+ dependencies:
18
+ - !ruby/object:Gem::Dependency
26
19
  name: rest-client
27
- prerelease: false
28
- requirement: &id001 !ruby/object:Gem::Requirement
20
+ requirement: !ruby/object:Gem::Requirement
29
21
  none: false
30
- requirements:
22
+ requirements:
31
23
  - - ~>
32
- - !ruby/object:Gem::Version
33
- hash: 13
34
- segments:
35
- - 1
36
- - 6
37
- - 1
24
+ - !ruby/object:Gem::Version
38
25
  version: 1.6.1
39
26
  type: :runtime
40
- version_requirements: *id001
41
- - !ruby/object:Gem::Dependency
42
- name: mime-types
43
27
  prerelease: false
44
- requirement: &id002 !ruby/object:Gem::Requirement
28
+ version_requirements: !ruby/object:Gem::Requirement
29
+ none: false
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: 1.6.1
34
+ - !ruby/object:Gem::Dependency
35
+ name: mime-types
36
+ requirement: !ruby/object:Gem::Requirement
45
37
  none: false
46
- requirements:
38
+ requirements:
47
39
  - - ~>
48
- - !ruby/object:Gem::Version
49
- hash: 17
50
- segments:
51
- - 1
52
- - 15
53
- version: "1.15"
40
+ - !ruby/object:Gem::Version
41
+ version: '1.15'
54
42
  type: :runtime
55
- version_requirements: *id002
56
- - !ruby/object:Gem::Dependency
57
- name: multi_json
58
43
  prerelease: false
59
- requirement: &id003 !ruby/object:Gem::Requirement
44
+ version_requirements: !ruby/object:Gem::Requirement
60
45
  none: false
61
- requirements:
46
+ requirements:
62
47
  - - ~>
63
- - !ruby/object:Gem::Version
64
- hash: 23
65
- segments:
66
- - 1
67
- - 0
68
- - 0
69
- version: 1.0.0
48
+ - !ruby/object:Gem::Version
49
+ version: '1.15'
50
+ - !ruby/object:Gem::Dependency
51
+ name: multi_json
52
+ requirement: !ruby/object:Gem::Requirement
53
+ none: false
54
+ requirements:
55
+ - - ~>
56
+ - !ruby/object:Gem::Version
57
+ version: '1.0'
70
58
  type: :runtime
71
- version_requirements: *id003
72
- - !ruby/object:Gem::Dependency
73
- name: json
74
59
  prerelease: false
75
- requirement: &id004 !ruby/object:Gem::Requirement
60
+ version_requirements: !ruby/object:Gem::Requirement
76
61
  none: false
77
- requirements:
62
+ requirements:
78
63
  - - ~>
79
- - !ruby/object:Gem::Version
80
- hash: 1
81
- segments:
82
- - 1
83
- - 5
84
- - 1
64
+ - !ruby/object:Gem::Version
65
+ version: '1.0'
66
+ - !ruby/object:Gem::Dependency
67
+ name: json
68
+ requirement: !ruby/object:Gem::Requirement
69
+ none: false
70
+ requirements:
71
+ - - ~>
72
+ - !ruby/object:Gem::Version
85
73
  version: 1.5.1
86
74
  type: :development
87
- version_requirements: *id004
88
- - !ruby/object:Gem::Dependency
89
- name: rspec
90
75
  prerelease: false
91
- requirement: &id005 !ruby/object:Gem::Requirement
76
+ version_requirements: !ruby/object:Gem::Requirement
77
+ none: false
78
+ requirements:
79
+ - - ~>
80
+ - !ruby/object:Gem::Version
81
+ version: 1.5.1
82
+ - !ruby/object:Gem::Dependency
83
+ name: rspec
84
+ requirement: !ruby/object:Gem::Requirement
92
85
  none: false
93
- requirements:
86
+ requirements:
94
87
  - - ~>
95
- - !ruby/object:Gem::Version
96
- hash: 23
97
- segments:
98
- - 2
99
- - 6
100
- - 0
88
+ - !ruby/object:Gem::Version
101
89
  version: 2.6.0
102
90
  type: :development
103
- version_requirements: *id005
104
- 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.
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ none: false
94
+ requirements:
95
+ - - ~>
96
+ - !ruby/object:Gem::Version
97
+ version: 2.6.0
98
+ description: CouchRest provides a simple interface on top of CouchDB's RESTful HTTP
99
+ API, as well as including some utility scripts for managing views and attachments.
105
100
  email: jchris@apache.org
106
101
  executables: []
107
-
108
102
  extensions: []
109
-
110
- extra_rdoc_files:
103
+ extra_rdoc_files:
111
104
  - LICENSE
112
105
  - README.md
113
106
  - THANKS.md
114
- files:
107
+ files:
115
108
  - .gitignore
116
109
  - Gemfile
117
110
  - LICENSE
@@ -169,41 +162,47 @@ files:
169
162
  - spec/spec_helper.rb
170
163
  - utils/remap.rb
171
164
  - utils/subset.rb
172
- has_rdoc: true
173
165
  homepage: http://github.com/couchrest/couchrest
174
166
  licenses: []
175
-
176
167
  post_install_message:
177
- rdoc_options:
168
+ rdoc_options:
178
169
  - --charset=UTF-8
179
- require_paths:
170
+ require_paths:
180
171
  - lib
181
- required_ruby_version: !ruby/object:Gem::Requirement
172
+ required_ruby_version: !ruby/object:Gem::Requirement
182
173
  none: false
183
- requirements:
184
- - - ">="
185
- - !ruby/object:Gem::Version
186
- hash: 3
187
- segments:
188
- - 0
189
- version: "0"
190
- required_rubygems_version: !ruby/object:Gem::Requirement
174
+ requirements:
175
+ - - ! '>='
176
+ - !ruby/object:Gem::Version
177
+ version: '0'
178
+ required_rubygems_version: !ruby/object:Gem::Requirement
191
179
  none: false
192
- requirements:
193
- - - ">"
194
- - !ruby/object:Gem::Version
195
- hash: 25
196
- segments:
197
- - 1
198
- - 3
199
- - 1
180
+ requirements:
181
+ - - ! '>'
182
+ - !ruby/object:Gem::Version
200
183
  version: 1.3.1
201
184
  requirements: []
202
-
203
185
  rubyforge_project:
204
- rubygems_version: 1.6.2
186
+ rubygems_version: 1.8.24
205
187
  signing_key:
206
188
  specification_version: 3
207
189
  summary: Lean and RESTful interface to CouchDB.
208
- test_files: []
209
-
190
+ test_files:
191
+ - spec/couchrest/couchrest_spec.rb
192
+ - spec/couchrest/database_spec.rb
193
+ - spec/couchrest/design_spec.rb
194
+ - spec/couchrest/document_spec.rb
195
+ - spec/couchrest/helpers/pager_spec.rb
196
+ - spec/couchrest/helpers/streamer_spec.rb
197
+ - spec/couchrest/rest_api_spec.rb
198
+ - spec/couchrest/server_spec.rb
199
+ - spec/fixtures/attachments/README
200
+ - spec/fixtures/attachments/couchdb.png
201
+ - spec/fixtures/attachments/test.html
202
+ - spec/fixtures/views/lib.js
203
+ - spec/fixtures/views/test_view/lib.js
204
+ - spec/fixtures/views/test_view/only-map.js
205
+ - spec/fixtures/views/test_view/test-map.js
206
+ - spec/fixtures/views/test_view/test-reduce.js
207
+ - spec/spec.opts
208
+ - spec/spec_helper.rb