x 0.12.1 → 0.13.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 +25 -7
- data/lib/x/errors/too_many_requests.rb +8 -5
- data/lib/x/rate_limit.rb +33 -0
- data/lib/x/version.rb +1 -1
- data/sig/x.rbs +18 -3
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4f4970075e9256b31a7f53ca6a3a06df7559631b9104c2069372b3797845cd77
|
4
|
+
data.tar.gz: a0e25d20e521f8a3408b9e04b8826d7f8959257ecf6748687a0d1b0292719f38
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7be87f0b82af146429afa88288f60d53d07185d2ed47f57d534c729758a3bfc426c4a57e11703665eedd19b9d994ce4e51bd4f08e3de84cdc49ca7a2de28eae6
|
7
|
+
data.tar.gz: 3e28cfc6ee5d244eff7671e0f724c0a07071d1872792d9fb742ee44bcf2fc2f1a797053dc0d2a415a51a625d85629115f71ad003bb3b9fcaf75049cde6b5d0d1
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -1,7 +1,7 @@
|
|
1
|
-
![Tests](https://github.com/sferik/x-ruby/actions/workflows/test.yml/badge.svg)
|
2
|
-
![
|
3
|
-
![Mutant](https://github.com/sferik/x-ruby/actions/workflows/mutant.yml/badge.svg)
|
4
|
-
![Typer Checker](https://github.com/sferik/x-ruby/actions/workflows/
|
1
|
+
[![Tests](https://github.com/sferik/x-ruby/actions/workflows/test.yml/badge.svg)](https://github.com/sferik/x-ruby/actions/workflows/test.yml)
|
2
|
+
[![RuboCop](https://github.com/sferik/x-ruby/actions/workflows/rubocop.yml/badge.svg)](https://github.com/sferik/x-ruby/actions/workflows/rubocop.yml)
|
3
|
+
[![Mutant](https://github.com/sferik/x-ruby/actions/workflows/mutant.yml/badge.svg)](https://github.com/sferik/x-ruby/actions/workflows/mutant.yml)
|
4
|
+
[![Typer Checker](https://github.com/sferik/x-ruby/actions/workflows/steep.yml/badge.svg)](https://github.com/sferik/x-ruby/actions/workflows/steep.yml)
|
5
5
|
[![Gem Version](https://badge.fury.io/rb/x.svg)](https://rubygems.org/gems/x)
|
6
6
|
|
7
7
|
# A [Ruby](https://www.ruby-lang.org) interface to the [X API](https://developer.x.com)
|
@@ -55,7 +55,7 @@ v1_client = X::Client.new(base_url: "https://api.twitter.com/1.1/", **x_credenti
|
|
55
55
|
# Get your account settings
|
56
56
|
v1_client.get("account/settings.json")
|
57
57
|
|
58
|
-
# Initialize an
|
58
|
+
# Initialize an Ads API client
|
59
59
|
ads_client = X::Client.new(base_url: "https://ads-api.twitter.com/12/", **x_credentials)
|
60
60
|
|
61
61
|
# Get your ad accounts
|
@@ -80,6 +80,23 @@ The tests for the previous version of this library executed in about 2 seconds.
|
|
80
80
|
|
81
81
|
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.
|
82
82
|
|
83
|
+
## Features
|
84
|
+
|
85
|
+
If this entire library is implemented in just 500 lines of code, why should you use it at all vs. writing your own library that suits your needs? If you feel inspired to do that, don’t let me discourage you, but this library has some advanced features that may not be apparent without diving into the code:
|
86
|
+
|
87
|
+
* OAuth 1.0 Revision A
|
88
|
+
* OAuth 2.0 Bearer Token
|
89
|
+
* Thread safety
|
90
|
+
* HTTP redirect following
|
91
|
+
* HTTP proxy support
|
92
|
+
* HTTP logging
|
93
|
+
* HTTP timeout configuration
|
94
|
+
* HTTP error handling
|
95
|
+
* Rate limit handling
|
96
|
+
* Parsing JSON into custom response objects (e.g. OpenStruct)
|
97
|
+
* Configurable base URLs for accessing different APIs/versions
|
98
|
+
* Parallel uploading of large media files in chunks
|
99
|
+
|
83
100
|
## Sponsorship
|
84
101
|
|
85
102
|
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:
|
@@ -132,9 +149,9 @@ Bug reports and pull requests are welcome on GitHub at https://github.com/sferik
|
|
132
149
|
|
133
150
|
Pull requests will only be accepted if they meet all the following criteria:
|
134
151
|
|
135
|
-
1. Code must conform to [
|
152
|
+
1. Code must conform to [RuboCop rules](https://github.com/rubocop/rubocop). This can be verified with:
|
136
153
|
|
137
|
-
bundle exec
|
154
|
+
bundle exec rubocop
|
138
155
|
|
139
156
|
2. 100% C0 code coverage. This can be verified with:
|
140
157
|
|
@@ -142,6 +159,7 @@ Pull requests will only be accepted if they meet all the following criteria:
|
|
142
159
|
|
143
160
|
3. 100% mutation coverage. This can be verified with:
|
144
161
|
|
162
|
+
git remote add upstream https://github.com/sferik/x-ruby
|
145
163
|
bundle exec rake mutant
|
146
164
|
|
147
165
|
4. RBS type signatures (in `sig/x.rbs`). This can be verified with:
|
@@ -1,17 +1,20 @@
|
|
1
1
|
require_relative "client_error"
|
2
|
+
require_relative "../rate_limit"
|
2
3
|
|
3
4
|
module X
|
4
5
|
class TooManyRequests < ClientError
|
5
|
-
def
|
6
|
-
|
6
|
+
def rate_limit
|
7
|
+
rate_limits.max_by(&:reset_at)
|
7
8
|
end
|
8
9
|
|
9
|
-
def
|
10
|
-
|
10
|
+
def rate_limits
|
11
|
+
@rate_limits ||= RateLimit::TYPES.filter_map do |type|
|
12
|
+
RateLimit.new(type: type, response: response) if response["x-#{type}-remaining"].eql?("0")
|
13
|
+
end
|
11
14
|
end
|
12
15
|
|
13
16
|
def reset_at
|
14
|
-
Time.at(
|
17
|
+
rate_limit&.reset_at || Time.at(0)
|
15
18
|
end
|
16
19
|
|
17
20
|
def reset_in
|
data/lib/x/rate_limit.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
module X
|
2
|
+
class RateLimit
|
3
|
+
RATE_LIMIT_TYPE = "rate-limit".freeze
|
4
|
+
APP_LIMIT_TYPE = "app-limit-24hour".freeze
|
5
|
+
USER_LIMIT_TYPE = "user-limit-24hour".freeze
|
6
|
+
TYPES = [RATE_LIMIT_TYPE, APP_LIMIT_TYPE, USER_LIMIT_TYPE].freeze
|
7
|
+
|
8
|
+
attr_accessor :type, :response
|
9
|
+
|
10
|
+
def initialize(type:, response:)
|
11
|
+
@type = type
|
12
|
+
@response = response
|
13
|
+
end
|
14
|
+
|
15
|
+
def limit
|
16
|
+
Integer(response.fetch("x-#{type}-limit"))
|
17
|
+
end
|
18
|
+
|
19
|
+
def remaining
|
20
|
+
Integer(response.fetch("x-#{type}-remaining"))
|
21
|
+
end
|
22
|
+
|
23
|
+
def reset_at
|
24
|
+
Time.at(Integer(response.fetch("x-#{type}-reset")))
|
25
|
+
end
|
26
|
+
|
27
|
+
def reset_in
|
28
|
+
[(reset_at - Time.now).ceil, 0].max
|
29
|
+
end
|
30
|
+
|
31
|
+
alias_method :retry_after, :reset_in
|
32
|
+
end
|
33
|
+
end
|
data/lib/x/version.rb
CHANGED
data/sig/x.rbs
CHANGED
@@ -102,10 +102,10 @@ module X
|
|
102
102
|
end
|
103
103
|
|
104
104
|
class TooManyRequests < ClientError
|
105
|
-
@
|
105
|
+
@rate_limits: Array[RateLimit]
|
106
106
|
|
107
|
-
def
|
108
|
-
def
|
107
|
+
def rate_limit: -> RateLimit?
|
108
|
+
def rate_limits: -> Array[RateLimit]
|
109
109
|
def reset_at: -> Time
|
110
110
|
def reset_in: -> Integer?
|
111
111
|
end
|
@@ -147,6 +147,21 @@ module X
|
|
147
147
|
def configure_http_client: (Net::HTTP http_client) -> Net::HTTP
|
148
148
|
end
|
149
149
|
|
150
|
+
class RateLimit
|
151
|
+
RATE_LIMIT_TYPE: String
|
152
|
+
APP_LIMIT_TYPE: String
|
153
|
+
USER_LIMIT_TYPE: String
|
154
|
+
TYPES: [String, String, String]
|
155
|
+
|
156
|
+
attr_accessor type: String
|
157
|
+
attr_accessor response: Net::HTTPResponse
|
158
|
+
def initialize: (type: String, response: Net::HTTPResponse) -> void
|
159
|
+
def limit: -> Integer
|
160
|
+
def remaining: -> Integer
|
161
|
+
def reset_at: -> Time
|
162
|
+
def reset_in: -> Integer?
|
163
|
+
end
|
164
|
+
|
150
165
|
class RequestBuilder
|
151
166
|
HTTP_METHODS: Hash[Symbol, (singleton(Net::HTTP::Get) | singleton(Net::HTTP::Post) | singleton(Net::HTTP::Put) | singleton(Net::HTTP::Delete))]
|
152
167
|
DEFAULT_HEADERS: Hash[String, String]
|
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.13.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-
|
11
|
+
date: 2023-12-04 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description:
|
14
14
|
email:
|
@@ -50,6 +50,7 @@ files:
|
|
50
50
|
- lib/x/errors/unprocessable_entity.rb
|
51
51
|
- lib/x/media_uploader.rb
|
52
52
|
- lib/x/oauth_authenticator.rb
|
53
|
+
- lib/x/rate_limit.rb
|
53
54
|
- lib/x/redirect_handler.rb
|
54
55
|
- lib/x/request_builder.rb
|
55
56
|
- lib/x/response_parser.rb
|