rufus-jig 0.1.2 → 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG.txt CHANGED
@@ -1,11 +1,21 @@
1
1
 
2
2
  = rufus-jig CHANGELOG.txt
3
3
 
4
+
5
+ == rufus-jig - 0.1.3 released 2009/12/15
6
+
7
+ - delete(doc) without _rev now raises ArgumentError
8
+ - Patron session go stale. Now refreshing them at each request.
9
+ - CouchDatabase#put_doc : 1 or 2 params
10
+
11
+
4
12
  == rufus-jig - 0.1.2 released 2009/12/07
5
13
 
6
14
  - fixed issue with '/' and net/http. Thanks Torsten.
7
15
 
16
+
8
17
  == rufus-jig - 0.1.1 released
9
18
 
19
+
10
20
  == rufus-jig - 0.1.0 released 2009/11/09
11
21
 
data/README.rdoc CHANGED
@@ -71,73 +71,30 @@ posting...
71
71
  For the real thing : http://github.com/couchrest/couchrest
72
72
  There is also the excellent : http://github.com/langalex/couch_potato
73
73
 
74
- require 'patron'
75
- require 'yajl'
76
- require 'rufus/jig'
77
-
78
- c = Rufus::Jig::Couch.get_couch('127.0.0.1', 5984)
79
- # connecting to the local couch
80
-
81
- db = @c.put_db('rufus_jig_test')
82
- # let's create a database named 'rufus_jig_test'
74
+ The class Rufus::Jig::Couch provides a get/put/delete trio that is couch-oriented. Json encoding/decoding is automatically handled as well as
83
75
 
84
- d = @db.put_doc('ct2', { 'item' => 'suit', 'brand' => 'suit company' })
85
- p [ d._id, d._rev, d['item'] ]
86
- #
87
- # => [ "ct2", "1-755f205df9f3c3a05849df3554ea24f7", "suit" ]
88
-
89
- # meanwhile, somebody else modifies the doc ...
90
-
91
- d['size'] = 'XL'
92
-
93
- d.put
94
- #
95
- # ouch, this gives us :
96
- # => conflict: Document update conflict. (Rufus::Jig::CouchError)
97
-
98
- d.get
99
- p [ d._id, d._rev, d['size'] ]
100
- #
101
- # re-getting the document
102
- #
103
- # => [ "ct2", "2-3a09eafe8739b54ab46105b96c1c69a2", "XL" ]
104
-
105
- d.delete
106
- #
107
- # getting rid of the document
108
-
109
- Some class methods (getting right to the stuff).
76
+ put and delete return nil in case of success and true (conflict) or and exception else.
110
77
 
111
78
  require 'patron'
112
79
  require 'yajl'
113
80
  require 'rufus/jig'
114
81
 
115
- db = Rufus::Jig::Couch.get_db('http://127.0.0.1:5984/test_db')
116
- # returns a Rufus::Jig::CouchDatabase instance
117
- # or nil if the db doesn't exist
118
-
119
- db = Rufus::Jig::Couch.put_db('http://127.0.0.1:5984/test_db')
120
- # creates a new database, or raise an exception if the db already exists
121
-
122
- doc = Rufus::Jig::Couch.get_doc('http://127.0.0.1:5984/test_db/doc0')
123
- # returns a Rufus::Jig::CouchDocument instance
124
- # or nil the document doesn't exist
125
-
126
- # ...
127
-
128
- Perhaps the right way to interact from rufus-jig to CouchDB is something like :
82
+ c = Rufus::Jig::Couch.new('127.0.0.1', 5984, 'my_couch_db')
129
83
 
130
- db = Rufus::Jig::Couch.get_db('http://127.0.0.1:5984/test_db')
84
+ c.put('_id' => 'coffee0', 'category' => 'espresso')
85
+ c.put('_id' => 'coffee1', 'category' => 'instantaneous')
131
86
 
132
- doc = db.get_doc('doc0')
87
+ doc0 = c.get('coffee0')
88
+ doc1 = c.get('coffee1')
133
89
 
134
- doc['car'] = { 'brand' => 'BMW', 'model' => 'MarkIII' }
90
+ c.delete(doc0)
135
91
 
136
- doc.put
92
+ doc1['category'] => 'instant'
93
+ c.put(doc1)
137
94
 
138
- # ...
95
+ c.delete(doc1['_id'], doc1['_rev'])
139
96
 
140
- Get a CouchDatabase instance then play from it.
97
+ ...
141
98
 
142
99
 
143
100
  == rdoc
data/TODO.txt CHANGED
@@ -19,3 +19,5 @@
19
19
 
20
20
  [ ] put_doc(h) where _id is set ?
21
21
 
22
+ [ ] :update_rev => true...
23
+
@@ -25,125 +25,98 @@
25
25
 
26
26
  module Rufus::Jig
27
27
 
28
- #
29
- # An error class for the couch stuff.
30
- #
31
- # Has a #status and an #original methods.
32
- #
33
- class CouchError < HttpError
34
-
35
- # the original error hash
36
- #
37
- attr_reader :original
28
+ class Couch
38
29
 
39
- def initialize (status, message)
30
+ attr_reader :http
40
31
 
41
- @original = (Rufus::Jig::Json.decode(message) rescue nil) || message
32
+ def initialize (*args)
42
33
 
43
- if @original.is_a?(String)
44
- super(status, @original)
45
- else
46
- super(status, "#{@original['error']}: #{@original['reason']}")
47
- end
34
+ @http, @path, payload, @opts = Rufus::Jig::Http.extract_http(false, *args)
35
+
36
+ @path ||= '/'
48
37
  end
49
- end
50
38
 
51
- #
52
- # The parent class of Rufus::Jig::Couch CouchDatabase and CouchDocument.
53
- #
54
- class CouchResource
39
+ def put (doc_or_path, opts={})
55
40
 
56
- # the jig client
57
- #
58
- attr_reader :http
41
+ path, payload = if doc_or_path.is_a?(String)
42
+ [ doc_or_path, '' ]
43
+ else
44
+ [ doc_or_path['_id'], doc_or_path ]
45
+ end
59
46
 
60
- # the path for this couch resource
61
- #
62
- attr_reader :path
47
+ #if opts[:update_rev] && payload.is_a?(Hash) && payload['_rev']
48
+ # pre = get(path)
49
+ # payload['_rev'] = prev['_rev']
50
+ #end
63
51
 
64
- # nil for a Couch instance, the Couch instance for a CouchDatabase or
65
- # the CouchDatabase for a CouchDocument.
66
- #
67
- attr_reader :parent
52
+ path = adjust(path)
53
+
54
+ begin
68
55
 
69
- def initialize (parent_or_http, path)
56
+ r = @http.put(path, payload, :content_type => :json, :cache => false)
70
57
 
71
- @path = path
58
+ if opts[:update_rev] && doc_or_path.is_a?(Hash)
59
+ doc_or_path['_rev'] = r['rev']
60
+ end
72
61
 
73
- path = path.split('/').select { |e| e != '' }
62
+ nil
74
63
 
75
- @parent, @http = if parent_or_http.is_a?(Rufus::Jig::Http)
64
+ rescue Rufus::Jig::HttpError => he
76
65
 
77
- parent = if path.length == 0
78
- nil
79
- elsif path.length == 1
80
- Couch.new(parent_or_http)
66
+ if he.status == 409
67
+ true
81
68
  else
82
- CouchDatabase.new(parent_or_http, path.first)
69
+ raise he
83
70
  end
84
- [ parent, parent_or_http ]
71
+ end
72
+ end
85
73
 
86
- else
74
+ def get (doc_or_path)
75
+
76
+ path = doc_or_path.is_a?(Hash) ? doc_or_path['_id'] : doc_or_path
77
+ path = adjust(path)
87
78
 
88
- [ parent_or_http, parent_or_http.http ]
79
+ opts = {}
80
+
81
+ if et = etag(path)
82
+ opts[:etag] = et
89
83
  end
90
84
 
91
- @http.options[:error_class] = CouchError
85
+ @http.get(path, opts)
92
86
  end
93
87
 
94
- # Returns the Rufus::Jig::Couch instance holding this couch resource.
95
- #
96
- def couch
88
+ def delete (doc_or_path, rev=nil)
97
89
 
98
- @parent == nil ? self : @parent.couch
99
- end
90
+ doc_or_path = { '_id' => doc_or_path, '_rev' => rev } if rev
100
91
 
101
- # Returns the Rufus::Jig::CouchDatabase instance holding this couch
102
- # resource (or nil if this resource is a Rufus::Jig::Couch instance).
103
- #
104
- def db
92
+ begin
105
93
 
106
- return nil if @parent.nil?
107
- return self if self.is_a?(CouchDatabase)
108
- @parent # self is a document
109
- end
94
+ if doc_or_path.is_a?(String)
110
95
 
111
- # GET, relatively to this resource.
112
- #
113
- def get (path, opts={})
114
- @http.get(adjust(path), opts)
115
- end
96
+ @http.delete(adjust(doc_or_path))
116
97
 
117
- # POST, relatively to this resource.
118
- #
119
- def post (path, data, opts={})
120
- @http.post(adjust(path), data, opts)
121
- end
98
+ else
122
99
 
123
- # DELETE, relatively to this resource.
124
- #
125
- def delete (path, opts={})
126
- @http.delete(adjust(path), opts)
127
- end
100
+ raise(
101
+ ArgumentError.new("cannot delete document without _rev")
102
+ ) unless doc_or_path['_rev']
128
103
 
129
- # PUT, relatively to this resource.
130
- #
131
- def put (path, data, opts={})
132
- @http.put(adjust(path), data, opts)
133
- end
104
+ path = adjust(doc_or_path['_id'])
105
+ path = Rufus::Jig::Path.add_params(path, :rev => doc_or_path['_rev'])
134
106
 
135
- # Returns an array of 1 or more UUIDs generated by CouchDB.
136
- #
137
- def get_uuids (count=1)
107
+ @http.delete(path)
108
+ end
138
109
 
139
- @http.get("/_uuids?count=#{count}")['uuids']
140
- end
110
+ nil
141
111
 
142
- # Returns the list of all database [names] in this couch.
143
- #
144
- def get_databases
112
+ rescue Rufus::Jig::HttpError => he
145
113
 
146
- @http.get('/_all_dbs')
114
+ if he.status == 409
115
+ true
116
+ else
117
+ raise he
118
+ end
119
+ end
147
120
  end
148
121
 
149
122
  protected
@@ -166,368 +139,5 @@ module Rufus::Jig
166
139
  r ? r.first : nil
167
140
  end
168
141
  end
169
-
170
- #
171
- # Wrapping info about a Couch server.
172
- #
173
- #
174
- # Also provides a set of class methods for interacting directly with couch
175
- # resources.
176
- #
177
- # * get_couch
178
- # * get_db
179
- # * put_db
180
- # * delete_db
181
- # * get_doc
182
- # * put_doc
183
- # * delete_doc
184
- #
185
- # The first one is very important
186
- #
187
- class Couch < CouchResource
188
-
189
- # Never call this method directly.
190
- #
191
- # Do
192
- #
193
- # couch = Rufus::Jig::Couch.get_couch('127.0.0.1', 5984)
194
- #
195
- # instead.
196
- #
197
- def initialize (parent_or_http)
198
-
199
- super(parent_or_http, '/')
200
- end
201
-
202
- # Returns a CouchDatabase instance or nil if the database doesn't
203
- # exist in this couch.
204
- #
205
- # couch = Rufus::Jig::Couch.get_couch('127.0.0.1', 5984)
206
- # db = couch.get_db('hr_documents')
207
- #
208
- def get_db (name)
209
-
210
- return nil if get(name).nil?
211
-
212
- CouchDatabase.new(couch, name)
213
- end
214
-
215
- # Creates a database and returns the new CouchDatabase instance.
216
- #
217
- # Will raise a Rufus::Jig::CouchError if the db already exists.
218
- #
219
- # couch = Rufus::Jig::Couch.get_couch('127.0.0.1', 5984)
220
- # db = couch.put_db('financial_results')
221
- #
222
- def put_db (name)
223
-
224
- d = CouchDatabase.new(couch, name)
225
- d.put('.', '')
226
-
227
- d
228
- end
229
-
230
- # Deletes a database, given its name.
231
- #
232
- # Will raise a Rufus::Jig::CouchError if the db doesn't exist.
233
- #
234
- # couch = Rufus::Jig::Couch.get_couch('127.0.0.1', 5984)
235
- # db = couch.delete_db('financial_results')
236
- #
237
- def delete_db (name)
238
-
239
- raise(CouchError.new(404, "no db named '#{name}'")) if get(name).nil?
240
-
241
- delete(name)
242
- end
243
-
244
- #--
245
- # handy class methods
246
- #++
247
-
248
- # Returns a Rufus::Jig::Couch instance.
249
- #
250
- # couch = Rufus::Jig::Couch.get_couch('http://127.0.0.1:5984')
251
- # # or
252
- # couch = Rufus::Jig::Couch.get_couch('127.0.0.1', 5984)
253
- #
254
- # Will raise a Rufus::Jig::CouchError in case of trouble.
255
- #
256
- def self.get_couch (*args)
257
-
258
- ht, pt, pl, op = extract_http(false, *args)
259
-
260
- Couch.new(ht)
261
- end
262
-
263
- # Returns a CouchDatabase instance or nil if the db doesn't exist.
264
- #
265
- # db = Rufus::Jig::Couch.get_db('127.0.0.1', 5984, 'my_database')
266
- # # or
267
- # db = Rufus::Jig::Couch.get_db('http://127.0.0.1:5984/my_database')
268
- #
269
- def self.get_db (*args)
270
-
271
- ht, pt, pl, op = extract_http(false, *args)
272
-
273
- return nil unless ht.get(pt)
274
-
275
- CouchDatabase.new(ht, Rufus::Jig::Path.to_name(pt))
276
- end
277
-
278
- # Creates a database and returns a CouchDatabase instance.
279
- #
280
- # db = Rufus::Jig::Couch.put_db('127.0.0.1', 5984, 'my_database')
281
- # # or
282
- # db = Rufus::Jig::Couch.put_db('http://127.0.0.1:5984/my_database')
283
- #
284
- # Will raise a Rufus::Jig::CouchError if the db already exists.
285
- #
286
- def self.put_db (*args)
287
-
288
- ht, pt, pl, op = extract_http(false, *args)
289
-
290
- ht.put(pt, '')
291
-
292
- CouchDatabase.new(ht, Rufus::Jig::Path.to_name(pt))
293
- end
294
-
295
- # Deletes a database.
296
- #
297
- # Rufus::Jig::Couch.delete_db('127.0.0.1', 5984, 'my_database')
298
- # # or
299
- # Rufus::Jig::Couch.delete_db('http://127.0.0.1:5984/my_database')
300
- #
301
- # Will raise a Rufus::Jig::CouchError if the db doesn't exist.
302
- #
303
- def self.delete_db (*args)
304
-
305
- ht, pt, pl, op = extract_http(false, *args)
306
-
307
- ht.delete(pt)
308
- end
309
-
310
- # Fetches a document. Returns nil if not found or a CouchDocument instance.
311
- #
312
- # Rufus::Jig::Couch.get_doc('127.0.0.1', 5984, 'my_database/doc0')
313
- # # or
314
- # Rufus::Jig::Couch.get_doc('http://127.0.0.1:5984/my_database/doc0')
315
- #
316
- def self.get_doc (*args)
317
-
318
- ht, pt, pl, op = extract_http(false, *args)
319
-
320
- doc = ht.get(pt)
321
-
322
- doc ? CouchDocument.new(ht, pt, doc) : nil
323
- end
324
-
325
- # Puts (creates) a document
326
- #
327
- # Rufus::Jig::Couch.put_doc(
328
- # '127.0.0.1', 5984, 'my_database/doc0', { 'a' => 'b' })
329
- # # or
330
- # Rufus::Jig::Couch.put_doc(
331
- # 'http://127.0.0.1:5984/my_database/doc0', { 'x' => 'y' })
332
- #
333
- # To update a doc, get it first, then change its content and put it
334
- # via its put method.
335
- #
336
- def self.put_doc (*args)
337
-
338
- ht, pt, pl, op = extract_http(true, *args)
339
-
340
- info = ht.put(pt, pl, :content_type => :json, :cache => false)
341
-
342
- CouchDocument.new(ht, pt, Rufus::Jig.marshal_copy(pl), info)
343
- end
344
-
345
- # Deletes a document.
346
- #
347
- # Rufus::Jig::Couch.delete_doc('127.0.0.1', 5984, 'my_database/doc0')
348
- # # or
349
- # Rufus::Jig::Couch.delete_doc('http://127.0.0.1:5984/my_database/doc0')
350
- #
351
- # Will raise a Rufus::Jig::CouchError if the doc doesn't exist.
352
- #
353
- def self.delete_doc (*args)
354
-
355
- ht, pt, pl, op = extract_http(false, *args)
356
-
357
- ht.delete(pt)
358
- end
359
-
360
- # This method is used from get_couch, get_db, put_db and co...
361
- #
362
- # Never used directly.
363
- #
364
- def self.extract_http (payload_expected, *args)
365
-
366
- a = Rufus::Jig::Http.extract_http(payload_expected, *args)
367
-
368
- a.first.error_class = Rufus::Jig::CouchError
369
-
370
- a
371
- end
372
- end
373
-
374
- #
375
- # Wrapping info about a Couch database.
376
- #
377
- # You usually grab an instance of it like that :
378
- #
379
- # db = Rufus::Jig::Couch.get_db('127.0.0.1', 5984, 'my_database')
380
- # # or
381
- # db = Rufus::Jig::Couch.get_db('http://127.0.0.1:5984/my_database')
382
- #
383
- # # or
384
- # couch = Rufus::Jig::Couch.get_couch('127.0.0.1', 5984)
385
- # db = Rufus::Jig::Couch.get_db('my_database')
386
- #
387
- class CouchDatabase < CouchResource
388
-
389
- attr_reader :name
390
-
391
- # Usually called via Couch#get_database(name)
392
- #
393
- def initialize (parent_or_http, name)
394
-
395
- @name = name
396
-
397
- super(parent_or_http, Rufus::Jig::Path.to_path(@name))
398
- end
399
-
400
- # Given an id and an JSONable hash, puts the doc to the database
401
- # and returns a CouchDocument instance wrapping it.
402
- #
403
- # db.put_doc('doc0', { 'item' => 'car', 'brand' => 'bmw' })
404
- #
405
- def put_doc (doc_id, doc)
406
-
407
- info = put(doc_id, doc, :content_type => :json, :cache => false)
408
-
409
- CouchDocument.new(
410
- self,
411
- Rufus::Jig::Path.join(@name, doc_id),
412
- Rufus::Jig.marshal_copy(doc), info)
413
- end
414
-
415
- # Gets a document, given its id.
416
- # (conditional GET).
417
- #
418
- # db.get_doc('doc0')
419
- #
420
- def get_doc (doc_id)
421
-
422
- path = Rufus::Jig::Path.join(@path, doc_id)
423
- opts = {}
424
-
425
- if et = etag(path)
426
- opts[:etag] = et
427
- end
428
-
429
- doc = get(path, opts)
430
-
431
- doc ?
432
- CouchDocument.new(self, Rufus::Jig::Path.join(@name, doc_id), doc) :
433
- nil
434
- end
435
-
436
- # Deletes a document, you have to provide the current revision.
437
- #
438
- # db.delete_doc('doc0')
439
- #
440
- def delete_doc (doc_id, rev)
441
-
442
- raise(ArgumentError.new("no doc '#{name}'")) if get(doc_id).nil?
443
-
444
- delete(Rufus::Jig::Path.add_params(doc_id, :rev => rev))
445
- end
446
- end
447
-
448
- #
449
- # Wrapping a couch document.
450
- #
451
- # Responds to [] and []=
452
- #
453
- class CouchDocument < CouchResource
454
-
455
- attr_reader :payload
456
-
457
- # Don't call this method directly, use one of the get_doc or put_doc
458
- # methods.
459
- #
460
- def initialize (parent_or_http, path, doc, put_result=nil)
461
-
462
- super(parent_or_http, path)
463
- @payload = doc
464
-
465
- if put_result
466
- @payload['_id'] = put_result['id']
467
- @payload['_rev'] = put_result['rev']
468
- end
469
- end
470
-
471
- # Gets a value.
472
- #
473
- def [] (k)
474
- @payload[k]
475
- end
476
-
477
- # Sets a value.
478
- #
479
- def []= (k, v)
480
- @payload[k] = v
481
- end
482
-
483
- # Returns to CouchDB id of the document.
484
- #
485
- def _id
486
- @payload['_id']
487
- end
488
-
489
- # Returns the revision string for this copy of the document.
490
- #
491
- def _rev
492
- @payload['_rev']
493
- end
494
-
495
- # Re-gets this document (updating its _rev and content if necessary).
496
- #
497
- def get
498
-
499
- opts = {}
500
-
501
- if @payload && rev = @payload['_rev']
502
- opts[:etag] = "\"#{rev}\""
503
- end
504
-
505
- h = super(@path, opts)
506
-
507
- raise(CouchError.new(410, 'probably gone')) unless h
508
-
509
- @payload = h
510
-
511
- self
512
- end
513
-
514
- # Deletes this document (from Couch).
515
- #
516
- def delete
517
-
518
- super(Rufus::Jig::Path.add_params(@path, :rev => _rev))
519
- end
520
-
521
- # Puts this document (assumes you have updated it).
522
- #
523
- def put
524
-
525
- h = super(
526
- @path, @payload,
527
- :content_type => :json, :etag => "\"#{@payload['_rev']}\"")
528
-
529
- @payload['_rev'] = h['rev']
530
- end
531
- end
532
142
  end
533
143
 
@@ -290,16 +290,29 @@ if defined?(Patron) # gem install patron
290
290
 
291
291
  super(host, port, opts)
292
292
 
293
+ refresh
294
+ end
295
+
296
+ # Patron sessions tends to wear out. Have to refresh them.
297
+ #
298
+ def refresh
299
+
293
300
  @patron = Patron::Session.new
294
- @patron.base_url = "#{host}:#{port}"
301
+ @patron.base_url = "#{@host}:#{@port}"
295
302
 
296
303
  @patron.headers['User-Agent'] =
297
- opts[:user_agent] ||
298
- "#{self.class} #{Rufus::Jig::VERSION} (patron)"
304
+ @options[:user_agent] || "#{self.class} #{Rufus::Jig::VERSION} (patron)"
299
305
  end
300
306
 
301
307
  protected
302
308
 
309
+ def request (method, path, data, opts={})
310
+
311
+ refresh
312
+
313
+ super(method, path, data, opts)
314
+ end
315
+
303
316
  def do_get (path, data, opts)
304
317
 
305
318
  @patron.get(path, opts)
@@ -339,6 +352,7 @@ elsif defined?( EventMachine::HttpRequest )
339
352
  protected
340
353
 
341
354
  def response_headers( hash )
355
+
342
356
  hash.inject({}) do |headers, (key, value)|
343
357
  key = key.downcase.split('_').map { |c| c.capitalize }.join('-')
344
358
  headers[ key ] = value
data/lib/rufus/jig.rb CHANGED
@@ -29,7 +29,7 @@ module Jig
29
29
  require 'rufus/jig/http'
30
30
  require 'rufus/jig/json'
31
31
 
32
- VERSION = '0.1.2'
32
+ VERSION = '0.1.3'
33
33
 
34
34
  autoload :Couch, 'rufus/jig/couch'
35
35
  autoload :CouchError, 'rufus/jig/couch'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rufus-jig
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.1.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - John Mettraux
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2009-12-07 00:00:00 +09:00
13
+ date: 2009-12-15 00:00:00 +09:00
14
14
  default_executable:
15
15
  dependencies: []
16
16