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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 0bf2079b03cdc4a3630504bab0adf6fceb39116d
4
- data.tar.gz: 41ffa08e6b041c58d284a94489a55926d8be22aa
2
+ SHA256:
3
+ metadata.gz: 6ea0e771d6f0bb4fe73d87bdc54b96f97c26e58e2dca54c0d956f73263acf557
4
+ data.tar.gz: 78e582d52e5ddfee249448c3f5bef36e8f56e165c5d241e3f8cb4c9633d6730a
5
5
  SHA512:
6
- metadata.gz: 76523d2373dc284161ba63dd8b914028a17bbbc09bb943984f4b8610e766d2f2e9fec30be23c76fae2b633e452d389d523e34fbaa9b0d18b44020a1b4d83a91d
7
- data.tar.gz: be44f0721b36dcb13f97dba807dc34b81de66612179a82b878aa9f143f05bb9aefba5a0e7b174e74c3e7cd212e2e83e5486be86cd9aeb0fa0ac06460f4dcd736
6
+ metadata.gz: 70521658f5c0df28b749559f336ed4c6e418257914fa7b3e4572e88166a1347eca0197422ba8c48bbefc4e9c55ca57524aeee83ae6f2b94f41b1846e90d55f70
7
+ data.tar.gz: d309c6a3874443910a06b7d156a87f29764be70ac6cb79bad8692b0b1436958b31730f3673bf473f4be569b4dda8a321459d53a30e4e0fad098058f9e5734925
@@ -1,10 +1,10 @@
1
1
  sudo: false
2
2
 
3
3
  rvm:
4
- - 2.1
5
- - 2.2
6
4
  - 2.3
7
5
  - 2.4
6
+ - 2.5
7
+ - 2.6
8
8
 
9
9
  script:
10
10
  - bundle exec rake test
data/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright (c) 2011-2015 Dan Sosedoff <dan.sosedoff@gmail.com>
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-2015 Dan Sosedoff, <dan.sosedoff@gmail.com>
220
+ Copyright (c) 2011-2018 Dan Sosedoff, <dan.sosedoff@gmail.com>
@@ -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.6"
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", "~> 0.5"
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")
@@ -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 = options[:api_key] || Goodreads.configuration[:api_key]
35
- @api_secret = options[:api_secret] || Goodreads.configuration[: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
@@ -4,4 +4,6 @@ module Goodreads
4
4
  class Forbidden < Error; end
5
5
  class Unauthorized < Error; end
6
6
  class NotFound < Error; end
7
+ class ServerError < Error; end
8
+ class UnknownError < Error; end
7
9
  end
@@ -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 oauth_request(path, params = nil)
74
+ def oauth_request_method(http_method, path, params = {})
47
75
  fail "OAuth access token required!" unless @oauth_token
48
- if params
49
- url_params = params.map { |k, v| "#{k}=#{v}" }.join("&")
50
- path = "#{path}?#{url_params}"
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
@@ -1,3 +1,3 @@
1
1
  module Goodreads
2
- VERSION = "0.5.0"
2
+ VERSION = "0.8.0"
3
3
  end
@@ -1,24 +1,37 @@
1
1
  require "spec_helper"
2
2
 
3
- describe "Client" do
3
+ describe Goodreads::Client do
4
4
  before :each do
5
5
  Goodreads.reset_configuration
6
6
  end
7
7
 
8
- it "raises Goodreads::ConfigurationError if API key was not provided" do
9
- client = Goodreads::Client.new
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
- expect { client.book_by_isbn("0307463745") }
12
- .to raise_error(Goodreads::ConfigurationError, "API key required.")
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
- it "raises Goodreads::Unauthorized if API key is not valid" do
16
- client = Goodreads::Client.new(api_key: "INVALID_KEY")
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
- stub_request(:get, "https://www.goodreads.com/book/isbn?format=xml&isbn=054748250711&key=INVALID_KEY")
19
- .to_return(status: 401)
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
- expect { client.book_by_isbn("054748250711") }
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
@@ -1,7 +1,7 @@
1
1
  require "spec_helper"
2
2
  require "oauth"
3
3
 
4
- describe "Client" do
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>&lt;p&gt;&lt;i&gt;Mindware&lt;/i&gt; 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.&lt;br /&gt;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.&lt;/p&gt;</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. &lt;br /&gt;&lt;br /&gt;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? &lt;br /&gt;&lt;br /&gt;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. &lt;br /&gt;&lt;br /&gt;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>&lt;p&gt;&lt;i&gt;Mindware&lt;/i&gt; 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.&lt;br /&gt;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.&lt;/p&gt;</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>
@@ -1,6 +1,6 @@
1
1
  require "spec_helper"
2
2
 
3
- describe "Goodreads" do
3
+ describe Goodreads do
4
4
  describe ".new" do
5
5
  it "returns a new client instance" do
6
6
  expect(Goodreads.new).to be_a(Goodreads::Client)
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.5.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: 2017-10-03 00:00:00.000000000 Z
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.6'
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.6'
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: '0.5'
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: '0.5'
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
- rubyforge_project:
223
- rubygems_version: 2.6.13
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