tweetwine 0.3.2 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +6 -0
- data/CHANGELOG.rdoc +9 -0
- data/Gemfile +5 -13
- data/LICENSE.txt +1 -1
- data/README.md +3 -2
- data/Rakefile +8 -2
- data/lib/tweetwine/character_encoding.rb +1 -1
- data/lib/tweetwine/cli.rb +9 -3
- data/lib/tweetwine/config.rb +3 -3
- data/lib/tweetwine/exceptions.rb +54 -0
- data/lib/tweetwine/http.rb +1 -1
- data/lib/tweetwine/{util.rb → support.rb} +19 -12
- data/lib/tweetwine/tweet.rb +69 -0
- data/lib/tweetwine/twitter.rb +70 -72
- data/lib/tweetwine/ui.rb +36 -41
- data/lib/tweetwine/uri.rb +31 -0
- data/lib/tweetwine/version.rb +15 -0
- data/lib/tweetwine.rb +6 -64
- data/man/tweetwine.7 +4 -3
- data/man/tweetwine.7.ronn +3 -2
- data/release-script.txt +10 -0
- data/test/example/authorization_example.rb +40 -0
- data/test/example/example_helper.rb +1 -1
- data/test/example/global_options_example.rb +64 -0
- data/test/example/search_statuses_example.rb +36 -31
- data/test/example/show_followers_example.rb +1 -1
- data/test/example/show_friends_example.rb +1 -1
- data/test/example/show_home_example.rb +17 -29
- data/test/example/show_mentions_example.rb +2 -2
- data/test/example/show_user_example.rb +14 -12
- data/test/example/update_status_example.rb +9 -9
- data/test/example/use_http_proxy_example.rb +7 -6
- data/test/example/{application_behavior_example.rb → user_help_example.rb} +6 -39
- data/test/unit/config_test.rb +1 -1
- data/test/unit/http_test.rb +1 -21
- data/test/unit/oauth_test.rb +11 -11
- data/test/unit/{util_test.rb → support_test.rb} +37 -38
- data/test/unit/tweet_helper.rb +83 -0
- data/test/unit/tweet_test.rb +153 -0
- data/test/unit/twitter_test.rb +240 -248
- data/test/unit/ui_test.rb +174 -78
- data/test/unit/unit_helper.rb +18 -6
- data/test/unit/uri_test.rb +41 -0
- data/test/unit/url_shortener_test.rb +7 -7
- data/tweetwine.gemspec +12 -22
- metadata +52 -73
data/.gitignore
ADDED
data/CHANGELOG.rdoc
CHANGED
@@ -1,3 +1,12 @@
|
|
1
|
+
=== 0.4.0 released 2011-02-22
|
2
|
+
|
3
|
+
* Add option <tt>-r</tt> to reverse the order of showing tweets
|
4
|
+
* Show retweets as whole tweets
|
5
|
+
* Properly display error message on invalid argument to <tt>--page</tt> or
|
6
|
+
<tt>--num</tt> options
|
7
|
+
* Fix deprecation warning about <tt>URI.escape</tt> on MRI 1.9.2
|
8
|
+
* Minor cleanups
|
9
|
+
|
1
10
|
=== 0.3.2 released 2010-11-17
|
2
11
|
|
3
12
|
* Drop <tt>json</tt> gem dependency from gemspec in order to allow the user to
|
data/Gemfile
CHANGED
@@ -1,17 +1,9 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
1
3
|
source :rubygems
|
2
4
|
|
5
|
+
gemspec
|
6
|
+
|
7
|
+
# Special handling at runtime.
|
3
8
|
gem 'json', '>= 1.0.0', :platforms => [:ruby_18, :jruby]
|
4
9
|
gem 'nokogiri', '~> 1.4.4'
|
5
|
-
gem 'oauth', '~> 0.4.4'
|
6
|
-
|
7
|
-
group :test do
|
8
|
-
gem 'contest', '~> 0.1.2'
|
9
|
-
gem 'coulda', '~> 0.6.0'
|
10
|
-
gem 'gem-man', '~> 0.2.0'
|
11
|
-
gem 'mcmire-matchy', '~> 0.5.2', :require => 'matchy'
|
12
|
-
gem 'mocha', '= 0.9.8'
|
13
|
-
gem 'open4', '~> 1.0.1'
|
14
|
-
gem 'ronn', '~> 0.7.3'
|
15
|
-
gem 'timecop', '~> 0.3.5'
|
16
|
-
gem 'webmock', '~> 1.6.1'
|
17
|
-
end
|
data/LICENSE.txt
CHANGED
data/README.md
CHANGED
@@ -77,6 +77,7 @@ enabled via `shorten_urls` field in the configuration file; for example:
|
|
77
77
|
|
78
78
|
username: spoonman
|
79
79
|
colors: true
|
80
|
+
show_reverse: true
|
80
81
|
shorten_urls:
|
81
82
|
service_url: http://is.gd/create.php
|
82
83
|
method: post
|
@@ -124,8 +125,8 @@ snippet to your Bash initialization script (such as `~/.bashrc`):
|
|
124
125
|
|
125
126
|
## COPYRIGHT
|
126
127
|
|
127
|
-
Tweetwine is
|
128
|
+
Tweetwine is copyright © 2009-2011 Tuomas Kareinen. See `LICENSE.txt`.
|
128
129
|
|
129
130
|
## SEE ALSO
|
130
131
|
|
131
|
-
<https://github.com/
|
132
|
+
<https://github.com/tkareine/tweetwine>
|
data/Rakefile
CHANGED
@@ -4,8 +4,8 @@ require 'rake/clean'
|
|
4
4
|
|
5
5
|
$LOAD_PATH.unshift(File.expand_path('lib', File.dirname(__FILE__)))
|
6
6
|
name = 'tweetwine'
|
7
|
-
require name
|
8
|
-
version = Tweetwine.version
|
7
|
+
require "#{name}/version"
|
8
|
+
version = Tweetwine.version
|
9
9
|
|
10
10
|
namespace :gem do
|
11
11
|
CLOBBER.include "#{name}-*.gem"
|
@@ -42,6 +42,12 @@ namespace :man do
|
|
42
42
|
end
|
43
43
|
end
|
44
44
|
|
45
|
+
CLOBBER.include 'rdoc'
|
46
|
+
desc "Generate RDoc"
|
47
|
+
task :rdoc do
|
48
|
+
sh %{rdoc --encoding=UTF-8 --line-numbers --title='#{name} #{version}' --output=rdoc *.rdoc LICENSE.txt lib}
|
49
|
+
end
|
50
|
+
|
45
51
|
namespace :test do
|
46
52
|
def create_test_task(type, options = {})
|
47
53
|
base_dir = options[:base_dir]
|
data/lib/tweetwine/cli.rb
CHANGED
@@ -8,6 +8,9 @@ module Tweetwine
|
|
8
8
|
:config_file => "#{(ENV['HOME'] || ENV['USERPROFILE'])}/.tweetwine",
|
9
9
|
:env_lookouts => [:http_proxy],
|
10
10
|
:excludes => [:command],
|
11
|
+
:num_tweets => 20,
|
12
|
+
:page => 1,
|
13
|
+
:show_reverse => false,
|
11
14
|
:shorten_urls => {:disable => true},
|
12
15
|
:username => ENV['USER']
|
13
16
|
}.freeze
|
@@ -84,12 +87,15 @@ module Tweetwine
|
|
84
87
|
options[:shorten_urls] ||= {}
|
85
88
|
options[:shorten_urls][:disable] = true
|
86
89
|
end
|
87
|
-
parser.on '-n', '--num <n>', Integer, "Number of
|
88
|
-
options[:
|
90
|
+
parser.on '-n', '--num <n>', Integer, "Number of tweets per page (default #{DEFAULT_CONFIG[:num_tweets]})." do |arg|
|
91
|
+
options[:num_tweets] = arg
|
89
92
|
end
|
90
|
-
parser.on '-p', '--page <p>', Integer, "Page number for
|
93
|
+
parser.on '-p', '--page <p>', Integer, "Page number for tweets (default #{DEFAULT_CONFIG[:page]})." do |arg|
|
91
94
|
options[:page] = arg
|
92
95
|
end
|
96
|
+
parser.on '-r', '--reverse', "Show tweets in reverse order (default #{DEFAULT_CONFIG[:show_reverse]})." do
|
97
|
+
options[:show_reverse] = true
|
98
|
+
end
|
93
99
|
parser.on '-u', '--username <user>', String, "User to authenticate (default '#{DEFAULT_CONFIG[:username]}')." do |arg|
|
94
100
|
options[:username] = arg
|
95
101
|
end
|
data/lib/tweetwine/config.rb
CHANGED
@@ -27,7 +27,7 @@ module Tweetwine
|
|
27
27
|
should_set_file_access_to_user_only = !File.exist?(@file)
|
28
28
|
File.open(@file, 'w') do |io|
|
29
29
|
io.chmod(0600) if should_set_file_access_to_user_only
|
30
|
-
YAML.dump(
|
30
|
+
YAML.dump(Support.stringify_hash_keys(to_file), io)
|
31
31
|
end
|
32
32
|
end
|
33
33
|
|
@@ -52,14 +52,14 @@ module Tweetwine
|
|
52
52
|
def self.parse_env_vars(env_lookouts)
|
53
53
|
env_lookouts.inject({}) do |result, env_var_name|
|
54
54
|
env_option = ENV[env_var_name.to_s]
|
55
|
-
result[env_var_name.to_sym] = env_option
|
55
|
+
result[env_var_name.to_sym] = env_option if Support.present?(env_option)
|
56
56
|
result
|
57
57
|
end
|
58
58
|
end
|
59
59
|
|
60
60
|
def self.parse_config_file(config_file)
|
61
61
|
options = File.open(config_file, 'r') { |io| YAML.load(io) }
|
62
|
-
|
62
|
+
Support.symbolize_hash_keys(options)
|
63
63
|
end
|
64
64
|
end
|
65
65
|
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
module Tweetwine
|
4
|
+
class Error < StandardError
|
5
|
+
@status_code = 42
|
6
|
+
|
7
|
+
# Idea got from Bundler.
|
8
|
+
def self.status_code(code = nil)
|
9
|
+
return @status_code unless code
|
10
|
+
@status_code = code
|
11
|
+
end
|
12
|
+
|
13
|
+
def status_code
|
14
|
+
self.class.status_code
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
class CommandLineError < Error; status_code(13); end
|
19
|
+
class UnknownCommandError < Error; status_code(14); end
|
20
|
+
|
21
|
+
class RequiredOptionError < Error
|
22
|
+
status_code(15)
|
23
|
+
|
24
|
+
attr_reader :key, :owner
|
25
|
+
|
26
|
+
def initialize(key, owner)
|
27
|
+
@key, @owner = key, owner
|
28
|
+
end
|
29
|
+
|
30
|
+
def to_s
|
31
|
+
"#{key} is required for #{owner}"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
class ConnectionError < Error; status_code(21); end
|
36
|
+
class TimeoutError < Error; status_code(22); end
|
37
|
+
|
38
|
+
class HttpError < Error
|
39
|
+
status_code(25)
|
40
|
+
|
41
|
+
attr_reader :http_code, :http_message
|
42
|
+
|
43
|
+
def initialize(code, message)
|
44
|
+
@http_code, @http_message = code.to_i, message
|
45
|
+
end
|
46
|
+
|
47
|
+
def to_s
|
48
|
+
"#{http_code} #{http_message}"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
class TranscodeError < Error; status_code(31); end
|
53
|
+
class AuthorizationError < Error; status_code(32); end
|
54
|
+
end
|
data/lib/tweetwine/http.rb
CHANGED
@@ -1,15 +1,26 @@
|
|
1
1
|
# coding: utf-8
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require "uri"
|
3
|
+
require 'cgi'
|
4
|
+
require 'time'
|
6
5
|
|
7
6
|
module Tweetwine
|
8
|
-
module
|
7
|
+
module Support
|
9
8
|
extend self
|
10
9
|
|
11
|
-
def blank?(
|
12
|
-
|
10
|
+
def blank?(var)
|
11
|
+
var.nil? || var.empty?
|
12
|
+
end
|
13
|
+
|
14
|
+
def present?(var)
|
15
|
+
!blank?(var)
|
16
|
+
end
|
17
|
+
|
18
|
+
def presence(var)
|
19
|
+
if present? var
|
20
|
+
block_given? ? yield(var) : var
|
21
|
+
else
|
22
|
+
nil
|
23
|
+
end
|
13
24
|
end
|
14
25
|
|
15
26
|
def humanize_time_diff(from, to)
|
@@ -69,10 +80,6 @@ module Tweetwine
|
|
69
80
|
dup_str
|
70
81
|
end
|
71
82
|
|
72
|
-
def percent_encode(str)
|
73
|
-
URI.escape(str.to_s, /[^#{URI::PATTERN::UNRESERVED}]/)
|
74
|
-
end
|
75
|
-
|
76
83
|
def unescape_html(str)
|
77
84
|
CGI.unescapeHTML(str.gsub(' ', ' '))
|
78
85
|
end
|
@@ -99,8 +106,8 @@ module Tweetwine
|
|
99
106
|
end
|
100
107
|
|
101
108
|
def pluralize_unit(value, unit)
|
102
|
-
if
|
103
|
-
unit = unit +
|
109
|
+
if %w{hour day}.include?(unit) && value > 1
|
110
|
+
unit = unit + 's'
|
104
111
|
end
|
105
112
|
unit
|
106
113
|
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
module Tweetwine
|
4
|
+
class Tweet
|
5
|
+
attr_reader :from_user, :to_user, :rt_user, :created_at, :status
|
6
|
+
|
7
|
+
def initialize(record, paths)
|
8
|
+
if field_present? record, paths[:retweet]
|
9
|
+
@rt_user = parse_string_field record, paths[:from_user]
|
10
|
+
fields = Support.find_hash_path record, paths[:retweet]
|
11
|
+
else
|
12
|
+
@rt_user = nil
|
13
|
+
fields = record
|
14
|
+
end
|
15
|
+
@to_user = parse_string_field fields, paths[:to_user]
|
16
|
+
@from_user = parse_string_field fields, paths[:from_user]
|
17
|
+
raise ArgumentError, 'from user record field is required' unless @from_user
|
18
|
+
@created_at = parse_time_field fields, paths[:created_at]
|
19
|
+
@status = parse_string_field fields, paths[:status]
|
20
|
+
end
|
21
|
+
|
22
|
+
def timestamped?
|
23
|
+
!@created_at.nil?
|
24
|
+
end
|
25
|
+
|
26
|
+
def retweet?
|
27
|
+
!@rt_user.nil?
|
28
|
+
end
|
29
|
+
|
30
|
+
def status?
|
31
|
+
!@status.nil?
|
32
|
+
end
|
33
|
+
|
34
|
+
def reply?
|
35
|
+
!@to_user.nil?
|
36
|
+
end
|
37
|
+
|
38
|
+
def ==(other)
|
39
|
+
other.is_a?(self.class) &&
|
40
|
+
self.rt_user == other.rt_user &&
|
41
|
+
self.to_user == other.to_user &&
|
42
|
+
self.from_user == other.from_user &&
|
43
|
+
self.created_at == other.created_at &&
|
44
|
+
self.status == other.status
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def field_present?(record, path)
|
50
|
+
!!find_field(record, path) { |f| Support.present?(f) }
|
51
|
+
end
|
52
|
+
|
53
|
+
def field_presence(record, path, &block)
|
54
|
+
find_field(record, path) { |f| Support.presence(f, &block) }
|
55
|
+
end
|
56
|
+
|
57
|
+
def parse_string_field(record, path)
|
58
|
+
field_presence(record, path) { |f| f.to_s }
|
59
|
+
end
|
60
|
+
|
61
|
+
def parse_time_field(record, path)
|
62
|
+
field_presence(record, path) { |f| Time.parse(f.to_s) }
|
63
|
+
end
|
64
|
+
|
65
|
+
def find_field(record, path)
|
66
|
+
yield(Support.find_hash_path(record, path)) rescue nil
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
data/lib/tweetwine/twitter.rb
CHANGED
@@ -4,36 +4,56 @@ require "uri"
|
|
4
4
|
|
5
5
|
module Tweetwine
|
6
6
|
class Twitter
|
7
|
-
DEFAULT_NUM_STATUSES = 20
|
8
|
-
DEFAULT_PAGE_NUM = 1
|
9
7
|
MAX_STATUS_LENGTH = 140
|
10
8
|
|
11
|
-
|
9
|
+
REST_API_STATUS_PATHS = {
|
10
|
+
:from_user => %w{user screen_name},
|
11
|
+
:to_user => %w{in_reply_to_screen_name},
|
12
|
+
:retweet => %w{retweeted_status},
|
13
|
+
:created_at => %w{created_at},
|
14
|
+
:status => %w{text}
|
15
|
+
}
|
16
|
+
|
17
|
+
REST_API_USER_PATHS = {
|
18
|
+
:from_user => %w{screen_name},
|
19
|
+
:to_user => %w{status in_reply_to_screen_name},
|
20
|
+
:retweet => %w{retweeted_status},
|
21
|
+
:created_at => %w{status created_at},
|
22
|
+
:status => %w{status text}
|
23
|
+
}
|
24
|
+
|
25
|
+
SEARCH_API_STATUS_PATHS = {
|
26
|
+
:from_user => %w{from_user},
|
27
|
+
:to_user => %w{to_user},
|
28
|
+
:retweet => %w{retweeted_status},
|
29
|
+
:created_at => %w{created_at},
|
30
|
+
:status => %w{text}
|
31
|
+
}
|
32
|
+
|
33
|
+
attr_reader :num_tweets, :page, :username
|
12
34
|
|
13
35
|
def initialize(options = {})
|
14
|
-
@
|
15
|
-
@page
|
16
|
-
@username
|
36
|
+
@num_tweets = Support.parse_int_gt(options[:num_tweets], CLI::DEFAULT_CONFIG[:num_tweets], 1, "number of tweets to show")
|
37
|
+
@page = Support.parse_int_gt(options[:page], CLI::DEFAULT_CONFIG[:page], 1, "page number")
|
38
|
+
@username = options[:username].to_s
|
39
|
+
rescue ArgumentError => e
|
40
|
+
raise CommandLineError, e
|
17
41
|
end
|
18
42
|
|
19
43
|
def followers
|
20
|
-
|
21
|
-
show_users_from_rest_api(*response)
|
44
|
+
show_users_from_rest_api(get_from_rest_api("statuses/followers"))
|
22
45
|
end
|
23
46
|
|
24
47
|
def friends
|
25
|
-
|
26
|
-
show_users_from_rest_api(*response)
|
48
|
+
show_users_from_rest_api(get_from_rest_api("statuses/friends"))
|
27
49
|
end
|
28
50
|
|
29
51
|
def home
|
30
|
-
|
31
|
-
show_statuses_from_rest_api(*response)
|
52
|
+
show_tweets_from_rest_api(get_from_rest_api("statuses/home_timeline"))
|
32
53
|
end
|
33
54
|
|
34
55
|
def mentions
|
35
|
-
|
36
|
-
show_statuses_from_rest_api(*response)
|
56
|
+
show_tweets_from_rest_api(get_from_rest_api("statuses/mentions"))
|
37
57
|
end
|
38
58
|
|
39
59
|
def search(words = [], operator = nil)
|
@@ -41,7 +61,7 @@ module Tweetwine
|
|
41
61
|
operator = :and unless operator
|
42
62
|
query = operator == :and ? words.join(' ') : words.join(' OR ')
|
43
63
|
response = get_from_search_api query
|
44
|
-
|
64
|
+
show_tweets_from_search_api(response["results"])
|
45
65
|
end
|
46
66
|
|
47
67
|
def update(msg = nil)
|
@@ -53,7 +73,7 @@ module Tweetwine
|
|
53
73
|
if CLI.ui.confirm("Really send?")
|
54
74
|
response = post_to_rest_api("statuses/update", :status => status_in_utf8)
|
55
75
|
CLI.ui.info "Sent status update.\n\n"
|
56
|
-
|
76
|
+
show_tweets_from_rest_api([response])
|
57
77
|
completed = true
|
58
78
|
end
|
59
79
|
end
|
@@ -61,25 +81,24 @@ module Tweetwine
|
|
61
81
|
end
|
62
82
|
|
63
83
|
def user(who = username)
|
64
|
-
|
84
|
+
show_tweets_from_rest_api(get_from_rest_api(
|
65
85
|
"statuses/user_timeline",
|
66
86
|
common_rest_api_query_params.merge!({ :screen_name => who })
|
67
|
-
)
|
68
|
-
show_statuses_from_rest_api(*response)
|
87
|
+
))
|
69
88
|
end
|
70
89
|
|
71
90
|
private
|
72
91
|
|
73
92
|
def common_rest_api_query_params
|
74
93
|
{
|
75
|
-
:count => @
|
94
|
+
:count => @num_tweets,
|
76
95
|
:page => @page
|
77
96
|
}
|
78
97
|
end
|
79
98
|
|
80
99
|
def common_search_api_query_params
|
81
100
|
{
|
82
|
-
:rpp => @
|
101
|
+
:rpp => @num_tweets,
|
83
102
|
:page => @page
|
84
103
|
}
|
85
104
|
end
|
@@ -113,7 +132,7 @@ module Tweetwine
|
|
113
132
|
end
|
114
133
|
|
115
134
|
def get_from_search_api(query, params = common_search_api_query_params)
|
116
|
-
query = "q=#{
|
135
|
+
query = "q=#{Uri.percent_encode(query)}&" << format_query_params(params)
|
117
136
|
JSON.parse search_api["search.json?#{query}"].get
|
118
137
|
end
|
119
138
|
|
@@ -133,55 +152,34 @@ module Tweetwine
|
|
133
152
|
CLI.config.save
|
134
153
|
end
|
135
154
|
|
136
|
-
def
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
)
|
146
|
-
end
|
147
|
-
|
148
|
-
def
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
:status => ["status", "text"]
|
156
|
-
}
|
157
|
-
)
|
158
|
-
end
|
159
|
-
|
160
|
-
def show_statuses_from_search_api(*responses)
|
161
|
-
show_records(
|
162
|
-
responses,
|
163
|
-
{
|
164
|
-
:from_user => "from_user",
|
165
|
-
:to_user => "to_user",
|
166
|
-
:created_at => "created_at",
|
167
|
-
:status => "text"
|
168
|
-
}
|
169
|
-
)
|
170
|
-
end
|
171
|
-
|
172
|
-
def show_records(twitter_records, paths)
|
173
|
-
twitter_records.each do |twitter_record|
|
174
|
-
internal_record = [ :from_user, :to_user, :created_at, :status ].inject({}) do |result, key|
|
175
|
-
result[key] = Util.find_hash_path(twitter_record, paths[key])
|
176
|
-
result
|
155
|
+
def show_tweets_from_rest_api(records)
|
156
|
+
show_tweets(records, REST_API_STATUS_PATHS)
|
157
|
+
end
|
158
|
+
|
159
|
+
def show_users_from_rest_api(records)
|
160
|
+
show_tweets(records, REST_API_USER_PATHS)
|
161
|
+
end
|
162
|
+
|
163
|
+
def show_tweets_from_search_api(records)
|
164
|
+
show_tweets(records, SEARCH_API_STATUS_PATHS)
|
165
|
+
end
|
166
|
+
|
167
|
+
def show_tweets(records, paths)
|
168
|
+
tweets = records.map do |record|
|
169
|
+
begin
|
170
|
+
Tweet.new(record, paths)
|
171
|
+
rescue ArgumentError
|
172
|
+
CLI.ui.warn "Invalid tweet. Skipping..."
|
173
|
+
nil
|
177
174
|
end
|
178
|
-
CLI.ui.show_record(internal_record)
|
179
175
|
end
|
176
|
+
tweets.reject! { |tweet| tweet.nil? }
|
177
|
+
CLI.ui.show_tweets tweets
|
180
178
|
end
|
181
179
|
|
182
180
|
def create_status_update(status)
|
183
|
-
status = if
|
184
|
-
CLI.ui.prompt
|
181
|
+
status = if Support.blank? status
|
182
|
+
CLI.ui.prompt "Status update"
|
185
183
|
else
|
186
184
|
status.dup
|
187
185
|
end
|
@@ -192,11 +190,11 @@ module Tweetwine
|
|
192
190
|
end
|
193
191
|
|
194
192
|
def shorten_urls_in(status)
|
195
|
-
url_pairs =
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
193
|
+
url_pairs = Uri.
|
194
|
+
extract(status, %w{http https}).
|
195
|
+
uniq.
|
196
|
+
map { |full_url| [full_url, CLI.url_shortener.shorten(full_url)] }.
|
197
|
+
reject { |(full_url, short_url)| Support.blank? short_url }
|
200
198
|
url_pairs.each { |(full_url, short_url)| status.gsub!(full_url, short_url) }
|
201
199
|
rescue HttpError, LoadError => e
|
202
200
|
CLI.ui.warn "#{e}\nSkipping URL shortening..."
|
@@ -204,7 +202,7 @@ module Tweetwine
|
|
204
202
|
|
205
203
|
def truncate_status(status)
|
206
204
|
status.replace status[0...MAX_STATUS_LENGTH]
|
207
|
-
CLI.ui.warn
|
205
|
+
CLI.ui.warn "Status will be truncated."
|
208
206
|
end
|
209
207
|
end
|
210
208
|
end
|