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.
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