ruby-feedbooks 0.1

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -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,67 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: 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 +02: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
+ licenses: []
41
+
42
+ post_install_message:
43
+ rdoc_options: []
44
+
45
+ require_paths:
46
+ - lib
47
+ required_ruby_version: !ruby/object:Gem::Requirement
48
+ requirements:
49
+ - - ">="
50
+ - !ruby/object:Gem::Version
51
+ version: "0"
52
+ version:
53
+ required_rubygems_version: !ruby/object:Gem::Requirement
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ version: "0"
58
+ version:
59
+ requirements: []
60
+
61
+ rubyforge_project:
62
+ rubygems_version: 1.3.5
63
+ signing_key:
64
+ specification_version: 3
65
+ summary: ruby-feedbooks is a dead simple ruby interface to feedbooks.com
66
+ test_files: []
67
+