x 0.14.1 → 0.15.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +3 -0
- data/README.md +6 -5
- data/lib/x/client.rb +12 -20
- data/lib/x/errors/http_error.rb +1 -1
- data/lib/x/errors/too_many_requests.rb +1 -1
- data/lib/x/media_uploader.rb +26 -31
- data/lib/x/oauth_authenticator.rb +4 -4
- data/lib/x/redirect_handler.rb +3 -3
- data/lib/x/request_builder.rb +4 -5
- data/lib/x/response_parser.rb +7 -8
- data/lib/x/version.rb +1 -1
- data/sig/x.rbs +32 -43
- metadata +4 -9
- data/lib/x/cgi.rb +0 -14
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 546b7411941d44ee91c52d183794a25c0335df8bc86606a6eb6464a2e45222b6
|
4
|
+
data.tar.gz: 17d533d29594706aef376c5970269ea634d5c8eb67216b6b4b9b78c3d3861db1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fd1be4aa484b43ac51d0a6ef04375b9de9c5f3f132ae3d8b33f108838710ef4ea5303ddf8fc89c334639383da5986d5ca16b90be3ae6e9f3b26cc929de091276
|
7
|
+
data.tar.gz: a0c0335a499edc77b0c6c260f16d35a0ffcc9de485b546e0f8477c2eb92426796d7c2588b006926718bcc8b989c06c0c15c20cde177582ede998cfbcf20b1910
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -1,8 +1,9 @@
|
|
1
|
-
[](https://github.com/sferik/x-ruby/actions/workflows/test.yml)
|
2
|
+
[](https://github.com/sferik/x-ruby/actions/workflows/mutant.yml)
|
3
|
+
[](https://github.com/sferik/x-ruby/actions/workflows/lint.yml)
|
4
|
+
[](https://github.com/sferik/x-ruby/actions/workflows/steep.yml)
|
5
|
+
[](https://codeclimate.com/github/sferik/x-ruby/maintainability)
|
6
|
+
[](https://rubygems.org/gems/x)
|
6
7
|
|
7
8
|
# A [Ruby](https://www.ruby-lang.org) interface to the [X API](https://developer.x.com)
|
8
9
|
|
data/lib/x/client.rb
CHANGED
@@ -33,35 +33,30 @@ module X
|
|
33
33
|
default_array_class: DEFAULT_ARRAY_CLASS,
|
34
34
|
default_object_class: DEFAULT_OBJECT_CLASS,
|
35
35
|
max_redirects: RedirectHandler::DEFAULT_MAX_REDIRECTS)
|
36
|
-
|
37
36
|
initialize_oauth(api_key, api_key_secret, access_token, access_token_secret, bearer_token)
|
38
37
|
initialize_authenticator
|
39
38
|
@base_url = base_url
|
40
39
|
initialize_default_classes(default_array_class, default_object_class)
|
41
|
-
@connection = Connection.new(open_timeout
|
42
|
-
write_timeout: write_timeout, debug_output: debug_output, proxy_url: proxy_url)
|
40
|
+
@connection = Connection.new(open_timeout:, read_timeout:, write_timeout:, debug_output:, proxy_url:)
|
43
41
|
@request_builder = RequestBuilder.new
|
44
|
-
@redirect_handler = RedirectHandler.new(connection: @connection, request_builder: @request_builder,
|
45
|
-
max_redirects: max_redirects)
|
42
|
+
@redirect_handler = RedirectHandler.new(connection: @connection, request_builder: @request_builder, max_redirects:)
|
46
43
|
@response_parser = ResponseParser.new
|
47
44
|
end
|
48
45
|
|
49
46
|
def get(endpoint, headers: {}, array_class: default_array_class, object_class: default_object_class)
|
50
|
-
execute_request(:get, endpoint, headers
|
47
|
+
execute_request(:get, endpoint, headers:, array_class:, object_class:)
|
51
48
|
end
|
52
49
|
|
53
50
|
def post(endpoint, body = nil, headers: {}, array_class: default_array_class, object_class: default_object_class)
|
54
|
-
execute_request(:post, endpoint, body
|
55
|
-
object_class: object_class)
|
51
|
+
execute_request(:post, endpoint, body:, headers:, array_class:, object_class:)
|
56
52
|
end
|
57
53
|
|
58
54
|
def put(endpoint, body = nil, headers: {}, array_class: default_array_class, object_class: default_object_class)
|
59
|
-
execute_request(:put, endpoint, body
|
60
|
-
object_class: object_class)
|
55
|
+
execute_request(:put, endpoint, body:, headers:, array_class:, object_class:)
|
61
56
|
end
|
62
57
|
|
63
58
|
def delete(endpoint, headers: {}, array_class: default_array_class, object_class: default_object_class)
|
64
|
-
execute_request(:delete, endpoint, headers
|
59
|
+
execute_request(:delete, endpoint, headers:, array_class:, object_class:)
|
65
60
|
end
|
66
61
|
|
67
62
|
def api_key=(api_key)
|
@@ -106,10 +101,9 @@ module X
|
|
106
101
|
|
107
102
|
def initialize_authenticator
|
108
103
|
@authenticator = if api_key && api_key_secret && access_token && access_token_secret
|
109
|
-
OAuthAuthenticator.new(api_key
|
110
|
-
access_token_secret: access_token_secret)
|
104
|
+
OAuthAuthenticator.new(api_key:, api_key_secret:, access_token:, access_token_secret:)
|
111
105
|
elsif bearer_token
|
112
|
-
BearerTokenAuthenticator.new(bearer_token:
|
106
|
+
BearerTokenAuthenticator.new(bearer_token:)
|
113
107
|
elsif @authenticator.nil?
|
114
108
|
Authenticator.new
|
115
109
|
else
|
@@ -119,12 +113,10 @@ module X
|
|
119
113
|
|
120
114
|
def execute_request(http_method, endpoint, body: nil, headers: {}, array_class: default_array_class, object_class: default_object_class)
|
121
115
|
uri = URI.join(base_url, endpoint)
|
122
|
-
request = @request_builder.build(http_method
|
123
|
-
|
124
|
-
response = @
|
125
|
-
|
126
|
-
authenticator: @authenticator)
|
127
|
-
@response_parser.parse(response: response, array_class: array_class, object_class: object_class)
|
116
|
+
request = @request_builder.build(http_method:, uri:, body:, headers:, authenticator: @authenticator)
|
117
|
+
response = @connection.perform(request:)
|
118
|
+
response = @redirect_handler.handle(response:, request:, base_url:, authenticator: @authenticator)
|
119
|
+
@response_parser.parse(response:, array_class:, object_class:)
|
128
120
|
end
|
129
121
|
end
|
130
122
|
end
|
data/lib/x/errors/http_error.rb
CHANGED
@@ -9,7 +9,7 @@ module X
|
|
9
9
|
|
10
10
|
def rate_limits
|
11
11
|
@rate_limits ||= RateLimit::TYPES.filter_map do |type|
|
12
|
-
RateLimit.new(type
|
12
|
+
RateLimit.new(type:, response:) if response["x-#{type}-remaining"].eql?("0")
|
13
13
|
end
|
14
14
|
end
|
15
15
|
|
data/lib/x/media_uploader.rb
CHANGED
@@ -14,33 +14,29 @@ module X
|
|
14
14
|
GIF_MIME_TYPE, JPEG_MIME_TYPE, MP4_MIME_TYPE, PNG_MIME_TYPE, SUBRIP_MIME_TYPE, WEBP_MIME_TYPE = MIME_TYPES
|
15
15
|
MIME_TYPE_MAP = {"gif" => GIF_MIME_TYPE, "jpg" => JPEG_MIME_TYPE, "jpeg" => JPEG_MIME_TYPE, "mp4" => MP4_MIME_TYPE,
|
16
16
|
"png" => PNG_MIME_TYPE, "srt" => SUBRIP_MIME_TYPE, "webp" => WEBP_MIME_TYPE}.freeze
|
17
|
+
PROCESSING_INFO_STATES = %w[failed succeeded].freeze
|
17
18
|
|
18
19
|
def upload(client:, file_path:, media_category:, media_type: infer_media_type(file_path, media_category),
|
19
20
|
boundary: SecureRandom.hex)
|
20
|
-
validate!(file_path
|
21
|
-
|
22
|
-
upload_body = construct_upload_body(file_path: file_path, media_type: media_type, boundary: boundary)
|
21
|
+
validate!(file_path:, media_category:)
|
22
|
+
upload_body = construct_upload_body(file_path:, media_type:, boundary:)
|
23
23
|
headers = {"Content-Type" => "multipart/form-data, boundary=#{boundary}"}
|
24
|
-
|
24
|
+
client.post("media/upload?media_category=#{media_category}", upload_body, headers:)
|
25
25
|
end
|
26
26
|
|
27
27
|
def chunked_upload(client:, file_path:, media_category:, media_type: infer_media_type(file_path,
|
28
|
-
media_category), boundary: SecureRandom.hex, chunk_size_mb:
|
29
|
-
validate!(file_path
|
30
|
-
|
31
|
-
media = init(upload_client: upload_client, file_path: file_path, media_type: media_type,
|
32
|
-
media_category: media_category)
|
28
|
+
media_category), boundary: SecureRandom.hex, chunk_size_mb: 1)
|
29
|
+
validate!(file_path:, media_category:)
|
30
|
+
media = init(client:, file_path:, media_type:, media_category:)
|
33
31
|
chunk_size = chunk_size_mb * BYTES_PER_MB
|
34
|
-
append(
|
35
|
-
|
36
|
-
upload_client.post("media/upload.json?command=FINALIZE&media_id=#{media["media_id"]}")
|
32
|
+
append(client:, file_paths: split(file_path, chunk_size), media:, media_type:, boundary:)
|
33
|
+
client.post("media/upload?command=FINALIZE&media_key=#{media["media_key"]}")&.fetch("data")
|
37
34
|
end
|
38
35
|
|
39
36
|
def await_processing(client:, media:)
|
40
|
-
upload_client = client.dup.tap { |c| c.base_url = "https://upload.twitter.com/1.1/" }
|
41
37
|
loop do
|
42
|
-
status =
|
43
|
-
return status if !status["processing_info"] ||
|
38
|
+
status = client.get("media/upload?command=STATUS&media_key=#{media["media_key"]}")&.fetch("data")
|
39
|
+
return status if !status["processing_info"] || PROCESSING_INFO_STATES.include?(status["processing_info"]["state"])
|
44
40
|
|
45
41
|
sleep status["processing_info"]["check_after_secs"].to_i
|
46
42
|
end
|
@@ -67,39 +63,38 @@ module X
|
|
67
63
|
|
68
64
|
def split(file_path, chunk_size)
|
69
65
|
file_number = -1
|
66
|
+
file_paths = [] # @type var file_paths: Array[String]
|
70
67
|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
end
|
77
|
-
end
|
68
|
+
File.open(file_path, "rb") do |f|
|
69
|
+
while (chunk = f.read(chunk_size))
|
70
|
+
path = "#{Dir.mktmpdir}/x#{format("%03d", file_number += 1)}"
|
71
|
+
File.binwrite(path, chunk)
|
72
|
+
file_paths << path
|
78
73
|
end
|
79
74
|
end
|
75
|
+
file_paths
|
80
76
|
end
|
81
77
|
|
82
|
-
def init(
|
78
|
+
def init(client:, file_path:, media_type:, media_category:)
|
83
79
|
total_bytes = File.size(file_path)
|
84
80
|
query = "command=INIT&media_type=#{media_type}&media_category=#{media_category}&total_bytes=#{total_bytes}"
|
85
|
-
|
81
|
+
client.post("media/upload?#{query}")&.fetch("data")
|
86
82
|
end
|
87
83
|
|
88
|
-
def append(
|
84
|
+
def append(client:, file_paths:, media:, media_type:, boundary: SecureRandom.hex)
|
89
85
|
threads = file_paths.map.with_index do |file_path, index|
|
90
86
|
Thread.new do
|
91
|
-
upload_body = construct_upload_body(file_path
|
92
|
-
query = "command=APPEND&
|
87
|
+
upload_body = construct_upload_body(file_path:, media_type:, boundary:)
|
88
|
+
query = "command=APPEND&media_key=#{media["media_key"]}&segment_index=#{index}"
|
93
89
|
headers = {"Content-Type" => "multipart/form-data, boundary=#{boundary}"}
|
94
|
-
upload_chunk(
|
95
|
-
headers: headers)
|
90
|
+
upload_chunk(client:, query:, upload_body:, file_path:, headers:)
|
96
91
|
end
|
97
92
|
end
|
98
93
|
threads.each(&:join)
|
99
94
|
end
|
100
95
|
|
101
|
-
def upload_chunk(
|
102
|
-
|
96
|
+
def upload_chunk(client:, query:, upload_body:, file_path:, headers: {})
|
97
|
+
client.post("media/upload?#{query}", upload_body, headers:)
|
103
98
|
rescue NetworkError, ServerError
|
104
99
|
retries ||= 0
|
105
100
|
((retries += 1) < MAX_RETRIES) ? retry : raise
|
@@ -1,10 +1,10 @@
|
|
1
1
|
require "base64"
|
2
|
+
require "cgi"
|
2
3
|
require "json"
|
3
4
|
require "openssl"
|
4
5
|
require "securerandom"
|
5
6
|
require "uri"
|
6
7
|
require_relative "authenticator"
|
7
|
-
require_relative "cgi"
|
8
8
|
|
9
9
|
module X
|
10
10
|
class OAuthAuthenticator < Authenticator
|
@@ -39,7 +39,7 @@ module X
|
|
39
39
|
end
|
40
40
|
|
41
41
|
def uri_without_query(uri)
|
42
|
-
uri.
|
42
|
+
"#{uri.scheme}://#{uri.host}#{uri.path}"
|
43
43
|
end
|
44
44
|
|
45
45
|
def build_oauth_header(method, url, query_params)
|
@@ -71,7 +71,7 @@ module X
|
|
71
71
|
end
|
72
72
|
|
73
73
|
def signature_base_string(method, url, params)
|
74
|
-
"#{method}&#{CGI.
|
74
|
+
"#{method}&#{CGI.escapeURIComponent(url)}&#{CGI.escapeURIComponent(URI.encode_www_form(params.sort))}"
|
75
75
|
end
|
76
76
|
|
77
77
|
def signing_key
|
@@ -79,7 +79,7 @@ module X
|
|
79
79
|
end
|
80
80
|
|
81
81
|
def format_oauth_header(params)
|
82
|
-
"OAuth #{params.sort.map { |k, v| "#{k}=\"#{CGI.
|
82
|
+
"OAuth #{params.sort.map { |k, v| "#{k}=\"#{CGI.escapeURIComponent(v)}\"" }.join(", ")}"
|
83
83
|
end
|
84
84
|
end
|
85
85
|
end
|
data/lib/x/redirect_handler.rb
CHANGED
@@ -28,7 +28,7 @@ module X
|
|
28
28
|
new_request = build_request(request, new_uri, Integer(response.code), authenticator)
|
29
29
|
new_response = connection.perform(request: new_request)
|
30
30
|
|
31
|
-
handle(response: new_response, request: new_request, base_url
|
31
|
+
handle(response: new_response, request: new_request, base_url:, redirect_count: redirect_count + 1)
|
32
32
|
else
|
33
33
|
response
|
34
34
|
end
|
@@ -42,7 +42,7 @@ module X
|
|
42
42
|
URI.join(base_url, location)
|
43
43
|
end
|
44
44
|
|
45
|
-
def build_request(request,
|
45
|
+
def build_request(request, uri, response_code, authenticator)
|
46
46
|
http_method, body = case response_code
|
47
47
|
in 307 | 308
|
48
48
|
[request.method.downcase.to_sym, request.body]
|
@@ -50,7 +50,7 @@ module X
|
|
50
50
|
[:get, nil]
|
51
51
|
end
|
52
52
|
|
53
|
-
request_builder.build(http_method
|
53
|
+
request_builder.build(http_method:, uri:, body:, authenticator:)
|
54
54
|
end
|
55
55
|
end
|
56
56
|
end
|
data/lib/x/request_builder.rb
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
require "net/http"
|
2
2
|
require "uri"
|
3
3
|
require_relative "authenticator"
|
4
|
-
require_relative "cgi"
|
5
4
|
require_relative "version"
|
6
5
|
|
7
6
|
module X
|
@@ -18,9 +17,9 @@ module X
|
|
18
17
|
}.freeze
|
19
18
|
|
20
19
|
def build(http_method:, uri:, body: nil, headers: {}, authenticator: Authenticator.new)
|
21
|
-
request = create_request(http_method
|
22
|
-
add_headers(request
|
23
|
-
add_authentication(request
|
20
|
+
request = create_request(http_method:, uri:, body:)
|
21
|
+
add_headers(request:, headers:)
|
22
|
+
add_authentication(request:, authenticator:)
|
24
23
|
request
|
25
24
|
end
|
26
25
|
|
@@ -51,7 +50,7 @@ module X
|
|
51
50
|
end
|
52
51
|
|
53
52
|
def escape_query_params(uri)
|
54
|
-
URI(uri).tap { |u| u.query =
|
53
|
+
URI(uri).tap { |u| u.query = URI.encode_www_form(URI.decode_www_form(u.query)) if u.query }
|
55
54
|
end
|
56
55
|
end
|
57
56
|
end
|
data/lib/x/response_parser.rb
CHANGED
@@ -34,28 +34,27 @@ module X
|
|
34
34
|
503 => ServiceUnavailable,
|
35
35
|
504 => GatewayTimeout
|
36
36
|
}.freeze
|
37
|
-
JSON_CONTENT_TYPE_REGEXP = %r{application/json}
|
38
37
|
|
39
38
|
def parse(response:, array_class: nil, object_class: nil)
|
40
39
|
raise error(response) unless response.is_a?(Net::HTTPSuccess)
|
41
40
|
|
42
|
-
return
|
41
|
+
return if response.instance_of?(Net::HTTPNoContent)
|
43
42
|
|
44
|
-
|
43
|
+
begin
|
44
|
+
JSON.parse(response.body, array_class:, object_class:)
|
45
|
+
rescue JSON::ParserError
|
46
|
+
nil
|
47
|
+
end
|
45
48
|
end
|
46
49
|
|
47
50
|
private
|
48
51
|
|
49
52
|
def error(response)
|
50
|
-
error_class(response).new(response:
|
53
|
+
error_class(response).new(response:)
|
51
54
|
end
|
52
55
|
|
53
56
|
def error_class(response)
|
54
57
|
ERROR_MAP[Integer(response.code)] || HTTPError
|
55
58
|
end
|
56
|
-
|
57
|
-
def json?(response)
|
58
|
-
JSON_CONTENT_TYPE_REGEXP.match?(response["content-type"])
|
59
|
-
end
|
60
59
|
end
|
61
60
|
end
|
data/lib/x/version.rb
CHANGED
data/sig/x.rbs
CHANGED
@@ -125,6 +125,8 @@ module X
|
|
125
125
|
DEFAULT_DEBUG_OUTPUT: IO
|
126
126
|
NETWORK_ERRORS: Array[(singleton(Errno::ECONNREFUSED) | singleton(Errno::ECONNRESET) | singleton(Net::OpenTimeout) | singleton(Net::ReadTimeout) | singleton(OpenSSL::SSL::SSLError))]
|
127
127
|
|
128
|
+
@proxy_url: URI::Generic | String
|
129
|
+
|
128
130
|
extend Forwardable
|
129
131
|
|
130
132
|
attr_accessor open_timeout : Float | Integer
|
@@ -151,7 +153,7 @@ module X
|
|
151
153
|
RATE_LIMIT_TYPE: String
|
152
154
|
APP_LIMIT_TYPE: String
|
153
155
|
USER_LIMIT_TYPE: String
|
154
|
-
TYPES: [String
|
156
|
+
TYPES: Array[String]
|
155
157
|
|
156
158
|
attr_accessor type: String
|
157
159
|
attr_accessor response: Net::HTTPResponse
|
@@ -167,7 +169,7 @@ module X
|
|
167
169
|
DEFAULT_HEADERS: Hash[String, String]
|
168
170
|
|
169
171
|
def initialize: (?content_type: String, ?user_agent: String) -> void
|
170
|
-
def build: (
|
172
|
+
def build: (http_method: Symbol, uri: URI::Generic, ?body: String?, ?headers: Hash[String, String], ?authenticator: Authenticator) -> (Net::HTTPRequest)
|
171
173
|
|
172
174
|
private
|
173
175
|
def create_request: (http_method: Symbol, uri: URI::Generic, body: String?) -> (Net::HTTPRequest)
|
@@ -183,7 +185,7 @@ module X
|
|
183
185
|
attr_reader connection: Connection
|
184
186
|
attr_reader request_builder: RequestBuilder
|
185
187
|
attr_reader max_redirects: Integer
|
186
|
-
def initialize: (connection: Connection, request_builder: RequestBuilder, ?max_redirects: Integer) -> void
|
188
|
+
def initialize: (?connection: Connection, ?request_builder: RequestBuilder, ?max_redirects: Integer) -> void
|
187
189
|
def handle: (response: Net::HTTPResponse, request: Net::HTTPRequest, base_url: String, ?authenticator: Authenticator, ?redirect_count: Integer) -> Net::HTTPResponse
|
188
190
|
|
189
191
|
private
|
@@ -193,60 +195,51 @@ module X
|
|
193
195
|
end
|
194
196
|
|
195
197
|
class ResponseParser
|
196
|
-
ERROR_MAP: Hash[Integer, singleton(
|
197
|
-
JSON_CONTENT_TYPE_REGEXP: Regexp
|
198
|
+
ERROR_MAP: Hash[Integer, singleton(BadGateway) | singleton(BadRequest) | singleton(ConnectionException) | singleton(Forbidden) | singleton(GatewayTimeout) | singleton(Gone) | singleton(InternalServerError) | singleton(NotAcceptable) | singleton(NotFound) | singleton(PayloadTooLarge) | singleton(ServiceUnavailable) | singleton(TooManyRequests) | singleton(Unauthorized) | singleton(UnprocessableEntity)]
|
198
199
|
|
199
200
|
def parse: (response: Net::HTTPResponse, ?array_class: Class?, ?object_class: Class?) -> untyped
|
200
201
|
|
201
202
|
private
|
202
|
-
def error: (Net::HTTPResponse response) ->
|
203
|
-
def error_class: (Net::HTTPResponse response) -> (singleton(
|
203
|
+
def error: (Net::HTTPResponse response) -> HTTPError
|
204
|
+
def error_class: (Net::HTTPResponse response) -> (singleton(BadGateway) | singleton(BadRequest) | singleton(ConnectionException) | singleton(Forbidden) | singleton(GatewayTimeout) | singleton(Gone) | singleton(InternalServerError) | singleton(NotAcceptable) | singleton(NotFound) | singleton(PayloadTooLarge) | singleton(ServiceUnavailable) | singleton(TooManyRequests) | singleton(Unauthorized) | singleton(UnprocessableEntity))
|
204
205
|
def json?: (Net::HTTPResponse response) -> bool
|
205
206
|
end
|
206
207
|
|
207
208
|
class Client
|
208
209
|
DEFAULT_BASE_URL: String
|
209
|
-
DEFAULT_ARRAY_CLASS:
|
210
|
-
DEFAULT_OBJECT_CLASS:
|
211
|
-
|
210
|
+
DEFAULT_ARRAY_CLASS: singleton(Array)
|
211
|
+
DEFAULT_OBJECT_CLASS: singleton(Hash)
|
212
212
|
extend Forwardable
|
213
|
-
@authenticator: Authenticator
|
213
|
+
@authenticator: Authenticator | BearerTokenAuthenticator | OAuthAuthenticator
|
214
214
|
@connection: Connection
|
215
215
|
@request_builder: RequestBuilder
|
216
216
|
@redirect_handler: RedirectHandler
|
217
217
|
@response_parser: ResponseParser
|
218
218
|
|
219
|
-
attr_accessor access_token: String
|
220
|
-
attr_accessor access_token_secret: String
|
221
|
-
attr_accessor api_key: String
|
222
|
-
attr_accessor api_key_secret: String
|
223
|
-
attr_accessor bearer_token: String
|
224
219
|
attr_accessor base_url: String
|
225
|
-
attr_accessor
|
226
|
-
attr_accessor
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
attr_accessor authenticator: Authenticator
|
234
|
-
attr_accessor connection: Connection
|
235
|
-
attr_accessor request_builder: RequestBuilder
|
236
|
-
attr_accessor redirect_handler: RedirectHandler
|
237
|
-
attr_accessor response_parser: ResponseParser
|
238
|
-
|
239
|
-
def initialize: (?api_key: String?, ?api_key_secret: String?, ?access_token: String?, ?access_token_secret: String?, ?bearer_token: String?, ?base_url: String, ?open_timeout: Float | Integer, ?read_timeout: Float | Integer, ?write_timeout: Float | Integer, ?proxy_url: URI::Generic? | String?, ?debug_output: IO, ?default_array_class: Class, ?default_object_class: Class, ?max_redirects: Integer) -> void
|
220
|
+
attr_accessor default_array_class: singleton(Array)
|
221
|
+
attr_accessor default_object_class: singleton(Hash)
|
222
|
+
attr_reader api_key: String?
|
223
|
+
attr_reader api_key_secret: String?
|
224
|
+
attr_reader access_token: String?
|
225
|
+
attr_reader access_token_secret: String?
|
226
|
+
attr_reader bearer_token: String?
|
227
|
+
def initialize: (?api_key: nil, ?api_key_secret: nil, ?access_token: nil, ?access_token_secret: nil, ?bearer_token: nil, ?base_url: String, ?open_timeout: Integer, ?read_timeout: Integer, ?write_timeout: Integer, ?debug_output: untyped, ?proxy_url: nil, ?default_array_class: singleton(Array), ?default_object_class: singleton(Hash), ?max_redirects: Integer) -> void
|
240
228
|
def get: (String endpoint, ?headers: Hash[String, String], ?array_class: Class, ?object_class: Class) -> untyped
|
241
229
|
def post: (String endpoint, ?String? body, ?headers: Hash[String, String], ?array_class: Class, ?object_class: Class) -> untyped
|
242
230
|
def put: (String endpoint, ?String? body, ?headers: Hash[String, String], ?array_class: Class, ?object_class: Class) -> untyped
|
243
231
|
def delete: (String endpoint, ?headers: Hash[String, String], ?array_class: Class, ?object_class: Class) -> untyped
|
232
|
+
def api_key=: (String api_key) -> void
|
233
|
+
def api_key_secret=: (String api_key_secret) -> void
|
234
|
+
def access_token=: (String access_token) -> void
|
235
|
+
def access_token_secret=: (String access_token_secret) -> void
|
236
|
+
def bearer_token=: (String bearer_token) -> void
|
244
237
|
|
245
238
|
private
|
246
239
|
def initialize_oauth: (String? api_key, String? api_key_secret, String? access_token, String? access_token_secret, String? bearer_token) -> void
|
247
|
-
def initialize_default_classes: (
|
248
|
-
def initialize_authenticator: -> Authenticator
|
249
|
-
def execute_request: (
|
240
|
+
def initialize_default_classes: (singleton(Array) default_array_class, singleton(Hash) default_object_class) -> singleton(Hash)
|
241
|
+
def initialize_authenticator: -> (Authenticator | BearerTokenAuthenticator | OAuthAuthenticator)
|
242
|
+
def execute_request: (:delete | :get | :post | :put http_method, String endpoint, ?body: String?, ?headers: Hash[String, String], ?array_class: Class, ?object_class: Class) -> nil
|
250
243
|
end
|
251
244
|
|
252
245
|
module MediaUploader
|
@@ -269,6 +262,7 @@ module X
|
|
269
262
|
SUBRIP_MIME_TYPE: String
|
270
263
|
WEBP_MIME_TYPE: String
|
271
264
|
MIME_TYPE_MAP: Hash[String, String]
|
265
|
+
PROCESSING_INFO_STATES: Array[String]
|
272
266
|
extend MediaUploader
|
273
267
|
|
274
268
|
def upload: (client: Client, file_path: String, media_category: String, ?media_type: String, ?boundary: String) -> untyped
|
@@ -279,16 +273,11 @@ module X
|
|
279
273
|
def validate!: (file_path: String, media_category: String) -> nil
|
280
274
|
def infer_media_type: (String file_path, String media_category) -> String
|
281
275
|
def split: (String file_path, Integer chunk_size) -> Array[String]
|
282
|
-
def init: (
|
283
|
-
def append: (
|
284
|
-
def upload_chunk: (
|
276
|
+
def init: (client: Client, file_path: String, media_type: String, media_category: String) -> untyped
|
277
|
+
def append: (client: Client, file_paths: Array[String], media: untyped, media_type: String, ?boundary: String) -> Array[String]
|
278
|
+
def upload_chunk: (client: Client, query: String, upload_body: String, file_path: String, ?headers: Hash[String, String]) -> Integer?
|
285
279
|
def cleanup_file: (String file_path) -> Integer?
|
286
|
-
def finalize: (
|
280
|
+
def finalize: (client: Client, media: untyped) -> untyped
|
287
281
|
def construct_upload_body: (file_path: String, media_type: String, ?boundary: String) -> String
|
288
282
|
end
|
289
|
-
|
290
|
-
class CGI
|
291
|
-
def self.escape: (String value) -> String
|
292
|
-
def self.escape_params: (Hash[String, String] | Array[[String, String]] params) -> String
|
293
|
-
end
|
294
283
|
end
|
metadata
CHANGED
@@ -1,16 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: x
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.15.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Erik Berlin
|
8
|
-
autorequire:
|
9
8
|
bindir: exe
|
10
9
|
cert_chain: []
|
11
|
-
date:
|
10
|
+
date: 2025-02-06 00:00:00.000000000 Z
|
12
11
|
dependencies: []
|
13
|
-
description:
|
14
12
|
email:
|
15
13
|
- sferik@gmail.com
|
16
14
|
executables: []
|
@@ -25,7 +23,6 @@ files:
|
|
25
23
|
- lib/x.rb
|
26
24
|
- lib/x/authenticator.rb
|
27
25
|
- lib/x/bearer_token_authenticator.rb
|
28
|
-
- lib/x/cgi.rb
|
29
26
|
- lib/x/client.rb
|
30
27
|
- lib/x/connection.rb
|
31
28
|
- lib/x/errors/bad_gateway.rb
|
@@ -67,7 +64,6 @@ metadata:
|
|
67
64
|
changelog_uri: https://github.com/sferik/x-ruby/blob/master/CHANGELOG.md
|
68
65
|
bug_tracker_uri: https://github.com/sferik/x-ruby/issues
|
69
66
|
documentation_uri: https://rubydoc.info/gems/x/
|
70
|
-
post_install_message:
|
71
67
|
rdoc_options: []
|
72
68
|
require_paths:
|
73
69
|
- lib
|
@@ -75,15 +71,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
75
71
|
requirements:
|
76
72
|
- - ">="
|
77
73
|
- !ruby/object:Gem::Version
|
78
|
-
version: '3.
|
74
|
+
version: '3.2'
|
79
75
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
80
76
|
requirements:
|
81
77
|
- - ">="
|
82
78
|
- !ruby/object:Gem::Version
|
83
79
|
version: '0'
|
84
80
|
requirements: []
|
85
|
-
rubygems_version: 3.
|
86
|
-
signing_key:
|
81
|
+
rubygems_version: 3.6.3
|
87
82
|
specification_version: 4
|
88
83
|
summary: A Ruby interface to the X API.
|
89
84
|
test_files: []
|
data/lib/x/cgi.rb
DELETED
@@ -1,14 +0,0 @@
|
|
1
|
-
require "cgi"
|
2
|
-
|
3
|
-
module X
|
4
|
-
class CGI
|
5
|
-
# TODO: Replace CGI.escape with CGI.escapeURIComponent when support for Ruby 3.1 is dropped
|
6
|
-
def self.escape(value)
|
7
|
-
::CGI.escape(value).gsub("+", "%20")
|
8
|
-
end
|
9
|
-
|
10
|
-
def self.escape_params(params)
|
11
|
-
params.map { |k, v| "#{k}=#{escape(v)}" }.join("&")
|
12
|
-
end
|
13
|
-
end
|
14
|
-
end
|