instapaper 1.0.0.pre3 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b394bf891476b148b96540e672a0802158338390
4
- data.tar.gz: b397e12efbfe0eeb28e579d66fea4ccc0b4ad549
3
+ metadata.gz: 9d5a373c9cb9c47ef7fcadc1b9608974f9710756
4
+ data.tar.gz: d3f197b58e0cd8a74f69bf6644333d0071a76220
5
5
  SHA512:
6
- metadata.gz: 08564a692be926e773019744589923d8359ce098701d172fd8f77a69604c11f2920a673a3e920f363839a2264704118ca23fe16fff41b3c1ac3047c942ec62e0
7
- data.tar.gz: e67be46762dbf22c8d0e3b492aaf8e02abc45d7683cfd7d11d795c975dffe5b1d627044180520b7f90ff1592c1c9092c5611041240c705d7c2669ab6bbecf182
6
+ metadata.gz: c1cb814139e10f430465001d096a71e48c4b94f5da15f5ea960c80647c4a67e6946d8bd219b4a7c0acd01a5fff0462a9467fe628c49b90694f6e13710a47d8ce
7
+ data.tar.gz: 716df4e63310adf3a2dba476cfd75e66d31ed42483cd9441fdb59beb583af65527138d927f123b2f7a31f43fca4a9991c98ba70133dfe9fd42af6cca5abe2f45
data/README.md CHANGED
@@ -1,7 +1,14 @@
1
- # Instapaper [![Build Status](https://secure.travis-ci.org/stve/instapaper.png?branch=master)][travis] [![Dependency Status](https://gemnasium.com/stve/instapaper.png?travis)][gemnasium]
1
+ # Instapaper
2
2
 
3
- [travis]: http://travis-ci.org/stve/instapaper
3
+ [![Gem Version](http://img.shields.io/gem/v/instapaper.svg)][gem]
4
+ [![Build Status](http://img.shields.io/travis/stve/instapaper.svg)][travis]
5
+ [![Dependency Status](http://img.shields.io/gemnasium/stve/instapaper.svg)][gemnasium]
6
+ [![Code Climate](http://img.shields.io/codeclimate/github/stve/instapaper.svg)][codeclimate]
7
+
8
+ [gem]: https://rubygems.org/gems/instapaper
9
+ [travis]: https://travis-ci.org/stve/instapaper
4
10
  [gemnasium]: https://gemnasium.com/stve/instapaper
11
+ [codeclimate]: https://codeclimate.com/github/stve/instapaper
5
12
 
6
13
 
7
14
  Instapaper is a ruby wrapper for interacting with [Instapaper's Full API](https://www.instapaper.com/api/full). Note that access to the Full API is restricted to Instapaper subscribers only.
@@ -4,7 +4,7 @@ require 'instapaper/version'
4
4
 
5
5
  Gem::Specification.new do |spec|
6
6
  spec.add_dependency 'addressable', '~> 2.3'
7
- spec.add_dependency 'http', '~> 1.0'
7
+ spec.add_dependency 'http', '~> 2'
8
8
  spec.add_dependency 'multi_json', '~> 1'
9
9
  spec.add_dependency 'simple_oauth', '~> 0.3'
10
10
  spec.add_dependency 'virtus', '~> 1'
@@ -9,7 +9,7 @@ module Instapaper
9
9
  def access_token(username, password)
10
10
  response = perform_post_with_unparsed_response('/api/1.1/oauth/access_token', x_auth_username: username, x_auth_password: password, x_auth_mode: 'client_auth')
11
11
  parsed_response = QLineParser.parse(response)
12
- fail Instapaper::Error::OAuthError, parsed_response['error'] if parsed_response.key?('error')
12
+ raise Instapaper::Error::OAuthError, parsed_response['error'] if parsed_response.key?('error')
13
13
  Instapaper::Credentials.new(parsed_response)
14
14
  end
15
15
  end
@@ -4,14 +4,32 @@ module Instapaper
4
4
  # @return [Integer]
5
5
  attr_reader :code
6
6
 
7
+ ClientError = Class.new(self)
8
+ ServerError = Class.new(self)
7
9
  ServiceUnavailableError = Class.new(self)
8
10
  BookmarkError = Class.new(self)
9
11
  FolderError = Class.new(self)
10
12
  HighlightError = Class.new(self)
11
13
  OAuthError = Class.new(self)
12
14
 
13
- ERRORS = {
14
- 401 => 'Unauthorized',
15
+ CLIENT_ERRORS = {
16
+ 400 => 'Bad Request',
17
+ 401 => 'Unauthorized',
18
+ 402 => 'Payment Required',
19
+ 403 => 'Forbidden',
20
+ 404 => 'Not Found',
21
+ 405 => 'Method Not Allowed',
22
+ }
23
+
24
+ SERVER_ERRORS = {
25
+ 500 => 'Internal Server Error',
26
+ 501 => 'Not Implemented',
27
+ 502 => 'Bad Gateway',
28
+ 503 => 'Service Unavailable',
29
+ 504 => 'Gateway Timeout',
30
+ }
31
+
32
+ SERVICE_ERRORS = {
15
33
  1040 => 'Rate-limit exceeded',
16
34
  1041 => 'Premium account required',
17
35
  1042 => 'Application is suspended',
@@ -43,29 +61,47 @@ module Instapaper
43
61
  }
44
62
 
45
63
  CODES = [
46
- ERRORS,
64
+ CLIENT_ERRORS,
65
+ SERVER_ERRORS,
66
+ SERVICE_ERRORS,
47
67
  BOOKMARK_ERRORS,
48
68
  FOLDER_ERRORS,
49
69
  HIGHLIGHT_ERRORS,
50
70
  ].collect(&:keys).flatten
51
71
 
72
+ HTTP_ERRORS = CLIENT_ERRORS.merge(SERVER_ERRORS)
73
+
52
74
  # Create a new error from an HTTP response
53
75
  #
54
76
  # @param response [HTTP::Response]
55
77
  # @return [Instapaper::Error]
56
78
  def self.from_response(code, path)
57
- if ERRORS.keys.include?(code)
58
- new(ERRORS[code], code)
79
+ if (HTTP_ERRORS.keys + SERVICE_ERRORS.keys).include?(code)
80
+ from_response_code(code)
59
81
  else
60
82
  case path
61
83
  when /highlights/ then HighlightError.new(HIGHLIGHT_ERRORS[code], code)
62
84
  when /bookmarks/ then BookmarkError.new(BOOKMARK_ERRORS[code], code)
63
85
  when /folders/ then FolderError.new(FOLDER_ERRORS[code], code)
64
- else new('Unknown Error Code', code)
86
+ else new('Unknown Error', code)
65
87
  end
66
88
  end
67
89
  end
68
90
 
91
+ # Create a new error from an HTTP response code
92
+ #
93
+ # @param code [Integer]
94
+ # @return [Instapaper::Error]
95
+ def self.from_response_code(code)
96
+ if CLIENT_ERRORS.keys.include?(code)
97
+ ClientError.new(CLIENT_ERRORS[code], code)
98
+ elsif SERVER_ERRORS.keys.include?(code)
99
+ ServerError.new(SERVER_ERRORS[code], code)
100
+ elsif SERVICE_ERRORS.keys.include?(code)
101
+ new(SERVICE_ERRORS[code], code)
102
+ end
103
+ end
104
+
69
105
  # Initializes a new Error object
70
106
  #
71
107
  # @param message [Exception, String]
@@ -1,10 +1,7 @@
1
1
  require 'addressable/uri'
2
2
  require 'http'
3
- require 'json'
4
- require 'net/https'
5
- require 'openssl'
6
- require 'instapaper/error'
7
3
  require 'instapaper/http/headers'
4
+ require 'instapaper/http/response'
8
5
 
9
6
  module Instapaper
10
7
  module HTTP
@@ -27,61 +24,17 @@ module Instapaper
27
24
 
28
25
  # @return [Array, Hash]
29
26
  def perform
30
- perform_request
27
+ raw = @options.delete(:raw)
28
+ response = Instapaper::HTTP::Response.new(perform_request, path, raw)
29
+ response.valid? && response.body
31
30
  end
32
31
 
33
32
  private
34
33
 
35
34
  def perform_request
36
- raw = @options.delete(:raw)
37
35
  @headers = Instapaper::HTTP::Headers.new(@client, @request_method, @uri, @options).request_headers
38
36
  options_key = @request_method == :get ? :params : :form
39
- response = ::HTTP.headers(@headers).public_send(@request_method, @uri.to_s, options_key => @options)
40
- fail_if_error(response, raw)
41
- raw ? response.to_s : parsed_response(response)
42
- end
43
-
44
- def fail_if_error(response, raw)
45
- fail_if_error_unparseable_response(response) unless raw
46
- fail_if_error_in_body(parsed_response(response))
47
- fail_if_error_response_code(response)
48
- end
49
-
50
- def fail_if_error_response_code(response)
51
- return if response.status == 200
52
-
53
- if Instapaper::Error::CODES.include?(response.status.code)
54
- fail Instapaper::Error.from_response(response.status.code, @path)
55
- else
56
- fail Instapaper::Error::ServiceUnavailableError
57
- end
58
- end
59
-
60
- def fail_if_error_unparseable_response(response)
61
- response.parse(:json)
62
- rescue JSON::ParserError
63
- raise Instapaper::Error::ServiceUnavailableError
64
- end
65
-
66
- def fail_if_error_in_body(response)
67
- error = error(response)
68
- fail(error) if error
69
- end
70
-
71
- def error(response)
72
- return unless response.is_a?(Array)
73
- return unless response.size > 0
74
- return unless response.first['type'] == 'error'
75
-
76
- Instapaper::Error.from_response(response.first['error_code'], @path)
77
- end
78
-
79
- def parsed_response(response)
80
- @parsed_response ||= begin
81
- response.parse(:json)
82
- rescue
83
- response.body
84
- end
37
+ ::HTTP.headers(@headers).public_send(@request_method, @uri.to_s, options_key => @options)
85
38
  end
86
39
  end
87
40
  end
@@ -0,0 +1,63 @@
1
+ require 'json'
2
+ require 'instapaper/error'
3
+
4
+ module Instapaper
5
+ module HTTP
6
+ class Response
7
+ attr_reader :response, :raw_format, :path
8
+ def initialize(response, path, raw_format = false)
9
+ @response = response
10
+ @path = path
11
+ @raw_format = raw_format
12
+ end
13
+
14
+ def body
15
+ raw_format ? response.to_s : parsed
16
+ end
17
+
18
+ def valid?
19
+ !error?
20
+ end
21
+
22
+ def error?
23
+ fail_if_body_unparseable unless raw_format
24
+ fail_if_body_contains_error
25
+ fail_if_http_error
26
+ end
27
+
28
+ private
29
+
30
+ def parsed
31
+ @parsed_response ||= begin
32
+ response.parse(:json)
33
+ rescue
34
+ response.body
35
+ end
36
+ end
37
+
38
+ def fail_if_http_error
39
+ return if response.status.ok?
40
+
41
+ if Instapaper::Error::CODES.include?(response.status.code) # rubocop:disable Style/GuardClause
42
+ raise Instapaper::Error.from_response(response.status.code, path)
43
+ else
44
+ raise Instapaper::Error, 'Unknown Error'
45
+ end
46
+ end
47
+
48
+ def fail_if_body_unparseable
49
+ response.parse(:json)
50
+ rescue JSON::ParserError
51
+ raise Instapaper::Error::ServiceUnavailableError
52
+ end
53
+
54
+ def fail_if_body_contains_error
55
+ return unless parsed.is_a?(Array)
56
+ return if parsed.empty?
57
+ return unless parsed.first['type'] == 'error'
58
+
59
+ raise Instapaper::Error.from_response(parsed.first['error_code'], @path)
60
+ end
61
+ end
62
+ end
63
+ end
@@ -60,6 +60,11 @@ module Instapaper
60
60
  if response.key?('hash')
61
61
  response['instapaper_hash'] = response.delete('hash')
62
62
  end
63
+ if response.key?('bookmarks')
64
+ response['bookmarks'] = response['bookmarks'].collect do |bookmark|
65
+ coerce_hash(bookmark)
66
+ end
67
+ end
63
68
  response
64
69
  end
65
70
  end
@@ -1,3 +1,3 @@
1
1
  module Instapaper
2
- VERSION = '1.0.0.pre3'
2
+ VERSION = '1.0.0'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: instapaper
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0.pre3
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Steve Agalloco
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-01-15 00:00:00.000000000 Z
11
+ date: 2017-02-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: addressable
@@ -30,14 +30,14 @@ dependencies:
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '1.0'
33
+ version: '2'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '1.0'
40
+ version: '2'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: multi_json
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -120,6 +120,7 @@ files:
120
120
  - lib/instapaper/http/headers.rb
121
121
  - lib/instapaper/http/qline_parser.rb
122
122
  - lib/instapaper/http/request.rb
123
+ - lib/instapaper/http/response.rb
123
124
  - lib/instapaper/http/utils.rb
124
125
  - lib/instapaper/user.rb
125
126
  - lib/instapaper/version.rb
@@ -138,14 +139,13 @@ required_ruby_version: !ruby/object:Gem::Requirement
138
139
  version: 2.0.0
139
140
  required_rubygems_version: !ruby/object:Gem::Requirement
140
141
  requirements:
141
- - - ">"
142
+ - - ">="
142
143
  - !ruby/object:Gem::Version
143
- version: 1.3.1
144
+ version: '0'
144
145
  requirements: []
145
146
  rubyforge_project:
146
- rubygems_version: 2.4.8
147
+ rubygems_version: 2.6.10
147
148
  signing_key:
148
149
  specification_version: 4
149
150
  summary: Ruby Instapaper Client
150
151
  test_files: []
151
- has_rdoc: