zetaben-ruby-feedbooks 0.1
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/README +24 -0
- data/Rakefile +16 -0
- data/lib/ruby-feedbooks.rb +575 -0
- data/spec/ruby-feedbooks_spec.rb +316 -0
- metadata +65 -0
data/README
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
Feedbooks.com ruby access library
|
2
|
+
=================================
|
3
|
+
|
4
|
+
A dead simple library to access feedbooks.com endpoints. It should be really easy
|
5
|
+
to use :
|
6
|
+
|
7
|
+
* for public access point :
|
8
|
+
require 'ruby-feedbooks'
|
9
|
+
include FeedBooks
|
10
|
+
|
11
|
+
book=Book.new(1)
|
12
|
+
puts book.title
|
13
|
+
puts book.similar(10).inspect
|
14
|
+
|
15
|
+
* for private access point first set your user/pass :
|
16
|
+
|
17
|
+
FeedBooks::Book.connection=FeedBooks::Connection.new("user","pass")
|
18
|
+
puts FeedBooks::Book.recommended.inspect
|
19
|
+
|
20
|
+
References
|
21
|
+
=========
|
22
|
+
|
23
|
+
http://feedbooks.com/api
|
24
|
+
http://www.slideshare.net/zeta/the-new-feedbooks-api
|
data/Rakefile
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'spec/rake/spectask'
|
3
|
+
|
4
|
+
Spec::Rake::SpecTask.new do |t|
|
5
|
+
t.warning = true
|
6
|
+
t.rcov = true
|
7
|
+
end
|
8
|
+
|
9
|
+
|
10
|
+
desc "Run all examples"
|
11
|
+
Spec::Rake::SpecTask.new('all_spec') do |t|
|
12
|
+
t.spec_files = FileList['spec/*_spec.rb']
|
13
|
+
t.spec_opts = ["--format","specdoc"]
|
14
|
+
end
|
15
|
+
|
16
|
+
task :default => [:all_spec]
|
@@ -0,0 +1,575 @@
|
|
1
|
+
# Access Library to FeedBooks API
|
2
|
+
# More information at : http://www.feedbooks.com/api
|
3
|
+
#
|
4
|
+
# Author:: Benoit Larroque ( firstname dot surname at feedbooks.com)
|
5
|
+
# Copyright:: Feedbooks.com
|
6
|
+
# Licence:: Public Domain
|
7
|
+
|
8
|
+
require 'open-uri'
|
9
|
+
require 'hpricot'
|
10
|
+
require 'digest/md5'
|
11
|
+
|
12
|
+
#Module for the library
|
13
|
+
#
|
14
|
+
#=Usage example
|
15
|
+
#==Search for books mathcing keyword "test"
|
16
|
+
# Feedbooks::Book.search("test")
|
17
|
+
#==Access Recommandations
|
18
|
+
# FeedBooks::Book.connection=FeedBooks::Connection.new('uesr','passwd')
|
19
|
+
# FeedBooks::Book.recommended
|
20
|
+
#
|
21
|
+
module FeedBooks
|
22
|
+
|
23
|
+
#User Agent Name
|
24
|
+
NAME = 'Ruby/FeedBooks'
|
25
|
+
#Library Version
|
26
|
+
VERSION = '0.1'
|
27
|
+
#Complete User-Agent
|
28
|
+
USER_AGENT = "%s %s" % [NAME, VERSION]
|
29
|
+
|
30
|
+
#Error class when not authenticated
|
31
|
+
class FeedBooks::UnauthenticatedError < StandardError
|
32
|
+
def initialize(m=nil)
|
33
|
+
super(m.nil? ? "You are not connected (no user/password)": m)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
#Error class when password and user mismatched
|
38
|
+
class FeedBooks::WrongCredentialsError < FeedBooks::UnauthenticatedError
|
39
|
+
def initialize()
|
40
|
+
super("User / password mismatched")
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
#Connection class used to specify credentials and proxy settings
|
45
|
+
class Connection
|
46
|
+
#user password
|
47
|
+
attr_accessor :password
|
48
|
+
#username
|
49
|
+
attr_accessor :user
|
50
|
+
#proxy url eg. http://user:pass@proxy:8080
|
51
|
+
attr_writer :proxy
|
52
|
+
|
53
|
+
def initialize(user=nil,pass=nil)
|
54
|
+
@user=user
|
55
|
+
@password=pass
|
56
|
+
end
|
57
|
+
|
58
|
+
#proxy getter
|
59
|
+
def proxy
|
60
|
+
return @proxy unless @proxy.nil?
|
61
|
+
ENV["proxy"]
|
62
|
+
end
|
63
|
+
|
64
|
+
def openfb(url) #:nodoc:
|
65
|
+
begin
|
66
|
+
return open(url,"r",http_opts)
|
67
|
+
rescue OpenURI::HTTPError => e
|
68
|
+
if e.io.status.first.to_i == 401
|
69
|
+
raise (user.nil? ? FeedBooks::UnauthenticatedError.new : FeedBooks::WrongCredentialsError.new )
|
70
|
+
end
|
71
|
+
raise e
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def http_opts #:nodoc:
|
76
|
+
ret={}
|
77
|
+
ret[:http_basic_authentication]=[user,Digest::MD5.hexdigest(password)] unless user.nil?
|
78
|
+
ret[:proxy]=proxy
|
79
|
+
ret["User-Agent"]=USER_AGENT
|
80
|
+
return ret
|
81
|
+
end
|
82
|
+
|
83
|
+
|
84
|
+
end
|
85
|
+
|
86
|
+
|
87
|
+
#Parent class for all API objects
|
88
|
+
class FBobject
|
89
|
+
@@connection = Connection.new
|
90
|
+
|
91
|
+
#connection setter
|
92
|
+
def self.connection=(con)
|
93
|
+
@@connection=con
|
94
|
+
@@connection=Connection.new if @@connection.nil?
|
95
|
+
end
|
96
|
+
|
97
|
+
#connection getter
|
98
|
+
#should be a Connection
|
99
|
+
def self.connection
|
100
|
+
@@connection
|
101
|
+
end
|
102
|
+
|
103
|
+
#connection setter
|
104
|
+
def connection=(con)
|
105
|
+
@@connection=con
|
106
|
+
@@connection=Connection.new if @@connection.nil?
|
107
|
+
end
|
108
|
+
|
109
|
+
#connection getter
|
110
|
+
def connection
|
111
|
+
@@connection
|
112
|
+
end
|
113
|
+
|
114
|
+
def self.from_xml(txt) #:nodoc:
|
115
|
+
doc=Hpricot.XML(txt)
|
116
|
+
book=doc/"/*"
|
117
|
+
return from_xml_elm(book)
|
118
|
+
end
|
119
|
+
protected
|
120
|
+
|
121
|
+
def openfb(url) #:nodoc:
|
122
|
+
return @@connection.openfb(url)
|
123
|
+
end
|
124
|
+
|
125
|
+
def self.openfb(url) #:nodoc:
|
126
|
+
return @@connection.openfb(url)
|
127
|
+
end
|
128
|
+
|
129
|
+
def get_attr(name=nil) #:nodoc:
|
130
|
+
name=self.class.to_s.downcase.split(':').last if name.nil?
|
131
|
+
book=nil
|
132
|
+
raise Exception("No Id given") if @id.nil? || @id < 1
|
133
|
+
doc = Hpricot.XML(openfb("http://www.feedbooks.com/"+name+"s/search.xml?query=id:#{@id}"))
|
134
|
+
book=doc/("//"+name+"[@id='#{@id}']")
|
135
|
+
return FBobject::from_xml_elm(book)
|
136
|
+
end
|
137
|
+
|
138
|
+
|
139
|
+
def self.from_xml_elm(book) #:nodoc:
|
140
|
+
h=Hash.new
|
141
|
+
(book.at('.').containers).each do |el|
|
142
|
+
tmp=el.containers
|
143
|
+
name=el.name
|
144
|
+
name=name.split(':').last if name.include?(':')
|
145
|
+
if tmp.empty?
|
146
|
+
tmp=el.inner_text
|
147
|
+
tmp={"id"=>el.attributes['id'].to_i,name=> tmp} unless el.attributes['id'].nil?
|
148
|
+
if h[name].nil?
|
149
|
+
h[name]=tmp
|
150
|
+
else
|
151
|
+
h[name]=[h[name], tmp].flatten
|
152
|
+
end
|
153
|
+
else
|
154
|
+
h[name]=Hash.new
|
155
|
+
tmp.each do |elc|
|
156
|
+
h[name][elc.name.split(':').last]=elc.inner_text
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
return h
|
161
|
+
end
|
162
|
+
|
163
|
+
#iterate trough results pages
|
164
|
+
def self.iterate(url) #:nodoc:
|
165
|
+
url+='?' if url.index('?').nil?
|
166
|
+
name=self.to_s.downcase.split(':').last
|
167
|
+
page=1
|
168
|
+
maxpages=0
|
169
|
+
begin
|
170
|
+
doc=Hpricot.XML(openfb("http://www.feedbooks.com#{url}&page=#{page}"))
|
171
|
+
maxpages=doc.root.attributes['total'].to_i
|
172
|
+
book=doc.search("//"+name) do |b|
|
173
|
+
yield(b)
|
174
|
+
end
|
175
|
+
page+=1
|
176
|
+
end while page<=maxpages
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
#Book api object
|
181
|
+
#see http://feedbooks.com/api/books
|
182
|
+
class Book < FBobject
|
183
|
+
attr_reader :id
|
184
|
+
def initialize(id=nil)
|
185
|
+
@id=id
|
186
|
+
end
|
187
|
+
|
188
|
+
def title
|
189
|
+
get_attr if @title==nil
|
190
|
+
@title
|
191
|
+
end
|
192
|
+
|
193
|
+
#authors is an array of Author
|
194
|
+
def authors
|
195
|
+
get_attr if @author==nil
|
196
|
+
@author
|
197
|
+
end
|
198
|
+
|
199
|
+
def date
|
200
|
+
get_attr if @date==nil
|
201
|
+
@date
|
202
|
+
end
|
203
|
+
|
204
|
+
def cover
|
205
|
+
get_attr if @title==nil
|
206
|
+
@cover
|
207
|
+
end
|
208
|
+
|
209
|
+
def language
|
210
|
+
get_attr if @title==nil
|
211
|
+
@language
|
212
|
+
end
|
213
|
+
|
214
|
+
def rights
|
215
|
+
get_attr if @title==nil
|
216
|
+
@rights
|
217
|
+
end
|
218
|
+
|
219
|
+
#give an url bases on asked format
|
220
|
+
#using the API results (other format may be available)
|
221
|
+
def file(format)
|
222
|
+
get_attr if @files==nil
|
223
|
+
@files[format]
|
224
|
+
end
|
225
|
+
|
226
|
+
def description
|
227
|
+
get_attr if @title==nil
|
228
|
+
@description
|
229
|
+
end
|
230
|
+
|
231
|
+
|
232
|
+
#subjects is an array of Type elements
|
233
|
+
def subjects
|
234
|
+
get_attr if @title==nil
|
235
|
+
@subject.collect{|s| FeedBooks::Type.new(s)}
|
236
|
+
end
|
237
|
+
|
238
|
+
alias :types :subjects
|
239
|
+
|
240
|
+
#get similar books
|
241
|
+
def similar(limit=nil)
|
242
|
+
self.class.generic_iterate("/book/#{@id}/similar.xml",limit)
|
243
|
+
end
|
244
|
+
|
245
|
+
#Search in books catalog returns an Array
|
246
|
+
def self.search(txt,limit=nil)
|
247
|
+
return [] if txt.strip.size==0
|
248
|
+
generic_iterate("/books/search.xml?query=#{URI.escape(txt)}",limit)
|
249
|
+
end
|
250
|
+
|
251
|
+
#get top books (can be limited)
|
252
|
+
def self.top(limit=nil)
|
253
|
+
generic_iterate("/books/top.xml",limit)
|
254
|
+
end
|
255
|
+
|
256
|
+
#get recent books (can be limited)
|
257
|
+
def self.recent(limit=nil)
|
258
|
+
generic_iterate("/books/recent.xml",limit)
|
259
|
+
end
|
260
|
+
|
261
|
+
#get recommedations based on user profile
|
262
|
+
#the user needs to be authenticatided see Connection
|
263
|
+
def self.recommended(limit=nil)
|
264
|
+
generic_iterate("/recommendations.xml",limit)
|
265
|
+
end
|
266
|
+
|
267
|
+
#get an array of lists containing the book
|
268
|
+
def lists(limit=nil)
|
269
|
+
FeedBooks::List.send('generic_iterate',"/book/#{@id}/lists.xml",limit)
|
270
|
+
end
|
271
|
+
|
272
|
+
private
|
273
|
+
|
274
|
+
def self.generic_iterate(url,limit=nil)
|
275
|
+
res=[]
|
276
|
+
self.iterate(url) do |b|
|
277
|
+
tmp=Book.new
|
278
|
+
tmp.send('from_h',Book::from_xml_elm(b))
|
279
|
+
tmp.instance_variable_set('@id',b.attributes['id'].to_i)
|
280
|
+
res.push(tmp)
|
281
|
+
return res[0...limit] if !limit.nil? && res.size >= limit
|
282
|
+
|
283
|
+
end
|
284
|
+
res
|
285
|
+
end
|
286
|
+
|
287
|
+
def from_h(h)
|
288
|
+
h.each do |k,v|
|
289
|
+
if k!="author"
|
290
|
+
self.instance_variable_set('@'+k,v)
|
291
|
+
else
|
292
|
+
v=[v].flatten
|
293
|
+
self.instance_variable_set('@'+k,v.collect{|a| FeedBooks::Author.from_h(a)})
|
294
|
+
end
|
295
|
+
end
|
296
|
+
end
|
297
|
+
|
298
|
+
def get_attr
|
299
|
+
from_h(super)
|
300
|
+
end
|
301
|
+
end
|
302
|
+
|
303
|
+
#Author object
|
304
|
+
#see http://feedbooks.com/api/authors
|
305
|
+
class Author < FBobject
|
306
|
+
attr_reader :id
|
307
|
+
|
308
|
+
def initialize(id=nil)
|
309
|
+
@id=id
|
310
|
+
end
|
311
|
+
|
312
|
+
def fullname=(txt) #:nodoc:
|
313
|
+
@name,@firstname=txt.split(",")
|
314
|
+
end
|
315
|
+
|
316
|
+
#virtual attribute fullname based on firstname and name
|
317
|
+
def fullname
|
318
|
+
get_attr if @name==nil
|
319
|
+
@name+", "+@firstname
|
320
|
+
end
|
321
|
+
|
322
|
+
def name
|
323
|
+
get_attr if @name==nil
|
324
|
+
@name
|
325
|
+
end
|
326
|
+
|
327
|
+
def firstname
|
328
|
+
get_attr if @firstname==nil
|
329
|
+
@firstname
|
330
|
+
end
|
331
|
+
|
332
|
+
def birth
|
333
|
+
get_attr if @birth==nil
|
334
|
+
@birth
|
335
|
+
end
|
336
|
+
|
337
|
+
def death
|
338
|
+
get_attr if @birth==nil
|
339
|
+
@death
|
340
|
+
end
|
341
|
+
|
342
|
+
#Number of books written by this author
|
343
|
+
def books_count
|
344
|
+
get_attr if @books==nil
|
345
|
+
@books
|
346
|
+
end
|
347
|
+
|
348
|
+
#Count of downloaded books from author
|
349
|
+
def downloads_count
|
350
|
+
get_attr if @downloads==nil
|
351
|
+
@downloads
|
352
|
+
end
|
353
|
+
|
354
|
+
def biography
|
355
|
+
get_attr if @biography==nil
|
356
|
+
@biography
|
357
|
+
end
|
358
|
+
|
359
|
+
def self.from_h(h) #:nodoc:
|
360
|
+
r=Author.new
|
361
|
+
r.send('id=',h['id'])
|
362
|
+
r.fullname=h['author']
|
363
|
+
r
|
364
|
+
end
|
365
|
+
|
366
|
+
#Search through author catalog
|
367
|
+
def self.search(txt,limit=nil)
|
368
|
+
return [] if txt.strip.size==0
|
369
|
+
generic_iterate("/authors/search.xml?query=#{URI.escape(txt)}",limit)
|
370
|
+
end
|
371
|
+
|
372
|
+
#Top authors (by download)
|
373
|
+
def self.top(limit=nil)
|
374
|
+
generic_iterate("/authors/top.xml",limit)
|
375
|
+
end
|
376
|
+
|
377
|
+
#Recent authors
|
378
|
+
def self.recent(limit=nil)
|
379
|
+
generic_iterate("/authors/recent.xml",limit)
|
380
|
+
end
|
381
|
+
|
382
|
+
#Array of books written by this author
|
383
|
+
def books(limit=nil)
|
384
|
+
FeedBooks::Book.send('generic_iterate',"/author/#{@id}/books.xml",limit)
|
385
|
+
end
|
386
|
+
|
387
|
+
#Array of top books written by this author
|
388
|
+
def top_books(limit=nil)
|
389
|
+
FeedBooks::Book.send('generic_iterate',"/author/#{@id}/books/top.xml",limit)
|
390
|
+
end
|
391
|
+
|
392
|
+
#Array of recent books written by this author
|
393
|
+
def recent_books(limit=nil)
|
394
|
+
FeedBooks::Book.send('generic_iterate',"/author/#{@id}/books/recent.xml",limit)
|
395
|
+
end
|
396
|
+
|
397
|
+
private
|
398
|
+
|
399
|
+
def id=(i)
|
400
|
+
@id=i
|
401
|
+
end
|
402
|
+
|
403
|
+
def self.generic_iterate(url,limit=nil)
|
404
|
+
res=[]
|
405
|
+
self.iterate(url) do |b|
|
406
|
+
tmp=Author.new
|
407
|
+
tmp.send('from_h_priv',Author::from_xml_elm(b))
|
408
|
+
tmp.instance_variable_set('@id',b.attributes['id'].to_i)
|
409
|
+
res.push(tmp)
|
410
|
+
return res[0...limit] if !limit.nil? && res.size >= limit
|
411
|
+
|
412
|
+
end
|
413
|
+
res
|
414
|
+
end
|
415
|
+
|
416
|
+
def get_attr
|
417
|
+
from_h_priv(super)
|
418
|
+
end
|
419
|
+
|
420
|
+
def from_h_priv(h)
|
421
|
+
h.each do |k,v|
|
422
|
+
if k=='name'
|
423
|
+
send('fullname=',v)
|
424
|
+
else
|
425
|
+
self.instance_variable_set('@'+k,v)
|
426
|
+
end
|
427
|
+
end
|
428
|
+
end
|
429
|
+
end
|
430
|
+
|
431
|
+
#Type object
|
432
|
+
#see http://feedbooks.com/api/types
|
433
|
+
class Type < FBobject
|
434
|
+
attr_reader :name
|
435
|
+
attr_reader :total_books
|
436
|
+
|
437
|
+
def initialize(name=nil)
|
438
|
+
@name=name
|
439
|
+
end
|
440
|
+
|
441
|
+
def total_books
|
442
|
+
get_attr if @total_books.nil?
|
443
|
+
@total_books.to_i
|
444
|
+
end
|
445
|
+
|
446
|
+
#List all types known on feedbooks
|
447
|
+
def self.all(lim=nil)
|
448
|
+
generic_iterate('/types.xml',lim)
|
449
|
+
end
|
450
|
+
|
451
|
+
#all books tagged with this type
|
452
|
+
def books(limit=nil)
|
453
|
+
|
454
|
+
FeedBooks::Book.send('generic_iterate',"/type/#{@name}/books.xml",limit)
|
455
|
+
end
|
456
|
+
|
457
|
+
#top books tagged with this type
|
458
|
+
def top_books(limit=nil)
|
459
|
+
FeedBooks::Book.send('generic_iterate',"/type/#{@name}/books/top.xml",limit)
|
460
|
+
end
|
461
|
+
|
462
|
+
#recent books tagged with this type
|
463
|
+
def recent_books(limit=nil)
|
464
|
+
FeedBooks::Book.send('generic_iterate',"/type/#{@name}/books/recent.xml",limit)
|
465
|
+
end
|
466
|
+
|
467
|
+
private
|
468
|
+
|
469
|
+
def self.generic_iterate(url,limit=nil)
|
470
|
+
res=[]
|
471
|
+
self.iterate(url) do |b|
|
472
|
+
tmp=Type.new
|
473
|
+
tmp.send('from_h',Type::from_xml_elm(b))
|
474
|
+
tmp.instance_variable_set('@id',b.attributes['id'].to_i)
|
475
|
+
res.push(tmp)
|
476
|
+
return res[0...limit] if !limit.nil? && res.size >= limit
|
477
|
+
|
478
|
+
end
|
479
|
+
res
|
480
|
+
end
|
481
|
+
|
482
|
+
def from_h(h)
|
483
|
+
h.each do |k,v|
|
484
|
+
self.instance_variable_set('@'+k,v)
|
485
|
+
end
|
486
|
+
end
|
487
|
+
|
488
|
+
def get_attr
|
489
|
+
@total_books=Type.all.find{|t| t.name==@name}.total_books
|
490
|
+
end
|
491
|
+
|
492
|
+
end
|
493
|
+
|
494
|
+
#List object
|
495
|
+
#see http://feedbooks.com/api/lists.
|
496
|
+
#A list is a collection of Book
|
497
|
+
class List < FBobject
|
498
|
+
include Enumerable
|
499
|
+
attr_reader :id
|
500
|
+
def initialize(id=nil)
|
501
|
+
@id=id
|
502
|
+
end
|
503
|
+
|
504
|
+
def title
|
505
|
+
get_attr if @title==nil
|
506
|
+
@title
|
507
|
+
end
|
508
|
+
|
509
|
+
def identifier
|
510
|
+
get_attr if @title==nil
|
511
|
+
@identifier
|
512
|
+
end
|
513
|
+
|
514
|
+
def description
|
515
|
+
get_attr if @title==nil
|
516
|
+
@description
|
517
|
+
end
|
518
|
+
|
519
|
+
def favorites
|
520
|
+
get_attr if @title==nil
|
521
|
+
@favorites.to_i
|
522
|
+
end
|
523
|
+
|
524
|
+
def items
|
525
|
+
get_attr if @title==nil
|
526
|
+
@items.to_i
|
527
|
+
end
|
528
|
+
|
529
|
+
#All books in the list
|
530
|
+
def books(limit=nil)
|
531
|
+
FeedBooks::Book.send('generic_iterate',"/list/#{@id}.xml",limit)
|
532
|
+
end
|
533
|
+
|
534
|
+
#All list on feedbooks
|
535
|
+
def self.all(lim=nil)
|
536
|
+
generic_iterate('/lists.xml',lim)
|
537
|
+
end
|
538
|
+
|
539
|
+
#iterate through books in the list
|
540
|
+
def each_books(lim=nil)
|
541
|
+
books.each{|b| yield b}
|
542
|
+
end
|
543
|
+
|
544
|
+
alias :each :each_books
|
545
|
+
|
546
|
+
private
|
547
|
+
|
548
|
+
def self.generic_iterate(url,limit=nil)
|
549
|
+
res=[]
|
550
|
+
self.iterate(url) do |b|
|
551
|
+
tmp=List.new
|
552
|
+
tmp.send('from_h',List::from_xml_elm(b))
|
553
|
+
tmp.instance_variable_set('@id',b.attributes['id'].to_i)
|
554
|
+
res.push(tmp)
|
555
|
+
return res[0...limit] if !limit.nil? && res.size >= limit
|
556
|
+
|
557
|
+
end
|
558
|
+
res
|
559
|
+
end
|
560
|
+
|
561
|
+
def from_h(h)
|
562
|
+
h.each do |k,v|
|
563
|
+
self.instance_variable_set('@'+k,v)
|
564
|
+
end
|
565
|
+
end
|
566
|
+
|
567
|
+
def get_attr
|
568
|
+
List::iterate('/lists.xml') do |l|
|
569
|
+
next unless l.attributes['id'].to_i==@id
|
570
|
+
return from_h(List::from_xml_elm(l))
|
571
|
+
end
|
572
|
+
end
|
573
|
+
|
574
|
+
end
|
575
|
+
end
|
@@ -0,0 +1,316 @@
|
|
1
|
+
require 'lib/ruby-feedbooks.rb'
|
2
|
+
|
3
|
+
describe FeedBooks::Book do
|
4
|
+
before(:each) do
|
5
|
+
@book=FeedBooks::Book.new(1)
|
6
|
+
end
|
7
|
+
|
8
|
+
it "should have an id" do
|
9
|
+
@book.should respond_to('id')
|
10
|
+
end
|
11
|
+
|
12
|
+
it "shouldn't have an id=" do
|
13
|
+
@book.should_not respond_to('id=')
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should have an author list" do
|
17
|
+
@book.should respond_to('authors')
|
18
|
+
@book.authors.class.should ==Array
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should have a full author list" do
|
22
|
+
@book.authors.size.should >0
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should have *author* list" do
|
26
|
+
@book.authors.each{|a| a.class.should ==FeedBooks::Author}
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should have a title" do
|
30
|
+
@book.should respond_to('title')
|
31
|
+
@book.title.nil?.should ==false
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should have a date" do
|
35
|
+
@book.should respond_to('date')
|
36
|
+
@book.date.nil?.should ==false
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should have a cover" do
|
40
|
+
@book.should respond_to('cover')
|
41
|
+
@book.cover.nil?.should ==false
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should have subjects" do
|
45
|
+
@book.should respond_to('subjects')
|
46
|
+
@book.subjects.should have_at_least(1).item
|
47
|
+
end
|
48
|
+
|
49
|
+
it "should subjects that are types" do
|
50
|
+
@book.subjects.each{|s| s.class.should == FeedBooks::Type}
|
51
|
+
end
|
52
|
+
|
53
|
+
it "should have a language" do
|
54
|
+
@book.should respond_to('language')
|
55
|
+
@book.language.nil?.should ==false
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should have a rights" do
|
59
|
+
@book.should respond_to('rights')
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should have a download links" do
|
63
|
+
@book.should respond_to('file')
|
64
|
+
end
|
65
|
+
|
66
|
+
it "should have a description" do
|
67
|
+
@book.should respond_to('description')
|
68
|
+
end
|
69
|
+
it "should be able to get similar books" do
|
70
|
+
@book.should respond_to('similar')
|
71
|
+
@book.similar(10).size.should ==10
|
72
|
+
end
|
73
|
+
|
74
|
+
it "should be able to search" do
|
75
|
+
FeedBooks::Book.should respond_to('search')
|
76
|
+
end
|
77
|
+
|
78
|
+
it "should be able to get top books" do
|
79
|
+
FeedBooks::Book.should respond_to('top')
|
80
|
+
FeedBooks::Book.top(10).size.should ==10
|
81
|
+
end
|
82
|
+
|
83
|
+
it "should be able to get recent books" do
|
84
|
+
FeedBooks::Book.should respond_to('recent')
|
85
|
+
FeedBooks::Book.recent(10).size.should ==10
|
86
|
+
end
|
87
|
+
|
88
|
+
it "should be present in lists" do
|
89
|
+
@book.should respond_to('lists')
|
90
|
+
FeedBooks::List.all(1).first.books.first.lists.should have_at_least(1).item
|
91
|
+
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
95
|
+
|
96
|
+
describe FeedBooks::Connection do
|
97
|
+
|
98
|
+
before(:each) do
|
99
|
+
@con=FeedBooks::Connection.new()
|
100
|
+
end
|
101
|
+
|
102
|
+
it "should have a nil user when new" do
|
103
|
+
@con.user.should be_nil
|
104
|
+
end
|
105
|
+
|
106
|
+
it "should have a nil password when new" do
|
107
|
+
@con.password.should be_nil
|
108
|
+
end
|
109
|
+
|
110
|
+
it "should have the env proxy when new" do
|
111
|
+
@con.proxy.should == ENV["proxy"]
|
112
|
+
end
|
113
|
+
|
114
|
+
it "should have a option hash" do
|
115
|
+
@con.should respond_to(:http_opts)
|
116
|
+
@con.http_opts.should_not be_nil
|
117
|
+
end
|
118
|
+
|
119
|
+
it "should have :http_basic_authentication set given a user" do
|
120
|
+
@con.user="test"
|
121
|
+
@con.password="test"
|
122
|
+
a=@con.http_opts[:http_basic_authentication]
|
123
|
+
a.first.should =="test"
|
124
|
+
a.last.should ==Digest::MD5.hexdigest("test")
|
125
|
+
end
|
126
|
+
|
127
|
+
it "should have a User-agent" do
|
128
|
+
@con.http_opts["User-Agent"].should == FeedBooks::USER_AGENT
|
129
|
+
end
|
130
|
+
|
131
|
+
it "should throw an error trying to get recommendations" do
|
132
|
+
lambda { FeedBooks::Book.recommended}.should raise_error(FeedBooks::UnauthenticatedError)
|
133
|
+
end
|
134
|
+
|
135
|
+
end
|
136
|
+
|
137
|
+
|
138
|
+
describe "Book (authenticated_user)" do
|
139
|
+
before(:each) do
|
140
|
+
@book=FeedBooks::Book.new(1)
|
141
|
+
FeedBooks::Book.connection=FeedBooks::Connection.new("test","test")
|
142
|
+
end
|
143
|
+
|
144
|
+
it "should respond to recommended" do
|
145
|
+
FeedBooks::Book.should respond_to(:recommended)
|
146
|
+
end
|
147
|
+
|
148
|
+
it "should get recommendations" do
|
149
|
+
FeedBooks::Book.connection=FeedBooks::Connection.new("test","test")
|
150
|
+
FeedBooks::Book.recommended.should have_at_least(1).item
|
151
|
+
end
|
152
|
+
|
153
|
+
it "should throw an error trying to get recommendations with wrong password" do
|
154
|
+
con = FeedBooks::Connection.new
|
155
|
+
con.user="test"
|
156
|
+
con.password="plop"
|
157
|
+
FeedBooks::Book.connection=con
|
158
|
+
lambda { FeedBooks::Book.recommended}.should raise_error(FeedBooks::WrongCredentialsError)
|
159
|
+
end
|
160
|
+
|
161
|
+
after(:each) do
|
162
|
+
FeedBooks::Book.connection=nil
|
163
|
+
end
|
164
|
+
|
165
|
+
end
|
166
|
+
|
167
|
+
describe FeedBooks::Author do
|
168
|
+
before(:each) do
|
169
|
+
@author=FeedBooks::Author.new(1)
|
170
|
+
end
|
171
|
+
|
172
|
+
it "should have an id" do
|
173
|
+
@author.should respond_to('id')
|
174
|
+
end
|
175
|
+
|
176
|
+
it "shouldn't have an id=" do
|
177
|
+
@author.should_not respond_to('id=')
|
178
|
+
end
|
179
|
+
|
180
|
+
it "should have a name" do
|
181
|
+
@author.should respond_to('name')
|
182
|
+
@author.name.nil?.should ==false
|
183
|
+
end
|
184
|
+
|
185
|
+
it "should have a firstname" do
|
186
|
+
@author.should respond_to('firstname')
|
187
|
+
@author.firstname.nil?.should ==false
|
188
|
+
end
|
189
|
+
|
190
|
+
it "should have a fullname" do
|
191
|
+
@author.should respond_to('fullname')
|
192
|
+
@author.fullname.nil?.should ==false
|
193
|
+
end
|
194
|
+
|
195
|
+
it "should have a birth year" do
|
196
|
+
@author.should respond_to('birth')
|
197
|
+
@author.birth.nil?.should ==false
|
198
|
+
end
|
199
|
+
|
200
|
+
it "should have a death year" do
|
201
|
+
@author.should respond_to('death')
|
202
|
+
end
|
203
|
+
|
204
|
+
it "should have a book count" do
|
205
|
+
@author.should respond_to('books_count')
|
206
|
+
end
|
207
|
+
|
208
|
+
it "should have a download count" do
|
209
|
+
@author.should respond_to('downloads_count')
|
210
|
+
end
|
211
|
+
|
212
|
+
it "should have a biography" do
|
213
|
+
@author.should respond_to('biography')
|
214
|
+
end
|
215
|
+
|
216
|
+
it "should be able to search" do
|
217
|
+
FeedBooks::Author.should respond_to('search')
|
218
|
+
end
|
219
|
+
|
220
|
+
it "should be able to get top" do
|
221
|
+
FeedBooks::Author.should respond_to('top')
|
222
|
+
FeedBooks::Author.top(10).size.should ==10
|
223
|
+
end
|
224
|
+
|
225
|
+
it "should be able to get recent" do
|
226
|
+
FeedBooks::Author.should respond_to('recent')
|
227
|
+
FeedBooks::Author.recent(10).size.should ==10
|
228
|
+
end
|
229
|
+
|
230
|
+
it "should be able to get books" do
|
231
|
+
@author.should respond_to('books')
|
232
|
+
end
|
233
|
+
|
234
|
+
it "should be able to get top books" do
|
235
|
+
@author.should respond_to('top_books')
|
236
|
+
@author.top_books(10).size.should ==10
|
237
|
+
end
|
238
|
+
|
239
|
+
it "should be able to get recent books" do
|
240
|
+
@author.should respond_to('recent_books')
|
241
|
+
@author.recent_books(10).size.should ==10
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
describe FeedBooks::Type do
|
246
|
+
before(:each) do
|
247
|
+
@typ=FeedBooks::Type.new("Biography")
|
248
|
+
end
|
249
|
+
|
250
|
+
it "should have a name" do
|
251
|
+
@typ.should respond_to(:name)
|
252
|
+
end
|
253
|
+
|
254
|
+
it "should have a total " do
|
255
|
+
@typ.should respond_to(:total_books)
|
256
|
+
end
|
257
|
+
|
258
|
+
it "should have a non zero total " do
|
259
|
+
@typ.total_books.should have_at_least(1).item
|
260
|
+
end
|
261
|
+
|
262
|
+
it "should be able to get all types" do
|
263
|
+
FeedBooks::Type.all.should have_at_least(1).item
|
264
|
+
end
|
265
|
+
|
266
|
+
it "should be able to get books with this type" do
|
267
|
+
@typ.books.should have(@typ.total_books).item
|
268
|
+
end
|
269
|
+
|
270
|
+
it "should be able to get top books with this type" do
|
271
|
+
@typ.top_books.should have([100,@typ.total_books].min).items
|
272
|
+
end
|
273
|
+
|
274
|
+
it "should be able to get recent books with this type" do
|
275
|
+
@typ.recent_books.should have([100,@typ.total_books].min).items
|
276
|
+
end
|
277
|
+
|
278
|
+
|
279
|
+
end
|
280
|
+
|
281
|
+
|
282
|
+
describe FeedBooks::List do
|
283
|
+
before(:each) do
|
284
|
+
@list=FeedBooks::List.new(1)
|
285
|
+
end
|
286
|
+
|
287
|
+
it "should have a title" do
|
288
|
+
@list.should respond_to(:title)
|
289
|
+
end
|
290
|
+
|
291
|
+
it "should have an identifier" do
|
292
|
+
@list.should respond_to(:identifier)
|
293
|
+
end
|
294
|
+
|
295
|
+
it "should have a description" do
|
296
|
+
@list.should respond_to(:description)
|
297
|
+
end
|
298
|
+
|
299
|
+
it "should have a favorites count" do
|
300
|
+
@list.should respond_to(:favorites)
|
301
|
+
end
|
302
|
+
|
303
|
+
it "should have an item count" do
|
304
|
+
@list.should respond_to(:items)
|
305
|
+
@list.should have_at_least(1).items
|
306
|
+
end
|
307
|
+
|
308
|
+
it "should have books" do
|
309
|
+
@list.should respond_to(:books)
|
310
|
+
@list.should have(@list.items).books
|
311
|
+
end
|
312
|
+
|
313
|
+
it do
|
314
|
+
@list.should respond_to(:each)
|
315
|
+
end
|
316
|
+
end
|
metadata
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: zetaben-ruby-feedbooks
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: "0.1"
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Benoit Larroque
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-04-13 00:00:00 -07:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: hpricot
|
17
|
+
type: :runtime
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: "0.6"
|
24
|
+
version:
|
25
|
+
description: ruby-feedbooks is a dead simple ruby interface to feedbooks.com
|
26
|
+
email: zeta dot ben at gmail dot com
|
27
|
+
executables: []
|
28
|
+
|
29
|
+
extensions: []
|
30
|
+
|
31
|
+
extra_rdoc_files: []
|
32
|
+
|
33
|
+
files:
|
34
|
+
- README
|
35
|
+
- Rakefile
|
36
|
+
- lib/ruby-feedbooks.rb
|
37
|
+
- spec/ruby-feedbooks_spec.rb
|
38
|
+
has_rdoc: true
|
39
|
+
homepage: http://github.com/ruby-feedbooks
|
40
|
+
post_install_message:
|
41
|
+
rdoc_options: []
|
42
|
+
|
43
|
+
require_paths:
|
44
|
+
- lib
|
45
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
46
|
+
requirements:
|
47
|
+
- - ">="
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: "0"
|
50
|
+
version:
|
51
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
52
|
+
requirements:
|
53
|
+
- - ">="
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: "0"
|
56
|
+
version:
|
57
|
+
requirements: []
|
58
|
+
|
59
|
+
rubyforge_project:
|
60
|
+
rubygems_version: 1.2.0
|
61
|
+
signing_key:
|
62
|
+
specification_version: 2
|
63
|
+
summary: ruby-feedbooks is a dead simple ruby interface to feedbooks.com
|
64
|
+
test_files: []
|
65
|
+
|