pry-twitter 1.22.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 +7 -0
- data/CHANGELOG.md +13 -0
- data/LICENSE.txt +24 -0
- data/PRY_LICENSE.txt +25 -0
- data/README.md +546 -0
- data/Vagrantfile +48 -0
- data/art/16-60174b5812.jpg +0 -0
- data/art/16-a31deea6f0.jpg +0 -0
- data/art/17-b3d5d6f6c2.jpg +0 -0
- data/art/44-e44743a5bb.jpg +0 -0
- data/art/51-5e4dc5fd92.jpg +0 -0
- data/art/51-82bde81305.jpg +0 -0
- data/art/51-ad821fa377.jpg +0 -0
- data/art/51-b90d5dd6a6.jpg +0 -0
- data/art/51-da43a4ef4f.jpg +0 -0
- data/art/51-e94c3387e1.jpg +0 -0
- data/art/52-eec4df2edf.jpg +0 -0
- data/art/53-9d231893e1.jpg +0 -0
- data/art/54-39b1063483.jpg +0 -0
- data/art/55-e41f9896d0.jpg +0 -0
- data/art/56-c82d4e5b61.jpg +0 -0
- data/art/59-2a2c9cd962.jpg +0 -0
- data/art/61-3970c79d47.jpg +0 -0
- data/art/62-5704cc1652.jpg +0 -0
- data/art/62-b0aceb0fa6.jpg +0 -0
- data/art/62-da0faf972e.jpg +0 -0
- data/art/frankewilde.jpg +0 -0
- data/art/rollingstone.jpg +0 -0
- data/art/tide.jpg +0 -0
- data/art/windows10.png +0 -0
- data/lib/pry-send_tweet.rb +77 -0
- data/lib/pry/pager/system_pager.rb +25 -0
- data/lib/pry/send_tweet/commands/base_command.rb +72 -0
- data/lib/pry/send_tweet/commands/easter_eggs.rb +564 -0
- data/lib/pry/send_tweet/commands/paging/paging_support.rb +16 -0
- data/lib/pry/send_tweet/commands/read_tweets.rb +93 -0
- data/lib/pry/send_tweet/commands/read_tweets/translate_actions.rb +94 -0
- data/lib/pry/send_tweet/commands/send_tweet.rb +164 -0
- data/lib/pry/send_tweet/commands/twitter_action.rb +118 -0
- data/lib/pry/send_tweet/commands/twitter_action/delete_tweet_actions.rb +19 -0
- data/lib/pry/send_tweet/commands/twitter_action/follow_actions.rb +66 -0
- data/lib/pry/send_tweet/commands/twitter_action/like_actions.rb +23 -0
- data/lib/pry/send_tweet/commands/twitter_action/mute_actions.rb +23 -0
- data/lib/pry/send_tweet/commands/twitter_action/profile_actions.rb +60 -0
- data/lib/pry/send_tweet/commands/twitter_action/suggested_actions.rb +20 -0
- data/lib/pry/send_tweet/commands/twitter_search.rb +36 -0
- data/lib/pry/send_tweet/renderers/tweet_renderer.rb +103 -0
- data/lib/pry/send_tweet/renderers/user_renderer.rb +17 -0
- data/lib/pry/send_tweet/tty-box.rb +73 -0
- data/lib/pry/send_tweet/twitter_io.rb +26 -0
- data/lib/pry/send_tweet/version.rb +6 -0
- data/lib/time-ago-in-words/README.md +14 -0
- data/lib/time-ago-in-words/lib/time-ago-in-words.rb +37 -0
- data/lib/time-ago-in-words/time-ago-in-words.gemspec +14 -0
- data/pry-send_tweet.gemspec +23 -0
- data/samples/freebsd-zshrc +5 -0
- data/samples/loader.conf +1 -0
- data/samples/tmuxinator-vagrant.yml +11 -0
- data/vms/freebsd.rb +18 -0
- metadata +145 -0
@@ -0,0 +1,19 @@
|
|
1
|
+
module Pry::SendTweet::TwitterAction::DeleteTweetActions
|
2
|
+
def delete_retweet(retweets)
|
3
|
+
tweets = twitter.unretweet(retweets)
|
4
|
+
if tweets.size == 0
|
5
|
+
page_error "Are you sure you gave a valid reference to one or more retweets?"
|
6
|
+
else
|
7
|
+
render_tweets tweets, title: bold("Deleted retweets"), timeout: false
|
8
|
+
end
|
9
|
+
rescue Twitter::Error => e
|
10
|
+
page_error(e)
|
11
|
+
end
|
12
|
+
|
13
|
+
def delete_tweet(tweets)
|
14
|
+
tweets = twitter.destroy_status(tweets)
|
15
|
+
render_tweets tweets, title: bold("Deleted tweets"), timeout: false
|
16
|
+
rescue Twitter::Error => e
|
17
|
+
page_error(e)
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
module Pry::SendTweet::TwitterAction::FollowActions
|
2
|
+
def follow_user(users)
|
3
|
+
users = search_str_for_users(*users)
|
4
|
+
follows = twitter.follow(users)
|
5
|
+
if follows.size > 0
|
6
|
+
page_ok "followed #{join_usernames(follows.map(&:screen_name))}."
|
7
|
+
else
|
8
|
+
page_error "are you already following #{join_usernames(users)} ..?"
|
9
|
+
end
|
10
|
+
rescue Twitter::Error => e
|
11
|
+
page_error(e)
|
12
|
+
end
|
13
|
+
|
14
|
+
def unfollow_user(users)
|
15
|
+
users = search_str_for_users(*users)
|
16
|
+
unfollows = twitter.unfollow(users)
|
17
|
+
if unfollows.size > 0
|
18
|
+
page_ok "unfollowed #{join_usernames(unfollows.map(&:screen_name))}."
|
19
|
+
else
|
20
|
+
page_error "did you already unfollow #{join_usernames(users)} ..?"
|
21
|
+
end
|
22
|
+
rescue Twitter::Error => e
|
23
|
+
page_error(e)
|
24
|
+
end
|
25
|
+
|
26
|
+
def show_followers(pattern)
|
27
|
+
followers = Array twitter.followers(follow_request_options)
|
28
|
+
__follow_filter!(followers, pattern) if pattern
|
29
|
+
page numbered_list("Followers", followers) {|follower, index|
|
30
|
+
render_user(follower)
|
31
|
+
}
|
32
|
+
rescue Twitter::Error => e
|
33
|
+
page_error(e)
|
34
|
+
end
|
35
|
+
|
36
|
+
def show_following(pattern)
|
37
|
+
followings = Array twitter.following(follow_request_options)
|
38
|
+
__follow_filter!(followings, pattern) if pattern
|
39
|
+
page numbered_list("Following", followings) {|following, index|
|
40
|
+
render_user(following)
|
41
|
+
}
|
42
|
+
rescue Twitter::Error => e
|
43
|
+
page_error(e)
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
# @api private
|
49
|
+
def __follow_filter!(users, pattern)
|
50
|
+
users.select! do |u|
|
51
|
+
u.screen_name =~ /#{pattern}/
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
# @api private
|
56
|
+
def follow_request_options
|
57
|
+
{skip_status: true, include_user_entities: true}
|
58
|
+
end
|
59
|
+
|
60
|
+
# @api private
|
61
|
+
def join_usernames(users)
|
62
|
+
users.map do |username|
|
63
|
+
bold("@#{username}") + " ( https://twitter.com/#{username} )"
|
64
|
+
end.join(', ')
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Pry::SendTweet::TwitterAction::LikeActions
|
2
|
+
def like_tweet(tweets)
|
3
|
+
liked = twitter.favorite(tweets)
|
4
|
+
if liked.size > 0
|
5
|
+
render_tweets liked, title: bold("Liked tweets"), timeout: false
|
6
|
+
else
|
7
|
+
page_error "No tweets liked, are you sure you didn't already like those tweet(s) ..?"
|
8
|
+
end
|
9
|
+
rescue Twitter::Error => e
|
10
|
+
page_error(e)
|
11
|
+
end
|
12
|
+
|
13
|
+
def unlike_tweet(tweets)
|
14
|
+
unliked = twitter.unfavorite(tweets)
|
15
|
+
if unliked.size > 0
|
16
|
+
render_tweets unliked, title: bold("Unliked tweets"), timeout: false
|
17
|
+
else
|
18
|
+
page_error "No tweets unliked, are you sure you had liked those tweet(s) ..?"
|
19
|
+
end
|
20
|
+
rescue Twitter::Error => e
|
21
|
+
page_error(e)
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Pry::SendTweet::TwitterAction::MuteActions
|
2
|
+
def mute_user(strings)
|
3
|
+
muted = twitter.mute(*search_str_for_users(*strings))
|
4
|
+
if muted.size > 0
|
5
|
+
page numbered_list("Muted users", muted) {|user, index|
|
6
|
+
render_user(user)
|
7
|
+
}
|
8
|
+
else
|
9
|
+
page_error "No one was muted, did you mute those user(s) already ..?"
|
10
|
+
end
|
11
|
+
rescue Twitter::Error => e
|
12
|
+
page_error(e)
|
13
|
+
end
|
14
|
+
|
15
|
+
def unmute_user(strings)
|
16
|
+
unmuted = twitter.unmute(*search_str_for_users(*strings))
|
17
|
+
page numbered_list("Unmuted users", unmuted) {|user, index|
|
18
|
+
render_user(user)
|
19
|
+
}
|
20
|
+
rescue Twitter::Error => e
|
21
|
+
page_error(e)
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module Pry::SendTweet::TwitterAction::ProfileActions
|
2
|
+
def set_profile_url(url)
|
3
|
+
if twitter.update_profile url: url
|
4
|
+
page_ok "URL updated"
|
5
|
+
else
|
6
|
+
raise Pry::CommandError, "Something went wrong"
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
def set_profile_image(path)
|
11
|
+
twitter.update_profile_image(path)
|
12
|
+
page_ok "Profile image updated"
|
13
|
+
rescue Twitter::Error => e
|
14
|
+
page_error(e)
|
15
|
+
end
|
16
|
+
|
17
|
+
def set_profile_banner_image(path)
|
18
|
+
base64 = Base64.strict_encode64 File.binread(path)
|
19
|
+
twitter.update_profile_banner(base64)
|
20
|
+
page_ok "Profile banner updated"
|
21
|
+
rescue Twitter::Error => e
|
22
|
+
page_error(e)
|
23
|
+
end
|
24
|
+
|
25
|
+
def set_profile_name(name)
|
26
|
+
twitter.update_profile name: name
|
27
|
+
page_ok "Name updated"
|
28
|
+
rescue Twitter::Error => e
|
29
|
+
page_error(e)
|
30
|
+
end
|
31
|
+
|
32
|
+
def set_profile_bio
|
33
|
+
Tempfile.open('pry-send_tweet-set-profile-bio') do |file|
|
34
|
+
Pry::Editor.new(_pry_).invoke_editor(file.path, 0)
|
35
|
+
file.rewind
|
36
|
+
twitter.update_profile description: file.read
|
37
|
+
page_ok "Bio updated"
|
38
|
+
end
|
39
|
+
rescue Twitter::Error => e
|
40
|
+
page_error(e)
|
41
|
+
end
|
42
|
+
|
43
|
+
def set_profile_location
|
44
|
+
Tempfile.open('pry-send_tweet-set-profile-location') do |file|
|
45
|
+
Pry::Editor.new(_pry_).invoke_editor(file.path, 0)
|
46
|
+
file.rewind
|
47
|
+
twitter.update_profile location: file.read
|
48
|
+
page_ok "Location updated"
|
49
|
+
end
|
50
|
+
rescue Twitter::Error => e
|
51
|
+
page_error e
|
52
|
+
end
|
53
|
+
|
54
|
+
def set_profile_link_color(color)
|
55
|
+
twitter.update_profile profile_link_color: color
|
56
|
+
page_ok "Profile link color updated"
|
57
|
+
rescue Twitter::Error => e
|
58
|
+
page_error e
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Pry::SendTweet::TwitterAction::SuggestedActions
|
2
|
+
def suggested_topics
|
3
|
+
suggested_topics = twitter.suggestions lang: suggested_lang
|
4
|
+
page numbered_list("Suggested topics: ", suggested_topics) {|topic, index|
|
5
|
+
"#{index}. #{topic.slug}"
|
6
|
+
}
|
7
|
+
end
|
8
|
+
|
9
|
+
def suggested_users(topic)
|
10
|
+
topic = URI.escape(topic)
|
11
|
+
users = twitter.suggestions(topic, lang: suggested_lang).users
|
12
|
+
page numbered_list("Suggested users: ", users) {|user, index|
|
13
|
+
render_user(user)
|
14
|
+
}
|
15
|
+
end
|
16
|
+
|
17
|
+
def suggested_lang
|
18
|
+
opts['suggested-lang'] || 'en'
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
class Pry::SendTweet::TwitterSearch < Pry::SendTweet::BaseCommand
|
2
|
+
match 'twitter-search'
|
3
|
+
description 'Search Twitter.'
|
4
|
+
command_options argument_required: true, shellwords: false
|
5
|
+
banner <<-BANNER
|
6
|
+
twitter-search [options] query
|
7
|
+
|
8
|
+
#{description}
|
9
|
+
BANNER
|
10
|
+
|
11
|
+
def options(o)
|
12
|
+
o.on 'c=', 'count=', "The number of tweets to show. Default is " \
|
13
|
+
"#{default_read_size}."
|
14
|
+
end
|
15
|
+
|
16
|
+
def process(query)
|
17
|
+
super
|
18
|
+
tweets = filter twitter.search(query, search_options).to_a
|
19
|
+
if tweets.empty?
|
20
|
+
page "No results to show."
|
21
|
+
else
|
22
|
+
q = bright_blue(bold(query))
|
23
|
+
render_tweets(tweets, title: format("Showing search results for %{q}", q: q))
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
private def filter(tweets)
|
28
|
+
tweets.reject(&:retweet?)
|
29
|
+
end
|
30
|
+
|
31
|
+
private def search_options
|
32
|
+
{count: opts['count'] || default_read_size, tweet_mode: 'extended'}
|
33
|
+
end
|
34
|
+
|
35
|
+
Pry.commands.add_command self
|
36
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
module Pry::SendTweet::TweetRenderer
|
2
|
+
include Timeout
|
3
|
+
include TimeAgoInWords
|
4
|
+
|
5
|
+
def render_tweets(tweet_fetcher, title: nil, timeout: _pry_.config.twitter.refresh_interval)
|
6
|
+
pager = Pry::Pager::SystemPager.new(_pry_.output).tap(&:fork)
|
7
|
+
interval = __choose_render_interval(timeout)
|
8
|
+
timeout(interval) do
|
9
|
+
began_at, refresh_at = __find_timeout_range(interval)
|
10
|
+
rendered_title = __choose_title(title, began_at, refresh_at)
|
11
|
+
tweets = __fetch_tweets(tweet_fetcher)
|
12
|
+
tweets.empty? ? pager.write("No tweets to show.") :
|
13
|
+
pager.write(__render_tweets(rendered_title, tweets))
|
14
|
+
end
|
15
|
+
rescue Pry::Pager::StopPaging, Interrupt
|
16
|
+
pager.fast_exit!
|
17
|
+
system 'reset'
|
18
|
+
rescue Timeout::Error
|
19
|
+
pager.fast_exit!
|
20
|
+
system 'reset'
|
21
|
+
retry
|
22
|
+
ensure
|
23
|
+
pager.close
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
# @api private
|
28
|
+
def __render_tweets(title, tweets)
|
29
|
+
title + tweets.map {|tweet|
|
30
|
+
__render_tweet(tweet)
|
31
|
+
}.join("\n")
|
32
|
+
end
|
33
|
+
|
34
|
+
# @api private
|
35
|
+
def __render_tweet(tweet)
|
36
|
+
contents = __read_tweet_body(tweet)
|
37
|
+
body = "#{tweet.url}\n--\n#{contents}\n"
|
38
|
+
height = body.lines.count > box_height ? body.lines.count : box_height
|
39
|
+
TTY::Box.frame(height: height,
|
40
|
+
width: box_width,
|
41
|
+
title: {top_left: __render_tweet_title(tweet)}) {body}.to_s
|
42
|
+
end
|
43
|
+
|
44
|
+
# @api private
|
45
|
+
def __render_tweet_title(tweet)
|
46
|
+
user, created_at = tweet.user, tweet.created_at.getlocal
|
47
|
+
title = [
|
48
|
+
red("@#{user.screen_name}"),
|
49
|
+
"Around " + time_ago_in_words(created_at) + " before Last Refresh"
|
50
|
+
].join green(" | ")
|
51
|
+
" #{title} "
|
52
|
+
end
|
53
|
+
|
54
|
+
# @api private
|
55
|
+
def __read_tweet_body(tweet)
|
56
|
+
uris = tweet.uris
|
57
|
+
text = tweet.attrs[:full_text] ? tweet.attrs[:full_text] :
|
58
|
+
tweet.full_text
|
59
|
+
# 'text' might be a frozen string
|
60
|
+
text = text.dup
|
61
|
+
uris.each do |uri|
|
62
|
+
text.gsub!(uri.attrs[:url], uri.attrs[:expanded_url])
|
63
|
+
end
|
64
|
+
CGI.unescapeHTML(text).strip
|
65
|
+
end
|
66
|
+
|
67
|
+
# @api private
|
68
|
+
def __fetch_tweets(tweet_fetcher)
|
69
|
+
if tweet_fetcher.respond_to?(:call)
|
70
|
+
tweet_fetcher.call
|
71
|
+
else
|
72
|
+
# Already fetched
|
73
|
+
tweet_fetcher
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
# @api private
|
78
|
+
def __choose_title(title, began_at, refresh_at)
|
79
|
+
title = bold green(title || "Twitter")
|
80
|
+
timestamps = [bold("Last Refresh: "), began_at.strftime(time_format), "\n"]
|
81
|
+
timestamps.concat [
|
82
|
+
bold("Next Refresh: "),
|
83
|
+
refresh_at.strftime(time_format),
|
84
|
+
"\n"
|
85
|
+
] if refresh_at
|
86
|
+
title = "#{title}\n\n"
|
87
|
+
title += timestamps.join
|
88
|
+
title << "\n\n"
|
89
|
+
title
|
90
|
+
end
|
91
|
+
|
92
|
+
# @api private
|
93
|
+
def __choose_render_interval(timeout)
|
94
|
+
return nil if timeout == false
|
95
|
+
timeout || (60*5)
|
96
|
+
end
|
97
|
+
|
98
|
+
# @api private
|
99
|
+
def __find_timeout_range(seconds)
|
100
|
+
seconds ? [Time.now.getlocal, (Time.now + seconds).getlocal] :
|
101
|
+
[Time.now.getlocal, nil]
|
102
|
+
end
|
103
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Pry::SendTweet::UserRenderer
|
2
|
+
def render_user(user)
|
3
|
+
title = "@#{user.screen_name} ( https://twitter.com/#{user.screen_name} )"
|
4
|
+
body = CGI.unescapeHTML <<-USER.each_line.map(&:strip).join("\n")
|
5
|
+
#{bold("Tweets")} #{user.tweets_count}
|
6
|
+
#{bold("Followers")} #{user.followers_count}
|
7
|
+
#{bold("Following")} #{user.friends_count}
|
8
|
+
#{user.description}
|
9
|
+
USER
|
10
|
+
height = body.lines.count > box_height ? body.lines.count : box_height
|
11
|
+
TTY::Box.frame(
|
12
|
+
height: height,
|
13
|
+
width: box_width,
|
14
|
+
title: {top_left: title}
|
15
|
+
) { body }.to_s
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
#
|
2
|
+
# A monkey patch module that implements unicode & emoji support in the gem
|
3
|
+
# 'tty-box' when using its `frame` method.
|
4
|
+
#
|
5
|
+
module Pry::SendTweet::TTYPatch
|
6
|
+
require 'tty-box'
|
7
|
+
require 'unicode/display_width'
|
8
|
+
# Create a frame
|
9
|
+
#
|
10
|
+
# @api public
|
11
|
+
def frame(top: nil, left: nil, width: 35, height: 3, align: :left, padding: 0,
|
12
|
+
title: {}, border: :light, style: {})
|
13
|
+
output = []
|
14
|
+
content = []
|
15
|
+
position = top && left
|
16
|
+
|
17
|
+
border = TTY::Box::Border.parse(border)
|
18
|
+
top_size = border.top? ? 1: 0
|
19
|
+
bottom_size = border.bottom? ? 1: 0
|
20
|
+
left_size = border.left? ? 1 : 0
|
21
|
+
right_size = border.right ? 1 : 0
|
22
|
+
|
23
|
+
if block_given?
|
24
|
+
content = format(yield, width, padding, align)
|
25
|
+
end
|
26
|
+
|
27
|
+
fg, bg = *extract_style(style)
|
28
|
+
border_fg, border_bg = *extract_style(style[:border] || {})
|
29
|
+
|
30
|
+
if border.top?
|
31
|
+
output << cursor.move_to(left, top) if position
|
32
|
+
output << top_border(title, width, border, style)
|
33
|
+
output << "\n" unless position
|
34
|
+
end
|
35
|
+
|
36
|
+
(height - top_size - bottom_size).times do |i|
|
37
|
+
output << cursor.move_to(left, top + i + top_size) if position
|
38
|
+
if border.left?
|
39
|
+
output << border_bg.(border_fg.(pipe_char(border.type)))
|
40
|
+
end
|
41
|
+
|
42
|
+
content_size = width - left_size - right_size
|
43
|
+
unless content[i].nil?
|
44
|
+
output << bg.(fg.(content[i]))
|
45
|
+
plain_content = Pry::Helpers::Text.strip_color(content[i])
|
46
|
+
content_size -= Unicode::DisplayWidth.of(plain_content, 1, {})
|
47
|
+
end
|
48
|
+
if style[:fg] || style[:bg] || !position # something to color
|
49
|
+
output << bg.(fg.(' ' * content_size))
|
50
|
+
end
|
51
|
+
|
52
|
+
if border.right?
|
53
|
+
if position
|
54
|
+
output << cursor.move_to(left + width - right_size, top + i + top_size)
|
55
|
+
end
|
56
|
+
output << border_bg.(border_fg.(pipe_char(border.type)))
|
57
|
+
end
|
58
|
+
output << "\n" unless position
|
59
|
+
end
|
60
|
+
|
61
|
+
if border.bottom?
|
62
|
+
output << cursor.move_to(left, top + height - bottom_size) if position
|
63
|
+
output << bottom_border(title, width, border, style)
|
64
|
+
output << "\n" unless position
|
65
|
+
end
|
66
|
+
output.join
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
module TTY::Box
|
71
|
+
prepend Pry::SendTweet::TTYPatch
|
72
|
+
singleton_class.module_eval { prepend Pry::SendTweet::TTYPatch }
|
73
|
+
end
|