x 0.8.0 → 0.9.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 +8 -0
- data/README.md +16 -0
- data/bin/console +10 -0
- data/bin/setup +6 -0
- data/lib/x/client.rb +2 -1
- data/lib/x/connection.rb +57 -8
- data/lib/x/redirect_handler.rb +1 -1
- data/lib/x/version.rb +1 -1
- data/sig/x.rbs +17 -8
- metadata +8 -8
- data/.rubocop.yml +0 -54
- data/Gemfile +0 -18
- data/Rakefile +0 -23
- data/Steepfile +0 -13
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7ff134774b6d6b28f3f72c740c74b1f44b11ce94cff63fbfe4eabc0414f600c3
|
4
|
+
data.tar.gz: 9f3b9abd3ca2628979676b5f634781b960adf6afe8a77559cf6f3a96ee738098
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cd471d0b216161f5e68832e83b5024a8a89cdda1c815f49543f8361b225776ad46f84690eddf9a9b884cf0ab540924ecae94ebd145f26ac07e44ffdf7c4ff1f2
|
7
|
+
data.tar.gz: 3670666ca95e154a253be800af600cdcaf44195b9dcd3d001e1404d85f27dd5939ce09bd25588cfbe81cefef92ce22bfcd26e105dcb70d813bc4efa221a4360d
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,13 @@
|
|
1
1
|
## [Unreleased]
|
2
2
|
|
3
|
+
## [0.9.0] - 2023-09-26
|
4
|
+
|
5
|
+
- Add support for HTTP proxies (3740f4f)
|
6
|
+
|
7
|
+
## [0.8.1] - 2023-09-20
|
8
|
+
|
9
|
+
- Fix bug where setting Connection#base_uri= doesn't update the HTTP client (d5a89db)
|
10
|
+
|
3
11
|
## [0.8.0] - 2023-09-14
|
4
12
|
|
5
13
|
- Add (back) bearer token authentication (62e141d)
|
data/README.md
CHANGED
@@ -56,6 +56,8 @@ ads_client = X::Client.new(base_url: "https://ads-api.twitter.com/12/", **x_cred
|
|
56
56
|
ads_client.get("accounts")
|
57
57
|
```
|
58
58
|
|
59
|
+
See other common usage [examples](https://github.com/sferik/x-ruby/tree/main/examples).
|
60
|
+
|
59
61
|
## History and Philosophy
|
60
62
|
|
61
63
|
This library is a rewrite of the [Twitter Ruby library](https://github.com/sferik/twitter). Over 16 years of development, that library ballooned to over 3,000 lines of code (plus 7,500 lines of tests). At the time of writing, this library is about 300 lines of code (plus 200 test lines) and I’d like to keep it that way. That doesn’t mean new features won’t be added over time, but the benefits of more code must be weighted against the benefits of less:
|
@@ -74,6 +76,20 @@ The tests for the previous version of this library executed in about 2 seconds.
|
|
74
76
|
|
75
77
|
This code is not littered with comments that are intended to generate documentation. Rather, this code is intended to be simple enough to serve as its own documentation. If you want to understand how something works, don’t read the documentation—it might be wrong—read the code. The code is always right.
|
76
78
|
|
79
|
+
## Sponsorship
|
80
|
+
|
81
|
+
The X gem is free to use, but with X API pricing tiers, it actually costs money to develop and maintain. By contributing to the project, you help us:
|
82
|
+
|
83
|
+
1. Maintain the library: Keeping it up-to-date and secure.
|
84
|
+
2. Add new features: Enhancements that make your life easier.
|
85
|
+
3. Provide support: Faster responses to issues and feature requests.
|
86
|
+
|
87
|
+
⭐️ Bonus: Sponsors will get priority support and influence over the project roadmap. We will also list your name or your company's logo on our GitHub page.
|
88
|
+
|
89
|
+
Building and maintaining an open-source project like this takes a considerable amount of time and effort. Your sponsorship can help sustain this project. Even a small monthly donation makes a huge difference!
|
90
|
+
|
91
|
+
[Click here to sponsor this project.](https://github.com/sponsors/sferik)
|
92
|
+
|
77
93
|
## Development
|
78
94
|
|
79
95
|
1. Checkout and repo:
|
data/bin/console
ADDED
data/bin/setup
ADDED
data/lib/x/client.rb
CHANGED
@@ -26,6 +26,7 @@ module X
|
|
26
26
|
open_timeout: Connection::DEFAULT_OPEN_TIMEOUT,
|
27
27
|
read_timeout: Connection::DEFAULT_READ_TIMEOUT,
|
28
28
|
write_timeout: Connection::DEFAULT_WRITE_TIMEOUT,
|
29
|
+
proxy_url: nil,
|
29
30
|
content_type: RequestBuilder::DEFAULT_CONTENT_TYPE,
|
30
31
|
user_agent: RequestBuilder::DEFAULT_USER_AGENT,
|
31
32
|
debug_output: nil,
|
@@ -35,7 +36,7 @@ module X
|
|
35
36
|
|
36
37
|
initialize_authenticator(bearer_token, api_key, api_key_secret, access_token, access_token_secret)
|
37
38
|
@connection = Connection.new(base_url: base_url, open_timeout: open_timeout, read_timeout: read_timeout,
|
38
|
-
write_timeout: write_timeout, debug_output: debug_output)
|
39
|
+
write_timeout: write_timeout, debug_output: debug_output, proxy_url: proxy_url)
|
39
40
|
@request_builder = RequestBuilder.new(content_type: content_type, user_agent: user_agent)
|
40
41
|
@redirect_handler = RedirectHandler.new(@authenticator, @connection, @request_builder,
|
41
42
|
max_redirects: max_redirects)
|
data/lib/x/connection.rb
CHANGED
@@ -9,6 +9,8 @@ module X
|
|
9
9
|
extend Forwardable
|
10
10
|
|
11
11
|
DEFAULT_BASE_URL = "https://api.twitter.com/2/".freeze
|
12
|
+
DEFAULT_HOST = "https://api.twitter.com".freeze
|
13
|
+
DEFAULT_PORT = 443
|
12
14
|
DEFAULT_OPEN_TIMEOUT = 60 # seconds
|
13
15
|
DEFAULT_READ_TIMEOUT = 60 # seconds
|
14
16
|
DEFAULT_WRITE_TIMEOUT = 60 # seconds
|
@@ -18,21 +20,22 @@ module X
|
|
18
20
|
Net::ReadTimeout
|
19
21
|
].freeze
|
20
22
|
|
21
|
-
attr_reader :base_uri
|
23
|
+
attr_reader :base_uri, :proxy_uri, :http_client
|
22
24
|
|
23
25
|
def_delegators :@http_client, :open_timeout, :read_timeout, :write_timeout
|
24
26
|
def_delegators :@http_client, :open_timeout=, :read_timeout=, :write_timeout=
|
25
27
|
def_delegator :@http_client, :set_debug_output, :debug_output=
|
26
28
|
|
27
29
|
def initialize(base_url: DEFAULT_BASE_URL, open_timeout: DEFAULT_OPEN_TIMEOUT,
|
28
|
-
read_timeout: DEFAULT_READ_TIMEOUT, write_timeout: DEFAULT_WRITE_TIMEOUT, debug_output: nil)
|
30
|
+
read_timeout: DEFAULT_READ_TIMEOUT, write_timeout: DEFAULT_WRITE_TIMEOUT, proxy_url: nil, debug_output: nil)
|
31
|
+
@proxy_uri = URI(proxy_url) unless proxy_url.nil?
|
29
32
|
self.base_uri = base_url
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
33
|
+
apply_http_client_settings(
|
34
|
+
open_timeout: open_timeout,
|
35
|
+
read_timeout: read_timeout,
|
36
|
+
write_timeout: write_timeout,
|
37
|
+
debug_output: debug_output
|
38
|
+
)
|
36
39
|
end
|
37
40
|
|
38
41
|
def send_request(request)
|
@@ -46,10 +49,56 @@ module X
|
|
46
49
|
raise ArgumentError, "Invalid base URL" unless base_uri.is_a?(URI::HTTPS) || base_uri.is_a?(URI::HTTP)
|
47
50
|
|
48
51
|
@base_uri = base_uri
|
52
|
+
update_http_client_settings
|
49
53
|
end
|
50
54
|
|
51
55
|
def debug_output
|
52
56
|
@http_client.instance_variable_get(:@debug_output)
|
53
57
|
end
|
58
|
+
|
59
|
+
private
|
60
|
+
|
61
|
+
def apply_http_client_settings(open_timeout:, read_timeout:, write_timeout:, debug_output:)
|
62
|
+
@http_client.open_timeout = open_timeout
|
63
|
+
@http_client.read_timeout = read_timeout
|
64
|
+
@http_client.write_timeout = write_timeout
|
65
|
+
@http_client.set_debug_output(debug_output) if debug_output
|
66
|
+
end
|
67
|
+
|
68
|
+
def current_http_client_settings
|
69
|
+
{
|
70
|
+
open_timeout: @http_client.open_timeout,
|
71
|
+
read_timeout: @http_client.read_timeout,
|
72
|
+
write_timeout: @http_client.write_timeout,
|
73
|
+
debug_output: debug_output
|
74
|
+
}
|
75
|
+
end
|
76
|
+
|
77
|
+
def update_http_client_settings
|
78
|
+
conditionally_apply_http_client_settings do
|
79
|
+
host = @base_uri.host || DEFAULT_HOST
|
80
|
+
port = @base_uri.port || DEFAULT_PORT
|
81
|
+
@http_client = build_http_client(host: host, port: port)
|
82
|
+
@http_client.use_ssl = @base_uri.scheme == "https"
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def build_http_client(host:, port:)
|
87
|
+
if @proxy_uri.nil?
|
88
|
+
Net::HTTP.new(host, port)
|
89
|
+
else
|
90
|
+
Net::HTTP.new(host, port, @proxy_uri&.host, @proxy_uri&.port, @proxy_uri&.user, @proxy_uri&.password)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def conditionally_apply_http_client_settings
|
95
|
+
if @http_client
|
96
|
+
settings = current_http_client_settings
|
97
|
+
yield
|
98
|
+
apply_http_client_settings(**settings)
|
99
|
+
else
|
100
|
+
yield
|
101
|
+
end
|
102
|
+
end
|
54
103
|
end
|
55
104
|
end
|
data/lib/x/redirect_handler.rb
CHANGED
@@ -49,7 +49,7 @@ module X
|
|
49
49
|
def send_new_request(new_uri, new_request)
|
50
50
|
@connection = Connection.new(base_url: new_uri, open_timeout: connection.open_timeout,
|
51
51
|
read_timeout: connection.read_timeout, write_timeout: connection.write_timeout,
|
52
|
-
debug_output: connection.debug_output)
|
52
|
+
debug_output: connection.debug_output, proxy_url: connection.proxy_uri)
|
53
53
|
connection.send_request(new_request)
|
54
54
|
end
|
55
55
|
end
|
data/lib/x/version.rb
CHANGED
data/sig/x.rbs
CHANGED
@@ -82,23 +82,32 @@ module X
|
|
82
82
|
end
|
83
83
|
|
84
84
|
class Connection
|
85
|
-
extend Forwardable
|
86
|
-
|
87
85
|
DEFAULT_BASE_URL: String
|
86
|
+
DEFAULT_HOST: String
|
87
|
+
DEFAULT_PORT: Integer
|
88
88
|
DEFAULT_OPEN_TIMEOUT: Integer
|
89
89
|
DEFAULT_READ_TIMEOUT: Integer
|
90
90
|
DEFAULT_WRITE_TIMEOUT: Integer
|
91
91
|
NETWORK_ERRORS: Array[(singleton(::Errno::ECONNREFUSED) | singleton(::Net::OpenTimeout) | singleton(::Net::ReadTimeout))]
|
92
|
+
extend Forwardable
|
92
93
|
@http_client: Net::HTTP
|
93
94
|
|
94
95
|
attr_reader base_uri: URI::Generic
|
95
|
-
attr_reader
|
96
|
-
attr_reader
|
97
|
-
attr_reader
|
98
|
-
|
96
|
+
attr_reader proxy_uri: URI::Generic?
|
97
|
+
attr_reader open_timeout : Float | Integer
|
98
|
+
attr_reader read_timeout : Float | Integer
|
99
|
+
attr_reader write_timeout : Float | Integer
|
100
|
+
def initialize: (?base_url: URI::Generic | String, ?open_timeout: Float | Integer, ?read_timeout: Float | Integer, ?write_timeout: Float | Integer, ?proxy_url: URI::Generic? | String?, ?debug_output: IO?) -> void
|
99
101
|
def send_request: (Net::HTTPRequest request) -> Net::HTTPResponse
|
100
|
-
def base_uri=: (URI::Generic | String base_url) ->
|
102
|
+
def base_uri=: (URI::Generic | String base_url) -> void
|
101
103
|
def debug_output: -> IO?
|
104
|
+
|
105
|
+
private
|
106
|
+
def apply_http_client_settings: (open_timeout: Float | Integer, read_timeout: Float | Integer, write_timeout: Float | Integer, debug_output: IO?) -> untyped
|
107
|
+
def current_http_client_settings: -> {open_timeout: Float | Integer, read_timeout: Float | Integer, write_timeout: Float | Integer, debug_output: IO?}
|
108
|
+
def update_http_client_settings: -> untyped
|
109
|
+
def build_http_client: (host: String, port: Integer) -> (Net::HTTP)
|
110
|
+
def conditionally_apply_http_client_settings: { -> untyped } -> untyped
|
102
111
|
end
|
103
112
|
|
104
113
|
class RequestBuilder
|
@@ -161,7 +170,7 @@ module X
|
|
161
170
|
@response_handler: ResponseHandler
|
162
171
|
|
163
172
|
attr_reader base_uri: URI::Generic
|
164
|
-
def initialize: (?bearer_token: String?, ?api_key: String?, ?api_key_secret: String?, ?access_token: String?, ?access_token_secret: String?, ?base_url: URI::Generic | String, ?content_type: String, ?user_agent: String, ?open_timeout: Float | Integer, ?read_timeout: Float | Integer, ?write_timeout: Float | Integer, ?debug_output: IO?, ?array_class: Class, ?object_class: Class, ?max_redirects: Integer) -> void
|
173
|
+
def initialize: (?bearer_token: String?, ?api_key: String?, ?api_key_secret: String?, ?access_token: String?, ?access_token_secret: String?, ?base_url: URI::Generic | String, ?content_type: String, ?user_agent: String, ?open_timeout: Float | Integer, ?read_timeout: Float | Integer, ?write_timeout: Float | Integer, ?proxy_url: URI::Generic? | String?, ?debug_output: IO?, ?array_class: Class, ?object_class: Class, ?max_redirects: Integer) -> void
|
165
174
|
def get: (String endpoint) -> Hash[String, untyped]
|
166
175
|
def post: (String endpoint, ?nil body) -> Hash[String, untyped]
|
167
176
|
def put: (String endpoint, ?nil body) -> Hash[String, untyped]
|
metadata
CHANGED
@@ -1,14 +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.9.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Erik Berlin
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-09-
|
11
|
+
date: 2023-09-26 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description:
|
14
14
|
email:
|
@@ -17,13 +17,11 @@ executables: []
|
|
17
17
|
extensions: []
|
18
18
|
extra_rdoc_files: []
|
19
19
|
files:
|
20
|
-
- ".rubocop.yml"
|
21
20
|
- CHANGELOG.md
|
22
|
-
- Gemfile
|
23
21
|
- LICENSE.txt
|
24
22
|
- README.md
|
25
|
-
-
|
26
|
-
-
|
23
|
+
- bin/console
|
24
|
+
- bin/setup
|
27
25
|
- lib/x.rb
|
28
26
|
- lib/x/bearer_token_authenticator.rb
|
29
27
|
- lib/x/client.rb
|
@@ -50,10 +48,12 @@ licenses:
|
|
50
48
|
- MIT
|
51
49
|
metadata:
|
52
50
|
allowed_push_host: https://rubygems.org
|
51
|
+
rubygems_mfa_required: 'true'
|
53
52
|
homepage_uri: https://sferik.github.io/x-ruby
|
54
53
|
source_code_uri: https://github.com/sferik/x-ruby
|
55
54
|
changelog_uri: https://github.com/sferik/x-ruby/blob/master/CHANGELOG.md
|
56
|
-
|
55
|
+
bug_tracker_uri: https://github.com/sferik/x-ruby/issues
|
56
|
+
documentation_uri: https://rubydoc.info/gems/x/
|
57
57
|
post_install_message:
|
58
58
|
rdoc_options: []
|
59
59
|
require_paths:
|
@@ -69,7 +69,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
69
69
|
- !ruby/object:Gem::Version
|
70
70
|
version: '0'
|
71
71
|
requirements: []
|
72
|
-
rubygems_version: 3.4.
|
72
|
+
rubygems_version: 3.4.19
|
73
73
|
signing_key:
|
74
74
|
specification_version: 4
|
75
75
|
summary: A Ruby interface to the X API.
|
data/.rubocop.yml
DELETED
@@ -1,54 +0,0 @@
|
|
1
|
-
require:
|
2
|
-
- standard
|
3
|
-
- standard-performance
|
4
|
-
- rubocop-minitest
|
5
|
-
- rubocop-performance
|
6
|
-
- rubocop-rake
|
7
|
-
|
8
|
-
AllCops:
|
9
|
-
NewCops: enable
|
10
|
-
TargetRubyVersion: 3.0
|
11
|
-
|
12
|
-
Layout/ArgumentAlignment:
|
13
|
-
Enabled: true
|
14
|
-
EnforcedStyle: with_fixed_indentation
|
15
|
-
|
16
|
-
Layout/ArrayAlignment:
|
17
|
-
Enabled: true
|
18
|
-
EnforcedStyle: with_fixed_indentation
|
19
|
-
|
20
|
-
Layout/EndAlignment:
|
21
|
-
Enabled: true
|
22
|
-
EnforcedStyleAlignWith: variable
|
23
|
-
|
24
|
-
Layout/HashAlignment:
|
25
|
-
Enabled: true
|
26
|
-
EnforcedHashRocketStyle: key
|
27
|
-
EnforcedColonStyle: key
|
28
|
-
EnforcedLastArgumentHashStyle: always_inspect
|
29
|
-
|
30
|
-
Layout/ParameterAlignment:
|
31
|
-
Enabled: true
|
32
|
-
EnforcedStyle: with_fixed_indentation
|
33
|
-
IndentationWidth: ~
|
34
|
-
|
35
|
-
Layout/SpaceInsideHashLiteralBraces:
|
36
|
-
Enabled: false
|
37
|
-
|
38
|
-
Metrics/ParameterLists:
|
39
|
-
CountKeywordArgs: false
|
40
|
-
|
41
|
-
Style/Alias:
|
42
|
-
Enabled: true
|
43
|
-
EnforcedStyle: prefer_alias_method
|
44
|
-
|
45
|
-
Style/StringLiterals:
|
46
|
-
Enabled: true
|
47
|
-
EnforcedStyle: double_quotes
|
48
|
-
|
49
|
-
Style/StringLiteralsInInterpolation:
|
50
|
-
Enabled: true
|
51
|
-
EnforcedStyle: double_quotes
|
52
|
-
|
53
|
-
Style/FrozenStringLiteralComment:
|
54
|
-
Enabled: false
|
data/Gemfile
DELETED
@@ -1,18 +0,0 @@
|
|
1
|
-
source "https://rubygems.org"
|
2
|
-
|
3
|
-
# Specify your gem's dependencies in x.gemspec
|
4
|
-
gemspec
|
5
|
-
|
6
|
-
gem "hashie", ">= 5"
|
7
|
-
gem "minitest", ">= 5.19"
|
8
|
-
gem "rake", ">= 13.0.6"
|
9
|
-
gem "rbs", ">= 3.2.1"
|
10
|
-
gem "rubocop", ">= 1.21"
|
11
|
-
gem "rubocop-minitest", ">= 0.31"
|
12
|
-
gem "rubocop-performance", ">= 1.18"
|
13
|
-
gem "rubocop-rake", ">= 0.6"
|
14
|
-
gem "simplecov", ">= 0.22"
|
15
|
-
gem "standard", ">= 1.30.1"
|
16
|
-
gem "steep", ">= 1.5.3"
|
17
|
-
gem "timecop", ">= 0.9.6"
|
18
|
-
gem "webmock", ">= 3.18.1"
|
data/Rakefile
DELETED
@@ -1,23 +0,0 @@
|
|
1
|
-
require "bundler/gem_tasks"
|
2
|
-
require "rake/testtask"
|
3
|
-
|
4
|
-
Rake::TestTask.new(:test) do |t|
|
5
|
-
t.libs << "test"
|
6
|
-
t.libs << "lib"
|
7
|
-
t.test_files = FileList["test/**/*_test.rb"]
|
8
|
-
end
|
9
|
-
|
10
|
-
require "standard/rake"
|
11
|
-
require "rubocop/rake_task"
|
12
|
-
|
13
|
-
RuboCop::RakeTask.new
|
14
|
-
|
15
|
-
require "steep"
|
16
|
-
require "steep/cli"
|
17
|
-
|
18
|
-
desc "Type check with Steep"
|
19
|
-
task :steep do
|
20
|
-
Steep::CLI.new(argv: ["check"], stdout: $stdout, stderr: $stderr, stdin: $stdin).run
|
21
|
-
end
|
22
|
-
|
23
|
-
task default: %i[test rubocop standard steep]
|
data/Steepfile
DELETED
@@ -1,13 +0,0 @@
|
|
1
|
-
target :lib do
|
2
|
-
signature "sig"
|
3
|
-
check "lib"
|
4
|
-
library "base64"
|
5
|
-
library "cgi"
|
6
|
-
library "forwardable"
|
7
|
-
library "json"
|
8
|
-
library "net-http"
|
9
|
-
library "openssl"
|
10
|
-
library "securerandom"
|
11
|
-
library "uri"
|
12
|
-
configure_code_diagnostics(Steep::Diagnostic::Ruby.strict)
|
13
|
-
end
|