leanback 0.2.8 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Changelog.rdoc +12 -0
- data/Gemfile +1 -0
- data/Gemfile.lock +10 -0
- data/README.md +39 -0
- data/VERSION +1 -1
- data/leanback.gemspec +21 -9
- data/lib/leanback.rb +156 -54
- data/spec/admin_party/database_spec.rb +190 -0
- data/spec/no_admin_party/database_spec.rb +268 -0
- data/spec/no_admin_party/non_admin_user_spec.rb +52 -0
- data/spec/spec_base.rb +2 -0
- data/test/main.rb +154 -0
- data/test/test_leanback.rb +63 -19
- metadata +28 -31
- data/README.rdoc +0 -393
data/README.rdoc
DELETED
@@ -1,393 +0,0 @@
|
|
1
|
-
= leanback
|
2
|
-
|
3
|
-
Simple Ruby Interface to CouchDB.
|
4
|
-
|
5
|
-
--This project is still under development. Not complete by any means. I made this Gem to use in my projects. I will expose more CouchDB features soon.
|
6
|
-
|
7
|
-
==Goals
|
8
|
-
* To create a simple Ruby Interface to CouchDB
|
9
|
-
* Expose the features of CouchDB to the Ruby Lang.,
|
10
|
-
* Use a minimalist Ruby DSL to access CouchDB
|
11
|
-
* provide a very easy way to persist and retrieve data
|
12
|
-
|
13
|
-
==Install
|
14
|
-
|
15
|
-
gem install leanback
|
16
|
-
|
17
|
-
|
18
|
-
==Usage
|
19
|
-
|
20
|
-
Require the leanback Gem
|
21
|
-
require 'leanback'
|
22
|
-
|
23
|
-
Create a CouchDB database
|
24
|
-
Couchdb.create 'contacts'
|
25
|
-
|
26
|
-
# => {"ok"=>true}
|
27
|
-
|
28
|
-
Delete a database
|
29
|
-
Couchdb.delete 'contacts'
|
30
|
-
|
31
|
-
# => {"ok"=>true}
|
32
|
-
|
33
|
-
Return a list of all Databases
|
34
|
-
Couchdb.all
|
35
|
-
|
36
|
-
# => ["maps", "inventory", "monitors", "contacts", "books"]
|
37
|
-
|
38
|
-
Create a new document
|
39
|
-
data = {:firstname => 'Linda',
|
40
|
-
:lastname =>'smith',
|
41
|
-
:phone => '212-234-1234',
|
42
|
-
:email =>'john@mail.com'}
|
43
|
-
|
44
|
-
doc = {:database => 'contacts', :doc_id => 'Linda', :data => data}
|
45
|
-
Document.create doc
|
46
|
-
|
47
|
-
# => {"ok"=>true, "id"=>"Linda", "rev"=>"1-6f16274513f51e922ff1f745452a92b6"}
|
48
|
-
This will create a new document in the 'contacts' database, with document id 'Linda'.
|
49
|
-
|
50
|
-
Let's update that document to change the email address
|
51
|
-
data = {:email => "linda@mail.com" }
|
52
|
-
doc = { :database => 'contacts', :doc_id => 'Linda', :data => data}
|
53
|
-
Document.update doc
|
54
|
-
|
55
|
-
Let's add gender and age
|
56
|
-
data = {:age => "32", :gender => "female" }
|
57
|
-
doc = { :database => 'contacts', :doc_id => 'Linda', :data => data}
|
58
|
-
Document.update doc
|
59
|
-
|
60
|
-
|
61
|
-
To change phone# and add a fax number
|
62
|
-
data = {:phone => "718-234-2904",:fax => "646-309-4049" }
|
63
|
-
doc = { :database => 'contacts', :doc_id => 'Linda', :data => data}
|
64
|
-
Document.update doc
|
65
|
-
|
66
|
-
Let's add twitter account, facebook account and website url
|
67
|
-
data = { :twitter => "http://twitter.com/#!/linda",
|
68
|
-
:faceboook => "http://facebook.com/linda",
|
69
|
-
:website => "http://linda-blogs.com" }
|
70
|
-
|
71
|
-
doc = { :database => 'contacts', :doc_id => 'Linda', :data => data}
|
72
|
-
Document.update doc
|
73
|
-
|
74
|
-
Retrieve/view the document
|
75
|
-
doc = {:database => 'contacts', :doc_id => 'Linda'}
|
76
|
-
Couchdb.view doc
|
77
|
-
|
78
|
-
#=> {"_id"=>"Linda", "_rev"=>"5-f99fd63f2c784b5e2f7b7d92b2df9a1e", "firstname"=>"Linda", "lastname"=>"smith",
|
79
|
-
"phone"=>"718-234-2904", "email"=>"linda@mail.com", "age"=>"32", "gender"=>"female",
|
80
|
-
"fax"=>"646-309-4049", "twitter"=>"http://twitter.com/#!/linda",
|
81
|
-
"faceboook"=>"http://facebook.com/linda", "website"=>"http://linda-blogs.com"}
|
82
|
-
|
83
|
-
To edit the document and replace it with a new one
|
84
|
-
data = {:firstname => 'Linda',
|
85
|
-
:lastname =>'smith',
|
86
|
-
:email => 'linda@mail.com',
|
87
|
-
:gender=>'female',
|
88
|
-
:phone =>'718-245-5611',
|
89
|
-
:_rev=>'5-f99fd63f2c784b5e2f7b7d92b2df9a1e'}
|
90
|
-
|
91
|
-
doc = {:database => 'contacts', :doc_id => 'Linda', :data => data}
|
92
|
-
Document.edit doc
|
93
|
-
|
94
|
-
# => {"ok"=>true, "id"=>"Linda", "rev"=>"6-211ebb68bdd4ba8799387214b4a3b445"}
|
95
|
-
This replaces the existing document with a new one, the _rev number of the document must be included in the data.
|
96
|
-
|
97
|
-
Retrieve/view the document
|
98
|
-
doc = {:database => 'contacts', :doc_id => 'Linda'}
|
99
|
-
Couchdb.view doc
|
100
|
-
|
101
|
-
#=> {"_id"=>"Linda", "_rev"=>"6-211ebb68bdd4ba8799387214b4a3b445", "firstname"=>"Linda",
|
102
|
-
"lastname"=>"smith", "email"=>"linda@mail.com", "gender"=>"female", "phone"=>"718-245-5611"}
|
103
|
-
|
104
|
-
Delete the document
|
105
|
-
doc = {:database => 'contacts', :doc_id => 'Linda'}
|
106
|
-
Document.delete doc
|
107
|
-
|
108
|
-
#=> {"ok"=>true, "id"=>"Linda", "rev"=>"7-a2cfbbb607a668c26256bc19ff270ecf"}
|
109
|
-
|
110
|
-
Delete the document using it's revision number (_rev):
|
111
|
-
doc = {:database => 'contacts', :doc_id => 'Linda', :rev => '2-e813a0e902e3ac114400ff3959a2adde'}
|
112
|
-
Document.delete_rev doc
|
113
|
-
|
114
|
-
#=> {"ok"=>true, "id"=>"Linda", "rev"=>"3-48580d1806983b32cb03f114efb064e3"}
|
115
|
-
|
116
|
-
Retrieve all documents in a database
|
117
|
-
docs = Couchdb.docs_from 'contacts'
|
118
|
-
docs.each do |d|
|
119
|
-
puts d["_rev"]
|
120
|
-
puts d["_id"]
|
121
|
-
puts d["firstname"]
|
122
|
-
puts d["lastname"]
|
123
|
-
puts d["email"]
|
124
|
-
puts d["phone"]
|
125
|
-
end
|
126
|
-
|
127
|
-
|
128
|
-
===To Find documents by key
|
129
|
-
To find documents by email key (example: to find all contacts with email = 'nancy@mail.com')
|
130
|
-
Couchdb.find_by( :database => 'contacts', :email => 'nancy@mail.com')
|
131
|
-
|
132
|
-
# => [{"_id"=>"Nancy", "_rev"=>"1-d15a83d2a23b495c19df2595b636ecc8", "firstname"=>"Nancy", "lastname"=>"Lee",
|
133
|
-
"phone"=>"347-808-3734", "email"=>"nancy@mail.com", "gender"=>"female"}]
|
134
|
-
|
135
|
-
To find all contacts with lastname = 'Smith'
|
136
|
-
Couchdb.find_by( :database => 'contacts', :lastname => 'Smith')
|
137
|
-
|
138
|
-
# => [{"_id"=>"john", "_rev"=>"5-642689e0a50843d6fa508159a01b4fd4", "firstname"=>"John", "lastname"=>"Smith",
|
139
|
-
"email"=>"john@mail.com", "gender"=>"male"}]
|
140
|
-
|
141
|
-
To find all female contacts
|
142
|
-
Couchdb.find_by( :database => 'contacts', :gender => 'female')
|
143
|
-
|
144
|
-
# => [{"_id"=>"Nancy", "_rev"=>"1-d15a83d2a23b495c19df2595b636ecc8", "firstname"=>"Nancy", "lastname"=>"Lee",
|
145
|
-
"phone"=>"347-808-3734", "email"=>"nancy@mail.com", "gender"=>"female"}]
|
146
|
-
|
147
|
-
|
148
|
-
====How it works
|
149
|
-
The method
|
150
|
-
Couchdb.find_by(:database => 'contacts', :email => 'nancy@mail.com')
|
151
|
-
sends a
|
152
|
-
GET http://127.0.0.1:5984/contacts/_design/email_finder/_view/find_by_email?key="nancy@mail.com"
|
153
|
-
This returns all contacts with email = 'nancy@mail.com'. Leanback will parse the native JSON results to return only the data values. If the design_document (_design/email_finder) and the view (find_by_email) doesn't exist, Leanback will create it in the database. See the source for the generated design_document;
|
154
|
-
{
|
155
|
-
"_id": "_design/email_finder",
|
156
|
-
"_rev": "7-da7f3c0bf183f4a36a82013bd0ea6537",
|
157
|
-
"language": "javascript",
|
158
|
-
"views": {
|
159
|
-
"find_by_email": {
|
160
|
-
"map": "function(doc){
|
161
|
-
if(doc.email)
|
162
|
-
emit(doc.email,doc);
|
163
|
-
}"
|
164
|
-
}
|
165
|
-
}
|
166
|
-
}
|
167
|
-
|
168
|
-
If you ran
|
169
|
-
Couchdb.find_by( :database => 'contacts', :lastname => 'Smith')
|
170
|
-
Couchdb.find_by( :database => 'contacts', :gender => 'female')
|
171
|
-
you will notice the following design_documents have been added to the database
|
172
|
-
_design/lastname_finder
|
173
|
-
_design/gender_finder
|
174
|
-
|
175
|
-
====Usage
|
176
|
-
You can do
|
177
|
-
docs = Couchdb.find_by( :database => 'contacts', :email => 'nancy@mail.com')
|
178
|
-
docs.each do |d|
|
179
|
-
puts d["_rev"]
|
180
|
-
puts d["_id"]
|
181
|
-
puts d["firstname"]
|
182
|
-
puts d["lastname"]
|
183
|
-
puts d["email"]
|
184
|
-
puts d["phone"]
|
185
|
-
end
|
186
|
-
|
187
|
-
# => rev1-d15a83d2a23b495c19df2595b636ecc8
|
188
|
-
Nancy
|
189
|
-
Nancy
|
190
|
-
Lee
|
191
|
-
nancy@mail.com
|
192
|
-
347-808-3734
|
193
|
-
|
194
|
-
===Query a permanent view
|
195
|
-
view = { :database => "contacts", :design_doc => 'my_views', :view => 'get_female_contacts'}
|
196
|
-
Couchdb.find view
|
197
|
-
|
198
|
-
# => [{"_id"=>"Mary", "_rev"=>"5-bfcd67fd17dbb6a875af8f6dc497b15f", "firstname"=>"Mary", "lastname"=>"smith",
|
199
|
-
"phone"=>"212-234-1234", "email"=>"mary@mail.com", "gender"=>"female"},
|
200
|
-
{"_id"=>"Nancy", "_rev"=>"1-d15a83d2a23b495c19df2595b636ecc8", "firstname"=>"Nancy", "lastname"=>"Lee",
|
201
|
-
"phone"=>"347-808-3734", "email"=>"nancy@mail.com", "gender"=>"female"}]
|
202
|
-
|
203
|
-
This is similar to sending a
|
204
|
-
GET http://127.0.0.1:5984/[database]/_design/[design_doc]/_view/[view_name]
|
205
|
-
For the above example
|
206
|
-
GET http://127.0.0.1:5984/contacts/_design/my_views/_view/get_female_contacts
|
207
|
-
Leanback parses the native JSON results to return only the data values.
|
208
|
-
|
209
|
-
===Query a view by key
|
210
|
-
view = { :database => "contacts", :design_doc => 'the_view', :view => 'age'}
|
211
|
-
age = "36"
|
212
|
-
Couchdb.find(view,key = age)
|
213
|
-
|
214
|
-
# => [{"_id"=>"Nancy", "_rev"=>"2-4404d0a5a1a3dff103fd46faf1e46c30", "firstname"=>"Nancy", "lastname"=>"Lee",
|
215
|
-
"phone"=>"347-808-3734", "email"=>"nancy@mail.com", "gender"=>"female", "age"=>"36"}]
|
216
|
-
|
217
|
-
The above example will return all contacts with age = 36.
|
218
|
-
|
219
|
-
This is similar to sending a
|
220
|
-
GET http://127.0.0.1:5984/[database]/_design/[design_doc]/_view/[view_name]?key="searchterm"
|
221
|
-
For the above example
|
222
|
-
GET http://127.0.0.1:5984/contacts/_design/the_view/_view/age?key="36"
|
223
|
-
Leanback parses the native JSON results to return only the data values.
|
224
|
-
|
225
|
-
|
226
|
-
===Create a design document with permanent views:
|
227
|
-
First define the views in a JSON file
|
228
|
-
//my_views.json
|
229
|
-
{
|
230
|
-
"language" : "javascript",
|
231
|
-
"views" :{
|
232
|
-
"get_email" : {
|
233
|
-
"map" : "function(doc){
|
234
|
-
if(doc.lastname && doc.email)
|
235
|
-
emit(doc.id,{Firstname: doc.firstname, Lastname: doc.lastname, Email: doc.email});
|
236
|
-
}"
|
237
|
-
}
|
238
|
-
}
|
239
|
-
}
|
240
|
-
|
241
|
-
Now create the design document and add the json file
|
242
|
-
doc = { :database => 'contacts', :design_doc => 'more_views', :json_doc => '/path/to/my_views.json' }
|
243
|
-
Couchdb.create_design doc
|
244
|
-
|
245
|
-
# => {"ok"=>true, "id"=>"_design/more_views", "rev"=>"1-d67ae97ff03a98f68ddc300bf9ae5048"}
|
246
|
-
|
247
|
-
To query the view
|
248
|
-
view = { :database => "contacts", :design_doc => 'more_views', :view => 'get_email'}
|
249
|
-
Couchdb.find view
|
250
|
-
|
251
|
-
# => [{"Firstname"=>"Nancy", "Lastname"=>"Lee", "Email"=>"nancy@mail.com"},
|
252
|
-
{"Firstname"=>"john", "Lastname"=>"smith", "Email"=>"john@mail.com"}]
|
253
|
-
|
254
|
-
|
255
|
-
===Query a View and Create it on the fly if it doesn't already exist
|
256
|
-
Let's say we want to query a view, and create it on the fly if it doesn't already exist, and still return the values. In this example we will query a view called get_emails view (which returns emails of all contacts), if this view doesn't already exist it will be added to the database.
|
257
|
-
|
258
|
-
|
259
|
-
def get_emails
|
260
|
-
view = {:database => 'contacts',
|
261
|
-
:design_doc => 'my_views',
|
262
|
-
:view => 'get_emails',
|
263
|
-
:json_doc => '/path/to/my_views.json'}
|
264
|
-
|
265
|
-
Couchdb.find_on_fly(view)
|
266
|
-
end
|
267
|
-
|
268
|
-
email_list = get_emails()
|
269
|
-
puts email_list.inspect
|
270
|
-
|
271
|
-
# => [{"Name"=>"Nancy", "Email"=>"nancy@mail.com"}, {"Name"=>"John", "Email"=>"john@mail.com"}]
|
272
|
-
|
273
|
-
In get_emails(),
|
274
|
-
Couchdb.find_on_fly(view)
|
275
|
-
sends a request to the design_document (my_views) and view (get_emails). If this view is found in the database, it returns an Array with the name and email of all contacts:
|
276
|
-
[{"Name"=>"Nancy", "Email"=>"nancy@mail.com"}, {"Name"=>"John", "Email"=>"john@mail.com"}]
|
277
|
-
if the design document and view doesn't already exist, it creates it and adds it to the database using the json document
|
278
|
-
:json_doc => '/path/to/my_views.json'
|
279
|
-
|
280
|
-
next it sends a request for the view again and then it returns the email list.
|
281
|
-
|
282
|
-
So the first time the get_emails() method is called, the view will be created on the fly and added to the database. Future calls to get_email would simply return the values from the view.
|
283
|
-
|
284
|
-
Source for the get_emails view:
|
285
|
-
#my_views.json
|
286
|
-
{
|
287
|
-
"language" : "javascript",
|
288
|
-
"views" :{
|
289
|
-
"get_emails" : {
|
290
|
-
"map" : "function(doc){
|
291
|
-
if(doc.firstname && doc.email)
|
292
|
-
emit(doc.id,{Name: doc.firstname, Email: doc.email});
|
293
|
-
}"
|
294
|
-
}
|
295
|
-
}
|
296
|
-
}
|
297
|
-
|
298
|
-
You can also query a permanent view with a key and create it on the fly, if it doesn't already exist.
|
299
|
-
Let's say we want to view all contacts with age = "36", and we already defined the view in a json file (view_age.json).
|
300
|
-
view = { :database => 'contacts',
|
301
|
-
:design_doc => 'the_view',
|
302
|
-
:view => 'age',
|
303
|
-
:json_doc => '/path/to/view_age.json'}
|
304
|
-
|
305
|
-
age = '36'
|
306
|
-
Couchdb.find_on_fly(view,key = age)
|
307
|
-
|
308
|
-
#=> [{"_id"=>"Nancy", "_rev"=>"2-4404d0a5a1a3dff103fd46faf1e46c30", "firstname"=>"Nancy", "lastname"=>"Lee",
|
309
|
-
"phone"=>"347-808-3734", "email"=>"nancy@mail.com", "gender"=>"female", "age"=>"36"}]
|
310
|
-
|
311
|
-
The above example will query the design_document (the_view) and view (age) in the database (contacts), using the key (age). If the view doesn't exist it will be created from the json document (view.age.json). And then return the values from the view.
|
312
|
-
|
313
|
-
This is similar to sending a
|
314
|
-
GET http://127.0.0.1:5984/contacts/_design/the_view/_view/age?key="36"
|
315
|
-
|
316
|
-
The view is generated from the source code:
|
317
|
-
#view_age.json
|
318
|
-
{
|
319
|
-
"language" : "javascript",
|
320
|
-
"views" :{
|
321
|
-
"age" : {
|
322
|
-
"map" : "function(doc){
|
323
|
-
if(doc.age)
|
324
|
-
emit(doc.age,doc);
|
325
|
-
}"
|
326
|
-
}
|
327
|
-
}
|
328
|
-
}
|
329
|
-
|
330
|
-
===Error handling
|
331
|
-
Every database operation raises a CouchdbException when things go wrong.
|
332
|
-
|
333
|
-
Attempting to create a database that already exists
|
334
|
-
begin
|
335
|
-
Couchdb.create 'contacts'
|
336
|
-
#create static views
|
337
|
-
rescue CouchdbException => e
|
338
|
-
puts "Error message: " + e.to_s
|
339
|
-
puts "Error value: " + e.error
|
340
|
-
end
|
341
|
-
|
342
|
-
# => Error message: CouchDB: Error - file_exists. Reason - The database could not be created, the file already exists.
|
343
|
-
Error value: file_exists
|
344
|
-
|
345
|
-
|
346
|
-
Attempting to delete a database that doesn't exist
|
347
|
-
begin
|
348
|
-
Couchdb.delete 'buildings'
|
349
|
-
rescue CouchdbException => e
|
350
|
-
puts "Error message: " + e.to_s
|
351
|
-
puts "Error value: " + e.error
|
352
|
-
end
|
353
|
-
|
354
|
-
# => Error message: CouchDB: Error - not_found. Reason - missing
|
355
|
-
Error value: not_found
|
356
|
-
|
357
|
-
Attempting to query a permanent view that doesn't exist
|
358
|
-
begin
|
359
|
-
view = { :database => "contacts", :design_doc => 'more_views', :view => 'get_user_email'}
|
360
|
-
Couchdb.find view
|
361
|
-
rescue CouchdbException => e
|
362
|
-
puts "Error message: " + e.to_s
|
363
|
-
puts "Error value: " + e.error
|
364
|
-
end
|
365
|
-
|
366
|
-
# => Error message: CouchDB: Error - not_found. Reason - missing_named_view
|
367
|
-
Error value: not_found
|
368
|
-
|
369
|
-
You can always check the information passed to the Exception.
|
370
|
-
|
371
|
-
===Bind Address
|
372
|
-
Leanback uses the default Couchdb bind address http://127.0.0.1:5984. To use a different bind address;
|
373
|
-
Couchdb.address = '192.168.2.16'
|
374
|
-
Couchdb.port = '6000'
|
375
|
-
...
|
376
|
-
Document.address = '192.168.2.16'
|
377
|
-
Document.port = '6000'
|
378
|
-
|
379
|
-
|
380
|
-
To change it back to default bind address at anytime, simply set the values to nil
|
381
|
-
Couchdb.address = nil
|
382
|
-
Couchdb.port = nil
|
383
|
-
...
|
384
|
-
Document.address = nil
|
385
|
-
Document.port = nil
|
386
|
-
|
387
|
-
|
388
|
-
== Copyright
|
389
|
-
|
390
|
-
Copyright (c) 2011 Obi Akubue. See LICENSE.txt for
|
391
|
-
further details.
|
392
|
-
|
393
|
-
|