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 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,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
+