fry-send_tweet.rb 0.1.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 (37) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +282 -0
  3. data/LICENSE.txt +24 -0
  4. data/PRY_LICENSE.txt +25 -0
  5. data/README.md +456 -0
  6. data/Vagrantfile +46 -0
  7. data/art/44-e44743a5bb.jpg +0 -0
  8. data/art/52-eec4df2edf.jpg +0 -0
  9. data/lib/pry-send_tweet.rb +75 -0
  10. data/lib/pry/pager/system_pager.rb +25 -0
  11. data/lib/pry/send_tweet/commands/base_command.rb +70 -0
  12. data/lib/pry/send_tweet/commands/easter_eggs.rb +184 -0
  13. data/lib/pry/send_tweet/commands/paging/paging_support.rb +16 -0
  14. data/lib/pry/send_tweet/commands/read_tweets.rb +93 -0
  15. data/lib/pry/send_tweet/commands/read_tweets/translate_actions.rb +94 -0
  16. data/lib/pry/send_tweet/commands/send_tweet.rb +151 -0
  17. data/lib/pry/send_tweet/commands/twitter_action.rb +118 -0
  18. data/lib/pry/send_tweet/commands/twitter_action/delete_tweet_actions.rb +19 -0
  19. data/lib/pry/send_tweet/commands/twitter_action/follow_actions.rb +66 -0
  20. data/lib/pry/send_tweet/commands/twitter_action/like_actions.rb +23 -0
  21. data/lib/pry/send_tweet/commands/twitter_action/mute_actions.rb +23 -0
  22. data/lib/pry/send_tweet/commands/twitter_action/profile_actions.rb +60 -0
  23. data/lib/pry/send_tweet/commands/twitter_action/suggested_actions.rb +20 -0
  24. data/lib/pry/send_tweet/commands/twitter_search.rb +36 -0
  25. data/lib/pry/send_tweet/renderers/tweet_renderer.rb +103 -0
  26. data/lib/pry/send_tweet/renderers/user_renderer.rb +17 -0
  27. data/lib/pry/send_tweet/tty-box.rb +73 -0
  28. data/lib/pry/send_tweet/twitter_io.rb +26 -0
  29. data/lib/pry/send_tweet/version.rb +5 -0
  30. data/lib/time-ago-in-words/README.md +14 -0
  31. data/lib/time-ago-in-words/lib/time-ago-in-words.rb +37 -0
  32. data/lib/time-ago-in-words/time-ago-in-words.gemspec +14 -0
  33. data/pry-send_tweet.gemspec +23 -0
  34. data/samples/freebsd-zshrc +5 -0
  35. data/samples/tmuxinator-vagrant.yml +11 -0
  36. data/vms/freebsd.rb +15 -0
  37. metadata +123 -0
@@ -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
@@ -0,0 +1,26 @@
1
+ #
2
+ # TwitterIO is a child of StringIO that implements an interface compatible
3
+ # with the expectations of the Twitter gem. The twitter gem expects a File object
4
+ # when uploading media, not an in-memory string as we would like.
5
+ #
6
+ class Pry::SendTweet::TwitterIO < StringIO
7
+ def initialize(str, basename)
8
+ super(str)
9
+ @basename = basename
10
+ end
11
+
12
+ def basename
13
+ @basename
14
+ end
15
+
16
+ #
17
+ # For compatibility with File.basename, which attempts String coercion when
18
+ # given an object other than a String.
19
+ #
20
+ # @example
21
+ # File.basename(twitter_io) => {TwitterIO#basename}
22
+ #
23
+ def to_str
24
+ basename
25
+ end
26
+ end
@@ -0,0 +1,5 @@
1
+ class Pry
2
+ module SendTweet
3
+ VERSION = '0.1.0'
4
+ end
5
+ end
@@ -0,0 +1,14 @@
1
+ # time-ago-in-words
2
+
3
+ ## Introduction
4
+
5
+ Add `time_ago_in_words` method to Time class.
6
+
7
+ ## Credits
8
+
9
+ This subdirectory is a modified clone of https://github.com/sirupsen/time-ago-in-words.
10
+ `time-ago-in-words` is a fork of `time-lord` that focuses on a single feature
11
+ instead of many features.
12
+
13
+ * Credits to author(s) of `time-lord` RubyGem.
14
+ * Credits to the author of its fork, `time-ago-in-words`.
@@ -0,0 +1,37 @@
1
+ module TimeAgoInWords
2
+ require 'time'
3
+ VERSION = "0.0.5"
4
+
5
+ module Units
6
+ Second = 1
7
+ Minute = Second * 60
8
+ Hour = Minute * 60
9
+ Day = Hour * 24
10
+ Week = Day * 7
11
+ Month = Week * 4
12
+ Year = Day * 365
13
+ Decade = Year * 10
14
+ Century = Decade * 10
15
+ Millennium = Century * 10
16
+ Eon = 1.0/0
17
+ end
18
+
19
+ module_function
20
+ def time_ago_in_words(time)
21
+ time_difference = Time.now.to_i - time.to_i
22
+ if time_difference <= 0
23
+ return "0 seconds since Last Refresh"
24
+ end
25
+ unit = get_unit(time_difference)
26
+ unit_rep = time_difference > 1 ? "#{unit.to_s.downcase}s" : unit.to_s.downcase
27
+ unit_difference = time_difference / Units.const_get(unit.capitalize)
28
+ "#{unit_difference} #{unit_rep}"
29
+ end
30
+
31
+ private
32
+ def get_unit(time_difference)
33
+ Units.constants.each_cons(2) do |con|
34
+ return con.first if (Units.const_get(con[0])...Units.const_get(con[1])) === time_difference
35
+ end
36
+ end
37
+ end