goodreads 0.2.1 → 0.2.2
Sign up to get free protection for your applications and to get access to all the features.
- data/.travis.yml +1 -1
- data/Gemfile +2 -3
- data/README.md +111 -48
- data/examples/oauth.md +57 -0
- data/goodreads.gemspec +6 -6
- data/lib/goodreads/client/authors.rb +8 -0
- data/lib/goodreads/client/friends.rb +12 -0
- data/lib/goodreads/client/groups.rb +15 -0
- data/lib/goodreads/client.rb +10 -6
- data/lib/goodreads/request.rb +16 -11
- data/lib/goodreads/version.rb +1 -1
- data/spec/client_spec.rb +265 -151
- data/spec/fixtures/author.xml +1 -1
- data/spec/fixtures/author_by_name.xml +17 -0
- data/spec/fixtures/friends.xml +30 -0
- data/spec/fixtures/group.xml +364 -0
- data/spec/fixtures/group_list.xml +422 -0
- data/spec/goodreads_spec.rb +14 -14
- metadata +102 -98
data/.travis.yml
CHANGED
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,18 +1,16 @@
|
|
1
|
-
# Goodreads
|
1
|
+
# Goodreads [![Build Status](https://secure.travis-ci.org/sosedoff/goodreads.png)](http://travis-ci.org/sosedoff/goodreads)
|
2
2
|
|
3
|
-
Ruby
|
4
|
-
|
5
|
-
[![Build Status](https://secure.travis-ci.org/sosedoff/goodreads.png)](http://travis-ci.org/sosedoff/goodreads)
|
3
|
+
Ruby wrapper to communicate with Goodreads API.
|
6
4
|
|
7
5
|
## Installation
|
8
6
|
|
9
|
-
|
7
|
+
Install gem with rubygems:
|
10
8
|
|
11
9
|
```
|
12
10
|
gem install goodreads
|
13
11
|
```
|
14
12
|
|
15
|
-
Or
|
13
|
+
Or manually:
|
16
14
|
|
17
15
|
```
|
18
16
|
rake install
|
@@ -20,28 +18,30 @@ rake install
|
|
20
18
|
|
21
19
|
## Getting Started
|
22
20
|
|
23
|
-
|
21
|
+
Before using Goodreads API you must create a new application. Visit [signup form](http://www.goodreads.com/api/keys) for details.
|
24
22
|
|
25
23
|
Setup client:
|
26
24
|
|
27
|
-
```ruby
|
28
|
-
client = Goodreads::Client.new(:api_key => '
|
29
|
-
|
30
|
-
# or using a shortcut
|
31
|
-
client = Goodreads.new(:api_key => 'YOUR_KEY')
|
25
|
+
``` ruby
|
26
|
+
client = Goodreads::Client.new(:api_key => 'KEY', :api_secret => 'SECRET')
|
27
|
+
client = Goodreads.new(:api_key => 'KEY') # short version
|
32
28
|
```
|
33
29
|
|
34
30
|
### Global configuration
|
35
31
|
|
36
|
-
|
32
|
+
You can define client credentials on global level. Just create an initializer file (if using rails) under
|
33
|
+
`config/initializers`:
|
37
34
|
|
38
|
-
```ruby
|
39
|
-
Goodreads.configure(
|
35
|
+
``` ruby
|
36
|
+
Goodreads.configure(
|
37
|
+
:api_key => 'KEY',
|
38
|
+
:api_secret => 'SECRET'
|
39
|
+
)
|
40
40
|
```
|
41
41
|
|
42
|
-
Get
|
42
|
+
Get global configuration:
|
43
43
|
|
44
|
-
```ruby
|
44
|
+
``` ruby
|
45
45
|
Goodreads.configuration # => {:api_key => 'YOUR_KEY'}
|
46
46
|
```
|
47
47
|
|
@@ -55,32 +55,55 @@ Goodreads.reset_configuration
|
|
55
55
|
|
56
56
|
### Lookup books
|
57
57
|
|
58
|
-
|
58
|
+
You can lookup a book by ISBN, ID or Title:
|
59
59
|
|
60
60
|
```ruby
|
61
|
-
|
61
|
+
client.book('id')
|
62
|
+
client.book_by_isbn('ISBN')
|
63
|
+
client.book_by_title('Book title')
|
62
64
|
```
|
63
|
-
|
64
|
-
|
65
|
+
|
66
|
+
Search for books (by title, isbn, genre):
|
65
67
|
|
66
68
|
```ruby
|
67
|
-
|
69
|
+
search = client.search_books('The Lord Of The Rings')
|
70
|
+
|
71
|
+
search.results.work.each do |book|
|
72
|
+
book.id # => book id
|
73
|
+
book.title # => book title
|
74
|
+
end
|
68
75
|
```
|
69
|
-
|
70
|
-
|
76
|
+
|
77
|
+
### Authors
|
78
|
+
|
79
|
+
Look up an author by their Goodreads Author ID:
|
71
80
|
|
72
81
|
```ruby
|
73
|
-
|
82
|
+
author = client.author('id')
|
83
|
+
|
84
|
+
author.id # => author id
|
85
|
+
author.name # => author's name
|
86
|
+
author.link # => link to author's Goodreads page
|
87
|
+
author.fans_count # => number of fans author has on Goodreads
|
88
|
+
author.image_url # => link to image of the author
|
89
|
+
author.small_image_url # => link to smaller of the author
|
90
|
+
author.about # => description of the author
|
91
|
+
author.influences # => list of links to author's influences
|
92
|
+
author.works_count # => number of works by the author in Goodreads
|
93
|
+
author.gender # => author's gender
|
94
|
+
author.hometown # => author's hometown
|
95
|
+
author.born_at # => author's birthdate
|
96
|
+
author.died_at # => date of author's death
|
74
97
|
```
|
75
|
-
|
76
|
-
|
98
|
+
|
99
|
+
Look up an author by name:
|
77
100
|
|
78
101
|
```ruby
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
102
|
+
author = client.author_by_name('Author Name')
|
103
|
+
|
104
|
+
author.id # => author id
|
105
|
+
author.name # => author name
|
106
|
+
author.link # => link to author's Goodreads page
|
84
107
|
```
|
85
108
|
|
86
109
|
### Reviews
|
@@ -95,15 +118,16 @@ client.recent_reviews.each do |r|
|
|
95
118
|
r.user.name # => review user name
|
96
119
|
end
|
97
120
|
```
|
98
|
-
|
121
|
+
|
99
122
|
Get review details:
|
100
123
|
|
101
124
|
```ruby
|
102
125
|
review = client.review('id')
|
103
|
-
|
104
|
-
review.
|
105
|
-
review.
|
106
|
-
review.
|
126
|
+
|
127
|
+
review.id # => review id
|
128
|
+
review.user # => user information
|
129
|
+
review.book # => uook information
|
130
|
+
review.rating # => user rating
|
107
131
|
```
|
108
132
|
|
109
133
|
### Shelves
|
@@ -112,37 +136,76 @@ Get the books on a user's shelf:
|
|
112
136
|
|
113
137
|
```ruby
|
114
138
|
shelf = client.shelf(user_id, shelf_name)
|
139
|
+
|
115
140
|
shelf.books # array of books on this shelf
|
116
141
|
shelf.start # start index of this page of paginated results
|
117
142
|
shelf.end # end index of this page of paginated results
|
118
143
|
shelf.total # total number of books on this shelf
|
119
144
|
```
|
120
145
|
|
121
|
-
###
|
146
|
+
### Groups
|
122
147
|
|
123
|
-
Get
|
148
|
+
Get group details:
|
124
149
|
|
125
150
|
```ruby
|
126
|
-
|
127
|
-
|
151
|
+
group = client.group('id')
|
152
|
+
|
153
|
+
group.id # => group id
|
154
|
+
group.title # => group title
|
155
|
+
group.access # => group's access settings
|
156
|
+
# => (e.g., public or private)
|
157
|
+
group.group_users_count # => number of users in the group
|
128
158
|
```
|
129
159
|
|
130
|
-
|
160
|
+
List the groups a given user is a member of:
|
131
161
|
|
132
|
-
|
162
|
+
```ruby
|
163
|
+
group_list = client.group_list('user_id', 'sort')
|
164
|
+
|
165
|
+
group_list.total # => total number of groups
|
166
|
+
group_list.group.count # => number of groups returned in the request
|
167
|
+
|
168
|
+
# Loop through the list to get details for each of the groups.
|
169
|
+
|
170
|
+
group_list.group.each do |g|
|
171
|
+
g.id # => group id
|
172
|
+
g.access # => access settings (private, public)
|
173
|
+
g.users_count # => number of members
|
174
|
+
g.title # => title
|
175
|
+
g.image_url # => url of the group's image
|
176
|
+
g.last_activity_at # => date and time of the group's last activity
|
177
|
+
end
|
178
|
+
```
|
133
179
|
|
134
|
-
|
180
|
+
The `sort` parameter is optional, and defaults to `my_activity`. For other sorting options, [see here](http://www.goodreads.com/api#group.list).
|
181
|
+
|
182
|
+
### OAuth
|
183
|
+
|
184
|
+
For API calls requiring permission, such as write operations or browsing friends, see our [OAuth tutorial](examples/oauth.md).
|
185
|
+
|
186
|
+
## Testing
|
187
|
+
|
188
|
+
To run the test suite:
|
189
|
+
|
190
|
+
```
|
191
|
+
rake test
|
192
|
+
```
|
193
|
+
|
194
|
+
## Contributions
|
135
195
|
|
136
|
-
|
196
|
+
You're welcome to submit patches and new features.
|
137
197
|
|
138
|
-
|
198
|
+
- Create a new branch for your feature of bugfix
|
199
|
+
- Add tests so it does not break any existing code
|
200
|
+
- Open a new pull request
|
201
|
+
- Check official [API documentation](http://www.goodreads.com/api)
|
139
202
|
|
140
203
|
## License
|
141
204
|
|
142
|
-
Copyright © 2011-
|
205
|
+
Copyright © 2011-2013 Dan Sosedoff.
|
143
206
|
|
144
207
|
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:
|
145
208
|
|
146
209
|
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
147
210
|
|
148
|
-
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.
|
211
|
+
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/examples/oauth.md
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
# Authorizing Goodreads via OAuth
|
2
|
+
|
3
|
+
For services requiring permission, such as write operations or browsing friends, the client must be authorized through OAuth.
|
4
|
+
|
5
|
+
## Request Tokens vs. Access Tokens
|
6
|
+
|
7
|
+
First, get an OAuth *request* token:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
request_token = OAuth::Consumer.new(
|
11
|
+
Goodreads.configuration[:api_key],
|
12
|
+
Goodreads.configuration[:api_secret],
|
13
|
+
:site => 'http://www.goodreads.com'
|
14
|
+
).get_request_token
|
15
|
+
```
|
16
|
+
|
17
|
+
Next, authorize by opening the authorization URL in a browser:
|
18
|
+
|
19
|
+
```ruby
|
20
|
+
request_token.authorize_url
|
21
|
+
```
|
22
|
+
|
23
|
+
Then request an OAuth *access* token:
|
24
|
+
|
25
|
+
```ruby
|
26
|
+
access_token = request_token.get_access_token
|
27
|
+
```
|
28
|
+
|
29
|
+
Finally, initialize a Goodreads client with it:
|
30
|
+
|
31
|
+
```ruby
|
32
|
+
goodreads_client = Goodreads.new :oauth_token => access_token
|
33
|
+
```
|
34
|
+
|
35
|
+
For more info, see the [Goodreads documentation](http://www.goodreads.com/api/oauth_example).
|
36
|
+
|
37
|
+
## User ID
|
38
|
+
|
39
|
+
Get the ID of the user who authorized via OAuth:
|
40
|
+
|
41
|
+
```ruby
|
42
|
+
goodreads_client.user_id
|
43
|
+
```
|
44
|
+
|
45
|
+
## Friends
|
46
|
+
|
47
|
+
Get the friend details for a user:
|
48
|
+
|
49
|
+
```ruby
|
50
|
+
friends_hash = goodreads_client.friends [user_id]
|
51
|
+
```
|
52
|
+
|
53
|
+
Get a list of their names:
|
54
|
+
|
55
|
+
```ruby
|
56
|
+
friends_hash.user.map{ |u| u.name }
|
57
|
+
```
|
data/goodreads.gemspec
CHANGED
@@ -9,17 +9,17 @@ 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.
|
13
|
-
s.add_development_dependency 'rake', '~> 0.
|
14
|
-
s.add_development_dependency 'rspec', '~> 2.
|
15
|
-
s.add_development_dependency 'simplecov', '~> 0.
|
12
|
+
s.add_development_dependency 'webmock', '~> 1.11'
|
13
|
+
s.add_development_dependency 'rake', '~> 0.9'
|
14
|
+
s.add_development_dependency 'rspec', '~> 2.12'
|
15
|
+
s.add_development_dependency 'simplecov', '~> 0.7'
|
16
16
|
s.add_development_dependency 'yard', '~> 0.6'
|
17
17
|
|
18
18
|
s.add_runtime_dependency 'rest-client', '~> 1.6'
|
19
|
-
s.add_runtime_dependency 'hashie', '~>
|
19
|
+
s.add_runtime_dependency 'hashie', '~> 2.0'
|
20
20
|
s.add_runtime_dependency 'activesupport', '~> 3'
|
21
21
|
s.add_runtime_dependency 'i18n', '~> 0.5'
|
22
|
-
s.add_runtime_dependency 'oauth',
|
22
|
+
s.add_runtime_dependency 'oauth', '~> 0.4'
|
23
23
|
|
24
24
|
s.files = `git ls-files`.split("\n")
|
25
25
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
@@ -7,5 +7,13 @@ module Goodreads
|
|
7
7
|
data = request('/author/show', params)
|
8
8
|
Hashie::Mash.new(data['author'])
|
9
9
|
end
|
10
|
+
|
11
|
+
# Search for an author by name
|
12
|
+
#
|
13
|
+
def author_by_name(name, params={})
|
14
|
+
params[:id] = name
|
15
|
+
data = request('/api/author_url', params)
|
16
|
+
Hashie::Mash.new(data['author'])
|
17
|
+
end
|
10
18
|
end
|
11
19
|
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Goodreads
|
2
|
+
module Groups
|
3
|
+
# Get group details
|
4
|
+
def group(group_id)
|
5
|
+
data = request('/group/show', :id => group_id)
|
6
|
+
Hashie::Mash.new(data['group'])
|
7
|
+
end
|
8
|
+
|
9
|
+
# Get list of groups a given user is a member of
|
10
|
+
def group_list(user_id, sort='my_activity')
|
11
|
+
data = request('/group/list', :id => user_id, :sort => sort)
|
12
|
+
Hashie::Mash.new(data['groups']['list'])
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
data/lib/goodreads/client.rb
CHANGED
@@ -5,6 +5,8 @@ require 'goodreads/client/authors'
|
|
5
5
|
require 'goodreads/client/users'
|
6
6
|
require 'goodreads/client/shelves'
|
7
7
|
require 'goodreads/client/authorized'
|
8
|
+
require 'goodreads/client/groups'
|
9
|
+
require 'goodreads/client/friends'
|
8
10
|
|
9
11
|
module Goodreads
|
10
12
|
class Client
|
@@ -15,22 +17,24 @@ module Goodreads
|
|
15
17
|
include Goodreads::Users
|
16
18
|
include Goodreads::Shelves
|
17
19
|
include Goodreads::Authorized
|
18
|
-
|
20
|
+
include Goodreads::Groups
|
21
|
+
include Goodreads::Friends
|
22
|
+
|
19
23
|
attr_reader :api_key, :api_secret, :oauth_token
|
20
|
-
|
24
|
+
|
21
25
|
# Initialize a Goodreads::Client instance
|
22
26
|
#
|
23
27
|
# options[:api_key] - Account API key
|
24
28
|
# options[:api_secret] - Account API secret
|
25
|
-
# options[:oauth_token] - OAuth token (optional, required for some calls)
|
29
|
+
# options[:oauth_token] - OAuth access token (optional, required for some calls)
|
26
30
|
#
|
27
31
|
def initialize(options={})
|
28
32
|
unless options.kind_of?(Hash)
|
29
33
|
raise ArgumentError, "Options hash required."
|
30
34
|
end
|
31
|
-
|
32
|
-
@api_key = options[:api_key]
|
33
|
-
@api_secret = options[:api_secret]
|
35
|
+
|
36
|
+
@api_key = options[:api_key] || Goodreads.configuration[:api_key]
|
37
|
+
@api_secret = options[:api_secret] || Goodreads.configuration[:api_secret]
|
34
38
|
@oauth_token = options[:oauth_token]
|
35
39
|
end
|
36
40
|
end
|
data/lib/goodreads/request.rb
CHANGED
@@ -6,9 +6,9 @@ module Goodreads
|
|
6
6
|
module Request
|
7
7
|
API_URL = 'http://www.goodreads.com'
|
8
8
|
API_FORMAT = 'xml'
|
9
|
-
|
9
|
+
|
10
10
|
protected
|
11
|
-
|
11
|
+
|
12
12
|
# Perform an API request
|
13
13
|
#
|
14
14
|
# path - Request path
|
@@ -16,14 +16,14 @@ module Goodreads
|
|
16
16
|
#
|
17
17
|
def request(path, params={})
|
18
18
|
token = api_key || Goodreads.configuration[:api_key]
|
19
|
-
|
19
|
+
|
20
20
|
if token.nil?
|
21
21
|
raise Goodreads::ConfigurationError, 'API key required.'
|
22
22
|
end
|
23
|
-
|
23
|
+
|
24
24
|
params.merge!(:format => API_FORMAT, :key => token)
|
25
25
|
url = "#{API_URL}#{path}"
|
26
|
-
|
26
|
+
|
27
27
|
resp = RestClient.get(url, :params => params) do |response, request, result, &block|
|
28
28
|
case response.code
|
29
29
|
when 200
|
@@ -38,15 +38,21 @@ module Goodreads
|
|
38
38
|
parse(resp)
|
39
39
|
end
|
40
40
|
|
41
|
+
# Perform an OAuth API request. Goodreads must have been initialized with a valid OAuth access token.
|
42
|
+
#
|
43
|
+
# path - Request path
|
44
|
+
# params - Parameters hash
|
45
|
+
#
|
41
46
|
def oauth_request(path, params=nil)
|
42
47
|
raise 'OAuth access token required!' unless @oauth_token
|
43
48
|
path = "#{path}?#{params.map{|k,v|"#{k}=#{v}"}.join('&')}" if params
|
44
|
-
resp = @oauth_token.get(path)
|
49
|
+
resp = @oauth_token.get(path, {'Accept'=>'application/xml'})
|
50
|
+
|
45
51
|
case resp
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
52
|
+
when Net::HTTPUnauthorized
|
53
|
+
raise Goodreads::Unauthorized
|
54
|
+
when Net::HTTPNotFound
|
55
|
+
raise Goodreads::NotFound
|
50
56
|
end
|
51
57
|
|
52
58
|
parse(resp)
|
@@ -57,6 +63,5 @@ module Goodreads
|
|
57
63
|
hash.delete('Request')
|
58
64
|
hash
|
59
65
|
end
|
60
|
-
|
61
66
|
end
|
62
67
|
end
|
data/lib/goodreads/version.rb
CHANGED