t 4.1.1 → 5.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/CHANGELOG.md +820 -0
- data/LICENSE.md +1 -1
- data/README.md +3 -3
- data/bin/t +7 -16
- data/lib/t/cli.rb +317 -310
- data/lib/t/collectable.rb +4 -4
- data/lib/t/delete.rb +28 -35
- data/lib/t/list.rb +17 -18
- data/lib/t/printable/messaging.rb +54 -0
- data/lib/t/printable/rendering.rb +100 -0
- data/lib/t/printable.rb +58 -181
- data/lib/t/rcfile.rb +9 -1
- data/lib/t/requestable.rb +13 -7
- data/lib/t/requestable_api/account_endpoints.rb +93 -0
- data/lib/t/requestable_api/dm_endpoints.rb +41 -0
- data/lib/t/requestable_api/dm_helpers.rb +107 -0
- data/lib/t/requestable_api/dm_parsing.rb +76 -0
- data/lib/t/requestable_api/helpers.rb +86 -0
- data/lib/t/requestable_api/http.rb +113 -0
- data/lib/t/requestable_api/list_endpoints.rb +70 -0
- data/lib/t/requestable_api/list_normalization.rb +74 -0
- data/lib/t/requestable_api/mutations.rb +88 -0
- data/lib/t/requestable_api/resolution.rb +108 -0
- data/lib/t/requestable_api/tweet_endpoints.rb +85 -0
- data/lib/t/requestable_api/tweet_normalization.rb +87 -0
- data/lib/t/requestable_api/user_endpoints.rb +82 -0
- data/lib/t/requestable_api/user_normalization.rb +68 -0
- data/lib/t/requestable_api.rb +69 -0
- data/lib/t/search.rb +43 -58
- data/lib/t/set.rb +8 -9
- data/lib/t/stream.rb +91 -131
- data/lib/t/utils.rb +55 -52
- data/lib/t/version.rb +3 -3
- data/t.gemspec +16 -4
- metadata +46 -12
- data/lib/t/core_ext/kernel.rb +0 -13
- data/lib/t/core_ext/string.rb +0 -15
data/lib/t/stream.rb
CHANGED
|
@@ -17,6 +17,8 @@ module T
|
|
|
17
17
|
"%s", # Last element does not need special formatting
|
|
18
18
|
].freeze
|
|
19
19
|
|
|
20
|
+
STREAM_FIELDS = "tweet.fields=author_id,created_at,entities,text&expansions=author_id&user.fields=username,name".freeze
|
|
21
|
+
|
|
20
22
|
check_unknown_options!
|
|
21
23
|
|
|
22
24
|
def initialize(*)
|
|
@@ -29,31 +31,8 @@ module T
|
|
|
29
31
|
method_option "decode_uris", aliases: "-d", type: :boolean, desc: "Decodes t.co URLs into their original form."
|
|
30
32
|
method_option "long", aliases: "-l", type: :boolean, desc: "Output in long format."
|
|
31
33
|
def all
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
require "csv"
|
|
35
|
-
say TWEET_HEADINGS.to_csv
|
|
36
|
-
elsif options["long"] && STDOUT.tty?
|
|
37
|
-
headings = Array.new(TWEET_HEADINGS.size) do |index|
|
|
38
|
-
TWEET_HEADINGS_FORMATTING[index] % TWEET_HEADINGS[index]
|
|
39
|
-
end
|
|
40
|
-
print_table([headings])
|
|
41
|
-
end
|
|
42
|
-
end
|
|
43
|
-
streaming_client.sample do |tweet|
|
|
44
|
-
next unless tweet.is_a?(Twitter::Tweet)
|
|
45
|
-
|
|
46
|
-
if options["csv"]
|
|
47
|
-
print_csv_tweet(tweet)
|
|
48
|
-
elsif options["long"]
|
|
49
|
-
array = build_long_tweet(tweet).each_with_index.collect do |element, index|
|
|
50
|
-
TWEET_HEADINGS_FORMATTING[index] % element
|
|
51
|
-
end
|
|
52
|
-
print_table([array], truncate: STDOUT.tty?)
|
|
53
|
-
else
|
|
54
|
-
print_message(tweet.user.screen_name, tweet.text)
|
|
55
|
-
end
|
|
56
|
-
end
|
|
34
|
+
print_stream_headings
|
|
35
|
+
stream_tweets("tweets/sample/stream") { |tweet| print_stream_tweet(tweet) }
|
|
57
36
|
end
|
|
58
37
|
|
|
59
38
|
desc "list [USER/]LIST", "Stream a timeline for members of the specified list (Control-C to stop)"
|
|
@@ -65,43 +44,29 @@ module T
|
|
|
65
44
|
def list(user_list)
|
|
66
45
|
owner, list_name = extract_owner(user_list, options)
|
|
67
46
|
require "t/list"
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
if options["csv"]
|
|
80
|
-
print_csv_tweet(tweet)
|
|
81
|
-
elsif options["long"]
|
|
82
|
-
array = build_long_tweet(tweet).each_with_index.collect do |element, index|
|
|
83
|
-
TWEET_HEADINGS_FORMATTING[index] % element
|
|
84
|
-
end
|
|
85
|
-
print_table([array], truncate: STDOUT.tty?)
|
|
86
|
-
else
|
|
87
|
-
print_message(tweet.user.screen_name, tweet.text)
|
|
88
|
-
end
|
|
89
|
-
end
|
|
47
|
+
list_obj = T::List.new
|
|
48
|
+
list_obj.options = list_obj.options.merge(options)
|
|
49
|
+
list_obj.options = list_obj.options.merge(reverse: true)
|
|
50
|
+
list_obj.options = list_obj.options.merge(format: TWEET_HEADINGS_FORMATTING)
|
|
51
|
+
list_obj.timeline(user_list)
|
|
52
|
+
members = fetch_list_members_v1(owner, list_name)
|
|
53
|
+
user_ids = members.collect { |member| member["id"] }
|
|
54
|
+
rule_ids = setup_stream_rules([{value: user_ids.map { |id| "from:#{id}" }.join(" OR ")}])
|
|
55
|
+
stream_tweets("tweets/search/stream") { |tweet| print_stream_tweet(tweet) }
|
|
56
|
+
ensure
|
|
57
|
+
remove_stream_rules(rule_ids || [])
|
|
90
58
|
end
|
|
91
59
|
map %w[tl] => :timeline
|
|
92
60
|
|
|
93
61
|
desc "matrix", "Unfortunately, no one can be told what the Matrix is. You have to see it for yourself."
|
|
94
62
|
def matrix
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
end
|
|
100
|
-
streaming_client.sample(language: "ja") do |tweet|
|
|
101
|
-
next unless tweet.is_a?(Twitter::Tweet)
|
|
102
|
-
|
|
103
|
-
say(tweet.text.gsub(/[^\u3000\u3040-\u309f]/, "").reverse, %i[bold green on_black], false)
|
|
63
|
+
rule_ids = setup_stream_rules([{value: "の lang:ja"}])
|
|
64
|
+
stream_tweets("tweets/search/stream") do |tweet|
|
|
65
|
+
text = (tweet["text"] || tweet["full_text"] || "").gsub(/[^\u3000\u3040-\u309f]/, "").reverse
|
|
66
|
+
say(text, %i[bold green on_black], false) unless text.empty?
|
|
104
67
|
end
|
|
68
|
+
ensure
|
|
69
|
+
remove_stream_rules(rule_ids || [])
|
|
105
70
|
end
|
|
106
71
|
|
|
107
72
|
desc "search KEYWORD [KEYWORD...]", "Stream Tweets that contain specified keywords, joined with logical ORs (Control-C to stop)"
|
|
@@ -111,27 +76,15 @@ module T
|
|
|
111
76
|
def search(keyword, *keywords)
|
|
112
77
|
keywords.unshift(keyword)
|
|
113
78
|
require "t/search"
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
if options["csv"]
|
|
125
|
-
print_csv_tweet(tweet)
|
|
126
|
-
elsif options["long"]
|
|
127
|
-
array = build_long_tweet(tweet).each_with_index.collect do |element, index|
|
|
128
|
-
TWEET_HEADINGS_FORMATTING[index] % element
|
|
129
|
-
end
|
|
130
|
-
print_table([array], truncate: STDOUT.tty?)
|
|
131
|
-
else
|
|
132
|
-
print_message(tweet.user.screen_name, tweet.text)
|
|
133
|
-
end
|
|
134
|
-
end
|
|
79
|
+
search_obj = T::Search.new
|
|
80
|
+
search_obj.options = search_obj.options.merge(options)
|
|
81
|
+
search_obj.options = search_obj.options.merge(reverse: true)
|
|
82
|
+
search_obj.options = search_obj.options.merge(format: TWEET_HEADINGS_FORMATTING)
|
|
83
|
+
search_obj.all(keywords.join(" OR "))
|
|
84
|
+
rule_ids = setup_stream_rules([{value: keywords.join(" OR ")}])
|
|
85
|
+
stream_tweets("tweets/search/stream") { |tweet| print_stream_tweet(tweet) }
|
|
86
|
+
ensure
|
|
87
|
+
remove_stream_rules(rule_ids || [])
|
|
135
88
|
end
|
|
136
89
|
|
|
137
90
|
desc "timeline", "Stream your timeline (Control-C to stop)"
|
|
@@ -140,27 +93,16 @@ module T
|
|
|
140
93
|
method_option "long", aliases: "-l", type: :boolean, desc: "Output in long format."
|
|
141
94
|
def timeline
|
|
142
95
|
require "t/cli"
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
if options["csv"]
|
|
154
|
-
print_csv_tweet(tweet)
|
|
155
|
-
elsif options["long"]
|
|
156
|
-
array = build_long_tweet(tweet).each_with_index.collect do |element, index|
|
|
157
|
-
TWEET_HEADINGS_FORMATTING[index] % element
|
|
158
|
-
end
|
|
159
|
-
print_table([array], truncate: STDOUT.tty?)
|
|
160
|
-
else
|
|
161
|
-
print_message(tweet.user.screen_name, tweet.text)
|
|
162
|
-
end
|
|
163
|
-
end
|
|
96
|
+
cli = T::CLI.new
|
|
97
|
+
cli.options = cli.options.merge(options)
|
|
98
|
+
cli.options = cli.options.merge(reverse: true)
|
|
99
|
+
cli.options = cli.options.merge(format: TWEET_HEADINGS_FORMATTING)
|
|
100
|
+
cli.timeline
|
|
101
|
+
username = @rcfile.active_profile[0]
|
|
102
|
+
rule_ids = setup_stream_rules([{value: "from:#{username} OR to:#{username}"}])
|
|
103
|
+
stream_tweets("tweets/search/stream") { |tweet| print_stream_tweet(tweet) }
|
|
104
|
+
ensure
|
|
105
|
+
remove_stream_rules(rule_ids || [])
|
|
164
106
|
end
|
|
165
107
|
|
|
166
108
|
desc "users USER_ID [USER_ID...]", "Stream Tweets either from or in reply to specified users (Control-C to stop)"
|
|
@@ -170,45 +112,63 @@ module T
|
|
|
170
112
|
def users(user_id, *user_ids)
|
|
171
113
|
user_ids.unshift(user_id)
|
|
172
114
|
user_ids.collect!(&:to_i)
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
headings = Array.new(TWEET_HEADINGS.size) do |index|
|
|
179
|
-
TWEET_HEADINGS_FORMATTING[index] % TWEET_HEADINGS[index]
|
|
180
|
-
end
|
|
181
|
-
print_table([headings])
|
|
182
|
-
end
|
|
183
|
-
end
|
|
184
|
-
streaming_client.filter(follow: user_ids.join(",")) do |tweet|
|
|
185
|
-
next unless tweet.is_a?(Twitter::Tweet)
|
|
186
|
-
|
|
187
|
-
if options["csv"]
|
|
188
|
-
print_csv_tweet(tweet)
|
|
189
|
-
elsif options["long"]
|
|
190
|
-
array = build_long_tweet(tweet).each_with_index.collect do |element, index|
|
|
191
|
-
TWEET_HEADINGS_FORMATTING[index] % element
|
|
192
|
-
end
|
|
193
|
-
print_table([array], truncate: STDOUT.tty?)
|
|
194
|
-
else
|
|
195
|
-
print_message(tweet.user.screen_name, tweet.text)
|
|
196
|
-
end
|
|
197
|
-
end
|
|
115
|
+
print_stream_headings
|
|
116
|
+
rule_ids = setup_stream_rules([{value: user_ids.map { |id| "from:#{id}" }.join(" OR ")}])
|
|
117
|
+
stream_tweets("tweets/search/stream") { |tweet| print_stream_tweet(tweet) }
|
|
118
|
+
ensure
|
|
119
|
+
remove_stream_rules(rule_ids || [])
|
|
198
120
|
end
|
|
199
121
|
|
|
200
122
|
private
|
|
201
123
|
|
|
202
|
-
def
|
|
203
|
-
|
|
124
|
+
def stream_tweets(endpoint)
|
|
125
|
+
bearer_client.stream("#{endpoint}?#{STREAM_FIELDS}") do |json|
|
|
126
|
+
tweet = extract_tweets(json).first
|
|
127
|
+
yield tweet if tweet
|
|
128
|
+
end
|
|
129
|
+
end
|
|
204
130
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
131
|
+
def setup_stream_rules(rules)
|
|
132
|
+
response = t_post_bearer_json("tweets/search/stream/rules", add: rules)
|
|
133
|
+
(response["data"] || []).filter_map { |rule| rule["id"] }
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def remove_stream_rules(rule_ids)
|
|
137
|
+
return if rule_ids.empty?
|
|
138
|
+
|
|
139
|
+
t_post_bearer_json("tweets/search/stream/rules", delete: {ids: rule_ids})
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
def print_stream_headings
|
|
143
|
+
if options["csv"]
|
|
144
|
+
require "csv"
|
|
145
|
+
say TWEET_HEADINGS.to_csv
|
|
146
|
+
elsif options["long"] && $stdout.tty?
|
|
147
|
+
headings = Array.new(TWEET_HEADINGS.size) do |index|
|
|
148
|
+
TWEET_HEADINGS_FORMATTING[index] % TWEET_HEADINGS[index]
|
|
149
|
+
end
|
|
150
|
+
print_table([headings])
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
def print_stream_tweet(tweet)
|
|
155
|
+
if options["csv"]
|
|
156
|
+
print_csv_tweet(tweet)
|
|
157
|
+
elsif options["long"]
|
|
158
|
+
array = build_long_tweet(tweet).each_with_index.collect do |element, index|
|
|
159
|
+
TWEET_HEADINGS_FORMATTING[index] % element
|
|
160
|
+
end
|
|
161
|
+
print_table([array], truncate: $stdout.tty?)
|
|
162
|
+
else
|
|
163
|
+
print_message(tweet["user"]["screen_name"], tweet["text"])
|
|
211
164
|
end
|
|
212
165
|
end
|
|
166
|
+
|
|
167
|
+
def fetch_list_members_v1(owner, slug)
|
|
168
|
+
client # ensure v1_client is initialized
|
|
169
|
+
params = URI.encode_www_form(cursor: -1, owner_screen_name: owner, slug: slug)
|
|
170
|
+
response = v1_client.get("lists/members.json?#{params}")
|
|
171
|
+
response["users"] || []
|
|
172
|
+
end
|
|
213
173
|
end
|
|
214
174
|
end
|
data/lib/t/utils.rb
CHANGED
|
@@ -1,48 +1,36 @@
|
|
|
1
1
|
module T
|
|
2
2
|
module Utils
|
|
3
|
+
# https://github.com/rails/rails/blob/bd8a970/actionpack/lib/action_view/helpers/date_helper.rb
|
|
4
|
+
DISTANCE_THRESHOLDS = [
|
|
5
|
+
[2, "a minute"],
|
|
6
|
+
[60, ->(m) { format("%<minutes>d minutes", minutes: m) }],
|
|
7
|
+
[120, "an hour"],
|
|
8
|
+
[1410, ->(m) { format("%<hours>d hours", hours: (m.to_f / 60.0).round) }],
|
|
9
|
+
[2880, "a day"],
|
|
10
|
+
[42_480, ->(m) { format("%<days>d days", days: (m.to_f / 1440.0).round) }],
|
|
11
|
+
[86_400, "a month"],
|
|
12
|
+
[503_700, ->(m) { format("%<months>d months", months: (m.to_f / 43_800.0).round) }],
|
|
13
|
+
[1_051_200, "a year"],
|
|
14
|
+
].freeze
|
|
15
|
+
|
|
3
16
|
private
|
|
4
17
|
|
|
5
|
-
|
|
6
|
-
def distance_of_time_in_words(from_time, to_time = Time.now) # rubocop:disable Metrics/CyclomaticComplexity
|
|
18
|
+
def distance_of_time_in_words(from_time, to_time = Time.now)
|
|
7
19
|
seconds = (to_time - from_time).abs
|
|
8
20
|
minutes = seconds / 60
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
"a split second"
|
|
14
|
-
when 1...2
|
|
15
|
-
"a second"
|
|
16
|
-
when 2...60
|
|
17
|
-
format("%<seconds>d seconds", seconds:)
|
|
18
|
-
end
|
|
19
|
-
when 1...2
|
|
20
|
-
"a minute"
|
|
21
|
-
when 2...60
|
|
22
|
-
format("%<minutes>d minutes", minutes:)
|
|
23
|
-
when 60...120
|
|
24
|
-
"an hour"
|
|
25
|
-
# 120 minutes up to 23.5 hours
|
|
26
|
-
when 120...1410
|
|
27
|
-
format("%<hours>d hours", hours: (minutes.to_f / 60.0).round)
|
|
28
|
-
# 23.5 hours up to 48 hours
|
|
29
|
-
when 1410...2880
|
|
30
|
-
"a day"
|
|
31
|
-
# 48 hours up to 29.5 days
|
|
32
|
-
when 2880...42_480
|
|
33
|
-
format("%<days>d days", days: (minutes.to_f / 1440.0).round)
|
|
34
|
-
# 29.5 days up to 60 days
|
|
35
|
-
when 42_480...86_400
|
|
36
|
-
"a month"
|
|
37
|
-
# 60 days up to 11.5 months
|
|
38
|
-
when 86_400...503_700
|
|
39
|
-
format("%<months>d months", months: (minutes.to_f / 43_800.0).round)
|
|
40
|
-
# 11.5 months up to 2 years
|
|
41
|
-
when 503_700...1_051_200
|
|
42
|
-
"a year"
|
|
43
|
-
else
|
|
44
|
-
format("%<years>d years", years: (minutes.to_f / 525_600.0).round)
|
|
21
|
+
return distance_in_seconds(seconds) if minutes < 1
|
|
22
|
+
|
|
23
|
+
DISTANCE_THRESHOLDS.each do |threshold, result|
|
|
24
|
+
return (result.is_a?(Proc) ? result.call(minutes) : result) if minutes < threshold
|
|
45
25
|
end
|
|
26
|
+
format("%<years>d years", years: (minutes.to_f / 525_600.0).round)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def distance_in_seconds(seconds)
|
|
30
|
+
return "a split second" if seconds < 1
|
|
31
|
+
return "a second" if seconds < 2
|
|
32
|
+
|
|
33
|
+
format("%<seconds>d seconds", seconds:)
|
|
46
34
|
end
|
|
47
35
|
alias time_ago_in_words distance_of_time_in_words
|
|
48
36
|
alias time_from_now_in_words distance_of_time_in_words
|
|
@@ -50,15 +38,14 @@ module T
|
|
|
50
38
|
def fetch_users(users, options)
|
|
51
39
|
format_users!(users, options)
|
|
52
40
|
require "retryable"
|
|
53
|
-
users = Retryable.retryable(tries: 3, on:
|
|
41
|
+
users = Retryable.retryable(tries: 3, on: X::Error, sleep: 0) do
|
|
54
42
|
yield users
|
|
55
43
|
end
|
|
56
44
|
[users, users.length]
|
|
57
45
|
end
|
|
58
46
|
|
|
59
47
|
def format_users!(users, options)
|
|
60
|
-
|
|
61
|
-
options["id"] ? users.collect!(&:to_i) : users.collect!(&:strip_ats)
|
|
48
|
+
options["id"] ? users.collect!(&:to_i) : users.collect! { |u| u.tr("@", "") }
|
|
62
49
|
end
|
|
63
50
|
|
|
64
51
|
def extract_owner(user_list, options)
|
|
@@ -67,8 +54,7 @@ module T
|
|
|
67
54
|
list_name = owner
|
|
68
55
|
owner = @rcfile.active_profile[0]
|
|
69
56
|
else
|
|
70
|
-
|
|
71
|
-
owner = options["id"] ? owner.to_i : owner.strip_ats
|
|
57
|
+
owner = options["id"] ? owner.to_i : owner.tr("@", "")
|
|
72
58
|
end
|
|
73
59
|
[owner, list_name]
|
|
74
60
|
end
|
|
@@ -78,32 +64,49 @@ module T
|
|
|
78
64
|
end
|
|
79
65
|
|
|
80
66
|
def number_with_delimiter(number, delimiter = ",")
|
|
81
|
-
|
|
82
|
-
groups = digits.reverse.each_slice(3).collect(&:join)
|
|
83
|
-
groups.join(delimiter).reverse
|
|
67
|
+
number.to_s.chars.reverse.each_slice(3).collect(&:join).join(delimiter).reverse
|
|
84
68
|
end
|
|
85
69
|
|
|
86
70
|
def pluralize(count, singular, plural = nil)
|
|
87
|
-
"#{count || 0} " + (count == 1 || count =~ /^1(\.0+)?$/ ? singular : (plural || "#{singular}s"))
|
|
71
|
+
"#{count || 0} " + (count == 1 || count.to_s =~ /^1(\.0+)?$/ ? singular : (plural || "#{singular}s"))
|
|
88
72
|
end
|
|
89
73
|
|
|
90
|
-
def decode_full_text(message, decode_full_uris
|
|
74
|
+
def decode_full_text(message, decode_full_uris: false)
|
|
91
75
|
require "htmlentities"
|
|
92
|
-
text = HTMLEntities.new.decode(message
|
|
93
|
-
|
|
94
|
-
text
|
|
76
|
+
text = HTMLEntities.new.decode(message["full_text"])
|
|
77
|
+
decode_full_uris ? decode_uris(text, message["uris"]) : text
|
|
95
78
|
end
|
|
96
79
|
|
|
97
80
|
def decode_uris(full_text, uri_entities)
|
|
98
81
|
return full_text if uri_entities.nil?
|
|
99
82
|
|
|
100
83
|
uri_entities.each do |uri_entity|
|
|
101
|
-
|
|
84
|
+
uri, expanded_uri = extract_uri_pair(uri_entity)
|
|
85
|
+
full_text = full_text.gsub(uri.to_s, expanded_uri.to_s)
|
|
102
86
|
end
|
|
103
87
|
|
|
104
88
|
full_text
|
|
105
89
|
end
|
|
106
90
|
|
|
91
|
+
def extract_uri_pair(uri_entity)
|
|
92
|
+
uri = uri_entity["url"] || uri_entity[:url]
|
|
93
|
+
expanded = uri_entity["expanded_url"] || uri_entity[:expanded_url] || uri
|
|
94
|
+
[uri, expanded]
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def build_timeline_opts
|
|
98
|
+
{include_entities: !!options["decode_uris"]}.tap do |opts|
|
|
99
|
+
opts[:exclude_replies] = true if options["exclude"] == "replies"
|
|
100
|
+
opts[:include_rts] = false if options["exclude"] == "retweets"
|
|
101
|
+
opts[:max_id] = options["max_id"] if options["max_id"]
|
|
102
|
+
opts[:since_id] = options["since_id"] if options["since_id"]
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def resolve_user_input(user)
|
|
107
|
+
options["id"] ? user.to_i : user.tr("@", "")
|
|
108
|
+
end
|
|
109
|
+
|
|
107
110
|
def open_or_print(uri, options)
|
|
108
111
|
Launchy.open(uri, options) do
|
|
109
112
|
say "Open: #{uri}"
|
data/lib/t/version.rb
CHANGED
data/t.gemspec
CHANGED
|
@@ -5,24 +5,36 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
|
5
5
|
require "t/version"
|
|
6
6
|
|
|
7
7
|
Gem::Specification.new do |spec|
|
|
8
|
+
spec.add_dependency "cgi", ">= 0.2"
|
|
8
9
|
spec.add_dependency "geokit", "~> 1.14"
|
|
9
10
|
spec.add_dependency "htmlentities", "~> 4.3"
|
|
10
11
|
spec.add_dependency "launchy", "~> 3.0"
|
|
11
12
|
spec.add_dependency "oauth", "~> 1.1"
|
|
12
13
|
spec.add_dependency "retryable", "~> 3.0"
|
|
13
14
|
spec.add_dependency "thor", "~> 1.3"
|
|
14
|
-
spec.add_dependency "
|
|
15
|
+
spec.add_dependency "x", "~> 0.19"
|
|
15
16
|
spec.author = "Erik Berlin"
|
|
16
17
|
spec.description = "A command-line power tool for Twitter."
|
|
17
18
|
spec.email = "sferik@gmail.com"
|
|
18
19
|
spec.executables = Dir["bin/*"].map { |f| File.basename(f) }
|
|
19
|
-
spec.files = %w[CONTRIBUTING.md LICENSE.md README.md t.gemspec] + Dir["bin/*"] + Dir["lib/**/*.rb"]
|
|
20
|
+
spec.files = %w[CHANGELOG.md CONTRIBUTING.md LICENSE.md README.md t.gemspec] + Dir["bin/*"] + Dir["lib/**/*.rb"]
|
|
20
21
|
spec.homepage = "http://sferik.github.com/t/"
|
|
21
22
|
spec.licenses = %w[MIT]
|
|
22
|
-
|
|
23
|
+
|
|
24
|
+
spec.metadata = {
|
|
25
|
+
"allowed_push_host" => "https://rubygems.org",
|
|
26
|
+
"bug_tracker_uri" => "https://github.com/sferik/t-ruby/issues",
|
|
27
|
+
"changelog_uri" => "https://github.com/sferik/t-ruby/blob/master/CHANGELOG.md",
|
|
28
|
+
"documentation_uri" => "https://rubydoc.info/gems/t/",
|
|
29
|
+
"funding_uri" => "https://github.com/sponsors/sferik/",
|
|
30
|
+
"homepage_uri" => spec.homepage,
|
|
31
|
+
"rubygems_mfa_required" => "true",
|
|
32
|
+
"source_code_uri" => "https://github.com/sferik/t-ruby",
|
|
33
|
+
}
|
|
34
|
+
|
|
23
35
|
spec.name = "t"
|
|
24
36
|
spec.require_paths = %w[lib]
|
|
25
|
-
spec.required_ruby_version = ">= 3.
|
|
37
|
+
spec.required_ruby_version = ">= 3.2"
|
|
26
38
|
spec.summary = "CLI for Twitter"
|
|
27
39
|
spec.version = T::Version
|
|
28
40
|
end
|
metadata
CHANGED
|
@@ -1,15 +1,28 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: t
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version:
|
|
4
|
+
version: 5.0.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Erik Berlin
|
|
8
|
-
autorequire:
|
|
9
8
|
bindir: bin
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
12
11
|
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: cgi
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - ">="
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: '0.2'
|
|
19
|
+
type: :runtime
|
|
20
|
+
prerelease: false
|
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
22
|
+
requirements:
|
|
23
|
+
- - ">="
|
|
24
|
+
- !ruby/object:Gem::Version
|
|
25
|
+
version: '0.2'
|
|
13
26
|
- !ruby/object:Gem::Dependency
|
|
14
27
|
name: geokit
|
|
15
28
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -95,19 +108,19 @@ dependencies:
|
|
|
95
108
|
- !ruby/object:Gem::Version
|
|
96
109
|
version: '1.3'
|
|
97
110
|
- !ruby/object:Gem::Dependency
|
|
98
|
-
name:
|
|
111
|
+
name: x
|
|
99
112
|
requirement: !ruby/object:Gem::Requirement
|
|
100
113
|
requirements:
|
|
101
114
|
- - "~>"
|
|
102
115
|
- !ruby/object:Gem::Version
|
|
103
|
-
version: '
|
|
116
|
+
version: '0.19'
|
|
104
117
|
type: :runtime
|
|
105
118
|
prerelease: false
|
|
106
119
|
version_requirements: !ruby/object:Gem::Requirement
|
|
107
120
|
requirements:
|
|
108
121
|
- - "~>"
|
|
109
122
|
- !ruby/object:Gem::Version
|
|
110
|
-
version: '
|
|
123
|
+
version: '0.19'
|
|
111
124
|
description: A command-line power tool for Twitter.
|
|
112
125
|
email: sferik@gmail.com
|
|
113
126
|
executables:
|
|
@@ -115,6 +128,7 @@ executables:
|
|
|
115
128
|
extensions: []
|
|
116
129
|
extra_rdoc_files: []
|
|
117
130
|
files:
|
|
131
|
+
- CHANGELOG.md
|
|
118
132
|
- CONTRIBUTING.md
|
|
119
133
|
- LICENSE.md
|
|
120
134
|
- README.md
|
|
@@ -122,15 +136,30 @@ files:
|
|
|
122
136
|
- lib/t.rb
|
|
123
137
|
- lib/t/cli.rb
|
|
124
138
|
- lib/t/collectable.rb
|
|
125
|
-
- lib/t/core_ext/kernel.rb
|
|
126
|
-
- lib/t/core_ext/string.rb
|
|
127
139
|
- lib/t/delete.rb
|
|
128
140
|
- lib/t/editor.rb
|
|
129
141
|
- lib/t/identicon.rb
|
|
130
142
|
- lib/t/list.rb
|
|
131
143
|
- lib/t/printable.rb
|
|
144
|
+
- lib/t/printable/messaging.rb
|
|
145
|
+
- lib/t/printable/rendering.rb
|
|
132
146
|
- lib/t/rcfile.rb
|
|
133
147
|
- lib/t/requestable.rb
|
|
148
|
+
- lib/t/requestable_api.rb
|
|
149
|
+
- lib/t/requestable_api/account_endpoints.rb
|
|
150
|
+
- lib/t/requestable_api/dm_endpoints.rb
|
|
151
|
+
- lib/t/requestable_api/dm_helpers.rb
|
|
152
|
+
- lib/t/requestable_api/dm_parsing.rb
|
|
153
|
+
- lib/t/requestable_api/helpers.rb
|
|
154
|
+
- lib/t/requestable_api/http.rb
|
|
155
|
+
- lib/t/requestable_api/list_endpoints.rb
|
|
156
|
+
- lib/t/requestable_api/list_normalization.rb
|
|
157
|
+
- lib/t/requestable_api/mutations.rb
|
|
158
|
+
- lib/t/requestable_api/resolution.rb
|
|
159
|
+
- lib/t/requestable_api/tweet_endpoints.rb
|
|
160
|
+
- lib/t/requestable_api/tweet_normalization.rb
|
|
161
|
+
- lib/t/requestable_api/user_endpoints.rb
|
|
162
|
+
- lib/t/requestable_api/user_normalization.rb
|
|
134
163
|
- lib/t/search.rb
|
|
135
164
|
- lib/t/set.rb
|
|
136
165
|
- lib/t/stream.rb
|
|
@@ -141,8 +170,14 @@ homepage: http://sferik.github.com/t/
|
|
|
141
170
|
licenses:
|
|
142
171
|
- MIT
|
|
143
172
|
metadata:
|
|
173
|
+
allowed_push_host: https://rubygems.org
|
|
174
|
+
bug_tracker_uri: https://github.com/sferik/t-ruby/issues
|
|
175
|
+
changelog_uri: https://github.com/sferik/t-ruby/blob/master/CHANGELOG.md
|
|
176
|
+
documentation_uri: https://rubydoc.info/gems/t/
|
|
177
|
+
funding_uri: https://github.com/sponsors/sferik/
|
|
178
|
+
homepage_uri: http://sferik.github.com/t/
|
|
144
179
|
rubygems_mfa_required: 'true'
|
|
145
|
-
|
|
180
|
+
source_code_uri: https://github.com/sferik/t-ruby
|
|
146
181
|
rdoc_options: []
|
|
147
182
|
require_paths:
|
|
148
183
|
- lib
|
|
@@ -150,15 +185,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
150
185
|
requirements:
|
|
151
186
|
- - ">="
|
|
152
187
|
- !ruby/object:Gem::Version
|
|
153
|
-
version: 3.
|
|
188
|
+
version: '3.2'
|
|
154
189
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
155
190
|
requirements:
|
|
156
191
|
- - ">="
|
|
157
192
|
- !ruby/object:Gem::Version
|
|
158
193
|
version: '0'
|
|
159
194
|
requirements: []
|
|
160
|
-
rubygems_version:
|
|
161
|
-
signing_key:
|
|
195
|
+
rubygems_version: 4.0.6
|
|
162
196
|
specification_version: 4
|
|
163
197
|
summary: CLI for Twitter
|
|
164
198
|
test_files: []
|
data/lib/t/core_ext/kernel.rb
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
module Kernel
|
|
2
|
-
def Bignum(arg, base = 0) # rubocop:disable Naming/MethodName
|
|
3
|
-
Integer(arg, base)
|
|
4
|
-
end
|
|
5
|
-
|
|
6
|
-
def Fixnum(arg, base = 0) # rubocop:disable Naming/MethodName
|
|
7
|
-
Integer(arg, base)
|
|
8
|
-
end
|
|
9
|
-
|
|
10
|
-
def NilClass(_) # rubocop:disable Naming/MethodName
|
|
11
|
-
nil
|
|
12
|
-
end
|
|
13
|
-
end
|