fry-send_tweet.rb 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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