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 +4 -4
- data/README.md +9 -2
- data/instapaper.gemspec +1 -1
- data/lib/instapaper/api/oauth.rb +1 -1
- data/lib/instapaper/error.rb +42 -6
- data/lib/instapaper/http/request.rb +5 -52
- data/lib/instapaper/http/response.rb +63 -0
- data/lib/instapaper/http/utils.rb +5 -0
- data/lib/instapaper/version.rb +1 -1
- metadata +8 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9d5a373c9cb9c47ef7fcadc1b9608974f9710756
|
4
|
+
data.tar.gz: d3f197b58e0cd8a74f69bf6644333d0071a76220
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c1cb814139e10f430465001d096a71e48c4b94f5da15f5ea960c80647c4a67e6946d8bd219b4a7c0acd01a5fff0462a9467fe628c49b90694f6e13710a47d8ce
|
7
|
+
data.tar.gz: 716df4e63310adf3a2dba476cfd75e66d31ed42483cd9441fdb59beb583af65527138d927f123b2f7a31f43fca4a9991c98ba70133dfe9fd42af6cca5abe2f45
|
data/README.md
CHANGED
@@ -1,7 +1,14 @@
|
|
1
|
-
# Instapaper
|
1
|
+
# Instapaper
|
2
2
|
|
3
|
-
[
|
3
|
+
[][gem]
|
4
|
+
[][travis]
|
5
|
+
[][gemnasium]
|
6
|
+
[][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.
|
data/instapaper.gemspec
CHANGED
@@ -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', '~>
|
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'
|
data/lib/instapaper/api/oauth.rb
CHANGED
@@ -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
|
-
|
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
|
data/lib/instapaper/error.rb
CHANGED
@@ -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
|
-
|
14
|
-
|
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
|
-
|
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
|
58
|
-
|
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
|
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
|
-
|
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
|
-
|
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
|
data/lib/instapaper/version.rb
CHANGED
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
|
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:
|
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: '
|
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: '
|
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:
|
144
|
+
version: '0'
|
144
145
|
requirements: []
|
145
146
|
rubyforge_project:
|
146
|
-
rubygems_version: 2.
|
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:
|