pry-send_tweet.rb 0.4.0 → 0.5.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 +18 -3
- data/README.md +141 -22
- data/lib/pry-send_tweet.rb +11 -56
- data/lib/pry/send_tweet/base_command.rb +57 -0
- data/lib/pry/send_tweet/mixins/tweet_renderer.rb +55 -0
- data/lib/pry/send_tweet/read_tweets_command.rb +78 -0
- data/lib/pry/send_tweet/send_tweet_command.rb +95 -0
- data/lib/pry/send_tweet/twitter_action_command.rb +166 -0
- data/pry-send_tweet.gemspec +2 -2
- metadata +9 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ed084e3b9fae0289169d8f868beb43339998d9d30349eacb5261979148721e56
|
4
|
+
data.tar.gz: 31d443e012af14a5e9b7dcdb9ec9ccc49ab735cf710ab5f9f34a8f924cdbf46f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b8e7dcf4fb5561197b1f428c6f0e3af4690d12f00d5ba30a0bb086e0e6b2ffd9a9fb5221e595262cce3049fd447c13ec7653332b21abbe527cf105ceb5b8f3d1
|
7
|
+
data.tar.gz: b2d006dc6fc9c62716b95ee382b5e6a9e2430e9a25bae531e90c1cd9f0e5b0a2ee77faa28d83577b9e05800e80661e7ec01e6f7ff9f7518f0b669871896ceeb8
|
data/CHANGELOG.md
CHANGED
@@ -1,13 +1,28 @@
|
|
1
1
|
# CHANGELOG
|
2
2
|
|
3
|
+
## master
|
4
|
+
|
5
|
+
## v0.5.0
|
6
|
+
|
7
|
+
* Automatically refresh the tweets on display every 4 minutes.
|
8
|
+
|
9
|
+
* `Pry.config.twitter.refresh_interval` can be used for setting a custom refresh
|
10
|
+
interval. The default is 240 seconds, or 4 minutes.
|
11
|
+
|
12
|
+
* Add the command `read-tweets`.
|
13
|
+
|
14
|
+
* Add the command `twitter-action`, aliased as `on-twitter`.
|
15
|
+
|
3
16
|
## v0.4.0
|
4
17
|
|
5
|
-
* Add support for attaching an image to a tweet with
|
6
|
-
|
18
|
+
* Add support for attaching an image to a tweet with
|
19
|
+
the optional `-f` / `--file` switch:
|
20
|
+
|
21
|
+
`send-tweet --file /path/to/image.jpg`
|
7
22
|
|
8
23
|
## v0.3.0
|
9
24
|
|
10
|
-
* Compose a tweet using `pry.editor`
|
25
|
+
* Compose a tweet using `pry.editor`
|
11
26
|
|
12
27
|
## v0.2.1
|
13
28
|
|
data/README.md
CHANGED
@@ -1,53 +1,172 @@
|
|
1
1
|
# pry-send_tweet.rb
|
2
2
|
|
3
|
-
|
4
|
-
personal twitter account.
|
3
|
+
## Introduction
|
5
4
|
|
6
|
-
|
5
|
+
Extends the Pry REPL with the capabilities of a Twitter client.
|
7
6
|
|
8
|
-
|
9
|
-
Twitter requires the following keys and tokens to do that:
|
7
|
+
## API Access
|
10
8
|
|
11
|
-
|
9
|
+
Using the Twitter API requires a developer account.
|
10
|
+
Follow the instructions at [https://developer.twitter.com](https://developer.twitter.com)
|
11
|
+
if you haven't already setup access to the Twitter API.
|
12
12
|
|
13
|
-
|
14
|
-
developer account and then creating an "app" for your account. This can be done
|
15
|
-
at [https://developer.twitter.com](https://developer.twitter.com).
|
13
|
+
## Configuration (required)
|
16
14
|
|
17
|
-
|
15
|
+
The placeholder keys and tokens in the below example can be replaced
|
16
|
+
by those from your developer account.
|
18
17
|
|
19
18
|
```ruby
|
19
|
+
# .pryrc
|
20
20
|
Pry.configure do |config|
|
21
21
|
config.twitter = Pry::Config.from_hash({
|
22
22
|
consumer_key: '<consumer key>',
|
23
23
|
consumer_secret: '<consumer secret>',
|
24
24
|
access_token: '<access token>',
|
25
25
|
access_token_secret: '<access token secret>'
|
26
|
-
}
|
26
|
+
})
|
27
27
|
end
|
28
28
|
```
|
29
29
|
|
30
30
|
## Usage
|
31
31
|
|
32
|
-
|
32
|
+
There are three commands added to Pry by this plugin, those commands are:
|
33
|
+
|
34
|
+
* `send-tweet`
|
35
|
+
For sending tweets.
|
36
|
+
|
37
|
+
* `read-tweets`
|
38
|
+
For reading tweets.
|
39
|
+
|
40
|
+
* `twitter-action` (aliased as: `on-twitter`)
|
41
|
+
For performing misc actions on Twitter, such as following, unfollowing, etc.
|
42
|
+
|
43
|
+
### Sending tweets
|
44
|
+
|
45
|
+
|
46
|
+
* Send a tweet:
|
47
|
+
|
48
|
+
# Your editor opens (`_pry_.editor`), compose a tweet then hit save & close.
|
49
|
+
# You'll then get the url for your tweet:
|
50
|
+
[1] pry(main)> send-tweet
|
51
|
+
https://twitter.com/xxx/status/xxx
|
52
|
+
|
53
|
+
|
54
|
+
* Send a tweet with an image attached:
|
55
|
+
|
56
|
+
[1] pry(main)> send-tweet --file #{File.join ENV['HOME'], 'photos', 'image.jpg'}
|
57
|
+
|
58
|
+
* Reply to a tweet:
|
59
|
+
|
60
|
+
[1] pry(main)> send-tweet --reply-to https://twitter.com/username/status/1
|
61
|
+
|
62
|
+
* There is built-in support for the `cowsay` program, which is a program that
|
63
|
+
draws humorous ascii art. The following example will send a tweet using the
|
64
|
+
Linux 'tux' mascot.
|
65
|
+
<br>
|
66
|
+
**Tip:** `--cowsay-char` is optional and can be left blank. A cow will be used
|
67
|
+
as the default. For a full list of available `cowsay` characters that can be
|
68
|
+
used with the `--cowsay-char` option, run `cowsay -l` from a shell.
|
69
|
+
|
70
|
+
**Extra Tip:** The `Dockerfile` in this repository installs `cowsay`.
|
71
|
+
|
72
|
+
[1] pry(main)> send-tweet --cowsay-text 'Hello, world' --cowsay-char tux
|
73
|
+
|
74
|
+
### Reading tweets
|
75
|
+
|
76
|
+
By default the tweets displayed by the `read-tweets` command are automatically
|
77
|
+
refreshed every 4 minutes.
|
78
|
+
|
79
|
+
That can be changed to a custom interval by setting `Pry.config.twitter.refresh_interval`
|
80
|
+
to a number of seconds, or to `nil` if you want to disable this feature.
|
81
|
+
|
82
|
+
* Read recent tweets from your timeline:
|
83
|
+
|
84
|
+
[1] pry(main)> read-tweets
|
85
|
+
|
86
|
+
* Read recent tweets from the timeline of another user:
|
87
|
+
|
88
|
+
[1] pry(main)> read-tweets -t rubygems
|
89
|
+
|
90
|
+
* Read recent tweets that `@mention` you:
|
91
|
+
|
92
|
+
[1] pry(main)> read-tweets --that-mention-me
|
93
|
+
|
94
|
+
* Read recent tweets that you've liked:
|
33
95
|
|
34
|
-
|
96
|
+
[1] pry(main) read-tweets --my-likes
|
35
97
|
|
36
|
-
|
37
|
-
# Your editor opens (`_pry_.editor`), compose a tweet then hit save & close.
|
38
|
-
# You'll then get the url for your tweet:
|
39
|
-
https://twitter.com/xxx/status/xxx
|
98
|
+
* Read recent tweets liked by another user:
|
40
99
|
|
41
|
-
|
100
|
+
[1] pry(main)> read-tweets --liked-by ladygaga
|
42
101
|
|
43
|
-
|
102
|
+
* By default retweets are not displayed.
|
103
|
+
To display retweets, pass the `--with-retweets` option.
|
44
104
|
|
45
|
-
|
105
|
+
[1] pry(main)> read-tweets --with-retweets
|
106
|
+
|
107
|
+
* Read 100 recent tweets instead of the default 35 recent tweets.
|
108
|
+
**Tip:** `--count` can be combined with all of the options described above.
|
109
|
+
|
110
|
+
[1] pry(main)> read-tweets --count 100
|
111
|
+
|
112
|
+
### Deleting tweets
|
113
|
+
|
114
|
+
* Delete a tweet:
|
115
|
+
|
116
|
+
[1] pry(main)> twitter-action --delete-tweet https://twitter.com/username/status/1
|
117
|
+
|
118
|
+
* Delete a retweet:
|
119
|
+
|
120
|
+
[1] pry(main)> twitter-action --delete-retweet https://twitter.com/username/status/1
|
121
|
+
|
122
|
+
### Liking tweets
|
123
|
+
|
124
|
+
* Like a tweet:
|
125
|
+
|
126
|
+
[1] pry(main)> twitter-action --like https://twitter.com/user/status/1
|
127
|
+
|
128
|
+
* Unlike a tweet:
|
129
|
+
|
130
|
+
[1] pry(main)> twitter-action --unlike https://twitter.com/user/status/1
|
131
|
+
|
132
|
+
### Retweets
|
133
|
+
|
134
|
+
* Retweet a tweet:
|
135
|
+
|
136
|
+
[1] pry(main)> twitter-action --retweet https://twitter.com/user/status/1
|
137
|
+
|
138
|
+
### Update your Twitter profile
|
139
|
+
|
140
|
+
* Update your profiles image:
|
141
|
+
|
142
|
+
[1] pry(main)> twitter-action --set-profile-image /path/to/image.jpg
|
143
|
+
|
144
|
+
* Update your profiles banner image:
|
145
|
+
|
146
|
+
[1] pry(main)> twitter-action --set-profile-banner-image /path/to/image.jpg
|
147
|
+
|
148
|
+
* Update your profiles bio:
|
149
|
+
|
150
|
+
# Your editor opens (`_pry_.editor`), write your bio then hit save & close.
|
151
|
+
# Your bio will be updated after closing your editor.
|
152
|
+
[1] pry(main)> twitter-action --set-profile-bio
|
46
153
|
|
47
154
|
## Install
|
48
155
|
|
49
|
-
|
156
|
+
Install the gem:
|
157
|
+
|
158
|
+
$ gem install pry-send_tweet.rb
|
159
|
+
|
160
|
+
There's also the option to clone this repository and then use the provided
|
161
|
+
`Dockerfile` to run pry-send_tweet.rb inside a Docker container.
|
162
|
+
The container is configured to use `emacs` when sending tweets and when using
|
163
|
+
other commands that open an editor.
|
164
|
+
|
165
|
+
$ git clone https://github.com/r-obert/pry-send_tweet.rb
|
166
|
+
$ cd pry-send_tweet.rb
|
167
|
+
$ ./dockerize.sh
|
168
|
+
|
50
169
|
|
51
170
|
## License
|
52
171
|
|
53
|
-
[
|
172
|
+
This project uses the MIT license, see [LICENSE.txt](./LICENSE.txt) for details.
|
data/lib/pry-send_tweet.rb
CHANGED
@@ -1,57 +1,12 @@
|
|
1
1
|
require 'pry' if not defined?(Pry::ClassCommand)
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
opts.on :f,
|
14
|
-
:file,
|
15
|
-
'A path to an image or other media to attach to a tweet',
|
16
|
-
argument: true
|
17
|
-
end
|
18
|
-
|
19
|
-
def process(*args)
|
20
|
-
if nil == _pry_.config.twitter
|
21
|
-
raise Pry::CommandError, "_pry_.config.twitter is nil!\n" \
|
22
|
-
"Please set the required keys and tokens to send " \
|
23
|
-
"tweets using Twitters API. \n" \
|
24
|
-
"Visit https://github.com/r-obert/pry-send_tweet.rb#readme to learn how."
|
25
|
-
end
|
26
|
-
send_tweet_using_editor
|
27
|
-
end
|
28
|
-
|
29
|
-
private
|
30
|
-
def send_tweet_using_editor
|
31
|
-
tmp_file = Tempfile.new('pry-send_tweet')
|
32
|
-
Pry::Editor.new(_pry_).invoke_editor(tmp_file.path, 0)
|
33
|
-
tmp_file.rewind
|
34
|
-
if opts.f?
|
35
|
-
file = File.new opts[:f], 'r'
|
36
|
-
_pry_.output.puts client.update_with_media(tmp_file.read, file).url
|
37
|
-
file.close
|
38
|
-
else
|
39
|
-
_pry_.output.puts client.update(tmp_file.read).url
|
40
|
-
end
|
41
|
-
ensure
|
42
|
-
tmp_file.close
|
43
|
-
tmp_file.unlink
|
44
|
-
end
|
45
|
-
|
46
|
-
|
47
|
-
def client
|
48
|
-
@client ||= begin
|
49
|
-
Twitter::REST::Client.new { |config|
|
50
|
-
config.consumer_key = _pry_.config.twitter.consumer_key
|
51
|
-
config.consumer_secret = _pry_.config.twitter.consumer_secret
|
52
|
-
config.access_token = _pry_.config.twitter.access_token
|
53
|
-
config.access_token_secret = _pry_.config.twitter.access_token_secret
|
54
|
-
}
|
55
|
-
end
|
56
|
-
end
|
57
|
-
}
|
2
|
+
require 'twitter'
|
3
|
+
require 'cgi'
|
4
|
+
require 'shellwords'
|
5
|
+
require 'timeout'
|
6
|
+
module Pry::SendTweet
|
7
|
+
require_relative 'pry/send_tweet/mixins/tweet_renderer'
|
8
|
+
require_relative 'pry/send_tweet/base_command'
|
9
|
+
require_relative 'pry/send_tweet/send_tweet_command'
|
10
|
+
require_relative 'pry/send_tweet/read_tweets_command'
|
11
|
+
require_relative 'pry/send_tweet/twitter_action_command'
|
12
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
class Pry::SendTweet::BaseCommand < Pry::ClassCommand
|
2
|
+
include Pry::SendTweet::TweetRenderer
|
3
|
+
|
4
|
+
def self.inherited(kls)
|
5
|
+
kls.group 'Twitter'
|
6
|
+
end
|
7
|
+
|
8
|
+
def process(*args)
|
9
|
+
if nil == _pry_.config.twitter
|
10
|
+
raise Pry::CommandError, "_pry_.config.twitter is nil!\n" \
|
11
|
+
"Please set the required keys and tokens to send " \
|
12
|
+
"tweets using Twitters API. \n" \
|
13
|
+
"Visit https://github.com/r-obert/pry-send_tweet.rb#readme to learn how."
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def page(txt)
|
20
|
+
_pry_.pager.page txt
|
21
|
+
end
|
22
|
+
|
23
|
+
def find_usernames_in(*ary)
|
24
|
+
ary.map do |str|
|
25
|
+
if str.start_with?('https://twitter.com')
|
26
|
+
File.basename URI.parse(URI.escape(str)).path
|
27
|
+
elsif str.start_with?('@')
|
28
|
+
str[1..-1]
|
29
|
+
else
|
30
|
+
str
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# With thanks to ActionView for this method
|
36
|
+
def word_wrap(text, options = {})
|
37
|
+
line_width = options.fetch(:line_width, 80)
|
38
|
+
text.split("\n").collect! do |line|
|
39
|
+
line.length > line_width ? line.gsub(/(.{1,#{line_width}})(\s+|$)/, "\\1\n").strip : line
|
40
|
+
end * "\n"
|
41
|
+
end
|
42
|
+
|
43
|
+
def numbered_list(title, ary)
|
44
|
+
underline = "-" * title.size
|
45
|
+
title = "#{bold(underline)}\n#{title.chomp}\n#{bold(underline)}\n\n"
|
46
|
+
title + ary.map.with_index { |item, index| yield(item, index+1) }.join("\n")
|
47
|
+
end
|
48
|
+
|
49
|
+
def client
|
50
|
+
@client ||= Twitter::REST::Client.new { |config|
|
51
|
+
config.consumer_key = _pry_.config.twitter.consumer_key
|
52
|
+
config.consumer_secret = _pry_.config.twitter.consumer_secret
|
53
|
+
config.access_token = _pry_.config.twitter.access_token
|
54
|
+
config.access_token_secret = _pry_.config.twitter.access_token_secret
|
55
|
+
}
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module Pry::SendTweet::TweetRenderer
|
2
|
+
include Timeout
|
3
|
+
|
4
|
+
def render_tweets(fetch_tweets_proc, title:)
|
5
|
+
pid = nil
|
6
|
+
refresh_interval = _pry_.config.twitter.refresh_interval || 240
|
7
|
+
timeout(refresh_interval) do
|
8
|
+
_pry_.pager.open do |pager|
|
9
|
+
pid = pager.send(:pager).pid
|
10
|
+
pager.write draw_tweets(title, fetch_tweets_proc.call)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
rescue Timeout::Error
|
14
|
+
Process.kill 'SIGKILL', pid
|
15
|
+
_pry_.output.puts bold(bright_yellow("\n\n** Refreshing Tweets **\n"))
|
16
|
+
sleep 0.3
|
17
|
+
system 'reset'
|
18
|
+
retry
|
19
|
+
end
|
20
|
+
|
21
|
+
def render_tweet(tweet)
|
22
|
+
text = tweet.attrs[:full_text] ? tweet.attrs[:full_text] : tweet.full_text
|
23
|
+
<<-TWEET.each_line.map{|s| s.chomp.strip}.join("\n")
|
24
|
+
#{tweet_title(tweet)}
|
25
|
+
#{tweet.url}
|
26
|
+
#{"-" * 80}
|
27
|
+
#{word_wrap(CGI.unescapeHTML(text))}
|
28
|
+
#{"-" * 80}
|
29
|
+
TWEET
|
30
|
+
end
|
31
|
+
|
32
|
+
def tweet_title(tweet)
|
33
|
+
if tweet.user
|
34
|
+
u = tweet.user
|
35
|
+
<<-TWEET_TITLE.each_line.map{|s| s.chomp.strip}.join
|
36
|
+
@#{u.screen_name}
|
37
|
+
#{bright_blue(" | ")}
|
38
|
+
#{tweet_timestamp(tweet)}
|
39
|
+
TWEET_TITLE
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def tweet_timestamp(tweet)
|
44
|
+
tweet
|
45
|
+
.created_at
|
46
|
+
.getlocal
|
47
|
+
.strftime("%-d %b %Y, %-I:%M%p")
|
48
|
+
end
|
49
|
+
|
50
|
+
def draw_tweets(heading, tweets)
|
51
|
+
"#{heading}\n\n" + tweets.map.with_index {|tweet, i|
|
52
|
+
"#{red bold('#')}#{red bold(i+1)}\n#{render_tweet(tweet)}"
|
53
|
+
}.join("\n\n")
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
class Pry::SendTweet::ReadTweets < Pry::SendTweet::BaseCommand
|
2
|
+
DEFAULT_COUNT = 35
|
3
|
+
match 'read-tweets'
|
4
|
+
description "Read tweets from your timeline or the timeline of another user"
|
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
|
@@ -0,0 +1,95 @@
|
|
1
|
+
class Pry::SendTweet::SendTweetCommand < Pry::SendTweet::BaseCommand
|
2
|
+
match 'send-tweet'
|
3
|
+
command_options argument_required: false
|
4
|
+
banner <<-BANNER
|
5
|
+
send-tweet [options]
|
6
|
+
|
7
|
+
Send a tweet.
|
8
|
+
BANNER
|
9
|
+
|
10
|
+
def options(opts)
|
11
|
+
opts.on :f=,
|
12
|
+
'file=',
|
13
|
+
'A path to an image or other media to attach to a tweet'
|
14
|
+
opts.on :r=,
|
15
|
+
'reply-to=',
|
16
|
+
'An absolute url to a tweet you want to reply to.'
|
17
|
+
opts.on 'cowsay-text=',
|
18
|
+
'A string of text that "cowsay" will use.'
|
19
|
+
opts.on 'cowsay-char=',
|
20
|
+
'Decides which character "cowsay" will use. Default is "cow".'
|
21
|
+
end
|
22
|
+
|
23
|
+
def process(args)
|
24
|
+
super
|
25
|
+
tweet = create_content_of_tweet
|
26
|
+
if opts.present?(:file)
|
27
|
+
media = File.new opts[:file], 'r'
|
28
|
+
_pry_.output.puts client.update_with_media(tweet, media, tweet_options).url
|
29
|
+
media.close
|
30
|
+
else
|
31
|
+
_pry_.output.puts client.update(tweet, tweet_options).url
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def prepend_username_to_reply!(tweet_url, file)
|
38
|
+
username = tweet_username_from(tweet_url)
|
39
|
+
file.write "@#{username} "
|
40
|
+
end
|
41
|
+
|
42
|
+
def tweet_username_from(tweet_url)
|
43
|
+
File.basename File.dirname(File.dirname(tweet_url))
|
44
|
+
end
|
45
|
+
|
46
|
+
def replying_to_other_tweet?
|
47
|
+
opts.present?('reply-to')
|
48
|
+
end
|
49
|
+
|
50
|
+
def tweet_options
|
51
|
+
options = {}
|
52
|
+
options.merge!({
|
53
|
+
in_reply_to_status_id: Integer(File.basename(opts['reply-to']))
|
54
|
+
}) if replying_to_other_tweet?
|
55
|
+
options
|
56
|
+
end
|
57
|
+
|
58
|
+
def create_content_of_tweet
|
59
|
+
if opts.present?('cowsay-text')
|
60
|
+
compose_tweet_with_cowsay
|
61
|
+
else
|
62
|
+
compose_tweet_with_editor
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def compose_tweet_with_editor
|
67
|
+
Tempfile.open('pry-send_tweet--compose-tweet') do |file|
|
68
|
+
if replying_to_other_tweet?
|
69
|
+
# During experimentation I noticed that without prefixing who we are
|
70
|
+
# replying to, the tweet we send will not be considered a reply even
|
71
|
+
# with reply_to_status_id being set.
|
72
|
+
prepend_username_to_reply!(opts['reply-to'], file)
|
73
|
+
end
|
74
|
+
file.rewind
|
75
|
+
Pry::Editor.new(_pry_).invoke_editor(file.path, 0)
|
76
|
+
file.read
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def compose_tweet_with_cowsay
|
81
|
+
username = if replying_to_other_tweet?
|
82
|
+
"@#{tweet_username_from(opts['reply-to'])} "
|
83
|
+
end
|
84
|
+
char = opts['cowsay-char'] || 'cow'
|
85
|
+
txt = "#{username}#{opts['cowsay-text']}"
|
86
|
+
`cowsay -f #{char.shellescape} #{txt.shellescape}`.tap do
|
87
|
+
if !$?.success?
|
88
|
+
raise Pry::CommandError,
|
89
|
+
"Something went wrong. Is 'cowsay' installed?"
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
Pry.commands.add_command self
|
95
|
+
end
|
@@ -0,0 +1,166 @@
|
|
1
|
+
class Pry::SendTweet::TwitterAction < Pry::SendTweet::BaseCommand
|
2
|
+
match 'twitter-action'
|
3
|
+
description 'Like, unlike, follow, unfollow and more'
|
4
|
+
banner <<-B
|
5
|
+
twitter-action OPTIONS
|
6
|
+
|
7
|
+
Like, unlike, follow, unfollow and more.
|
8
|
+
B
|
9
|
+
|
10
|
+
def options(o)
|
11
|
+
#
|
12
|
+
# Like / unlike tweets
|
13
|
+
#
|
14
|
+
o.on 'like-tweet=', 'Like a tweet'
|
15
|
+
o.on 'unlike-tweet=', 'Unlike a tweet'
|
16
|
+
#
|
17
|
+
# Follow / unfollow a user
|
18
|
+
#
|
19
|
+
o.on 'follow=', 'Follow a user'
|
20
|
+
o.on 'unfollow=', 'Unfollow a user'
|
21
|
+
#
|
22
|
+
# Delete tweets and reweets
|
23
|
+
#
|
24
|
+
o.on 'delete-retweet=', 'Delete a retweet'
|
25
|
+
o.on 'delete-tweet=', 'Delete a tweet'
|
26
|
+
#
|
27
|
+
# Retweet a tweet
|
28
|
+
#
|
29
|
+
o.on 'retweet=', 'Retweet a tweet'
|
30
|
+
#
|
31
|
+
# Profile management
|
32
|
+
#
|
33
|
+
o.on 'set-profile-bio', 'Set your profiles bio'
|
34
|
+
o.on 'set-profile-banner-image=', 'Set your profiles banner image'
|
35
|
+
o.on 'set-profile-name=', 'Set the name associated with your profile'
|
36
|
+
o.on 'set-profile-image=', 'Set your profile image'
|
37
|
+
end
|
38
|
+
|
39
|
+
def process
|
40
|
+
super
|
41
|
+
case
|
42
|
+
when opts.present?('like-tweet') then like_tweet
|
43
|
+
when opts.present?('unlike-tweet') then unlike_tweet
|
44
|
+
when opts.present?('follow') then follow_user
|
45
|
+
when opts.present?('unfollow') then unfollow_user
|
46
|
+
when opts.present?('delete-tweet') then delete_tweet
|
47
|
+
when opts.present?('delete-retweet') then delete_retweet
|
48
|
+
when opts.present?('retweet') then retweet_tweet
|
49
|
+
when opts.present?('set-profile-banner-image') then set_profile_banner_image
|
50
|
+
when opts.present?('set-profile-bio') then set_profile_bio
|
51
|
+
when opts.present?('set-profile-name') then set_profile_name
|
52
|
+
when opts.present?('set-profile-image') then set_profile_image
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
def set_profile_image
|
59
|
+
path = opts['set-profile-image']
|
60
|
+
if client.update_profile_image path
|
61
|
+
page "Profile image updated"
|
62
|
+
else
|
63
|
+
raise Pry::CommandError, "Something went wrong"
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def set_profile_banner_image
|
68
|
+
path = opts['set-profile-banner-image']
|
69
|
+
if client.update_profile_banner Base64.strict_encode64(File.binread(path))
|
70
|
+
page "Profile banner updated"
|
71
|
+
else
|
72
|
+
raise Pry::CommandError, "Something went wrong"
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def set_profile_name
|
77
|
+
client.update_profile name: opts['set-profile-name']
|
78
|
+
page "Profile name updated"
|
79
|
+
end
|
80
|
+
|
81
|
+
def set_profile_bio
|
82
|
+
Tempfile.open('pry-send_tweet-set-bio') do |file|
|
83
|
+
Pry::Editor.new(_pry_).invoke_editor(file.path, 0)
|
84
|
+
file.rewind
|
85
|
+
client.update_profile description: file.read
|
86
|
+
page "Profile bio updated"
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def retweet_tweet
|
91
|
+
tweet_url = opts['retweet']
|
92
|
+
if !client.retweet(tweet_url).empty?
|
93
|
+
page "Tweet retweeted"
|
94
|
+
else
|
95
|
+
raise Pry::CommandError, "Something went wrong"
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def like_tweet
|
100
|
+
tweets = client.favorite(opts['like-tweet'])
|
101
|
+
page numbered_list(bold("Tweets you liked"), tweets) {|tweet, index|
|
102
|
+
"#{index}. #{tweet.url}"
|
103
|
+
}
|
104
|
+
end
|
105
|
+
|
106
|
+
def unlike_tweet
|
107
|
+
tweets = client.unfavorite(opts['unlike-tweet'])
|
108
|
+
page numbered_list(bold("Tweets you unliked"), tweets) {|tweet, index|
|
109
|
+
"#{index}. #{tweet.url}"
|
110
|
+
}
|
111
|
+
end
|
112
|
+
|
113
|
+
def follow_user
|
114
|
+
usernames = find_usernames_in(opts['follow'])
|
115
|
+
follows = client.follow(usernames)
|
116
|
+
if follows.empty?
|
117
|
+
page "Didn't follow #{list_usernames(usernames)}, " \
|
118
|
+
"you could be following them already."
|
119
|
+
else
|
120
|
+
page numbered_list(bold("Users you started following"), follows) {|user, index|
|
121
|
+
display_followed_or_unfollowed(user, index)
|
122
|
+
}
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
def unfollow_user
|
127
|
+
usernames = find_usernames_in(opts['unfollow'])
|
128
|
+
unfollows = client.unfollow(usernames)
|
129
|
+
if unfollows.empty?
|
130
|
+
page "Didn't unfollow #{list_usernames(usernames)} " \
|
131
|
+
"you might not be following them already."
|
132
|
+
else
|
133
|
+
page numbered_list(bold("Users you stopped following"), unfollows) {|user, index|
|
134
|
+
display_followed_or_unfollowed(user, index)
|
135
|
+
}
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
def delete_retweet
|
140
|
+
tweets = client.unretweet(opts['delete-retweet'])
|
141
|
+
page numbered_list(bold("Retweets you deleted"), tweets) {|tweet, index|
|
142
|
+
"#{index}. #{tweet.url}"
|
143
|
+
}
|
144
|
+
end
|
145
|
+
|
146
|
+
def delete_tweet
|
147
|
+
tweets = client.destroy_status(opts['delete-tweet'])
|
148
|
+
page numbered_list(bold("Tweets you deleted"), tweets) {|tweet, index|
|
149
|
+
"#{index}. #{tweet.url}"
|
150
|
+
}
|
151
|
+
end
|
152
|
+
|
153
|
+
def display_followed_or_unfollowed(user, index)
|
154
|
+
sn = "@#{user.screen_name}"
|
155
|
+
"#{sn} #{bold(bright_blue('|'))} #{user.url}"
|
156
|
+
end
|
157
|
+
|
158
|
+
def list_usernames(ary)
|
159
|
+
find_usernames(ary).map do |username|
|
160
|
+
bold("@#{username}")
|
161
|
+
end.join(', ')
|
162
|
+
end
|
163
|
+
|
164
|
+
Pry.commands.add_command(self)
|
165
|
+
Pry.commands.alias_command "on-twitter", "twitter-action"
|
166
|
+
end
|
data/pry-send_tweet.gemspec
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
Gem::Specification.new do |spec|
|
2
2
|
spec.name = "pry-send_tweet.rb"
|
3
|
-
spec.version = "0.
|
3
|
+
spec.version = "0.5.0"
|
4
4
|
spec.authors = ["Robert Gleeson"]
|
5
5
|
spec.email = "trebor.g@protonmail.com"
|
6
|
-
spec.summary = "
|
6
|
+
spec.summary = "Extends the Pry REPL with the capabilities of a Twitter client."
|
7
7
|
spec.description = spec.summary
|
8
8
|
spec.homepage = "https://github.com/r-obert/pry-send_tweet.rb"
|
9
9
|
spec.licenses = ["MIT"]
|
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.5.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: 2018-12-
|
11
|
+
date: 2018-12-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: pry
|
@@ -38,8 +38,7 @@ dependencies:
|
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '6.0'
|
41
|
-
description:
|
42
|
-
personal twitter account.
|
41
|
+
description: Extends the Pry REPL with the capabilities of a Twitter client.
|
43
42
|
email: trebor.g@protonmail.com
|
44
43
|
executables: []
|
45
44
|
extensions: []
|
@@ -49,6 +48,11 @@ files:
|
|
49
48
|
- LICENSE.txt
|
50
49
|
- README.md
|
51
50
|
- lib/pry-send_tweet.rb
|
51
|
+
- lib/pry/send_tweet/base_command.rb
|
52
|
+
- lib/pry/send_tweet/mixins/tweet_renderer.rb
|
53
|
+
- lib/pry/send_tweet/read_tweets_command.rb
|
54
|
+
- lib/pry/send_tweet/send_tweet_command.rb
|
55
|
+
- lib/pry/send_tweet/twitter_action_command.rb
|
52
56
|
- pry-send_tweet.gemspec
|
53
57
|
homepage: https://github.com/r-obert/pry-send_tweet.rb
|
54
58
|
licenses:
|
@@ -73,6 +77,5 @@ rubyforge_project:
|
|
73
77
|
rubygems_version: 2.7.7
|
74
78
|
signing_key:
|
75
79
|
specification_version: 4
|
76
|
-
summary:
|
77
|
-
twitter account.
|
80
|
+
summary: Extends the Pry REPL with the capabilities of a Twitter client.
|
78
81
|
test_files: []
|