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 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 (`less
21
- tweetskim`), concat it to file (`tweetskim > tweets.txt`), search for specific stuff (`tweetskim | grep conference`) and so on.
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
- -e, --mentions
26
+ Options:
29
27
 
30
- -i, --inverse-order
28
+ -e, --mentions: Show mentions instead of timeline
31
29
 
32
- -h, --help
30
+ -i, --inverse-order Inverse/reverse ordered tweets
33
31
 
34
- -m, --mark-all-read
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|column|html
36
+ -o, --output-mode MODE Output as 'lines', 'column' or 'html'
39
37
 
40
- -u, --user
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
- options
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
- Finish options enumerated above
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
- #TODO o.on("-a", "--show-all", "Show all tweets, not just unread ones (max 300)") { |b| options[:show_all] = b }
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
- #TODO o.on("-m", "--mark-all-read", "Mark everything up to now as read") { |b| options[:mark_all_read] = b }
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(:count => options[:last_n_tweets] || 300)
39
+ tweets = adapter.mentions(tweet_count, since_id)
32
40
  else
33
- tweets = adapter.timeline(:count => options[:last_n_tweets] || 300)
41
+ tweets = adapter.timeline(tweet_count, since_id)
34
42
  end
35
43
 
36
- if options[:inverse_order]
37
- tweets = tweets.reverse
38
- end
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 => 40})
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)
@@ -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| "--#{tweet.user.name}-- #{tweet.text}"}
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(options = {})
41
- client = authenticated_client #
42
- mentions = client.mentions(options)
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(options = {})
102
+ def timeline(tweet_count, since_id)
46
103
  client = authenticated_client
47
- timeline = client.home_timeline(options)
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
- if user_tokens_stored?
56
- user_token, user_secret = load_user_tokens
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
- store_user_tokens(user_token, user_secret)
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
- print "What was the PIN that Twitter gave you? "
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
@@ -1,3 +1,3 @@
1
1
  module Tweetskim
2
- VERSION = "0.2.0"
2
+ VERSION = "0.3.0"
3
3
  end
@@ -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 = <<COLUMN
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.2.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-03 00:00:00.000000000Z
12
+ date: 2012-03-05 00:00:00.000000000Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: twitter
16
- requirement: &18929420 !ruby/object:Gem::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: *18929420
24
+ version_requirements: *15805940
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: oauth
27
- requirement: &18929000 !ruby/object:Gem::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: *18929000
35
+ version_requirements: *15805520
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: OptionParser
38
- requirement: &18928580 !ruby/object:Gem::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: *18928580
46
+ version_requirements: *15805100
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: mocha
49
- requirement: &18928160 !ruby/object:Gem::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: *18928160
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