pry-send_tweet.rb 0.6.0 → 0.7.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 +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
|