tweetskim 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +21 -17
- data/bin/tweetskim +25 -11
- data/lib/tweetskim/core.rb +74 -32
- data/lib/tweetskim/version.rb +1 -1
- data/test/test_tweetskim.rb +10 -18
- metadata +10 -11
- data/test.txt +0 -1
data/README.md
CHANGED
@@ -17,29 +17,25 @@ USAGE:
|
|
17
17
|
Prints the tweet timeline to stdout, either as plain lines, more readable column
|
18
18
|
or extra-readable single html page.
|
19
19
|
|
20
|
-
Use it like any other command line tool: page the output (`
|
21
|
-
|
20
|
+
Use it like any other command line tool: page the output (`tweetskim |
|
21
|
+
less`), concat it to file (`tweetskim > tweets.txt`), search for specific stuff (`tweetskim | grep conference`) and so on.
|
22
22
|
|
23
|
-
options
|
24
|
-
|
25
|
-
|
26
|
-
-a, --show-all
|
23
|
+
Default behavior if you don't pass any options: Print out last 10
|
24
|
+
tweets in your timeline, one on each line.
|
27
25
|
|
28
|
-
|
26
|
+
Options:
|
29
27
|
|
30
|
-
-
|
28
|
+
-e, --mentions: Show mentions instead of timeline
|
31
29
|
|
32
|
-
-
|
30
|
+
-i, --inverse-order Inverse/reverse ordered tweets
|
33
31
|
|
34
|
-
-
|
32
|
+
-h, --help Help page
|
35
33
|
|
36
|
-
-n, --last-n-tweets N
|
34
|
+
-n, --last-n-tweets N Show the last N tweets in your timeline
|
37
35
|
|
38
|
-
-o, --output-mode lines
|
36
|
+
-o, --output-mode MODE Output as 'lines', 'column' or 'html'
|
39
37
|
|
40
|
-
-
|
41
|
-
|
42
|
-
-v, --version
|
38
|
+
-v, --version Current version
|
43
39
|
|
44
40
|
|
45
41
|
PREREQUISITES:
|
@@ -61,10 +57,18 @@ TODO:
|
|
61
57
|
=====
|
62
58
|
|
63
59
|
|
64
|
-
|
60
|
+
mark-read
|
61
|
+
----
|
62
|
+
|
63
|
+
Support -m mark-as-read flag, to toggle "I've read all up till now,
|
64
|
+
next time only show new stuff"
|
65
|
+
|
66
|
+
|
67
|
+
show status identifier
|
65
68
|
----
|
66
69
|
|
67
|
-
|
70
|
+
option to prefix tweets with their status id and/or direct link (all modes)
|
71
|
+
|
68
72
|
|
69
73
|
multiple accounts
|
70
74
|
------
|
data/bin/tweetskim
CHANGED
@@ -8,11 +8,11 @@ def parse_options
|
|
8
8
|
options = {}
|
9
9
|
|
10
10
|
OptionParser.new do |o|
|
11
|
-
|
11
|
+
o.on("-a", "--show-all", "Show all tweets, not just unread ones (max 300)") { |b| options[:show_all] = b }
|
12
12
|
o.on("-e", "--mentions", "Show mentions instead of timeline") { |b| options[:mentions] = b }
|
13
13
|
o.on("-i", "--inverse-order", "Inverse/reverse ordered tweets") { |b| options[:inverse_order] = b }
|
14
14
|
o.on("-h", "--help", "Help page") { puts o; exit }
|
15
|
-
|
15
|
+
o.on("-m", "--mark-all-read", "Mark everything up to now as read") { |b| options[:mark_all_read] = b }
|
16
16
|
o.on("-n N", "--last-n-tweets N", "Show only the last N tweets") { |n| options[:last_n_tweets] = n }
|
17
17
|
o.on("-o MODE", "--output-mode MODE", "Output as 'lines', 'column' or 'html'") { |mode| options[:output_mode] = mode }
|
18
18
|
#TODO o.on("-u USER", "--user USER", "Which twitter user I am. Example: tweetskim -u thomanil") { |u| options[:user] = u }
|
@@ -24,22 +24,36 @@ def parse_options
|
|
24
24
|
return options
|
25
25
|
end
|
26
26
|
|
27
|
+
|
27
28
|
def fetch_tweets(options = {})
|
29
|
+
settings = Tweetskim::Settings.new
|
28
30
|
adapter = Tweetskim::TwitterAdapter.new
|
29
31
|
|
32
|
+
since_id = "111111"
|
33
|
+
if !options[:show_all]
|
34
|
+
since_id = settings.load_last_read_status_id
|
35
|
+
end
|
36
|
+
|
37
|
+
tweet_count = options[:last_n_tweets] || 15
|
30
38
|
if options[:mentions]
|
31
|
-
tweets = adapter.mentions(
|
39
|
+
tweets = adapter.mentions(tweet_count, since_id)
|
32
40
|
else
|
33
|
-
tweets = adapter.timeline(
|
41
|
+
tweets = adapter.timeline(tweet_count, since_id)
|
34
42
|
end
|
35
43
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
44
|
+
if options[:inverse_order]
|
45
|
+
tweets = tweets.reverse
|
46
|
+
end
|
47
|
+
|
48
|
+
last_tweet = tweets.sort { |t| t.id }.last
|
49
|
+
if options[:mark_all_read] && last_tweet
|
50
|
+
settings.save_last_read_status_id(last_tweet.id)
|
51
|
+
end
|
52
|
+
|
40
53
|
return tweets
|
41
54
|
end
|
42
55
|
|
56
|
+
|
43
57
|
def write_tweets_to_stdout(tweets, options = {})
|
44
58
|
formatter = Tweetskim::Formatter.new
|
45
59
|
output_mode = options[:output_mode]
|
@@ -47,12 +61,11 @@ def write_tweets_to_stdout(tweets, options = {})
|
|
47
61
|
if !output_mode || output_mode == "lines"
|
48
62
|
result = formatter.lines(tweets, options)
|
49
63
|
elsif output_mode == "column"
|
50
|
-
result = formatter.column(tweets, {:width =>
|
64
|
+
result = formatter.column(tweets, {:width => 60})
|
51
65
|
elsif output_mode == "html"
|
52
66
|
puts "Html mode not done yet."; exit
|
53
67
|
else
|
54
|
-
puts "Invalid output mode."
|
55
|
-
exit
|
68
|
+
puts "Invalid output mode."; exit
|
56
69
|
end
|
57
70
|
|
58
71
|
puts result
|
@@ -61,4 +74,5 @@ end
|
|
61
74
|
|
62
75
|
options = parse_options
|
63
76
|
tweets = fetch_tweets(options)
|
77
|
+
#TODO create result first, send that. Dont put errors in stdout.
|
64
78
|
write_tweets_to_stdout(tweets, options)
|
data/lib/tweetskim/core.rb
CHANGED
@@ -7,14 +7,13 @@ module Tweetskim
|
|
7
7
|
|
8
8
|
|
9
9
|
class Formatter
|
10
|
-
|
11
10
|
def lines(tweets, options = {})
|
12
11
|
tweet_texts = tweets.reverse.map {|tweet| "--#{tweet.user.name}-- #{tweet.text}\n"}
|
13
12
|
lines = tweet_texts.join("")
|
14
13
|
end
|
15
14
|
|
16
15
|
def column(tweets, options = {})
|
17
|
-
tweet_texts = tweets.reverse.map {|tweet| "
|
16
|
+
tweet_texts = tweets.reverse.map {|tweet| "--\\033[1;34m#{tweet.user.name}\\033[0m-- #{tweet.text}"}
|
18
17
|
reflowed_tweets = tweet_texts.map {|tweet| `echo "#{tweet}" | fmt -w #{options[:width]}` }
|
19
18
|
column = reflowed_tweets.join "\n\n"
|
20
19
|
end
|
@@ -27,24 +26,82 @@ module Tweetskim
|
|
27
26
|
end
|
28
27
|
padded_lines.join ""
|
29
28
|
end
|
30
|
-
|
31
29
|
end
|
32
30
|
|
31
|
+
|
32
|
+
class Settings
|
33
|
+
SETTINGS_TEMPLATE = {:token => nil,
|
34
|
+
:secret => nil,
|
35
|
+
:last_read_status_id => "0"}
|
36
|
+
|
37
|
+
SETTINGS_FILE_PATH = File.expand_path "~/.tweetskim/default-account"
|
38
|
+
|
39
|
+
def initialize
|
40
|
+
if !Dir[" ~/.tweetskim/"].empty?
|
41
|
+
`mkdir ~/.tweetskim/`
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def load
|
46
|
+
yml_str = `cat #{SETTINGS_FILE_PATH}`
|
47
|
+
YAML::load(yml_str) || SETTINGS_TEMPLATE
|
48
|
+
end
|
49
|
+
|
50
|
+
def save(settings)
|
51
|
+
yml_str = YAML::dump(settings)
|
52
|
+
`echo "#{yml_str}" > #{SETTINGS_FILE_PATH}`
|
53
|
+
end
|
54
|
+
|
55
|
+
def user_credentials_stored?
|
56
|
+
if File.exists? SETTINGS_FILE_PATH
|
57
|
+
settings = load
|
58
|
+
return (settings[:token] && !settings[:token].empty? &&
|
59
|
+
settings[:secret] && !settings[:secret].empty?)
|
60
|
+
else
|
61
|
+
false
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def save_credentials(token, secret)
|
66
|
+
settings = load
|
67
|
+
settings[:token] = token
|
68
|
+
settings[:secret] = secret
|
69
|
+
save settings
|
70
|
+
end
|
71
|
+
|
72
|
+
def load_credentials
|
73
|
+
settings = load
|
74
|
+
return settings[:token], settings[:secret]
|
75
|
+
end
|
76
|
+
|
77
|
+
def load_last_read_status_id
|
78
|
+
settings = load
|
79
|
+
return settings[:last_read_status_id]
|
80
|
+
end
|
81
|
+
|
82
|
+
def save_last_read_status_id(id)
|
83
|
+
settings = load
|
84
|
+
settings[:last_read_status_id] = id
|
85
|
+
save settings
|
86
|
+
end
|
87
|
+
|
88
|
+
end
|
89
|
+
|
90
|
+
|
33
91
|
|
34
92
|
class TwitterAdapter
|
35
|
-
|
36
93
|
# TODO call for each user in config
|
37
94
|
# implicit for the user authenticated in client. Different user =
|
38
95
|
# different client
|
39
96
|
|
40
|
-
def mentions(
|
41
|
-
client = authenticated_client
|
42
|
-
mentions = client.mentions(
|
97
|
+
def mentions(tweet_count, since_id)
|
98
|
+
client = authenticated_client
|
99
|
+
mentions = client.mentions({:count => tweet_count.to_i, :since_id => since_id.to_i})
|
43
100
|
end
|
44
101
|
|
45
|
-
def timeline(
|
102
|
+
def timeline(tweet_count, since_id)
|
46
103
|
client = authenticated_client
|
47
|
-
timeline = client.home_timeline(
|
104
|
+
timeline = client.home_timeline({:count => tweet_count.to_i, :since_id => since_id.to_i})
|
48
105
|
end
|
49
106
|
|
50
107
|
CONSUMER_KEY = "3oUZhYLZcaqqQePajIjnBg"
|
@@ -52,11 +109,13 @@ module Tweetskim
|
|
52
109
|
|
53
110
|
# TODO call for specific user
|
54
111
|
def authenticated_client
|
55
|
-
|
56
|
-
|
112
|
+
settings = Tweetskim::Settings.new
|
113
|
+
|
114
|
+
if settings.user_credentials_stored?
|
115
|
+
user_token, user_secret = settings.load_credentials
|
57
116
|
else
|
58
117
|
user_token, user_secret = oauth_pin_dance_for_token_and_secret
|
59
|
-
|
118
|
+
settings.save_credentials(user_token, user_secret)
|
60
119
|
end
|
61
120
|
|
62
121
|
Twitter.configure do |config|
|
@@ -86,31 +145,14 @@ module Tweetskim
|
|
86
145
|
puts "Please authenticate by following this URL:"
|
87
146
|
puts request_token.authorize_url
|
88
147
|
|
89
|
-
|
148
|
+
puts "What was the PIN that Twitter gave you? "
|
90
149
|
pin = gets.chomp
|
91
150
|
|
92
151
|
OAuth::RequestToken.new(oauth_consumer, rtoken, rsecret)
|
93
152
|
access_token = request_token.get_access_token(:oauth_verifier => pin)
|
94
153
|
|
95
154
|
return access_token.token, access_token.secret
|
96
|
-
end
|
97
|
-
|
98
|
-
#TODO store tokens for each user
|
99
|
-
TOKEN_FILE_PATH = File.expand_path "~/.tweetskim/default.tokens"
|
100
|
-
|
101
|
-
def user_tokens_stored?
|
102
|
-
File.exists? TOKEN_FILE_PATH
|
103
|
-
end
|
104
|
-
|
105
|
-
def store_user_tokens(token, secret)
|
106
|
-
`mkdir ~/.tweetskim/`
|
107
|
-
`echo "#{token}___#{secret}" > #{TOKEN_FILE_PATH}`
|
108
|
-
end
|
109
|
-
|
110
|
-
def load_user_tokens
|
111
|
-
token, secret = `cat #{TOKEN_FILE_PATH}`.split "___"
|
112
|
-
return token.chomp, secret.chomp
|
113
|
-
end
|
114
|
-
|
155
|
+
end
|
115
156
|
end
|
157
|
+
|
116
158
|
end
|
data/lib/tweetskim/version.rb
CHANGED
data/test/test_tweetskim.rb
CHANGED
@@ -18,26 +18,10 @@ class TestTweetskim < Test::Unit::TestCase
|
|
18
18
|
def test_column_creation
|
19
19
|
tweets = [t("Ut enimad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat."), t("Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. "), t("Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.")]
|
20
20
|
|
21
|
-
expected =
|
22
|
-
--Mock User-- Excepteur sint occaecat
|
23
|
-
cupidatat non proident, sunt in culpa
|
24
|
-
qui officia deserunt mollit anim id
|
25
|
-
est laborum.
|
26
|
-
|
27
|
-
|
28
|
-
--Mock User-- Duis aute irure dolor in
|
29
|
-
reprehenderit in voluptate velit esse
|
30
|
-
cillum dolore eu fugiat nulla pariatur.
|
31
|
-
|
32
|
-
|
33
|
-
--Mock User-- Ut enimad minim veniam,
|
34
|
-
quis nostrud exercitation ullamco
|
35
|
-
laboris nisi ut aliquip ex ea commodo
|
36
|
-
consequat.
|
37
|
-
COLUMN
|
21
|
+
expected = "--\e[1;34mMock User\e[0m-- Excepteur sint\noccaecat cupidatat non proident, sunt\nin culpa qui officia deserunt mollit\nanim id est laborum.\n\n\n--\e[1;34mMock User\e[0m-- Duis aute\nirure dolor in reprehenderit in\nvoluptate velit esse cillum dolore eu\nfugiat nulla pariatur.\n\n\n--\e[1;34mMock User\e[0m-- Ut enimad\nminim veniam, quis nostrud exercitation\nullamco laboris nisi ut aliquip ex ea\ncommodo consequat.\n"
|
38
22
|
|
39
23
|
actual = @f.column(tweets, {:width => 40})
|
40
|
-
|
24
|
+
|
41
25
|
assert_equal expected, actual
|
42
26
|
end
|
43
27
|
|
@@ -80,6 +64,14 @@ COL
|
|
80
64
|
|
81
65
|
assert_equal expected, @f.pad(col, 6)
|
82
66
|
end
|
67
|
+
|
68
|
+
def test_settings_persistence
|
69
|
+
|
70
|
+
|
71
|
+
|
72
|
+
end
|
73
|
+
|
74
|
+
|
83
75
|
|
84
76
|
end
|
85
77
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tweetskim
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-03-
|
12
|
+
date: 2012-03-05 00:00:00.000000000Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: twitter
|
16
|
-
requirement: &
|
16
|
+
requirement: &15805940 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: '0'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *15805940
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: oauth
|
27
|
-
requirement: &
|
27
|
+
requirement: &15805520 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ! '>='
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: '0'
|
33
33
|
type: :runtime
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *15805520
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: OptionParser
|
38
|
-
requirement: &
|
38
|
+
requirement: &15805100 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ! '>='
|
@@ -43,10 +43,10 @@ dependencies:
|
|
43
43
|
version: '0'
|
44
44
|
type: :runtime
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *15805100
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: mocha
|
49
|
-
requirement: &
|
49
|
+
requirement: &15804680 !ruby/object:Gem::Requirement
|
50
50
|
none: false
|
51
51
|
requirements:
|
52
52
|
- - ! '>='
|
@@ -54,7 +54,7 @@ dependencies:
|
|
54
54
|
version: '0'
|
55
55
|
type: :development
|
56
56
|
prerelease: false
|
57
|
-
version_requirements: *
|
57
|
+
version_requirements: *15804680
|
58
58
|
description: ! 'Usage: tweetskim [username]'
|
59
59
|
email:
|
60
60
|
- thomas@kjeldahlnilsson.net
|
@@ -71,7 +71,6 @@ files:
|
|
71
71
|
- lib/tweetskim.rb
|
72
72
|
- lib/tweetskim/core.rb
|
73
73
|
- lib/tweetskim/version.rb
|
74
|
-
- test.txt
|
75
74
|
- test/test_helper.rb
|
76
75
|
- test/test_tweetskim.rb
|
77
76
|
- tweetskim.gemspec
|
data/test.txt
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
hepp
|