goodreads 0.5.0 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.travis.yml +2 -2
- data/LICENSE +1 -1
- data/README.md +9 -2
- data/goodreads.gemspec +2 -2
- data/lib/goodreads/client.rb +11 -2
- data/lib/goodreads/client/friends.rb +2 -2
- data/lib/goodreads/client/reviews.rb +56 -0
- data/lib/goodreads/client/shelves.rb +68 -0
- data/lib/goodreads/errors.rb +2 -0
- data/lib/goodreads/request.rb +41 -6
- data/lib/goodreads/version.rb +1 -1
- data/spec/authentication_spec.rb +24 -11
- data/spec/client_spec.rb +185 -1
- data/spec/fixtures/review_create.xml +102 -0
- data/spec/fixtures/review_show_by_user_and_book.xml +144 -0
- data/spec/fixtures/review_update.xml +104 -0
- data/spec/fixtures/shelf_add_to_shelf.xml +24 -0
- data/spec/fixtures/shelf_list.xml +51 -0
- data/spec/goodreads_spec.rb +1 -1
- metadata +28 -13
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 6ea0e771d6f0bb4fe73d87bdc54b96f97c26e58e2dca54c0d956f73263acf557
|
4
|
+
data.tar.gz: 78e582d52e5ddfee249448c3f5bef36e8f56e165c5d241e3f8cb4c9633d6730a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 70521658f5c0df28b749559f336ed4c6e418257914fa7b3e4572e88166a1347eca0197422ba8c48bbefc4e9c55ca57524aeee83ae6f2b94f41b1846e90d55f70
|
7
|
+
data.tar.gz: d309c6a3874443910a06b7d156a87f29764be70ac6cb79bad8692b0b1436958b31730f3673bf473f4be569b4dda8a321459d53a30e4e0fad098058f9e5734925
|
data/.travis.yml
CHANGED
data/LICENSE
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
The MIT License (MIT)
|
2
2
|
|
3
|
-
Copyright (c) 2011-
|
3
|
+
Copyright (c) 2011-2018 Dan Sosedoff <dan.sosedoff@gmail.com>
|
4
4
|
|
5
5
|
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
6
6
|
this software and associated documentation files (the "Software"), to deal in
|
data/README.md
CHANGED
@@ -170,7 +170,6 @@ group_list.total # => total number of groups
|
|
170
170
|
group_list.group.count # => number of groups returned in the request
|
171
171
|
|
172
172
|
# Loop through the list to get details for each of the groups.
|
173
|
-
|
174
173
|
group_list.group.each do |g|
|
175
174
|
g.id # => group id
|
176
175
|
g.access # => access settings (private, public)
|
@@ -184,6 +183,14 @@ end
|
|
184
183
|
The `sort` parameter is optional, and defaults to `my_activity`.
|
185
184
|
For other sorting options, [see here](http://www.goodreads.com/api#group.list).
|
186
185
|
|
186
|
+
### Pagination
|
187
|
+
|
188
|
+
To retrieve results for a particular page use the `page` param when making calls:
|
189
|
+
|
190
|
+
```ruby
|
191
|
+
books = client.search_books("Term", page: 2)
|
192
|
+
```
|
193
|
+
|
187
194
|
### OAuth
|
188
195
|
|
189
196
|
For API calls requiring permission, such as write operations or browsing friends,
|
@@ -210,4 +217,4 @@ You're welcome to submit patches and new features.
|
|
210
217
|
|
211
218
|
The MIT License (MIT)
|
212
219
|
|
213
|
-
Copyright (c) 2011-
|
220
|
+
Copyright (c) 2011-2018 Dan Sosedoff, <dan.sosedoff@gmail.com>
|
data/goodreads.gemspec
CHANGED
@@ -14,12 +14,12 @@ Gem::Specification.new do |spec|
|
|
14
14
|
spec.add_development_dependency "rake", "~> 10"
|
15
15
|
spec.add_development_dependency "rspec", "~> 2.12"
|
16
16
|
spec.add_development_dependency "simplecov", "~> 0.7"
|
17
|
-
spec.add_development_dependency "yard", "~> 0.
|
17
|
+
spec.add_development_dependency "yard", "~> 0.9"
|
18
18
|
|
19
19
|
spec.add_runtime_dependency "rest-client", "~> 2.0"
|
20
20
|
spec.add_runtime_dependency "hashie", "~> 2.0"
|
21
21
|
spec.add_runtime_dependency "activesupport", ">= 3.0"
|
22
|
-
spec.add_runtime_dependency "i18n", "
|
22
|
+
spec.add_runtime_dependency "i18n", ">= 0.6", "< 2"
|
23
23
|
spec.add_runtime_dependency "oauth", "~> 0.4"
|
24
24
|
|
25
25
|
spec.files = `git ls-files`.split("\n")
|
data/lib/goodreads/client.rb
CHANGED
@@ -31,9 +31,18 @@ module Goodreads
|
|
31
31
|
def initialize(options = {})
|
32
32
|
fail(ArgumentError, "Options hash required.") unless options.is_a?(Hash)
|
33
33
|
|
34
|
-
@api_key
|
35
|
-
@api_secret
|
34
|
+
@api_key = options[:api_key] || Goodreads.configuration[:api_key]
|
35
|
+
@api_secret = options[:api_secret] || Goodreads.configuration[:api_secret]
|
36
36
|
@oauth_token = options[:oauth_token]
|
37
37
|
end
|
38
|
+
|
39
|
+
# Return if this client is configured with OAuth credentials
|
40
|
+
# for a single user
|
41
|
+
#
|
42
|
+
# False when client is instantiated with an api_key and secret,
|
43
|
+
# true when client is instantiated with an oauth_token
|
44
|
+
def oauth_configured?
|
45
|
+
!oauth_token.nil?
|
46
|
+
end
|
38
47
|
end
|
39
48
|
end
|
@@ -4,8 +4,8 @@ module Goodreads
|
|
4
4
|
#
|
5
5
|
# user_id - integer or string
|
6
6
|
#
|
7
|
-
def friends(user_id)
|
8
|
-
data = oauth_request("/friend/user/#{user_id}")
|
7
|
+
def friends(user_id, options={})
|
8
|
+
data = oauth_request("/friend/user/#{user_id}", options)
|
9
9
|
Hashie::Mash.new(data["friends"])
|
10
10
|
end
|
11
11
|
end
|
@@ -31,5 +31,61 @@ module Goodreads
|
|
31
31
|
[]
|
32
32
|
end
|
33
33
|
end
|
34
|
+
|
35
|
+
# Get a user's review for a given book
|
36
|
+
def user_review(user_id, book_id, params = {})
|
37
|
+
data = request('/review/show_by_user_and_book.xml', params.merge(v: "2", user_id: user_id, book_id: book_id))
|
38
|
+
Hashie::Mash.new(data["review"])
|
39
|
+
end
|
40
|
+
|
41
|
+
# Add review for a book
|
42
|
+
#
|
43
|
+
# Params can include :review, :rating, and :shelf
|
44
|
+
#
|
45
|
+
# review: text of the review (optional)
|
46
|
+
# rating: rating (0-5) (optional, default is 0 (no rating))
|
47
|
+
# shelf: Name of shelf to add book to (optional, must exist, see: shelves.list)
|
48
|
+
#
|
49
|
+
# Note that Goodreads API documentation says that this endpoint accepts
|
50
|
+
# the read_at parameter but it does not appear to work as of 2018-06.
|
51
|
+
def create_review(book_id, params = {})
|
52
|
+
params = params.merge(book_id: book_id, v: "2")
|
53
|
+
|
54
|
+
params[:read_at] = params[:read_at].strftime('%Y-%m-%d') if params[:read_at].is_a?(Time)
|
55
|
+
|
56
|
+
params[:'review[review]'] = params.delete(:review) if params[:review]
|
57
|
+
params[:'review[rating]'] = params.delete(:rating) if params[:rating]
|
58
|
+
params[:'review[read_at]'] = params.delete(:read_at) if params[:read_at]
|
59
|
+
|
60
|
+
data = oauth_request_method(:post, '/review.xml', params)
|
61
|
+
|
62
|
+
Hashie::Mash.new(data["review"])
|
63
|
+
end
|
64
|
+
|
65
|
+
# Edit review for a book
|
66
|
+
#
|
67
|
+
# Params can include :review, :rating, :read_at and :shelf, and :finished
|
68
|
+
#
|
69
|
+
# review: text of the review (optional)
|
70
|
+
# rating: rating (0-5) (optional, default is 0 (no rating))
|
71
|
+
# shelf: Name of shelf to add book to (optional, must exist, see: shelves.list)
|
72
|
+
# read_at: Time object or String in YYYY-MM-DD format (optional)
|
73
|
+
# finished: true to mark finished reading (optional)
|
74
|
+
# shelf: Name of shelf to add book to (optional, must exist, see: shelves.list)
|
75
|
+
def edit_review(review_id, params = {})
|
76
|
+
params = params.merge(v: "2")
|
77
|
+
|
78
|
+
params[:read_at] = params[:read_at].strftime('%Y-%m-%d') if params[:read_at].is_a?(Time)
|
79
|
+
|
80
|
+
params[:'review[review]'] = params.delete(:review) if params[:review]
|
81
|
+
params[:'review[rating]'] = params.delete(:rating) if params[:rating]
|
82
|
+
params[:'review[read_at]'] = params.delete(:read_at) if params[:read_at]
|
83
|
+
|
84
|
+
# Documentation says that you should use HTTP PUT, but API returns
|
85
|
+
# 401 Unauthorized when PUT is used instead of POST
|
86
|
+
data = oauth_request_method(:post, "/review/#{review_id}.xml", params)
|
87
|
+
|
88
|
+
Hashie::Mash.new(data["review"])
|
89
|
+
end
|
34
90
|
end
|
35
91
|
end
|
@@ -1,5 +1,36 @@
|
|
1
1
|
module Goodreads
|
2
2
|
module Shelves
|
3
|
+
# Lists shelves for a user
|
4
|
+
def shelves(user_id, options = {})
|
5
|
+
options = options.merge(user_id: user_id, v: 2)
|
6
|
+
data = request("/shelf/list.xml", options)
|
7
|
+
shelves = data["shelves"]
|
8
|
+
|
9
|
+
shelves = data["shelves"]["user_shelf"].map do |s|
|
10
|
+
Hashie::Mash.new({
|
11
|
+
id: s["id"],
|
12
|
+
name: s["name"],
|
13
|
+
book_count: s["book_count"],
|
14
|
+
exclusive: s["exclusive_flag"],
|
15
|
+
description: s["description"],
|
16
|
+
sort: s["sort"],
|
17
|
+
order: s["order"],
|
18
|
+
per_page: s["per_page"],
|
19
|
+
display_fields: s["display_fields"],
|
20
|
+
featured: s["featured"],
|
21
|
+
recommend_for: s["recommend_for"],
|
22
|
+
sticky: s["sticky"],
|
23
|
+
})
|
24
|
+
end
|
25
|
+
|
26
|
+
Hashie::Mash.new(
|
27
|
+
start: data["shelves"]["start"].to_i,
|
28
|
+
end: data["shelves"]["end"].to_i,
|
29
|
+
total: data["shelves"]["total"].to_i,
|
30
|
+
shelves: shelves
|
31
|
+
)
|
32
|
+
end
|
33
|
+
|
3
34
|
# Get books from a user's shelf
|
4
35
|
def shelf(user_id, shelf_name, options = {})
|
5
36
|
options = options.merge(shelf: shelf_name, v: 2)
|
@@ -20,5 +51,42 @@ module Goodreads
|
|
20
51
|
books: books
|
21
52
|
)
|
22
53
|
end
|
54
|
+
|
55
|
+
# Add book to a user's shelf
|
56
|
+
#
|
57
|
+
# Returns the user's review for the book, which includes all its current shelves
|
58
|
+
def add_to_shelf(book_id, shelf_name, options = {})
|
59
|
+
options = options.merge(book_id: book_id, name: shelf_name, v: 2)
|
60
|
+
data = oauth_request_method(:post, "/shelf/add_to_shelf.xml", options)
|
61
|
+
|
62
|
+
# when a book is on a single shelf it is a single hash
|
63
|
+
shelves = data["my_review"]["shelves"]["shelf"]
|
64
|
+
shelves = [shelves] unless shelves.instance_of?(Array)
|
65
|
+
shelves = shelves.map do |s|
|
66
|
+
Hashie::Mash.new({
|
67
|
+
id: s["id"].to_i,
|
68
|
+
name: s["name"],
|
69
|
+
exclusive: s["exclusive"] == "true",
|
70
|
+
sortable: s["sortable"] == "true",
|
71
|
+
})
|
72
|
+
end
|
73
|
+
|
74
|
+
Hashie::Mash.new(
|
75
|
+
id: data["my_review"]["id"].to_i,
|
76
|
+
book_id: data["my_review"]["book_id"].to_i,
|
77
|
+
|
78
|
+
rating: data["my_review"]["rating"].to_i,
|
79
|
+
body: data["my_review"]["body"],
|
80
|
+
body_raw: data["my_review"]["body_raw"],
|
81
|
+
spoiler: data["my_review"]["spoiler_flag"] == "true",
|
82
|
+
|
83
|
+
shelves: shelves,
|
84
|
+
|
85
|
+
read_at: data["my_review"]["read_at"],
|
86
|
+
started_at: data["my_review"]["started_at"],
|
87
|
+
date_added: data["my_review"]["date_added"],
|
88
|
+
updated_at: data["my_review"]["updated_at"],
|
89
|
+
)
|
90
|
+
end
|
23
91
|
end
|
24
92
|
end
|
data/lib/goodreads/errors.rb
CHANGED
data/lib/goodreads/request.rb
CHANGED
@@ -9,12 +9,26 @@ module Goodreads
|
|
9
9
|
|
10
10
|
protected
|
11
11
|
|
12
|
-
# Perform an API request
|
12
|
+
# Perform an API request using API key or OAuth token
|
13
13
|
#
|
14
14
|
# path - Request path
|
15
15
|
# params - Parameters hash
|
16
16
|
#
|
17
|
+
# Will make a request with the configured API key (application
|
18
|
+
# authentication) or OAuth token (user authentication) if available.
|
17
19
|
def request(path, params = {})
|
20
|
+
if oauth_configured?
|
21
|
+
oauth_request(path, params)
|
22
|
+
else
|
23
|
+
http_request(path, params)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# Perform an API request using API key
|
28
|
+
#
|
29
|
+
# path - Request path
|
30
|
+
# params - Parameters hash
|
31
|
+
def http_request(path, params)
|
18
32
|
token = api_key || Goodreads.configuration[:api_key]
|
19
33
|
|
20
34
|
fail(Goodreads::ConfigurationError, "API key required.") if token.nil?
|
@@ -32,24 +46,45 @@ module Goodreads
|
|
32
46
|
fail(Goodreads::Forbidden)
|
33
47
|
when 404
|
34
48
|
fail(Goodreads::NotFound)
|
49
|
+
when 500..599
|
50
|
+
fail(Goodreads::ServerError.new(response.code))
|
51
|
+
else
|
52
|
+
fail(Goodreads::UnknownError.new(response.code))
|
35
53
|
end
|
36
54
|
end
|
37
55
|
|
38
56
|
parse(resp)
|
39
57
|
end
|
40
58
|
|
59
|
+
# Perform an OAuth API GET request. Goodreads must have been initialized with a valid OAuth access token.
|
60
|
+
#
|
61
|
+
# path - Request path
|
62
|
+
# params - Parameters hash
|
63
|
+
#
|
64
|
+
def oauth_request(path, params = {})
|
65
|
+
oauth_request_method(:get, path, params)
|
66
|
+
end
|
67
|
+
|
41
68
|
# Perform an OAuth API request. Goodreads must have been initialized with a valid OAuth access token.
|
42
69
|
#
|
70
|
+
# http_method - HTTP verb supported by OAuth gem (one of :get, :post, :delete, etc.)
|
43
71
|
# path - Request path
|
44
72
|
# params - Parameters hash
|
45
73
|
#
|
46
|
-
def
|
74
|
+
def oauth_request_method(http_method, path, params = {})
|
47
75
|
fail "OAuth access token required!" unless @oauth_token
|
48
|
-
|
49
|
-
|
50
|
-
|
76
|
+
|
77
|
+
headers = { "Accept" => "application/xml" }
|
78
|
+
|
79
|
+
resp = if http_method == :get || http_method == :delete
|
80
|
+
if params
|
81
|
+
url_params = params.map { |k, v| "#{k}=#{v}" }.join("&")
|
82
|
+
path = "#{path}?#{url_params}"
|
83
|
+
end
|
84
|
+
@oauth_token.request(http_method, path, headers)
|
85
|
+
else
|
86
|
+
@oauth_token.request(http_method, path, params || {}, headers)
|
51
87
|
end
|
52
|
-
resp = @oauth_token.get(path, "Accept" => "application/xml")
|
53
88
|
|
54
89
|
case resp
|
55
90
|
when Net::HTTPUnauthorized
|
data/lib/goodreads/version.rb
CHANGED
data/spec/authentication_spec.rb
CHANGED
@@ -1,24 +1,37 @@
|
|
1
1
|
require "spec_helper"
|
2
2
|
|
3
|
-
describe
|
3
|
+
describe Goodreads::Client do
|
4
4
|
before :each do
|
5
5
|
Goodreads.reset_configuration
|
6
6
|
end
|
7
7
|
|
8
|
-
|
9
|
-
|
8
|
+
let(:client) do
|
9
|
+
described_class.new(api_key: api_key)
|
10
|
+
end
|
11
|
+
|
12
|
+
context "API key is missing" do
|
13
|
+
let(:api_key) {}
|
10
14
|
|
11
|
-
|
12
|
-
|
15
|
+
it "throws an error" do
|
16
|
+
expect { client.book_by_isbn("0307463745") }
|
17
|
+
.to raise_error(Goodreads::ConfigurationError, "API key required.")
|
18
|
+
end
|
13
19
|
end
|
14
20
|
|
15
|
-
|
16
|
-
|
21
|
+
context "API key is invalid" do
|
22
|
+
let(:api_key) { "INVALID_KEY" }
|
23
|
+
|
24
|
+
before do
|
25
|
+
stub_request(:get, "https://www.goodreads.com/book/isbn?format=xml&isbn=1&key=INVALID_KEY")
|
26
|
+
.to_return(status: 401)
|
17
27
|
|
18
|
-
|
19
|
-
|
28
|
+
stub_request(:get, "https://www.goodreads.com/book/isbn?format=xml&isbn=2&key=INVALID_KEY")
|
29
|
+
.to_return(status: 403)
|
30
|
+
end
|
20
31
|
|
21
|
-
|
22
|
-
.to raise_error(Goodreads::Unauthorized)
|
32
|
+
it "throws errors" do
|
33
|
+
expect { client.book_by_isbn("1") }.to raise_error(Goodreads::Unauthorized)
|
34
|
+
expect { client.book_by_isbn("2") }.to raise_error(Goodreads::Forbidden)
|
35
|
+
end
|
23
36
|
end
|
24
37
|
end
|
data/spec/client_spec.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
require "spec_helper"
|
2
2
|
require "oauth"
|
3
3
|
|
4
|
-
describe
|
4
|
+
describe Goodreads::Client do
|
5
5
|
let(:client) { Goodreads::Client.new(api_key: "SECRET_KEY") }
|
6
6
|
before(:each) { Goodreads.reset_configuration }
|
7
7
|
|
@@ -17,6 +17,45 @@ describe "Client" do
|
|
17
17
|
end
|
18
18
|
end
|
19
19
|
|
20
|
+
describe "#oauth_configured?" do
|
21
|
+
it "is true when OAuth token provided to constructor" do
|
22
|
+
client = Goodreads::Client.new(oauth_token: "a token")
|
23
|
+
expect(client.oauth_configured?).to be true
|
24
|
+
end
|
25
|
+
|
26
|
+
it "is true when oauth token is not provided to constructor" do
|
27
|
+
client = Goodreads::Client.new(api_key: "SECRET_KEY")
|
28
|
+
expect(client.oauth_configured?).to be false
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe "#request" do
|
33
|
+
context "with oauth token" do
|
34
|
+
it "makes an oauth request" do
|
35
|
+
oauth_token = double
|
36
|
+
response = double
|
37
|
+
|
38
|
+
allow(oauth_token).to receive(:request) { response }
|
39
|
+
allow(response).to receive(:body) { fixture("book.xml") }
|
40
|
+
|
41
|
+
client = Goodreads::Client.new(oauth_token: oauth_token)
|
42
|
+
expect(client.book(123)).to be_a Hash
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
context "without oauth token" do
|
47
|
+
before do
|
48
|
+
allow(client).to receive(:http_request) {
|
49
|
+
Hash.from_xml(fixture("book.xml"))["GoodreadsResponse"]
|
50
|
+
}
|
51
|
+
end
|
52
|
+
|
53
|
+
it "makes a request" do
|
54
|
+
expect(client.book(123)).to be_a Hash
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
20
59
|
describe "#book_by_isbn" do
|
21
60
|
before { stub_with_key_get("/book/isbn", { isbn: "0307463745" }, "book.xml") }
|
22
61
|
|
@@ -154,6 +193,26 @@ describe "Client" do
|
|
154
193
|
end
|
155
194
|
end
|
156
195
|
|
196
|
+
describe "#user_review" do
|
197
|
+
let(:consumer) { OAuth::Consumer.new("API_KEY", "SECRET_KEY", site: "https://www.goodreads.com") }
|
198
|
+
let(:token) { OAuth::AccessToken.new(consumer, "ACCESS_TOKEN", "ACCESS_SECRET") }
|
199
|
+
|
200
|
+
it "returns a user's existing review" do
|
201
|
+
stub_request(:get, "https://www.goodreads.com/review/show_by_user_and_book.xml?book_id=50&user_id=1&v=2")
|
202
|
+
.to_return(status: 200, body: fixture("review_show_by_user_and_book.xml"))
|
203
|
+
|
204
|
+
client = Goodreads::Client.new(api_key: "SECRET_KEY", oauth_token: token)
|
205
|
+
review = client.user_review(1, 50)
|
206
|
+
|
207
|
+
expect(review.id).to eq("21")
|
208
|
+
expect(review.book.id).to eq(50)
|
209
|
+
|
210
|
+
expect(review.rating).to eq("5")
|
211
|
+
expect(review.body.strip).to eq("")
|
212
|
+
expect(review.date_added).to eq("Tue Aug 29 11:20:01 -0700 2006")
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
157
216
|
describe "#author" do
|
158
217
|
before { stub_with_key_get("/author/show", { id: "18541" }, "author.xml") }
|
159
218
|
|
@@ -287,6 +346,131 @@ describe "Client" do
|
|
287
346
|
end
|
288
347
|
end
|
289
348
|
|
349
|
+
describe "#add_to_shelf" do
|
350
|
+
let(:consumer) { OAuth::Consumer.new("API_KEY", "SECRET_KEY", site: "https://www.goodreads.com") }
|
351
|
+
let(:token) { OAuth::AccessToken.new(consumer, "ACCESS_TOKEN", "ACCESS_SECRET") }
|
352
|
+
|
353
|
+
it "adds a book to a user's shelf" do
|
354
|
+
stub_request(:post, "https://www.goodreads.com/shelf/add_to_shelf.xml")
|
355
|
+
.with(:body => {"book_id"=>"456", "name"=>"read", "v"=>"2"})
|
356
|
+
.to_return(status: 201, body: fixture("shelf_add_to_shelf.xml"))
|
357
|
+
|
358
|
+
client = Goodreads::Client.new(api_key: "SECRET_KEY", oauth_token: token)
|
359
|
+
review = client.add_to_shelf(456, "read")
|
360
|
+
|
361
|
+
expect(review.id).to eq(2416981504)
|
362
|
+
expect(review.book_id).to eq(456)
|
363
|
+
|
364
|
+
expect(review.rating).to eq(0)
|
365
|
+
expect(review.body).to be nil
|
366
|
+
expect(review.body_raw).to be nil
|
367
|
+
expect(review.spoiler).to be false
|
368
|
+
|
369
|
+
expect(review.shelves.size).to eq(1)
|
370
|
+
expect(review.shelves.first.name).to eq("read")
|
371
|
+
expect(review.shelves.first.id).to eq(269274694)
|
372
|
+
expect(review.shelves.first.exclusive).to be true
|
373
|
+
expect(review.shelves.first.sortable).to be false
|
374
|
+
|
375
|
+
|
376
|
+
expect(review.read_at).to be nil
|
377
|
+
expect(review.started_at).to be nil
|
378
|
+
expect(review.date_added).to eq("Thu Jun 07 19:58:19 -0700 2018")
|
379
|
+
expect(review.updated_at).to eq("Thu Jun 07 19:58:53 -0700 2018")
|
380
|
+
|
381
|
+
expect(review.body).to be nil
|
382
|
+
expect(review.body_raw).to be nil
|
383
|
+
expect(review.spoiler).to be false
|
384
|
+
end
|
385
|
+
end
|
386
|
+
|
387
|
+
describe "#create_review" do
|
388
|
+
let(:consumer) { OAuth::Consumer.new("API_KEY", "SECRET_KEY", site: "https://www.goodreads.com") }
|
389
|
+
let(:token) { OAuth::AccessToken.new(consumer, "ACCESS_TOKEN", "ACCESS_SECRET") }
|
390
|
+
|
391
|
+
it "creates a new review for a book" do
|
392
|
+
stub_request(:post, "https://www.goodreads.com/review.xml")
|
393
|
+
.with(:body => {
|
394
|
+
"book_id"=>"456",
|
395
|
+
"review" => {
|
396
|
+
"rating" => "3",
|
397
|
+
"review" => "Good book.",
|
398
|
+
"read_at" => "2018-01-02",
|
399
|
+
},
|
400
|
+
"shelf" => "read",
|
401
|
+
"v"=>"2",
|
402
|
+
})
|
403
|
+
.to_return(status: 201, body: fixture("review_create.xml"))
|
404
|
+
|
405
|
+
client = Goodreads::Client.new(api_key: "SECRET_KEY", oauth_token: token)
|
406
|
+
review = client.create_review(456, {
|
407
|
+
:review => "Good book.",
|
408
|
+
:rating => 3,
|
409
|
+
:read_at => Time.parse('2018-01-02'),
|
410
|
+
:shelf => "read",
|
411
|
+
})
|
412
|
+
|
413
|
+
expect(review.id).to eq("67890")
|
414
|
+
expect(review.book.id).to eq(456)
|
415
|
+
expect(review.rating).to eq("3")
|
416
|
+
expect(review.body).to eq("Good book.")
|
417
|
+
end
|
418
|
+
end
|
419
|
+
|
420
|
+
describe "#edit_review" do
|
421
|
+
let(:consumer) { OAuth::Consumer.new("API_KEY", "SECRET_KEY", site: "https://www.goodreads.com") }
|
422
|
+
let(:token) { OAuth::AccessToken.new(consumer, "ACCESS_TOKEN", "ACCESS_SECRET") }
|
423
|
+
|
424
|
+
it "creates a new review for a book" do
|
425
|
+
stub_request(:post, "https://www.goodreads.com/review/67890.xml")
|
426
|
+
.with(:body => {
|
427
|
+
"finished" => "true",
|
428
|
+
"review" => {
|
429
|
+
"rating" => "5",
|
430
|
+
"review" => "Fantastic book.",
|
431
|
+
"read_at" => "2018-04-15",
|
432
|
+
},
|
433
|
+
"shelf" => "read",
|
434
|
+
"v"=>"2",
|
435
|
+
})
|
436
|
+
.to_return(status: 201, body: fixture("review_update.xml"))
|
437
|
+
|
438
|
+
client = Goodreads::Client.new(api_key: "SECRET_KEY", oauth_token: token)
|
439
|
+
review = client.edit_review(67890, {
|
440
|
+
:finished => true,
|
441
|
+
:review => "Fantastic book.",
|
442
|
+
:rating => 5,
|
443
|
+
:read_at => Time.parse('2018-04-15'),
|
444
|
+
:shelf => "read",
|
445
|
+
})
|
446
|
+
|
447
|
+
expect(review.id).to eq("67890")
|
448
|
+
expect(review.book.id).to eq(456)
|
449
|
+
expect(review.rating).to eq("5")
|
450
|
+
expect(review.body).to eq("Fantastic book.")
|
451
|
+
end
|
452
|
+
end
|
453
|
+
|
454
|
+
describe "#shelves" do
|
455
|
+
it "returns list of user's shelves" do
|
456
|
+
stub_with_key_get("/shelf/list.xml", { user_id: 123, v: "2" }, "shelf_list.xml")
|
457
|
+
|
458
|
+
response = client.shelves(123)
|
459
|
+
|
460
|
+
expect(response).to respond_to(:start)
|
461
|
+
expect(response).to respond_to(:end)
|
462
|
+
expect(response).to respond_to(:total)
|
463
|
+
expect(response).to respond_to(:shelves)
|
464
|
+
|
465
|
+
expect(response.start).to eq(1)
|
466
|
+
expect(response.end).to eq(3)
|
467
|
+
expect(response.total).to eq(3)
|
468
|
+
expect(response.shelves.length).to eq(3)
|
469
|
+
expect(response.shelves.first.id).to eq(9049904)
|
470
|
+
expect(response.shelves.first.name).to eq("read")
|
471
|
+
end
|
472
|
+
end
|
473
|
+
|
290
474
|
describe "#user_id" do
|
291
475
|
let(:consumer) { OAuth::Consumer.new("API_KEY", "SECRET_KEY", site: "https://www.goodreads.com") }
|
292
476
|
let(:token) { OAuth::AccessToken.new(consumer, "ACCESS_TOKEN", "ACCESS_SECRET") }
|
@@ -0,0 +1,102 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<GoodreadsResponse>
|
3
|
+
<Request>
|
4
|
+
<authentication>true</authentication>
|
5
|
+
<key><![CDATA[SECRET_KEY]]></key>
|
6
|
+
<method><![CDATA[review_create]]></method>
|
7
|
+
</Request>
|
8
|
+
|
9
|
+
<review>
|
10
|
+
<id>67890</id>
|
11
|
+
|
12
|
+
<user>
|
13
|
+
<id>123456</id>
|
14
|
+
<uri>kca://profile:goodreads/A25C3Y1SBGK9NK</uri>
|
15
|
+
<name>Test</name>
|
16
|
+
<display_name>Test User</display_name>
|
17
|
+
|
18
|
+
<location>Lafayette, CA</location>
|
19
|
+
|
20
|
+
<link><![CDATA[https://www.goodreads.com/user/show/123456-test-user]]></link>
|
21
|
+
|
22
|
+
<image_url><![CDATA[https://s.gr-assets.com/assets/nophoto/user/u_111x148-9394ebedbb3c6c218f64be9549657029.png]]></image_url>
|
23
|
+
<small_image_url><![CDATA[https://s.gr-assets.com/assets/nophoto/user/u_50x66-632230dc9882b4352d753eedf9396530.png]]></small_image_url>
|
24
|
+
<has_image>false</has_image>
|
25
|
+
|
26
|
+
</user>
|
27
|
+
|
28
|
+
<book>
|
29
|
+
<id type="integer">456</id>
|
30
|
+
<isbn>0195138570</isbn>
|
31
|
+
<isbn13>9780195138573</isbn13>
|
32
|
+
<text_reviews_count type="integer">11</text_reviews_count>
|
33
|
+
<uri>kca://book/amzn1.gr.book.v1.oHwPZrciugo6gPSINsfCaw</uri>
|
34
|
+
<title>Mindware: An Introduction to the Philosophy of Cognitive Science</title>
|
35
|
+
<title_without_series>Mindware: An Introduction to the Philosophy of Cognitive Science</title_without_series>
|
36
|
+
<image_url>https://s.gr-assets.com/assets/nophoto/book/111x148-bcc042a9c91a29c1d680899eff700a03.png</image_url>
|
37
|
+
<small_image_url>https://s.gr-assets.com/assets/nophoto/book/50x75-a91bf249278a81aabab721ef782c4a74.png</small_image_url>
|
38
|
+
<large_image_url/>
|
39
|
+
<link>https://www.goodreads.com/book/show/456.Mindware</link>
|
40
|
+
<num_pages>224</num_pages>
|
41
|
+
<format>Paperback</format>
|
42
|
+
<edition_information>1st edition</edition_information>
|
43
|
+
<publisher>Oxford University Press, USA</publisher>
|
44
|
+
<publication_day>21</publication_day>
|
45
|
+
<publication_year>2000</publication_year>
|
46
|
+
<publication_month>12</publication_month>
|
47
|
+
<average_rating>3.78</average_rating>
|
48
|
+
<ratings_count>210</ratings_count>
|
49
|
+
<description><p><i>Mindware</i> is an introductory text with a difference. In eight short chapters it tells a story and invites the reader to join in some up-to-the-minute conceptual discussion of the key issues, problems, and opportunities in cognitive science. The story is about the search for a cognitive scientific understanding of mind. It is presented as a no-holds-barred journey from early work in Artificial Intelligence, through connectionist (artificial neural network) counter-visions, and onto neuroscience artificial life, dynamics and robotics. The journey ends with some wide-ranging and provacative speculation about the role of technology and the changing nature of the human mind itself.<br />Each chapter is organized as an initial sketch of a research program or theme, followed by a substantial discussion section in which specific problems and issues (both familiear and cutting-edge) are raised and pursued. Discussion topics include mental causation, the hardware/software distinction, the relations between life and mind, the nature of perception, cognition and action, and the continuity (or otherwise) of high-level human intelligence with other forms of adaptive response. Classic topics are treated alongside the newer ones in an integrated treatment of the various discussions. The sketches and discussions are accompanied by numerous figures and boxed sections, and followed by suggestions for futher reading.</p></description>
|
50
|
+
<authors>
|
51
|
+
<author>
|
52
|
+
<id>3445871</id>
|
53
|
+
<name>Andy Clark</name>
|
54
|
+
<role></role>
|
55
|
+
<image_url nophoto='false'>
|
56
|
+
<![CDATA[https://images.gr-assets.com/authors/1269856267p5/3445871.jpg]]>
|
57
|
+
</image_url>
|
58
|
+
<small_image_url nophoto='false'>
|
59
|
+
<![CDATA[https://images.gr-assets.com/authors/1269856267p2/3445871.jpg]]>
|
60
|
+
</small_image_url>
|
61
|
+
<link><![CDATA[https://www.goodreads.com/author/show/3445871.Andy_Clark]]></link>
|
62
|
+
<average_rating>3.89</average_rating>
|
63
|
+
<ratings_count>992</ratings_count>
|
64
|
+
<text_reviews_count>74</text_reviews_count>
|
65
|
+
</author>
|
66
|
+
</authors>
|
67
|
+
<published>2000</published>
|
68
|
+
<work> <id>282613</id>
|
69
|
+
<uri>kca://work/amzn1.gr.work.v1.xCZQesiWRuaIVPV6wsdFGA</uri>
|
70
|
+
</work></book>
|
71
|
+
|
72
|
+
|
73
|
+
<rating>3</rating>
|
74
|
+
<votes>0</votes>
|
75
|
+
<spoiler_flag>false</spoiler_flag>
|
76
|
+
<spoilers_state>none</spoilers_state>
|
77
|
+
|
78
|
+
|
79
|
+
<shelves>
|
80
|
+
<shelf name="read" exclusive="true" id="269274694" review_shelf_id= ""/>
|
81
|
+
|
82
|
+
</shelves>
|
83
|
+
|
84
|
+
<recommended_for></recommended_for>
|
85
|
+
<recommended_by></recommended_by>
|
86
|
+
<started_at></started_at>
|
87
|
+
<read_at></read_at>
|
88
|
+
<date_added>Wed Jun 13 20:52:06 -0700 2018</date_added>
|
89
|
+
<date_updated>Wed Jun 13 20:52:07 -0700 2018</date_updated>
|
90
|
+
<read_count>1</read_count>
|
91
|
+
<body>Good book.</body>
|
92
|
+
|
93
|
+
|
94
|
+
|
95
|
+
<comments_count>0</comments_count>
|
96
|
+
<url><![CDATA[https://www.goodreads.com/review/show/67890]]></url>
|
97
|
+
<link><![CDATA[https://www.goodreads.com/review/show/67890]]></link>
|
98
|
+
<owned>0</owned>
|
99
|
+
</review>
|
100
|
+
|
101
|
+
|
102
|
+
</GoodreadsResponse>
|
@@ -0,0 +1,144 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<GoodreadsResponse>
|
3
|
+
<Request>
|
4
|
+
<authentication>true</authentication>
|
5
|
+
<key><![CDATA[SECRET_KEY]]></key>
|
6
|
+
<method><![CDATA[review_show_by_user_and_book]]></method>
|
7
|
+
</Request>
|
8
|
+
<review>
|
9
|
+
<id>21</id>
|
10
|
+
|
11
|
+
<user>
|
12
|
+
<id>1</id>
|
13
|
+
<uri>kca://profile:goodreads/A2CSQET51X1KEY</uri>
|
14
|
+
<name>Otis</name>
|
15
|
+
<display_name>Otis Chandler</display_name>
|
16
|
+
|
17
|
+
<location>San Francisco, CA</location>
|
18
|
+
|
19
|
+
<link><![CDATA[https://www.goodreads.com/user/show/1-otis-chandler]]></link>
|
20
|
+
|
21
|
+
<image_url><![CDATA[https://images.gr-assets.com/users/1506617226p3/1.jpg]]></image_url>
|
22
|
+
<small_image_url><![CDATA[https://images.gr-assets.com/users/1506617226p2/1.jpg]]></small_image_url>
|
23
|
+
<has_image>true</has_image>
|
24
|
+
|
25
|
+
</user>
|
26
|
+
|
27
|
+
<book>
|
28
|
+
<id type="integer">50</id>
|
29
|
+
<isbn>0689840926</isbn>
|
30
|
+
<isbn13>9780689840920</isbn13>
|
31
|
+
<text_reviews_count type="integer">10396</text_reviews_count>
|
32
|
+
<uri>kca://book/amzn1.gr.book.v1.RXVB3nJhipnhI-zLlVeRTg</uri>
|
33
|
+
<title>Hatchet</title>
|
34
|
+
<title_without_series>Hatchet</title_without_series>
|
35
|
+
<image_url>https://s.gr-assets.com/assets/nophoto/book/111x148-bcc042a9c91a29c1d680899eff700a03.png</image_url>
|
36
|
+
<small_image_url>https://s.gr-assets.com/assets/nophoto/book/50x75-a91bf249278a81aabab721ef782c4a74.png</small_image_url>
|
37
|
+
<large_image_url/>
|
38
|
+
<link>https://www.goodreads.com/book/show/50.Hatchet</link>
|
39
|
+
<num_pages>208</num_pages>
|
40
|
+
<format>Hardcover</format>
|
41
|
+
<edition_information/>
|
42
|
+
<publisher>Atheneum Books for Young Readers: Richard Jackson Books</publisher>
|
43
|
+
<publication_day>1</publication_day>
|
44
|
+
<publication_year>2000</publication_year>
|
45
|
+
<publication_month>4</publication_month>
|
46
|
+
<average_rating>3.69</average_rating>
|
47
|
+
<ratings_count>250763</ratings_count>
|
48
|
+
<description>Brian is on his way to Canada to visit his estranged father when the pilot of his small prop plane suffers a heart attack. Brian is forced to crash-land the plane in a lake--and finds himself stranded in the remote Canadian wilderness with only his clothing and the hatchet his mother gave him as a present before his departure. <br /><br />Brian had been distraught over his parents' impending divorce and the secret he carries about his mother, but now he is truly desolate and alone. Exhausted, terrified, and hungry, Brian struggles to find food and make a shelter for himself. He has no special knowledge of the woods, and he must find a new kind of awareness and patience as he meets each day's challenges. Is the water safe to drink? Are the berries he finds poisonous? <br /><br />Slowly, Brian learns to turn adversity to his advantage--an invading porcupine unexpectedly shows him how to make fire, a devastating tornado shows him how to retrieve supplies from the submerged airplane. Most of all, Brian leaves behind the self-pity he has felt about his predicament as he summons the courage to stay alive. <br /><br />A story of survival and of transformation, this riveting book has sparked many a reader's interest in venturing into the wild.</description>
|
49
|
+
<authors>
|
50
|
+
<author>
|
51
|
+
<id>18</id>
|
52
|
+
<name>Gary Paulsen</name>
|
53
|
+
<role></role>
|
54
|
+
<image_url nophoto='false'>
|
55
|
+
<![CDATA[https://images.gr-assets.com/authors/1309159225p5/18.jpg]]>
|
56
|
+
</image_url>
|
57
|
+
<small_image_url nophoto='false'>
|
58
|
+
<![CDATA[https://images.gr-assets.com/authors/1309159225p2/18.jpg]]>
|
59
|
+
</small_image_url>
|
60
|
+
<link><![CDATA[https://www.goodreads.com/author/show/18.Gary_Paulsen]]></link>
|
61
|
+
<average_rating>3.76</average_rating>
|
62
|
+
<ratings_count>399462</ratings_count>
|
63
|
+
<text_reviews_count>28012</text_reviews_count>
|
64
|
+
</author>
|
65
|
+
</authors>
|
66
|
+
<published>2000</published>
|
67
|
+
<work> <id>1158125</id>
|
68
|
+
<uri>kca://work/amzn1.gr.work.v1.r_sm_y7tG-b00YGE5HqhQQ</uri>
|
69
|
+
</work></book>
|
70
|
+
|
71
|
+
|
72
|
+
<read_statuses>
|
73
|
+
<read_status>
|
74
|
+
<id type="integer">1610038200</id>
|
75
|
+
<old_status></old_status>
|
76
|
+
<status>read</status>
|
77
|
+
<updated_at type="datetime">Fri Dec 09 22:55:21 -0800 2016</updated_at>
|
78
|
+
<ratings_count>0</ratings_count>
|
79
|
+
<comments_count>0</comments_count>
|
80
|
+
</read_status>
|
81
|
+
</read_statuses>
|
82
|
+
<rating>5</rating>
|
83
|
+
<votes>1</votes>
|
84
|
+
<spoiler_flag>false</spoiler_flag>
|
85
|
+
<spoilers_state>none</spoilers_state>
|
86
|
+
|
87
|
+
|
88
|
+
<shelves>
|
89
|
+
<shelf name="read" exclusive="true" id="5625761" review_shelf_id= ""/>
|
90
|
+
|
91
|
+
<shelf exclusive='false' id='343477' name='childrensbooks' review_shelf_id='175' sortable='false'></shelf>
|
92
|
+
|
93
|
+
<shelf exclusive='false' id='348056' name='fiction' review_shelf_id='687' sortable='false'></shelf>
|
94
|
+
|
95
|
+
<shelf exclusive='false' id='348035' name='fiction' review_shelf_id='209' sortable='false'></shelf>
|
96
|
+
|
97
|
+
</shelves>
|
98
|
+
|
99
|
+
<recommended_for></recommended_for>
|
100
|
+
<recommended_by></recommended_by>
|
101
|
+
<started_at></started_at>
|
102
|
+
<read_at></read_at>
|
103
|
+
<date_added>Tue Aug 29 11:20:01 -0700 2006</date_added>
|
104
|
+
<date_updated>Wed Mar 22 11:44:07 -0700 2017</date_updated>
|
105
|
+
<read_count>1</read_count>
|
106
|
+
<body>
|
107
|
+
</body>
|
108
|
+
|
109
|
+
|
110
|
+
|
111
|
+
<comments_count>1</comments_count>
|
112
|
+
<comments start="1" end="1" total="1">
|
113
|
+
<comment>
|
114
|
+
<id>161860175</id>
|
115
|
+
<body><![CDATA[love this book i read it in sixth grade and we had journals about it]]></body>
|
116
|
+
|
117
|
+
<user>
|
118
|
+
<id>64170165</id>
|
119
|
+
<uri>kca://profile:goodreads/A2PCDUCFEEK4OB</uri>
|
120
|
+
<name>Alise</name>
|
121
|
+
<display_name>Alise</display_name>
|
122
|
+
|
123
|
+
<location>The United States</location>
|
124
|
+
|
125
|
+
<link><![CDATA[https://www.goodreads.com/user/show/64170165-alise]]></link>
|
126
|
+
|
127
|
+
<image_url><![CDATA[https://s.gr-assets.com/assets/nophoto/user/u_111x148-9394ebedbb3c6c218f64be9549657029.png]]></image_url>
|
128
|
+
<small_image_url><![CDATA[https://s.gr-assets.com/assets/nophoto/user/u_50x66-632230dc9882b4352d753eedf9396530.png]]></small_image_url>
|
129
|
+
<has_image>false</has_image>
|
130
|
+
|
131
|
+
</user>
|
132
|
+
|
133
|
+
<created_at>Sun Jan 22 22:49:10 -0800 2017</created_at>
|
134
|
+
<updated_at>Sun Jan 22 22:49:10 -0800 2017</updated_at>
|
135
|
+
</comment>
|
136
|
+
|
137
|
+
</comments>
|
138
|
+
<url><![CDATA[https://www.goodreads.com/review/show/21]]></url>
|
139
|
+
<link><![CDATA[https://www.goodreads.com/review/show/21]]></link>
|
140
|
+
<owned>0</owned>
|
141
|
+
</review>
|
142
|
+
|
143
|
+
|
144
|
+
</GoodreadsResponse>
|
@@ -0,0 +1,104 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<GoodreadsResponse>
|
3
|
+
<Request>
|
4
|
+
<authentication>true</authentication>
|
5
|
+
<key><![CDATA[SECRET_KEY]]></key>
|
6
|
+
<method><![CDATA[review_update_xml]]></method>
|
7
|
+
</Request>
|
8
|
+
<review>
|
9
|
+
<id>67890</id>
|
10
|
+
|
11
|
+
<user>
|
12
|
+
<id>123456</id>
|
13
|
+
<uri>kca://profile:goodreads/A25C3Y1SBGK9NK</uri>
|
14
|
+
<name>Test</name>
|
15
|
+
<display_name>Test User</display_name>
|
16
|
+
|
17
|
+
<location>Lafayette, CA</location>
|
18
|
+
|
19
|
+
<link><![CDATA[https://www.goodreads.com/user/show/123456-test-user]]></link>
|
20
|
+
|
21
|
+
<image_url><![CDATA[https://s.gr-assets.com/assets/nophoto/user/u_111x148-9394ebedbb3c6c218f64be9549657029.png]]></image_url>
|
22
|
+
<small_image_url><![CDATA[https://s.gr-assets.com/assets/nophoto/user/u_50x66-632230dc9882b4352d753eedf9396530.png]]></small_image_url>
|
23
|
+
<has_image>false</has_image>
|
24
|
+
|
25
|
+
</user>
|
26
|
+
|
27
|
+
<book>
|
28
|
+
<id type="integer">456</id>
|
29
|
+
<isbn>0195138570</isbn>
|
30
|
+
<isbn13>9780195138573</isbn13>
|
31
|
+
<text_reviews_count type="integer">11</text_reviews_count>
|
32
|
+
<uri>kca://book/amzn1.gr.book.v1.oHwPZrciugo6gPSINsfCaw</uri>
|
33
|
+
<title>Mindware: An Introduction to the Philosophy of Cognitive Science</title>
|
34
|
+
<title_without_series>Mindware: An Introduction to the Philosophy of Cognitive Science</title_without_series>
|
35
|
+
<image_url>https://s.gr-assets.com/assets/nophoto/book/111x148-bcc042a9c91a29c1d680899eff700a03.png</image_url>
|
36
|
+
<small_image_url>https://s.gr-assets.com/assets/nophoto/book/50x75-a91bf249278a81aabab721ef782c4a74.png</small_image_url>
|
37
|
+
<large_image_url/>
|
38
|
+
<link>https://www.goodreads.com/book/show/456.Mindware</link>
|
39
|
+
<num_pages>224</num_pages>
|
40
|
+
<format>Paperback</format>
|
41
|
+
<edition_information>1st edition</edition_information>
|
42
|
+
<publisher>Oxford University Press, USA</publisher>
|
43
|
+
<publication_day>21</publication_day>
|
44
|
+
<publication_year>2000</publication_year>
|
45
|
+
<publication_month>12</publication_month>
|
46
|
+
<average_rating>3.78</average_rating>
|
47
|
+
<ratings_count>210</ratings_count>
|
48
|
+
<description><p><i>Mindware</i> is an introductory text with a difference. In eight short chapters it tells a story and invites the reader to join in some up-to-the-minute conceptual discussion of the key issues, problems, and opportunities in cognitive science. The story is about the search for a cognitive scientific understanding of mind. It is presented as a no-holds-barred journey from early work in Artificial Intelligence, through connectionist (artificial neural network) counter-visions, and onto neuroscience artificial life, dynamics and robotics. The journey ends with some wide-ranging and provacative speculation about the role of technology and the changing nature of the human mind itself.<br />Each chapter is organized as an initial sketch of a research program or theme, followed by a substantial discussion section in which specific problems and issues (both familiear and cutting-edge) are raised and pursued. Discussion topics include mental causation, the hardware/software distinction, the relations between life and mind, the nature of perception, cognition and action, and the continuity (or otherwise) of high-level human intelligence with other forms of adaptive response. Classic topics are treated alongside the newer ones in an integrated treatment of the various discussions. The sketches and discussions are accompanied by numerous figures and boxed sections, and followed by suggestions for futher reading.</p></description>
|
49
|
+
<authors>
|
50
|
+
<author>
|
51
|
+
<id>3445871</id>
|
52
|
+
<name>Andy Clark</name>
|
53
|
+
<role></role>
|
54
|
+
<image_url nophoto='false'>
|
55
|
+
<![CDATA[https://images.gr-assets.com/authors/1269856267p5/3445871.jpg]]>
|
56
|
+
</image_url>
|
57
|
+
<small_image_url nophoto='false'>
|
58
|
+
<![CDATA[https://images.gr-assets.com/authors/1269856267p2/3445871.jpg]]>
|
59
|
+
</small_image_url>
|
60
|
+
<link><![CDATA[https://www.goodreads.com/author/show/3445871.Andy_Clark]]></link>
|
61
|
+
<average_rating>3.89</average_rating>
|
62
|
+
<ratings_count>992</ratings_count>
|
63
|
+
<text_reviews_count>74</text_reviews_count>
|
64
|
+
</author>
|
65
|
+
</authors>
|
66
|
+
<published>2000</published>
|
67
|
+
<work> <id>282613</id>
|
68
|
+
<uri>kca://work/amzn1.gr.work.v1.xCZQesiWRuaIVPV6wsdFGA</uri>
|
69
|
+
</work></book>
|
70
|
+
|
71
|
+
|
72
|
+
<rating>5</rating>
|
73
|
+
<votes>0</votes>
|
74
|
+
<spoiler_flag>false</spoiler_flag>
|
75
|
+
<spoilers_state>none</spoilers_state>
|
76
|
+
|
77
|
+
|
78
|
+
<shelves>
|
79
|
+
<shelf name="read" exclusive="true" id="269274694" review_shelf_id= ""/>
|
80
|
+
|
81
|
+
</shelves>
|
82
|
+
|
83
|
+
<recommended_for></recommended_for>
|
84
|
+
<recommended_by></recommended_by>
|
85
|
+
<started_at></started_at>
|
86
|
+
<read_at>Fri Aug 20 00:00:00 -0700 2004</read_at>
|
87
|
+
<date_added>Wed Jun 13 20:52:06 -0700 2018</date_added>
|
88
|
+
<date_updated>Wed Jun 13 20:52:08 -0700 2018</date_updated>
|
89
|
+
<read_count>1</read_count>
|
90
|
+
<body>Fantastic book.</body>
|
91
|
+
<body_raw>
|
92
|
+
|
93
|
+
</body_raw>
|
94
|
+
|
95
|
+
|
96
|
+
|
97
|
+
<comments_count>0</comments_count>
|
98
|
+
<url><![CDATA[https://www.goodreads.com/review/show/67890]]></url>
|
99
|
+
<link><![CDATA[https://www.goodreads.com/review/show/67890]]></link>
|
100
|
+
<owned>0</owned>
|
101
|
+
</review>
|
102
|
+
|
103
|
+
|
104
|
+
</GoodreadsResponse>
|
@@ -0,0 +1,24 @@
|
|
1
|
+
<GoodreadsResponse>
|
2
|
+
<Request>
|
3
|
+
<authentication>true</authentication>
|
4
|
+
<key><![CDATA[SECRET_KEY]]></key>
|
5
|
+
<method><![CDATA[shelf_add_to_shelf]]></method>
|
6
|
+
</Request>
|
7
|
+
<my_review>
|
8
|
+
<id>2416981504</id>
|
9
|
+
<book_id>456</book_id>
|
10
|
+
<rating>0</rating>
|
11
|
+
<updated_at>Thu Jun 07 19:58:53 -0700 2018</updated_at>
|
12
|
+
|
13
|
+
<shelves>
|
14
|
+
<shelf name="read" exclusive="true" id="269274694" review_shelf_id= ""/>
|
15
|
+
</shelves>
|
16
|
+
|
17
|
+
<body></body>
|
18
|
+
<body_raw></body_raw>
|
19
|
+
<spoiler_flag>false</spoiler_flag>
|
20
|
+
<started_at></started_at>
|
21
|
+
<read_at></read_at>
|
22
|
+
<date_added>Thu Jun 07 19:58:19 -0700 2018</date_added>
|
23
|
+
</my_review>
|
24
|
+
</GoodreadsResponse>
|
@@ -0,0 +1,51 @@
|
|
1
|
+
<GoodreadsResponse>
|
2
|
+
<Request>
|
3
|
+
<authentication>true</authentication>
|
4
|
+
<key><![CDATA[SECRET_KEY]]></key>
|
5
|
+
<method><![CDATA[ shelf_list ]]></method>
|
6
|
+
</Request>
|
7
|
+
<shelves start="1" end="3" total="3">
|
8
|
+
<user_shelf>
|
9
|
+
<id type="integer">9049904</id>
|
10
|
+
<name>read</name>
|
11
|
+
<book_count type="integer">0</book_count>
|
12
|
+
<exclusive_flag type="boolean">true</exclusive_flag>
|
13
|
+
<description nil="true"/>
|
14
|
+
<sort nil="true"/>
|
15
|
+
<order nil="true"/>
|
16
|
+
<per_page type="integer" nil="true"/>
|
17
|
+
<display_fields/>
|
18
|
+
<featured type="boolean">true</featured>
|
19
|
+
<recommend_for type="boolean">true</recommend_for>
|
20
|
+
<sticky type="boolean" nil="true"/>
|
21
|
+
</user_shelf>
|
22
|
+
<user_shelf>
|
23
|
+
<id type="integer">3701</id>
|
24
|
+
<name>currently-reading</name>
|
25
|
+
<book_count type="integer">0</book_count>
|
26
|
+
<exclusive_flag type="boolean">true</exclusive_flag>
|
27
|
+
<description nil="true"/>
|
28
|
+
<sort nil="true"/>
|
29
|
+
<order nil="true"/>
|
30
|
+
<per_page type="integer" nil="true"/>
|
31
|
+
<display_fields/>
|
32
|
+
<featured type="boolean">false</featured>
|
33
|
+
<recommend_for type="boolean">true</recommend_for>
|
34
|
+
<sticky type="boolean" nil="true"/>
|
35
|
+
</user_shelf>
|
36
|
+
<user_shelf>
|
37
|
+
<id type="integer">3700</id>
|
38
|
+
<name>to-read</name>
|
39
|
+
<book_count type="integer">0</book_count>
|
40
|
+
<exclusive_flag type="boolean">true</exclusive_flag>
|
41
|
+
<description nil="true"/>
|
42
|
+
<sort nil="true"/>
|
43
|
+
<order>a</order>
|
44
|
+
<per_page type="integer" nil="true"/>
|
45
|
+
<display_fields/>
|
46
|
+
<featured type="boolean">false</featured>
|
47
|
+
<recommend_for type="boolean">true</recommend_for>
|
48
|
+
<sticky type="boolean" nil="true"/>
|
49
|
+
</user_shelf>
|
50
|
+
</shelves>
|
51
|
+
</GoodreadsResponse>
|
data/spec/goodreads_spec.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: goodreads
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.8.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dan Sosedoff
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-11-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: webmock
|
@@ -72,14 +72,14 @@ dependencies:
|
|
72
72
|
requirements:
|
73
73
|
- - "~>"
|
74
74
|
- !ruby/object:Gem::Version
|
75
|
-
version: '0.
|
75
|
+
version: '0.9'
|
76
76
|
type: :development
|
77
77
|
prerelease: false
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
79
79
|
requirements:
|
80
80
|
- - "~>"
|
81
81
|
- !ruby/object:Gem::Version
|
82
|
-
version: '0.
|
82
|
+
version: '0.9'
|
83
83
|
- !ruby/object:Gem::Dependency
|
84
84
|
name: rest-client
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
@@ -126,16 +126,22 @@ dependencies:
|
|
126
126
|
name: i18n
|
127
127
|
requirement: !ruby/object:Gem::Requirement
|
128
128
|
requirements:
|
129
|
-
- - "
|
129
|
+
- - ">="
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0.6'
|
132
|
+
- - "<"
|
130
133
|
- !ruby/object:Gem::Version
|
131
|
-
version: '
|
134
|
+
version: '2'
|
132
135
|
type: :runtime
|
133
136
|
prerelease: false
|
134
137
|
version_requirements: !ruby/object:Gem::Requirement
|
135
138
|
requirements:
|
136
|
-
- - "
|
139
|
+
- - ">="
|
140
|
+
- !ruby/object:Gem::Version
|
141
|
+
version: '0.6'
|
142
|
+
- - "<"
|
137
143
|
- !ruby/object:Gem::Version
|
138
|
-
version: '
|
144
|
+
version: '2'
|
139
145
|
- !ruby/object:Gem::Dependency
|
140
146
|
name: oauth
|
141
147
|
requirement: !ruby/object:Gem::Requirement
|
@@ -192,9 +198,14 @@ files:
|
|
192
198
|
- spec/fixtures/oauth_response.xml
|
193
199
|
- spec/fixtures/recent_reviews.xml
|
194
200
|
- spec/fixtures/review.xml
|
201
|
+
- spec/fixtures/review_create.xml
|
202
|
+
- spec/fixtures/review_show_by_user_and_book.xml
|
203
|
+
- spec/fixtures/review_update.xml
|
195
204
|
- spec/fixtures/reviews.xml
|
196
205
|
- spec/fixtures/reviews_empty.xml
|
197
206
|
- spec/fixtures/search_books_by_name.xml
|
207
|
+
- spec/fixtures/shelf_add_to_shelf.xml
|
208
|
+
- spec/fixtures/shelf_list.xml
|
198
209
|
- spec/fixtures/to-read-p2.xml
|
199
210
|
- spec/fixtures/to-read.xml
|
200
211
|
- spec/fixtures/user.xml
|
@@ -204,7 +215,7 @@ homepage: http://github.com/sosedoff/goodreads
|
|
204
215
|
licenses:
|
205
216
|
- MIT
|
206
217
|
metadata: {}
|
207
|
-
post_install_message:
|
218
|
+
post_install_message:
|
208
219
|
rdoc_options: []
|
209
220
|
require_paths:
|
210
221
|
- lib
|
@@ -219,9 +230,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
219
230
|
- !ruby/object:Gem::Version
|
220
231
|
version: '0'
|
221
232
|
requirements: []
|
222
|
-
|
223
|
-
|
224
|
-
signing_key:
|
233
|
+
rubygems_version: 3.0.6
|
234
|
+
signing_key:
|
225
235
|
specification_version: 4
|
226
236
|
summary: Goodreads API wrapper
|
227
237
|
test_files:
|
@@ -237,9 +247,14 @@ test_files:
|
|
237
247
|
- spec/fixtures/oauth_response.xml
|
238
248
|
- spec/fixtures/recent_reviews.xml
|
239
249
|
- spec/fixtures/review.xml
|
250
|
+
- spec/fixtures/review_create.xml
|
251
|
+
- spec/fixtures/review_show_by_user_and_book.xml
|
252
|
+
- spec/fixtures/review_update.xml
|
240
253
|
- spec/fixtures/reviews.xml
|
241
254
|
- spec/fixtures/reviews_empty.xml
|
242
255
|
- spec/fixtures/search_books_by_name.xml
|
256
|
+
- spec/fixtures/shelf_add_to_shelf.xml
|
257
|
+
- spec/fixtures/shelf_list.xml
|
243
258
|
- spec/fixtures/to-read-p2.xml
|
244
259
|
- spec/fixtures/to-read.xml
|
245
260
|
- spec/fixtures/user.xml
|