rufus-jig 0.1.2 → 0.1.3

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.
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