pry-send_tweet.rb 0.6.0 → 0.7.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 +43 -0
- data/Dockerfile +6 -4
- data/Gemfile +3 -1
- data/README.md +139 -52
- data/lib/pry-send_tweet.rb +31 -11
- data/lib/pry/send_tweet/{base_command.rb → commands/base_command.rb} +15 -6
- data/lib/pry/send_tweet/commands/read_tweets.rb +83 -0
- data/lib/pry/send_tweet/commands/send_tweet.rb +141 -0
- data/lib/pry/send_tweet/commands/twitter_action.rb +109 -0
- data/lib/pry/send_tweet/commands/twitter_action/delete_tweet_actions.rb +16 -0
- data/lib/pry/send_tweet/commands/twitter_action/follow_actions.rb +30 -0
- data/lib/pry/send_tweet/commands/twitter_action/like_actions.rb +17 -0
- data/lib/pry/send_tweet/commands/twitter_action/mute_actions.rb +20 -0
- data/lib/pry/send_tweet/commands/twitter_action/profile_actions.rb +42 -0
- data/lib/pry/send_tweet/commands/twitter_action/suggested_actions.rb +20 -0
- data/lib/pry/send_tweet/commands/twitter_search.rb +35 -0
- data/lib/pry/send_tweet/renderers/tweet_renderer.rb +78 -0
- data/lib/pry/send_tweet/version.rb +1 -1
- data/pry-send_tweet.gemspec +2 -1
- metadata +31 -10
- data/lib/pry/send_tweet/mixins/tweet_renderer.rb +0 -58
- data/lib/pry/send_tweet/read_tweets_command.rb +0 -78
- data/lib/pry/send_tweet/send_tweet_command.rb +0 -96
- data/lib/pry/send_tweet/twitter_action_command.rb +0 -184
@@ -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
|
+
display_followed_or_unfollowed(user, index)
|
14
|
+
}
|
15
|
+
end
|
16
|
+
|
17
|
+
def suggested_lang
|
18
|
+
opts['suggested-lang'] || 'en'
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
class Pry::SendTweet::TwitterSearch < Pry::SendTweet::BaseCommand
|
2
|
+
match 'twitter-search'
|
3
|
+
description 'Search Twitter for a given query.'
|
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 #{Pry::SendTweet::DEFAULT_READ_SIZE}."
|
13
|
+
end
|
14
|
+
|
15
|
+
def process(query)
|
16
|
+
super
|
17
|
+
tweets = filter twitter.search(query, search_options).to_a
|
18
|
+
if tweets.empty?
|
19
|
+
page "No results to show."
|
20
|
+
else
|
21
|
+
q = bright_blue(bold(query))
|
22
|
+
render_tweets(tweets, title: format("Showing search results for %{q}", q: q))
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
private def filter(tweets)
|
27
|
+
tweets.reject(&:retweet?)
|
28
|
+
end
|
29
|
+
|
30
|
+
private def search_options
|
31
|
+
{count: opts['count'] || Pry::SendTweet::DEFAULT_READ_SIZE, tweet_mode: 'extended'}
|
32
|
+
end
|
33
|
+
|
34
|
+
Pry.commands.add_command self
|
35
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
module Pry::SendTweet::TweetRenderer
|
2
|
+
include Timeout
|
3
|
+
|
4
|
+
def render_tweets(fetch_tweets, title:, timeout: _pry_.config.twitter.refresh_interval)
|
5
|
+
timeout = _pry_.config.twitter.refresh_interval
|
6
|
+
interval = if timeout == false
|
7
|
+
nil
|
8
|
+
else
|
9
|
+
timeout || (60*5)
|
10
|
+
end
|
11
|
+
pid = nil
|
12
|
+
timeout(interval) do
|
13
|
+
pid = Kernel.fork do
|
14
|
+
_pry_.pager.open do |pager|
|
15
|
+
__trap_signal(pager)
|
16
|
+
tweets = Proc === fetch_tweets ? fetch_tweets.call : fetch_tweets
|
17
|
+
tweets.empty? ? pager.write("No tweets to show.") :
|
18
|
+
pager.write(__render_tweets(title, tweets))
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
22
|
+
Process.wait(pid)
|
23
|
+
end
|
24
|
+
rescue Interrupt
|
25
|
+
__kill_pager!(pid)
|
26
|
+
system 'reset'
|
27
|
+
rescue Timeout::Error
|
28
|
+
__kill_pager!(pid)
|
29
|
+
system 'reset'
|
30
|
+
retry
|
31
|
+
end
|
32
|
+
|
33
|
+
def render_tweet(tweet)
|
34
|
+
line_width = _pry_.config.twitter.line_width || Pry::SendTweet::DEFAULT_LINE_WIDTH
|
35
|
+
text = tweet.attrs[:full_text] ? tweet.attrs[:full_text] : tweet.full_text
|
36
|
+
<<-TWEET.each_line.map{|s| s.chomp.strip}.join("\n")
|
37
|
+
#{render_tweet_title(tweet)}
|
38
|
+
#{tweet.url}
|
39
|
+
#{bold("-") * line_width}
|
40
|
+
#{word_wrap(CGI.unescapeHTML(text))}
|
41
|
+
TWEET
|
42
|
+
end
|
43
|
+
|
44
|
+
def render_tweet_title(tweet)
|
45
|
+
u = tweet.user
|
46
|
+
created_at = tweet.created_at.getlocal
|
47
|
+
<<-TWEET_TITLE.each_line.map{|s| s.chomp.strip}.join
|
48
|
+
#{bold("@#{u.screen_name}")}
|
49
|
+
#{bright_blue(" | ")}
|
50
|
+
#{created_at.ago.in_words}
|
51
|
+
#{bright_blue(" | ")}
|
52
|
+
#{created_at.strftime(time_format)}
|
53
|
+
TWEET_TITLE
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
# @api private
|
58
|
+
def __render_tweets(title, tweets)
|
59
|
+
title = bright_blue(bold((" " * 40) + title) + "\n\n")
|
60
|
+
title + tweets.map.with_index {|tweet, i|
|
61
|
+
"#{red bold('#')}#{red bold(i+1)}\n#{render_tweet(tweet)}"
|
62
|
+
}.join("\n\n")
|
63
|
+
end
|
64
|
+
|
65
|
+
# @api private
|
66
|
+
def __kill_pager!(pid)
|
67
|
+
Process.kill('SIGINT', pid)
|
68
|
+
end
|
69
|
+
|
70
|
+
# @api private
|
71
|
+
def __trap_signal(pager)
|
72
|
+
trap('SIGINT') {
|
73
|
+
# SimplePager does not have a PID, ignore NoMethodError
|
74
|
+
Process.kill('SIGKILL', pager.send(:pager).pid) rescue nil
|
75
|
+
Process.kill('SIGKILL', Process.pid)
|
76
|
+
}
|
77
|
+
end
|
78
|
+
end
|
data/pry-send_tweet.gemspec
CHANGED
@@ -4,7 +4,7 @@ Gem::Specification.new do |spec|
|
|
4
4
|
spec.version = Pry::SendTweet::VERSION
|
5
5
|
spec.authors = ["Robert Gleeson"]
|
6
6
|
spec.email = "trebor.g@protonmail.com"
|
7
|
-
spec.summary = "
|
7
|
+
spec.summary = "A Twitter client for the Pry REPL."
|
8
8
|
spec.description = spec.summary
|
9
9
|
spec.homepage = "https://github.com/r-obert/pry-send_tweet.rb"
|
10
10
|
spec.licenses = ["MIT"]
|
@@ -12,4 +12,5 @@ Gem::Specification.new do |spec|
|
|
12
12
|
spec.files = Dir["Dockerfile", "Gemfile", "*.{txt,gemspec,md}", "lib/**/*.rb"]
|
13
13
|
spec.add_runtime_dependency "pry", "~> 0.12"
|
14
14
|
spec.add_runtime_dependency "twitter", "~> 6.0"
|
15
|
+
spec.add_runtime_dependency "time-lord", "~> 1.0"
|
15
16
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pry-send_tweet.rb
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Robert Gleeson
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2019-01-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: pry
|
@@ -38,7 +38,21 @@ dependencies:
|
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '6.0'
|
41
|
-
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: time-lord
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '1.0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1.0'
|
55
|
+
description: A Twitter client for the Pry REPL.
|
42
56
|
email: trebor.g@protonmail.com
|
43
57
|
executables: []
|
44
58
|
extensions: []
|
@@ -50,11 +64,18 @@ files:
|
|
50
64
|
- LICENSE.txt
|
51
65
|
- README.md
|
52
66
|
- lib/pry-send_tweet.rb
|
53
|
-
- lib/pry/send_tweet/base_command.rb
|
54
|
-
- lib/pry/send_tweet/
|
55
|
-
- lib/pry/send_tweet/
|
56
|
-
- lib/pry/send_tweet/
|
57
|
-
- lib/pry/send_tweet/
|
67
|
+
- lib/pry/send_tweet/commands/base_command.rb
|
68
|
+
- lib/pry/send_tweet/commands/read_tweets.rb
|
69
|
+
- lib/pry/send_tweet/commands/send_tweet.rb
|
70
|
+
- lib/pry/send_tweet/commands/twitter_action.rb
|
71
|
+
- lib/pry/send_tweet/commands/twitter_action/delete_tweet_actions.rb
|
72
|
+
- lib/pry/send_tweet/commands/twitter_action/follow_actions.rb
|
73
|
+
- lib/pry/send_tweet/commands/twitter_action/like_actions.rb
|
74
|
+
- lib/pry/send_tweet/commands/twitter_action/mute_actions.rb
|
75
|
+
- lib/pry/send_tweet/commands/twitter_action/profile_actions.rb
|
76
|
+
- lib/pry/send_tweet/commands/twitter_action/suggested_actions.rb
|
77
|
+
- lib/pry/send_tweet/commands/twitter_search.rb
|
78
|
+
- lib/pry/send_tweet/renderers/tweet_renderer.rb
|
58
79
|
- lib/pry/send_tweet/version.rb
|
59
80
|
- pry-send_tweet.gemspec
|
60
81
|
homepage: https://github.com/r-obert/pry-send_tweet.rb
|
@@ -77,8 +98,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
77
98
|
version: '0'
|
78
99
|
requirements: []
|
79
100
|
rubyforge_project:
|
80
|
-
rubygems_version: 2.7.
|
101
|
+
rubygems_version: 2.7.8
|
81
102
|
signing_key:
|
82
103
|
specification_version: 4
|
83
|
-
summary:
|
104
|
+
summary: A Twitter client for the Pry REPL.
|
84
105
|
test_files: []
|
@@ -1,58 +0,0 @@
|
|
1
|
-
module Pry::SendTweet::TweetRenderer
|
2
|
-
include Timeout
|
3
|
-
|
4
|
-
def render_tweets(fetch_tweets, title: , timeout: _pry_.config.twitter.refresh_interval)
|
5
|
-
pid = nil
|
6
|
-
refresh_interval = timeout == false ? (nil) : (timeout || 240)
|
7
|
-
timeout(refresh_interval) do
|
8
|
-
_pry_.pager.open do |pager|
|
9
|
-
pid = pager.send(:pager).pid
|
10
|
-
pager.write draw_tweets(
|
11
|
-
title,
|
12
|
-
Proc === fetch_tweets ? fetch_tweets.call : fetch_tweets
|
13
|
-
)
|
14
|
-
end
|
15
|
-
end
|
16
|
-
rescue Timeout::Error
|
17
|
-
Process.kill 'SIGKILL', pid
|
18
|
-
_pry_.output.puts bold(bright_yellow("\n\n** Refreshing Tweets **\n"))
|
19
|
-
sleep 0.3
|
20
|
-
system 'reset'
|
21
|
-
retry
|
22
|
-
end
|
23
|
-
|
24
|
-
def render_tweet(tweet)
|
25
|
-
text = tweet.attrs[:full_text] ? tweet.attrs[:full_text] : tweet.full_text
|
26
|
-
<<-TWEET.each_line.map{|s| s.chomp.strip}.join("\n")
|
27
|
-
#{tweet_title(tweet)}
|
28
|
-
#{tweet.url}
|
29
|
-
#{"-" * 80}
|
30
|
-
#{word_wrap(CGI.unescapeHTML(text))}
|
31
|
-
#{"-" * 80}
|
32
|
-
TWEET
|
33
|
-
end
|
34
|
-
|
35
|
-
def tweet_title(tweet)
|
36
|
-
if tweet.user
|
37
|
-
u = tweet.user
|
38
|
-
<<-TWEET_TITLE.each_line.map{|s| s.chomp.strip}.join
|
39
|
-
@#{u.screen_name}
|
40
|
-
#{bright_blue(" | ")}
|
41
|
-
#{tweet_timestamp(tweet)}
|
42
|
-
TWEET_TITLE
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
def tweet_timestamp(tweet)
|
47
|
-
tweet
|
48
|
-
.created_at
|
49
|
-
.getlocal
|
50
|
-
.strftime("%-d %b %Y, %-I:%M%p")
|
51
|
-
end
|
52
|
-
|
53
|
-
def draw_tweets(heading, tweets)
|
54
|
-
"#{heading}\n\n" + tweets.map.with_index {|tweet, i|
|
55
|
-
"#{red bold('#')}#{red bold(i+1)}\n#{render_tweet(tweet)}"
|
56
|
-
}.join("\n\n")
|
57
|
-
end
|
58
|
-
end
|
@@ -1,78 +0,0 @@
|
|
1
|
-
class Pry::SendTweet::ReadTweets < Pry::SendTweet::BaseCommand
|
2
|
-
DEFAULT_COUNT = 35
|
3
|
-
match 'read-tweets'
|
4
|
-
description "Read tweets"
|
5
|
-
banner <<-B
|
6
|
-
read-tweets [options]
|
7
|
-
|
8
|
-
Read tweets from your timeline or the timeline of another user.
|
9
|
-
B
|
10
|
-
|
11
|
-
def options(o)
|
12
|
-
o.on :t=,
|
13
|
-
'The username whose timeline you want to read.'
|
14
|
-
o.on :c=,
|
15
|
-
'count=',
|
16
|
-
'The number of tweets to read. The maximum is 200.'
|
17
|
-
o.on 'with-retweets',
|
18
|
-
'Include retweets.'
|
19
|
-
o.on 'that-mention-me',
|
20
|
-
'Read tweets that @mention you.'
|
21
|
-
o.on 'my-likes',
|
22
|
-
'Read tweets you have liked.'
|
23
|
-
o.on 'liked-by=',
|
24
|
-
'The username whose likes you want to read.'
|
25
|
-
end
|
26
|
-
|
27
|
-
def process
|
28
|
-
super
|
29
|
-
case
|
30
|
-
when opts.present?('liked-by') then render_user_likes(opts['liked-by'])
|
31
|
-
when opts.present?('my-likes') then render_my_likes
|
32
|
-
when opts.present?('that-mention-me') then render_tweets_that_mention_me
|
33
|
-
else render_tweets_from_timeline(opts['t'])
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
private
|
38
|
-
|
39
|
-
def render_user_likes(str)
|
40
|
-
sn = find_usernames_in(str).first
|
41
|
-
asn = "@#{sn}"
|
42
|
-
render_tweets ->() { client.favorites(sn, count: opts['count'] || DEFAULT_COUNT)},
|
43
|
-
title: bright_white(bold("Tweets liked by #{bright_blue(asn)}"))
|
44
|
-
end
|
45
|
-
|
46
|
-
def render_my_likes
|
47
|
-
render_tweets ->() { client.favorites(count: opts['count'] || DEFAULT_COUNT) },
|
48
|
-
title: bright_blue(bold("Tweets liked by you"))
|
49
|
-
end
|
50
|
-
|
51
|
-
def render_tweets_that_mention_me
|
52
|
-
render_tweets ->() { client.mentions(timeline_options) },
|
53
|
-
title: bright_white(bold("Tweets that #{bright_blue('@mention')} #{bright_white(bold('you'))}"))
|
54
|
-
end
|
55
|
-
|
56
|
-
def render_tweets_from_timeline(target)
|
57
|
-
render_tweets ->() {
|
58
|
-
if target
|
59
|
-
client.user_timeline(target, timeline_options)
|
60
|
-
else
|
61
|
-
client.home_timeline(timeline_options)
|
62
|
-
end
|
63
|
-
},
|
64
|
-
title: target ?
|
65
|
-
bright_white(bold("Tweets from #{bright_blue("@#{target}")}")) :
|
66
|
-
bright_blue(bold('Twitter'))
|
67
|
-
end
|
68
|
-
|
69
|
-
def timeline_options
|
70
|
-
{
|
71
|
-
tweet_mode: 'extended',
|
72
|
-
include_rts: opts.present?('with-retweets'),
|
73
|
-
count: opts.present?('count') ? opts['count'] : DEFAULT_COUNT
|
74
|
-
}
|
75
|
-
end
|
76
|
-
|
77
|
-
Pry.commands.add_command self
|
78
|
-
end
|
@@ -1,96 +0,0 @@
|
|
1
|
-
class Pry::SendTweet::SendTweetCommand < Pry::SendTweet::BaseCommand
|
2
|
-
match 'send-tweet'
|
3
|
-
description 'Send a tweet'
|
4
|
-
command_options argument_required: false
|
5
|
-
banner <<-BANNER
|
6
|
-
send-tweet [options]
|
7
|
-
|
8
|
-
Send a tweet.
|
9
|
-
BANNER
|
10
|
-
|
11
|
-
def options(opts)
|
12
|
-
opts.on :f=,
|
13
|
-
'file=',
|
14
|
-
'A path to an image or other media to attach to a tweet'
|
15
|
-
opts.on :r=,
|
16
|
-
'reply-to=',
|
17
|
-
'An absolute url to a tweet you want to reply to.'
|
18
|
-
opts.on 'cowsay-text=',
|
19
|
-
'A string of text that "cowsay" will use.'
|
20
|
-
opts.on 'cowsay-char=',
|
21
|
-
'Decides which character "cowsay" will use. Default is "cow".'
|
22
|
-
end
|
23
|
-
|
24
|
-
def process(args)
|
25
|
-
super
|
26
|
-
tweet = create_content_of_tweet
|
27
|
-
if opts.present?(:file)
|
28
|
-
media = File.new opts[:file], 'r'
|
29
|
-
_pry_.output.puts client.update_with_media(tweet, media, tweet_options).url
|
30
|
-
media.close
|
31
|
-
else
|
32
|
-
_pry_.output.puts client.update(tweet, tweet_options).url
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
private
|
37
|
-
|
38
|
-
def prepend_username_to_reply!(tweet_url, file)
|
39
|
-
username = tweet_username_from(tweet_url)
|
40
|
-
file.write "@#{username} "
|
41
|
-
end
|
42
|
-
|
43
|
-
def tweet_username_from(tweet_url)
|
44
|
-
File.basename File.dirname(File.dirname(tweet_url))
|
45
|
-
end
|
46
|
-
|
47
|
-
def replying_to_other_tweet?
|
48
|
-
opts.present?('reply-to')
|
49
|
-
end
|
50
|
-
|
51
|
-
def tweet_options
|
52
|
-
options = {}
|
53
|
-
options.merge!({
|
54
|
-
in_reply_to_status_id: Integer(File.basename(opts['reply-to']))
|
55
|
-
}) if replying_to_other_tweet?
|
56
|
-
options
|
57
|
-
end
|
58
|
-
|
59
|
-
def create_content_of_tweet
|
60
|
-
if opts.present?('cowsay-text')
|
61
|
-
compose_tweet_with_cowsay
|
62
|
-
else
|
63
|
-
compose_tweet_with_editor
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
|
-
def compose_tweet_with_editor
|
68
|
-
Tempfile.open('pry-send_tweet--compose-tweet') do |file|
|
69
|
-
if replying_to_other_tweet?
|
70
|
-
# During experimentation I noticed that without prefixing who we are
|
71
|
-
# replying to, the tweet we send will not be considered a reply even
|
72
|
-
# with reply_to_status_id being set.
|
73
|
-
prepend_username_to_reply!(opts['reply-to'], file)
|
74
|
-
end
|
75
|
-
file.rewind
|
76
|
-
Pry::Editor.new(_pry_).invoke_editor(file.path, 0)
|
77
|
-
file.read
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
|
-
def compose_tweet_with_cowsay
|
82
|
-
username = if replying_to_other_tweet?
|
83
|
-
"@#{tweet_username_from(opts['reply-to'])} "
|
84
|
-
end
|
85
|
-
char = opts['cowsay-char'] || 'cow'
|
86
|
-
txt = "#{username}#{opts['cowsay-text']}"
|
87
|
-
`cowsay -f #{char.shellescape} #{txt.shellescape}`.tap do
|
88
|
-
if !$?.success?
|
89
|
-
raise Pry::CommandError,
|
90
|
-
"Something went wrong. Is 'cowsay' installed?"
|
91
|
-
end
|
92
|
-
end
|
93
|
-
end
|
94
|
-
|
95
|
-
Pry.commands.add_command self
|
96
|
-
end
|