pry-twitter 1.22.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (60) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +13 -0
  3. data/LICENSE.txt +24 -0
  4. data/PRY_LICENSE.txt +25 -0
  5. data/README.md +546 -0
  6. data/Vagrantfile +48 -0
  7. data/art/16-60174b5812.jpg +0 -0
  8. data/art/16-a31deea6f0.jpg +0 -0
  9. data/art/17-b3d5d6f6c2.jpg +0 -0
  10. data/art/44-e44743a5bb.jpg +0 -0
  11. data/art/51-5e4dc5fd92.jpg +0 -0
  12. data/art/51-82bde81305.jpg +0 -0
  13. data/art/51-ad821fa377.jpg +0 -0
  14. data/art/51-b90d5dd6a6.jpg +0 -0
  15. data/art/51-da43a4ef4f.jpg +0 -0
  16. data/art/51-e94c3387e1.jpg +0 -0
  17. data/art/52-eec4df2edf.jpg +0 -0
  18. data/art/53-9d231893e1.jpg +0 -0
  19. data/art/54-39b1063483.jpg +0 -0
  20. data/art/55-e41f9896d0.jpg +0 -0
  21. data/art/56-c82d4e5b61.jpg +0 -0
  22. data/art/59-2a2c9cd962.jpg +0 -0
  23. data/art/61-3970c79d47.jpg +0 -0
  24. data/art/62-5704cc1652.jpg +0 -0
  25. data/art/62-b0aceb0fa6.jpg +0 -0
  26. data/art/62-da0faf972e.jpg +0 -0
  27. data/art/frankewilde.jpg +0 -0
  28. data/art/rollingstone.jpg +0 -0
  29. data/art/tide.jpg +0 -0
  30. data/art/windows10.png +0 -0
  31. data/lib/pry-send_tweet.rb +77 -0
  32. data/lib/pry/pager/system_pager.rb +25 -0
  33. data/lib/pry/send_tweet/commands/base_command.rb +72 -0
  34. data/lib/pry/send_tweet/commands/easter_eggs.rb +564 -0
  35. data/lib/pry/send_tweet/commands/paging/paging_support.rb +16 -0
  36. data/lib/pry/send_tweet/commands/read_tweets.rb +93 -0
  37. data/lib/pry/send_tweet/commands/read_tweets/translate_actions.rb +94 -0
  38. data/lib/pry/send_tweet/commands/send_tweet.rb +164 -0
  39. data/lib/pry/send_tweet/commands/twitter_action.rb +118 -0
  40. data/lib/pry/send_tweet/commands/twitter_action/delete_tweet_actions.rb +19 -0
  41. data/lib/pry/send_tweet/commands/twitter_action/follow_actions.rb +66 -0
  42. data/lib/pry/send_tweet/commands/twitter_action/like_actions.rb +23 -0
  43. data/lib/pry/send_tweet/commands/twitter_action/mute_actions.rb +23 -0
  44. data/lib/pry/send_tweet/commands/twitter_action/profile_actions.rb +60 -0
  45. data/lib/pry/send_tweet/commands/twitter_action/suggested_actions.rb +20 -0
  46. data/lib/pry/send_tweet/commands/twitter_search.rb +36 -0
  47. data/lib/pry/send_tweet/renderers/tweet_renderer.rb +103 -0
  48. data/lib/pry/send_tweet/renderers/user_renderer.rb +17 -0
  49. data/lib/pry/send_tweet/tty-box.rb +73 -0
  50. data/lib/pry/send_tweet/twitter_io.rb +26 -0
  51. data/lib/pry/send_tweet/version.rb +6 -0
  52. data/lib/time-ago-in-words/README.md +14 -0
  53. data/lib/time-ago-in-words/lib/time-ago-in-words.rb +37 -0
  54. data/lib/time-ago-in-words/time-ago-in-words.gemspec +14 -0
  55. data/pry-send_tweet.gemspec +23 -0
  56. data/samples/freebsd-zshrc +5 -0
  57. data/samples/loader.conf +1 -0
  58. data/samples/tmuxinator-vagrant.yml +11 -0
  59. data/vms/freebsd.rb +18 -0
  60. 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