goodreads 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,5 @@
1
+ rvm:
2
+ - 1.8.7
3
+ - 1.9.2
4
+ - 1.9.3
5
+ - ree
@@ -0,0 +1,125 @@
1
+ # Goodreads API wrapper
2
+
3
+ Ruby library to connect with Goodreads API.
4
+
5
+ [![Build Status](https://secure.travis-ci.org/sosedoff/goodreads.png)](http://travis-ci.org/sosedoff/goodreads)
6
+
7
+ ## Installation
8
+
9
+ You can install this library via rubygems:
10
+
11
+ ```
12
+ gem install goodreads
13
+ ```
14
+
15
+ Or using rake:
16
+
17
+ ```
18
+ rake install
19
+ ```
20
+
21
+ ## Getting Started
22
+
23
+ In order to use Goodreads API you must obtain an API key for your account.
24
+
25
+ Setup client:
26
+
27
+ ```ruby
28
+ client = Goodreads::Client.new(:api_key => 'YOUR_KEY')
29
+
30
+ # or using a shortcut
31
+ client = Goodreads.new(:api_key => 'YOUR_KEY')
32
+ ```
33
+
34
+ ### Global configuration
35
+
36
+ Library allows you to define a global configuration options.
37
+
38
+ ```ruby
39
+ Goodreads.configure(:api_key => 'YOUR_KEY')
40
+ ```
41
+
42
+ Get current options:
43
+
44
+ ```ruby
45
+ Goodreads.configuration # => {:api_key => 'YOUR_KEY'}
46
+ ```
47
+
48
+ In case you need to reset options:
49
+
50
+ ```ruby
51
+ Goodreads.reset_configuration
52
+ ```
53
+
54
+ ## Usage
55
+
56
+ ### Lookup books
57
+
58
+ Find a book by ISBN:
59
+
60
+ ```ruby
61
+ book = client.book_by_isbn('ISBN')
62
+ ```
63
+
64
+ Find a book by Goodreads ID:
65
+
66
+ ```ruby
67
+ book = client.book('id')
68
+ ```
69
+
70
+ Find a book by title:
71
+
72
+ ```ruby
73
+ book = client.book_by_title('Book title')
74
+ ```
75
+
76
+ Search for books (by title, isbn, genre):
77
+
78
+ ```ruby
79
+ search = client.search_books('Your search query')
80
+ search.results.work.each do |book|
81
+ book.id # => book ID
82
+ book.title # => book title
83
+ end
84
+ ```
85
+
86
+ ### Reviews
87
+
88
+ Pull recent reviews:
89
+
90
+ ```ruby
91
+ client.recent_reviews.each do |r|
92
+ r.id # => review id
93
+ r.book.title # => review book title
94
+ r.body # => review message
95
+ r.user.name # => review user name
96
+ end
97
+ ```
98
+
99
+ Get review details:
100
+
101
+ ```ruby
102
+ review = client.review('id')
103
+ review.id # => ID
104
+ review.user # => User information
105
+ review.book # => Book information
106
+ review.rating # => User rating
107
+ ```
108
+
109
+ ## Contributions
110
+
111
+ Feel free to contribute any patches or new features.
112
+
113
+ Make sure to add a test coverage so it does not break any existing code.
114
+
115
+ For documentation please visit [API Reference](http://www.goodreads.com/api)
116
+
117
+ ## License
118
+
119
+ Copyright © 2011-2012 Dan Sosedoff.
120
+
121
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
122
+
123
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
124
+
125
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile CHANGED
@@ -1,9 +1,10 @@
1
1
  require 'bundler'
2
- require "rspec/core/rake_task"
2
+ require 'bundler/gem_tasks'
3
+ require 'rspec/core/rake_task'
3
4
 
4
5
  RSpec::Core::RakeTask.new(:test) do |t|
5
6
  t.pattern = 'spec/*_spec.rb'
6
7
  t.verbose = false
7
8
  end
8
9
 
9
- task :default => :test
10
+ task :default => :test
@@ -9,23 +9,19 @@ Gem::Specification.new do |s|
9
9
  s.authors = ["Dan Sosedoff"]
10
10
  s.email = ["dan.sosedoff@gmail.com"]
11
11
 
12
- s.add_development_dependency 'webmock', '~> 1.6'
13
- s.add_development_dependency 'rake', '~> 0.8'
14
- s.add_development_dependency 'rspec', '~> 2.5'
15
- s.add_development_dependency 'ZenTest', '~> 4.5'
12
+ s.add_development_dependency 'webmock', '~> 1.6'
13
+ s.add_development_dependency 'rake', '~> 0.8'
14
+ s.add_development_dependency 'rspec', '~> 2.5'
16
15
  s.add_development_dependency 'simplecov', '~> 0.4'
17
- s.add_development_dependency 'yard', '~> 0.6'
16
+ s.add_development_dependency 'yard', '~> 0.6'
18
17
 
19
- s.add_runtime_dependency 'rest-client', '~> 1.6.1'
20
- s.add_runtime_dependency 'hashie', '~> 1.0.0'
21
- s.add_runtime_dependency 'activesupport', '~> 3.0.0'
22
- s.add_runtime_dependency 'i18n', '~> 0.5'
23
-
24
- s.files = `git ls-files`.split("\n")
25
- s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
26
- s.executables = `git ls-files -- bin/*`.split("\n").map{|f| File.basename(f)}
18
+ s.add_runtime_dependency 'rest-client', '~> 1.6'
19
+ s.add_runtime_dependency 'hashie', '~> 1.0'
20
+ s.add_runtime_dependency 'activesupport', '~> 3'
21
+ s.add_runtime_dependency 'i18n', '~> 0.5'
22
+
23
+ s.files = `git ls-files`.split("\n")
24
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
25
+ s.executables = `git ls-files -- bin/*`.split("\n").map{|f| File.basename(f)}
27
26
  s.require_paths = ["lib"]
28
-
29
- s.platform = Gem::Platform::RUBY
30
- s.required_rubygems_version = Gem::Requirement.new('>= 1.3.6') if s.respond_to? :required_rubygems_version=
31
27
  end
@@ -1,6 +1,41 @@
1
- require 'rest-client'
2
- require 'active_support/core_ext'
3
- require 'hashie'
1
+ require 'goodreads/version'
2
+ require 'goodreads/errors'
3
+ require 'goodreads/request'
4
+ require 'goodreads/client'
4
5
 
5
- require 'goodreads/goodreads'
6
- require 'goodreads/client'
6
+ module Goodreads
7
+ @@options = {}
8
+
9
+ # Create a new Goodreads::Client instance
10
+ #
11
+ def self.new(options={})
12
+ Goodreads::Client.new(options)
13
+ end
14
+
15
+ # Define a global configuration
16
+ #
17
+ # options[:api_key] - Account API key
18
+ # options[:api_secret] - Account API secret
19
+ #
20
+ def self.configure(options={})
21
+ unless options.kind_of?(Hash)
22
+ raise ArgumentError, "Options hash required."
23
+ end
24
+
25
+ @@options[:api_key] = options[:api_key]
26
+ @@options[:api_secret] = options[:api_secret]
27
+ @@options
28
+ end
29
+
30
+ # Returns global configuration hash
31
+ #
32
+ def self.configuration
33
+ @@options
34
+ end
35
+
36
+ # Resets the global configuration
37
+ #
38
+ def self.reset_configuration
39
+ @@options = {}
40
+ end
41
+ end
@@ -1,94 +1,31 @@
1
+ require 'goodreads/client'
2
+ require 'goodreads/client/books'
3
+ require 'goodreads/client/reviews'
4
+ require 'goodreads/client/authors'
5
+ require 'goodreads/client/users'
6
+
1
7
  module Goodreads
2
8
  class Client
3
- @@config = {}
4
-
5
- # Initialize the API client
6
- # You must specify the API key given by goodreads in order to make requests
7
- # :api_key - Your api key
8
- def self.configure(opts={})
9
- key = opts[:api_key].to_s
10
- raise ArgumentError, 'API key required!' if key.empty?
11
- @@config[:api_key] = opts[:api_key]
12
- end
13
-
14
- # Search for books
15
- # q => The query text to match against book title, author, and ISBN fields.
16
- # params => Optional search parameters
17
- # :page => Which page to return (default 1, optional)
18
- # :field => Field to search, one of title, author, or genre (default is all)
19
- def search_books(q, params={})
20
- params[:q] = q.to_s.strip
21
- data = request('/search/index', params)
22
- Hashie::Mash.new(data['search'])
23
- end
24
-
25
- # Get book details by Goodreads book ID
26
- def book(id)
27
- Hashie::Mash.new(request('/book/show', :id => id)['book'])
28
- end
29
-
30
- # Get book details by book ISBN
31
- def book_by_isbn(isbn)
32
- Hashie::Mash.new(request('/book/isbn', :isbn => isbn)['book'])
33
- end
34
-
35
- # Get book details by book title
36
- def book_by_title(title)
37
- Hashie::Mash.new(request('/book/title', :title => title)['book'])
38
- end
39
-
40
- # Recent reviews from all members.
41
- # :skip_cropped - Select only non-cropped reviews
42
- def recent_reviews(params={})
43
- skip_cropped = params.delete(:skip_cropped) || false
44
- data = request('/review/recent_reviews', params)
45
- if data['reviews'] && data['reviews'].key?('review')
46
- reviews = data['reviews']['review'].map { |r| Hashie::Mash.new(r) }
47
- reviews = reviews.select { |r| !r.body.include?(r.url) } if skip_cropped
48
- reviews
9
+ include Goodreads::Request
10
+ include Goodreads::Books
11
+ include Goodreads::Reviews
12
+ include Goodreads::Authors
13
+ include Goodreads::Users
14
+
15
+ attr_reader :api_key, :api_secret
16
+
17
+ # Initialize a Goodreads::Client instance
18
+ #
19
+ # options[:api_key] - Account API key
20
+ # options[:api_secret] - Account API secret
21
+ #
22
+ def initialize(options={})
23
+ unless options.kind_of?(Hash)
24
+ raise ArgumentError, "Options hash required."
49
25
  end
50
- end
51
-
52
- # Get review details
53
- def review(id)
54
- data = request('/review/show', :id => id)
55
- Hashie::Mash.new(data['review'])
56
- end
57
-
58
- # Get author details
59
- def author(id, params={})
60
- params[:id] = id
61
- data = request('/author/show', params)
62
- Hashie::Mash.new(data['author'])
63
- end
64
-
65
- # Get user details
66
- def user(id)
67
- data = request('/user/show', :id => id)
68
- Hashie::Mash.new(data['user'])
69
- end
70
-
71
- private
72
-
73
- # Perform an API request
74
- def request(path, params={})
75
- raise 'API key required!' unless @@config.key?(:api_key)
76
- params.merge!(:format => 'xml', :key => @@config[:api_key])
77
-
78
- resp = RestClient.get("#{API_URL}#{path}", :params => params) { |response, request, result, &block|
79
- case response.code
80
- when 200
81
- response.return!(request, result, &block)
82
- when 401
83
- raise Goodreads::Unauthorized
84
- when 404
85
- raise Goodreads::NotFound
86
- end
87
- }
88
26
 
89
- hash = Hash.from_xml(resp)['GoodreadsResponse']
90
- hash.delete('Request')
91
- hash
27
+ @api_key = options[:api_key]
28
+ @api_secret = options[:api_secret]
92
29
  end
93
30
  end
94
31
  end
@@ -0,0 +1,11 @@
1
+ module Goodreads
2
+ module Authors
3
+ # Get author details
4
+ #
5
+ def author(id, params={})
6
+ params[:id] = id
7
+ data = request('/author/show', params)
8
+ Hashie::Mash.new(data['author'])
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,35 @@
1
+ module Goodreads
2
+ module Books
3
+ # Search for books
4
+ #
5
+ # query - Text to match against book title, author, and ISBN fields.
6
+ # options - Optional search parameters
7
+ #
8
+ # options[:page] - Which page to returns (default: 1)
9
+ # options[:field] - Search field. One of: title, author, or genre (default is all)
10
+ #
11
+ def search_books(query, params={})
12
+ params[:q] = query.to_s.strip
13
+ data = request('/search/index', params)
14
+ Hashie::Mash.new(data['search'])
15
+ end
16
+
17
+ # Get book details by Goodreads book ID
18
+ #
19
+ def book(id)
20
+ Hashie::Mash.new(request('/book/show', :id => id)['book'])
21
+ end
22
+
23
+ # Get book details by book ISBN
24
+ #
25
+ def book_by_isbn(isbn)
26
+ Hashie::Mash.new(request('/book/isbn', :isbn => isbn)['book'])
27
+ end
28
+
29
+ # Get book details by book title
30
+ #
31
+ def book_by_title(title)
32
+ Hashie::Mash.new(request('/book/title', :title => title)['book'])
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,24 @@
1
+ module Goodreads
2
+ module Reviews
3
+ # Recent reviews from all members.
4
+ #
5
+ # params[:skip_cropped] - Select only non-cropped reviews
6
+ #
7
+ def recent_reviews(params={})
8
+ skip_cropped = params.delete(:skip_cropped) || false
9
+ data = request('/review/recent_reviews', params)
10
+ if data['reviews'] && data['reviews'].key?('review')
11
+ reviews = data['reviews']['review'].map { |r| Hashie::Mash.new(r) }
12
+ reviews = reviews.select { |r| !r.body.include?(r.url) } if skip_cropped
13
+ reviews
14
+ end
15
+ end
16
+
17
+ # Get review details
18
+ #
19
+ def review(id)
20
+ data = request('/review/show', :id => id)
21
+ Hashie::Mash.new(data['review'])
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,10 @@
1
+ module Goodreads
2
+ module Users
3
+ # Get user details
4
+ #
5
+ def user(id)
6
+ data = request('/user/show', :id => id)
7
+ Hashie::Mash.new(data['user'])
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,6 @@
1
+ module Goodreads
2
+ class Error < StandardError; end
3
+ class ConfigurationError < Error ; end
4
+ class Unauthorized < Error ; end
5
+ class NotFound < Error ; end
6
+ end
@@ -0,0 +1,43 @@
1
+ require 'rest-client'
2
+ require 'active_support/core_ext'
3
+ require 'hashie'
4
+
5
+ module Goodreads
6
+ module Request
7
+ API_URL = 'http://www.goodreads.com'
8
+ API_FORMAT = 'xml'
9
+
10
+ protected
11
+
12
+ # Perform an API request
13
+ #
14
+ # path - Request path
15
+ # params - Parameters hash
16
+ #
17
+ def request(path, params={})
18
+ token = api_key || Goodreads.configuration[:api_key]
19
+
20
+ if token.nil?
21
+ raise Goodreads::ConfigurationError, 'API key required.'
22
+ end
23
+
24
+ params.merge!(:format => API_FORMAT, :key => token)
25
+ url = "#{API_URL}#{path}"
26
+
27
+ resp = RestClient.get(url, :params => params) do |response, request, result, &block|
28
+ case response.code
29
+ when 200
30
+ response.return!(request, result, &block)
31
+ when 401
32
+ raise Goodreads::Unauthorized
33
+ when 404
34
+ raise Goodreads::NotFound
35
+ end
36
+ end
37
+
38
+ hash = Hash.from_xml(resp)['GoodreadsResponse']
39
+ hash.delete('Request')
40
+ hash
41
+ end
42
+ end
43
+ end
@@ -1,3 +1,5 @@
1
1
  module Goodreads
2
- VERSION = '0.1.1'.freeze
2
+ unless defined?(Goodreads::VERSION)
3
+ VERSION = '0.2.0'.freeze
4
+ end
3
5
  end
@@ -2,19 +2,23 @@ require 'spec_helper'
2
2
 
3
3
  describe 'Client' do
4
4
  before :each do
5
- @client = Goodreads::Client.new
5
+ Goodreads.reset_configuration
6
6
  end
7
7
 
8
- it 'should raise exception if API key was not provided' do
9
- proc { @client.book_by_isbn('0307463745') }.should raise_error Exception, 'API key required!'
8
+ it 'raises Goodreads::ConfigurationError if API key was not provided' do
9
+ client = Goodreads::Client.new
10
+
11
+ proc { client.book_by_isbn('0307463745') }.
12
+ should raise_error Goodreads::ConfigurationError, 'API key required.'
10
13
  end
11
14
 
12
- it 'should raise Goodreads::Unauthorized if API key is not valid' do
13
- Goodreads.configure('INVALID_KEY')
15
+ it 'raises Goodreads::Unauthorized if API key is not valid' do
16
+ client = Goodreads::Client.new(:api_key => 'INVALID_KEY')
17
+
14
18
  stub_request(:get, "http://www.goodreads.com/book/isbn?format=xml&isbn=054748250711&key=INVALID_KEY").
15
19
  to_return(:status => 401)
16
20
 
17
- proc { @client.book_by_isbn('054748250711') }.should raise_error Goodreads::Unauthorized
21
+ proc { client.book_by_isbn('054748250711') }.
22
+ should raise_error Goodreads::Unauthorized
18
23
  end
19
24
  end
20
-
@@ -2,11 +2,19 @@ require 'spec_helper'
2
2
 
3
3
  describe 'Client' do
4
4
  before :each do
5
- Goodreads.configure('SECRET_KEY')
6
- @client = Goodreads::Client.new
5
+ Goodreads.reset_configuration
6
+ @client = Goodreads::Client.new(:api_key => 'SECRET_KEY')
7
7
  end
8
8
 
9
- it 'should return a book found by isbn' do
9
+ it 'raises error on invalid config parameter' do
10
+ proc { Goodreads::Client.new(nil) }.
11
+ should raise_error ArgumentError, "Options hash required."
12
+
13
+ proc { Goodreads::Client.new('foo') }.
14
+ should raise_error ArgumentError, "Options hash required."
15
+ end
16
+
17
+ it 'returns a book by isbn' do
10
18
  stub_with_key_get('/book/isbn', {:isbn => '0307463745'}, 'book.xml')
11
19
 
12
20
  proc { @book = @client.book_by_isbn('0307463745') }.should_not raise_error
@@ -14,24 +22,24 @@ describe 'Client' do
14
22
  @book.respond_to?(:title).should == true
15
23
  end
16
24
 
17
- it 'should return a book found by goodreads id' do
25
+ it 'returns a book by goodreads id' do
18
26
  stub_with_key_get('/book/show', {:id => '6732019'}, 'book.xml')
19
27
  proc { @client.book('6732019') }.should_not raise_error
20
28
  end
21
29
 
22
- it 'should return a book found by title' do
30
+ it 'returns a book by title' do
23
31
  stub_with_key_get('/book/title', {:title => 'Rework'}, 'book.xml')
24
32
  proc { @client.book_by_title('Rework') }.should_not raise_error
25
33
  end
26
34
 
27
- it 'should raise Goodreads::NotFound if book was not found' do
35
+ it 'raises Goodreads::NotFound if book was not found' do
28
36
  stub_request(:get, "http://www.goodreads.com/book/isbn?format=xml&isbn=123456789&key=SECRET_KEY").
29
37
  to_return(:status => 404, :body => "", :headers => {})
30
38
 
31
39
  proc { @client.book_by_isbn('123456789') }.should raise_error Goodreads::NotFound
32
40
  end
33
41
 
34
- it 'should return recent reviews' do
42
+ it 'returns recent reviews' do
35
43
  stub_with_key_get('/review/recent_reviews', {}, 'recent_reviews.xml')
36
44
 
37
45
  proc { @reviews = @client.recent_reviews }.should_not raise_error
@@ -42,7 +50,7 @@ describe 'Client' do
42
50
  end
43
51
  end
44
52
 
45
- it 'should return recent reviews with clean reviews' do
53
+ it 'returns only full reviewes' do
46
54
  stub_with_key_get('/review/recent_reviews', {}, 'recent_reviews.xml')
47
55
 
48
56
  proc { @reviews = @client.recent_reviews(:skip_cropped => true) }.should_not raise_error
@@ -53,7 +61,7 @@ describe 'Client' do
53
61
  end
54
62
  end
55
63
 
56
- it 'should return single review details' do
64
+ it 'returns review details' do
57
65
  stub_with_key_get('/review/show', {:id => '166204831'}, 'review.xml')
58
66
 
59
67
  proc { @review = @client.review('166204831') }.should_not raise_error
@@ -62,14 +70,14 @@ describe 'Client' do
62
70
  @review.id.should == '166204831'
63
71
  end
64
72
 
65
- it 'should raise Goodreads::NotFound if review was not found' do
73
+ it 'raises Goodreads::NotFound if review was not found' do
66
74
  stub_request(:get, "http://www.goodreads.com/review/show?format=xml&id=12345&key=SECRET_KEY").
67
75
  to_return(:status => 404, :body => "", :headers => {})
68
76
 
69
77
  proc { @client.review('12345') }.should raise_error Goodreads::NotFound
70
78
  end
71
79
 
72
- it 'should return author details' do
80
+ it 'returns author details' do
73
81
  stub_with_key_get('/author/show', {:id => '18541'}, 'author.xml')
74
82
 
75
83
  proc { @author = @client.author('18541') }.should_not raise_error
@@ -79,14 +87,14 @@ describe 'Client' do
79
87
  @author.name.should == "Tim O'Reilly"
80
88
  end
81
89
 
82
- it 'should raise Goodreads::NotFound if author was not found' do
90
+ it 'raises Goodreads::NotFound if author was not found' do
83
91
  stub_request(:get, "http://www.goodreads.com/author/show?format=xml&id=12345&key=SECRET_KEY").
84
92
  to_return(:status => 404, :body => "", :headers => {})
85
93
 
86
94
  proc { @client.author('12345') }.should raise_error Goodreads::NotFound
87
95
  end
88
96
 
89
- it 'should return user details' do
97
+ it 'returns user details' do
90
98
  stub_with_key_get('/user/show', {:id => '878044'}, 'user.xml')
91
99
 
92
100
  proc { @user = @client.user('878044') }.should_not raise_error
@@ -97,14 +105,14 @@ describe 'Client' do
97
105
  @user.user_name.should == 'janmt'
98
106
  end
99
107
 
100
- it 'should raise Goodreads::NotFound if user was not found' do
108
+ it 'raiser Goodreads::NotFound if user was not found' do
101
109
  stub_request(:get, "http://www.goodreads.com/user/show?format=xml&id=12345&key=SECRET_KEY").
102
110
  to_return(:status => 404, :body => "", :headers => {})
103
111
 
104
112
  proc { @client.user('12345') }.should raise_error Goodreads::NotFound
105
113
  end
106
114
 
107
- it 'should return book search results' do
115
+ it 'returns book search results' do
108
116
  stub_with_key_get('/search/index', {:q => 'Rework'}, 'search_books_by_name.xml')
109
117
 
110
118
  proc { @search = @client.search_books('Rework') }.should_not raise_error
@@ -0,0 +1,54 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Goodreads' do
4
+ context '.new' do
5
+ it 'returns a new client instance' do
6
+ Goodreads.new.should be_a Goodreads::Client
7
+ end
8
+ end
9
+
10
+ context '.configure' do
11
+ it 'sets a global configuration options' do
12
+ r = Goodreads.configure(:api_key => 'FOO', :api_secret => 'BAR')
13
+ r.should be_a Hash
14
+ r.should have_key(:api_key)
15
+ r.should have_key(:api_secret)
16
+ r[:api_key].should eql('FOO')
17
+ r[:api_secret].should eql('BAR')
18
+ end
19
+
20
+ it 'raises ConfigurationError on invalid config parameter' do
21
+ proc { Goodreads.new(nil) }.
22
+ should raise_error ArgumentError, "Options hash required."
23
+
24
+ proc { Goodreads.new('foo') }.
25
+ should raise_error ArgumentError, "Options hash required."
26
+ end
27
+ end
28
+
29
+ context '.configuration' do
30
+ before do
31
+ Goodreads.configure(:api_key => 'FOO', :api_secret => 'BAR')
32
+ end
33
+
34
+ it 'returns global configuration options' do
35
+ r = Goodreads.configuration
36
+ r.should be_a Hash
37
+ r.should have_key(:api_key)
38
+ r.should have_key(:api_secret)
39
+ r[:api_key].should eql('FOO')
40
+ r[:api_secret].should eql('BAR')
41
+ end
42
+ end
43
+
44
+ context '.reset_configuration' do
45
+ before do
46
+ Goodreads.configure(:api_key => 'FOO', :api_secret => 'BAR')
47
+ end
48
+
49
+ it 'resets global configuration options' do
50
+ Goodreads.reset_configuration
51
+ Goodreads.configuration.should eql({})
52
+ end
53
+ end
54
+ end
@@ -24,14 +24,15 @@ def stub_with_key_get(path, params, fixture_name)
24
24
  stub_get(path, params, fixture_name)
25
25
  end
26
26
 
27
- def fixture_path
28
- File.expand_path("../fixtures", __FILE__)
27
+ def fixture_path(file=nil)
28
+ path = File.expand_path("../fixtures", __FILE__)
29
+ file.nil? ? path : File.join(path, file)
29
30
  end
30
31
 
31
32
  def fixture(file)
32
- File.new(fixture_path + '/' + file)
33
+ File.read(fixture_path(file))
33
34
  end
34
35
 
35
36
  def api_url(path)
36
- "#{Goodreads::API_URL}#{path}"
37
+ "#{Goodreads::Request::API_URL}#{path}"
37
38
  end
metadata CHANGED
@@ -1,195 +1,137 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: goodreads
3
- version: !ruby/object:Gem::Version
4
- hash: 25
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.0
5
5
  prerelease:
6
- segments:
7
- - 0
8
- - 1
9
- - 1
10
- version: 0.1.1
11
6
  platform: ruby
12
- authors:
7
+ authors:
13
8
  - Dan Sosedoff
14
9
  autorequire:
15
10
  bindir: bin
16
11
  cert_chain: []
17
-
18
- date: 2011-06-08 00:00:00 -05:00
19
- default_executable:
20
- dependencies:
21
- - !ruby/object:Gem::Dependency
12
+ date: 2012-01-26 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
22
15
  name: webmock
23
- prerelease: false
24
- requirement: &id001 !ruby/object:Gem::Requirement
16
+ requirement: &2157623060 !ruby/object:Gem::Requirement
25
17
  none: false
26
- requirements:
18
+ requirements:
27
19
  - - ~>
28
- - !ruby/object:Gem::Version
29
- hash: 3
30
- segments:
31
- - 1
32
- - 6
33
- version: "1.6"
20
+ - !ruby/object:Gem::Version
21
+ version: '1.6'
34
22
  type: :development
35
- version_requirements: *id001
36
- - !ruby/object:Gem::Dependency
37
- name: rake
38
23
  prerelease: false
39
- requirement: &id002 !ruby/object:Gem::Requirement
24
+ version_requirements: *2157623060
25
+ - !ruby/object:Gem::Dependency
26
+ name: rake
27
+ requirement: &2157622560 !ruby/object:Gem::Requirement
40
28
  none: false
41
- requirements:
29
+ requirements:
42
30
  - - ~>
43
- - !ruby/object:Gem::Version
44
- hash: 27
45
- segments:
46
- - 0
47
- - 8
48
- version: "0.8"
31
+ - !ruby/object:Gem::Version
32
+ version: '0.8'
49
33
  type: :development
50
- version_requirements: *id002
51
- - !ruby/object:Gem::Dependency
52
- name: rspec
53
34
  prerelease: false
54
- requirement: &id003 !ruby/object:Gem::Requirement
35
+ version_requirements: *2157622560
36
+ - !ruby/object:Gem::Dependency
37
+ name: rspec
38
+ requirement: &2157622100 !ruby/object:Gem::Requirement
55
39
  none: false
56
- requirements:
40
+ requirements:
57
41
  - - ~>
58
- - !ruby/object:Gem::Version
59
- hash: 9
60
- segments:
61
- - 2
62
- - 5
63
- version: "2.5"
42
+ - !ruby/object:Gem::Version
43
+ version: '2.5'
64
44
  type: :development
65
- version_requirements: *id003
66
- - !ruby/object:Gem::Dependency
67
- name: ZenTest
68
45
  prerelease: false
69
- requirement: &id004 !ruby/object:Gem::Requirement
70
- none: false
71
- requirements:
72
- - - ~>
73
- - !ruby/object:Gem::Version
74
- hash: 17
75
- segments:
76
- - 4
77
- - 5
78
- version: "4.5"
79
- type: :development
80
- version_requirements: *id004
81
- - !ruby/object:Gem::Dependency
46
+ version_requirements: *2157622100
47
+ - !ruby/object:Gem::Dependency
82
48
  name: simplecov
83
- prerelease: false
84
- requirement: &id005 !ruby/object:Gem::Requirement
49
+ requirement: &2157621640 !ruby/object:Gem::Requirement
85
50
  none: false
86
- requirements:
51
+ requirements:
87
52
  - - ~>
88
- - !ruby/object:Gem::Version
89
- hash: 3
90
- segments:
91
- - 0
92
- - 4
93
- version: "0.4"
53
+ - !ruby/object:Gem::Version
54
+ version: '0.4'
94
55
  type: :development
95
- version_requirements: *id005
96
- - !ruby/object:Gem::Dependency
97
- name: yard
98
56
  prerelease: false
99
- requirement: &id006 !ruby/object:Gem::Requirement
57
+ version_requirements: *2157621640
58
+ - !ruby/object:Gem::Dependency
59
+ name: yard
60
+ requirement: &2157621180 !ruby/object:Gem::Requirement
100
61
  none: false
101
- requirements:
62
+ requirements:
102
63
  - - ~>
103
- - !ruby/object:Gem::Version
104
- hash: 7
105
- segments:
106
- - 0
107
- - 6
108
- version: "0.6"
64
+ - !ruby/object:Gem::Version
65
+ version: '0.6'
109
66
  type: :development
110
- version_requirements: *id006
111
- - !ruby/object:Gem::Dependency
112
- name: rest-client
113
67
  prerelease: false
114
- requirement: &id007 !ruby/object:Gem::Requirement
68
+ version_requirements: *2157621180
69
+ - !ruby/object:Gem::Dependency
70
+ name: rest-client
71
+ requirement: &2157620720 !ruby/object:Gem::Requirement
115
72
  none: false
116
- requirements:
73
+ requirements:
117
74
  - - ~>
118
- - !ruby/object:Gem::Version
119
- hash: 13
120
- segments:
121
- - 1
122
- - 6
123
- - 1
124
- version: 1.6.1
75
+ - !ruby/object:Gem::Version
76
+ version: '1.6'
125
77
  type: :runtime
126
- version_requirements: *id007
127
- - !ruby/object:Gem::Dependency
128
- name: hashie
129
78
  prerelease: false
130
- requirement: &id008 !ruby/object:Gem::Requirement
79
+ version_requirements: *2157620720
80
+ - !ruby/object:Gem::Dependency
81
+ name: hashie
82
+ requirement: &2157620260 !ruby/object:Gem::Requirement
131
83
  none: false
132
- requirements:
84
+ requirements:
133
85
  - - ~>
134
- - !ruby/object:Gem::Version
135
- hash: 23
136
- segments:
137
- - 1
138
- - 0
139
- - 0
140
- version: 1.0.0
86
+ - !ruby/object:Gem::Version
87
+ version: '1.0'
141
88
  type: :runtime
142
- version_requirements: *id008
143
- - !ruby/object:Gem::Dependency
144
- name: activesupport
145
89
  prerelease: false
146
- requirement: &id009 !ruby/object:Gem::Requirement
90
+ version_requirements: *2157620260
91
+ - !ruby/object:Gem::Dependency
92
+ name: activesupport
93
+ requirement: &2157619800 !ruby/object:Gem::Requirement
147
94
  none: false
148
- requirements:
95
+ requirements:
149
96
  - - ~>
150
- - !ruby/object:Gem::Version
151
- hash: 7
152
- segments:
153
- - 3
154
- - 0
155
- - 0
156
- version: 3.0.0
97
+ - !ruby/object:Gem::Version
98
+ version: '3'
157
99
  type: :runtime
158
- version_requirements: *id009
159
- - !ruby/object:Gem::Dependency
160
- name: i18n
161
100
  prerelease: false
162
- requirement: &id010 !ruby/object:Gem::Requirement
101
+ version_requirements: *2157619800
102
+ - !ruby/object:Gem::Dependency
103
+ name: i18n
104
+ requirement: &2157619340 !ruby/object:Gem::Requirement
163
105
  none: false
164
- requirements:
106
+ requirements:
165
107
  - - ~>
166
- - !ruby/object:Gem::Version
167
- hash: 1
168
- segments:
169
- - 0
170
- - 5
171
- version: "0.5"
108
+ - !ruby/object:Gem::Version
109
+ version: '0.5'
172
110
  type: :runtime
173
- version_requirements: *id010
111
+ prerelease: false
112
+ version_requirements: *2157619340
174
113
  description: Simple wrapper for the Goodreads API
175
- email:
114
+ email:
176
115
  - dan.sosedoff@gmail.com
177
116
  executables: []
178
-
179
117
  extensions: []
180
-
181
118
  extra_rdoc_files: []
182
-
183
- files:
119
+ files:
184
120
  - .gitignore
185
121
  - .rspec
122
+ - .travis.yml
186
123
  - Gemfile
187
- - README.rdoc
124
+ - README.md
188
125
  - Rakefile
189
126
  - goodreads.gemspec
190
127
  - lib/goodreads.rb
191
128
  - lib/goodreads/client.rb
192
- - lib/goodreads/goodreads.rb
129
+ - lib/goodreads/client/authors.rb
130
+ - lib/goodreads/client/books.rb
131
+ - lib/goodreads/client/reviews.rb
132
+ - lib/goodreads/client/users.rb
133
+ - lib/goodreads/errors.rb
134
+ - lib/goodreads/request.rb
193
135
  - lib/goodreads/version.rb
194
136
  - spec/authentication_spec.rb
195
137
  - spec/client_spec.rb
@@ -199,44 +141,33 @@ files:
199
141
  - spec/fixtures/review.xml
200
142
  - spec/fixtures/search_books_by_name.xml
201
143
  - spec/fixtures/user.xml
144
+ - spec/goodreads_spec.rb
202
145
  - spec/spec_helper.rb
203
- has_rdoc: true
204
146
  homepage: http://github.com/sosedoff/goodreads
205
147
  licenses: []
206
-
207
148
  post_install_message:
208
149
  rdoc_options: []
209
-
210
- require_paths:
150
+ require_paths:
211
151
  - lib
212
- required_ruby_version: !ruby/object:Gem::Requirement
152
+ required_ruby_version: !ruby/object:Gem::Requirement
213
153
  none: false
214
- requirements:
215
- - - ">="
216
- - !ruby/object:Gem::Version
217
- hash: 3
218
- segments:
219
- - 0
220
- version: "0"
221
- required_rubygems_version: !ruby/object:Gem::Requirement
154
+ requirements:
155
+ - - ! '>='
156
+ - !ruby/object:Gem::Version
157
+ version: '0'
158
+ required_rubygems_version: !ruby/object:Gem::Requirement
222
159
  none: false
223
- requirements:
224
- - - ">="
225
- - !ruby/object:Gem::Version
226
- hash: 23
227
- segments:
228
- - 1
229
- - 3
230
- - 6
231
- version: 1.3.6
160
+ requirements:
161
+ - - ! '>='
162
+ - !ruby/object:Gem::Version
163
+ version: '0'
232
164
  requirements: []
233
-
234
165
  rubyforge_project:
235
- rubygems_version: 1.6.2
166
+ rubygems_version: 1.8.10
236
167
  signing_key:
237
168
  specification_version: 3
238
169
  summary: Goodreads API wrapper
239
- test_files:
170
+ test_files:
240
171
  - spec/authentication_spec.rb
241
172
  - spec/client_spec.rb
242
173
  - spec/fixtures/author.xml
@@ -245,4 +176,5 @@ test_files:
245
176
  - spec/fixtures/review.xml
246
177
  - spec/fixtures/search_books_by_name.xml
247
178
  - spec/fixtures/user.xml
179
+ - spec/goodreads_spec.rb
248
180
  - spec/spec_helper.rb
@@ -1,66 +0,0 @@
1
- = Goodreads -- simple client for Goodreads.com API
2
-
3
- A simple API client to pull book information and reviews from Goodreads.com.
4
- Wrapper uses XML feed and transforms it into the object model.
5
-
6
- * Main page: http://github.com/sosedoff/goodreads
7
- * Goodreads API: http://goodreads.com/api
8
-
9
- == Getting Started
10
-
11
- First, you need to provide your API token
12
-
13
- Goodreads.configure('API_TOKEN')
14
-
15
- client = Goodreads::Client.new
16
-
17
- == Usage
18
-
19
- === Lookup books
20
-
21
- Find a book by ISBN:
22
-
23
- book = client.book_by_isbn('ISBN')
24
-
25
- Find a book by Goodreads ID:
26
-
27
- book = client.book('id')
28
-
29
- Find a book by title:
30
-
31
- book = client.book_by_title('Book title')
32
-
33
- Search for books (by title, isbn, genre)
34
-
35
- search = client.search_books('Your search query')
36
- search.results.work.each do |book|
37
- book.id # => book ID
38
- book.title # => book title
39
- end
40
-
41
- === Pull recent reviews
42
-
43
- client.recent_reviews.each do |r|
44
- r.id # => review id
45
- r.book.title # => review book title
46
- r.body # => review message
47
- r.user.name # => review user name
48
- end
49
-
50
- === Get review Details
51
-
52
- review = client.review('id')
53
- review.id # => review ID
54
- review.user # => review user information
55
- review.book # => review book information
56
- review.reting # => review rating
57
-
58
- == Limitation
59
-
60
- * According to Goodreads API there is a limit of 60 RPM (requests per minute)
61
- * Provided data cannot be stored for any usage
62
- * Please check original documentation for additional object fields and properties
63
-
64
- == Authors
65
-
66
- * Dan Sosedoff [http://github.com/sosedoff]
@@ -1,12 +0,0 @@
1
- module Goodreads
2
- API_URL = 'http://www.goodreads.com'
3
- API_FORMAT = 'xml'
4
-
5
- class Error < StandardError; end
6
- class Unauthorized < Error ; end
7
- class NotFound < Error ; end
8
-
9
- def self.configure(api_key)
10
- Goodreads::Client.configure({:api_key => api_key})
11
- end
12
- end