tweetskim 0.6.0 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -14,7 +14,7 @@ def parse_options
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
- o.on("-o MODE", "--output-mode MODE", "Output as 'lines', 'column' or 'html'") { |mode| options[:output_mode] = mode }
17
+ o.on("-l", "--html-output", "Output as html") { |b| options[:html_output] = true}
18
18
  #TODO o.on("-u USER", "--user USER", "Which twitter user I am. Example: tweetskim -u thomanil") { |u| options[:user] = u }
19
19
  o.on("-v", "--version", "Spit out version") { |b| puts Tweetskim::VERSION; exit }
20
20
 
@@ -56,16 +56,11 @@ end
56
56
 
57
57
  def write_tweets_to_stdout(tweets, options = {})
58
58
  formatter = Tweetskim::Formatter.new
59
- output_mode = options[:output_mode]
60
59
 
61
- if !output_mode || output_mode == "lines"
62
- result = formatter.lines(tweets, options)
63
- elsif output_mode == "column"
64
- result = formatter.column(tweets, {:width => 60})
65
- elsif output_mode == "html"
66
- puts "Html mode not done yet."; exit
60
+ if options[:html_output] # Print lines to stdout
61
+ result = formatter.html(tweets, options)
67
62
  else
68
- puts "Invalid output mode."; exit
63
+ result = formatter.lines(tweets, options)
69
64
  end
70
65
 
71
66
  puts result
@@ -1,5 +1,7 @@
1
1
  require "tweetskim/version"
2
- require "tweetskim/core"
2
+ require "tweetskim/settings"
3
+ require "tweetskim/twitter_adapter"
4
+ require "tweetskim/formatter"
3
5
 
4
6
  module Tweetskim
5
7
 
@@ -5,39 +5,6 @@ module Tweetskim
5
5
  require 'twitter'
6
6
  require 'oauth'
7
7
 
8
-
9
- class Formatter
10
- def lines(tweets, options = {})
11
- tweet_texts = tweets.reverse.map {|tweet| "--#{tweet.user.name}-- #{text(tweet)}\n"}
12
- lines = tweet_texts.join("")
13
- end
14
-
15
- def column(tweets, options = {})
16
- tweet_texts = tweets.reverse.map {|tweet| "--\\033[1;34m#{tweet.user.name}\\033[0m-- #{text(tweet)}"}
17
- reflowed_tweets = tweet_texts.map {|tweet| `echo "#{tweet}" | fmt -w #{options[:width]}` }
18
- column = reflowed_tweets.join "\n\n"
19
- end
20
-
21
- def pad(column, width)
22
- padded_lines = []
23
- column.each_line do |line|
24
- chopped_line = line.chop
25
- padded_lines.push `printf "%-#{width}s\n" "#{chopped_line}"`
26
- end
27
- padded_lines.join ""
28
- end
29
-
30
- def text(tweet)
31
- if tweet.retweeted_status
32
- "RT @#{tweet.retweeted_status.user.screen_name}: #{tweet.retweeted_status.text}"
33
- else
34
- tweet.text
35
- end
36
- end
37
-
38
- end
39
-
40
-
41
8
  class Settings
42
9
  SETTINGS_TEMPLATE = {:token => nil,
43
10
  :secret => nil,
@@ -168,4 +135,40 @@ module Tweetskim
168
135
  end
169
136
  end
170
137
 
138
+
139
+ class Formatter
140
+ def lines(tweets, options = {})
141
+ tweet_texts = tweets.reverse.map {|tweet| "--#{tweet.user.name}-- #{text(tweet)}\n"}
142
+ lines = tweet_texts.join("")
143
+ end
144
+
145
+ def column(tweets, options = {})
146
+ tweet_texts = tweets.reverse.map {|tweet| "--\\033[1;34m#{tweet.user.name}\\033[0m-- #{text(tweet)}"}
147
+ reflowed_tweets = tweet_texts.map {|tweet| `echo "#{tweet}" | fmt -w #{options[:width]}` }
148
+ column = reflowed_tweets.join "\n\n"
149
+ end
150
+
151
+ def html(tweets, options = {})
152
+
153
+ end
154
+
155
+ def pad(column, width)
156
+ padded_lines = []
157
+ column.each_line do |line|
158
+ chopped_line = line.chop
159
+ padded_lines.push `printf "%-#{width}s\n" "#{chopped_line}"`
160
+ end
161
+ padded_lines.join ""
162
+ end
163
+
164
+ def text(tweet)
165
+ if tweet.retweeted_status
166
+ "RT @#{tweet.retweeted_status.user.screen_name}: #{tweet.retweeted_status.text}"
167
+ else
168
+ tweet.text
169
+ end
170
+ end
171
+ end
172
+
173
+
171
174
  end
@@ -0,0 +1,86 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ module Tweetskim
4
+
5
+ class Formatter
6
+
7
+ def lines(tweets, options = {})
8
+ tweet_texts = tweets.reverse.map {|tweet| "--#{tweet.user.name}-- #{text(tweet)}\n"}
9
+ lines = tweet_texts.join("")
10
+ end
11
+
12
+ def text(tweet)
13
+ if tweet.retweeted_status
14
+ "RT @#{tweet.retweeted_status.user.screen_name}: #{tweet.retweeted_status.text}"
15
+ else
16
+ tweet.text
17
+ end
18
+ end
19
+
20
+ def htmlize(tweet)
21
+ text = text(tweet).gsub('\n', '<br/>')
22
+ "<div class='tweet'><h1>#{tweet.user.name} <span class='time'>#{time(tweet)}</span></h1><p>#{text}<p></div>"
23
+ end
24
+
25
+ def time(tweet)
26
+ tweet_time = tweet.created_at
27
+ now = Time.now
28
+ if now.day != tweet_time.day
29
+ "#{tweet_time.day} / #{tweet_time.mon}"
30
+ else
31
+ "#{tweet_time.hour}:#{tweet_time.min}"
32
+ end
33
+ end
34
+
35
+ def html(tweets, options = {})
36
+ html_tweets = tweets.reverse.map {|tweet| htmlize(tweet)}.join("")
37
+
38
+ body = <<HTML
39
+ <!DOCTYPE html>
40
+ <html lang="en">
41
+ <head>
42
+ <meta charset="utf-8">
43
+ <title>Tweetskim</title>
44
+ </head>
45
+ <body>
46
+ <style>
47
+ #tweets {
48
+ width: 500px;
49
+ margin-left: 50px;
50
+ }
51
+
52
+ .tweet {
53
+ margin-top: 50px;
54
+ margin-bottom: 50px;
55
+ }
56
+
57
+ .tweet h1 {
58
+ color: #ADADAD;
59
+ font-size: 2.0em;
60
+ margin-bottom: 0px;
61
+ }
62
+
63
+ .tweet .time {
64
+ color: #ADADAD;
65
+ font-size: 0.5em;
66
+ }
67
+
68
+ .tweet p {
69
+ font-size: 1.2em;
70
+ margin: 0 0 0 0;
71
+ margin-left: 50px;
72
+ font-family: sans-serif;
73
+ }
74
+ </style>
75
+ <div id="tweets">
76
+ #{html_tweets}
77
+ </div>
78
+ </body>
79
+ </html>
80
+ HTML
81
+ return body
82
+ end
83
+
84
+ end
85
+
86
+ end
@@ -0,0 +1,67 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ module Tweetskim
4
+
5
+ class Settings
6
+ SETTINGS_TEMPLATE = {:token => nil,
7
+ :secret => nil,
8
+ :last_read_status_id => "111111"}
9
+
10
+ SETTINGS_FILE_PATH = File.expand_path "~/.tweetskim/default-account"
11
+
12
+ require "fileutils"
13
+
14
+ def initialize
15
+ FileUtils.mkdir_p(File.expand_path("~/.tweetskim"))
16
+ FileUtils.touch SETTINGS_FILE_PATH
17
+ end
18
+
19
+ def load
20
+ File.open SETTINGS_FILE_PATH, "r" do |filebody|
21
+ YAML::load(filebody) || SETTINGS_TEMPLATE
22
+ end
23
+ end
24
+
25
+ def save(settings)
26
+ yml_str = YAML::dump(settings)
27
+ File.open SETTINGS_FILE_PATH, "w" do |filebody|
28
+ filebody.write yml_str
29
+ end
30
+ end
31
+
32
+ def user_credentials_stored?
33
+ if File.exists? SETTINGS_FILE_PATH
34
+ settings = load
35
+ return (settings[:token] && !settings[:token].empty? &&
36
+ settings[:secret] && !settings[:secret].empty?)
37
+ else
38
+ false
39
+ end
40
+ end
41
+
42
+ def save_credentials(token, secret)
43
+ settings = load
44
+ settings[:token] = token
45
+ settings[:secret] = secret
46
+ save settings
47
+ end
48
+
49
+ def load_credentials
50
+ settings = load
51
+ return settings[:token], settings[:secret]
52
+ end
53
+
54
+ def load_last_read_status_id
55
+ settings = load
56
+ return settings[:last_read_status_id]
57
+ end
58
+
59
+ def save_last_read_status_id(id)
60
+ settings = load
61
+ settings[:last_read_status_id] = id
62
+ save settings
63
+ end
64
+
65
+ end
66
+
67
+ end
@@ -0,0 +1,75 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'rubygems'
4
+ require 'twitter'
5
+ require 'oauth'
6
+
7
+ module Tweetskim
8
+
9
+ class TwitterAdapter
10
+ # TODO call for each user in config
11
+ # implicit for the user authenticated in client. Different user =
12
+ # different client
13
+
14
+ def mentions(tweet_count, since_id)
15
+ client = authenticated_client
16
+ mentions = client.mentions({:count => tweet_count.to_i, :since_id => since_id.to_i})
17
+ end
18
+
19
+ def timeline(tweet_count, since_id)
20
+ client = authenticated_client
21
+ timeline = client.home_timeline({:count => tweet_count.to_i, :since_id => since_id.to_i})
22
+ end
23
+
24
+ CONSUMER_KEY = "3oUZhYLZcaqqQePajIjnBg"
25
+ CONSUMER_SECRET = "mAYecEGPwy7BlkibFGHCACtY5x1Mm0YOvczxsll4OY"
26
+
27
+ # TODO call for specific user
28
+ def authenticated_client
29
+ settings = Tweetskim::Settings.new
30
+
31
+ if settings.user_credentials_stored?
32
+ user_token, user_secret = settings.load_credentials
33
+ else
34
+ user_token, user_secret = oauth_pin_dance_for_token_and_secret
35
+ settings.save_credentials(user_token, user_secret)
36
+ end
37
+
38
+ Twitter.configure do |config|
39
+ config.consumer_key = CONSUMER_KEY
40
+ config.consumer_secret = CONSUMER_SECRET
41
+ config.oauth_token = user_token
42
+ config.oauth_token_secret = user_secret
43
+ end
44
+
45
+ client = Twitter::Client.new
46
+ client.verify_credentials
47
+ return client
48
+ end
49
+
50
+ def oauth_pin_dance_for_token_and_secret
51
+ oauth_consumer = OAuth::Consumer.new(CONSUMER_KEY, CONSUMER_SECRET,
52
+ :site => 'http://api.twitter.com',
53
+ :request_token_path => '/oauth/request_token',
54
+ :access_token_path => '/oauth/access_token',
55
+ :authorize_path => '/oauth/authorize')
56
+
57
+ request_token = oauth_consumer.get_request_token
58
+ rtoken = request_token.token
59
+ rsecret = request_token.secret
60
+
61
+ puts "You have to set up Twitter authentication the first time you use tweetskim."
62
+ puts "Please authenticate by following this URL:"
63
+ puts request_token.authorize_url
64
+
65
+ puts "What was the PIN that Twitter gave you? "
66
+ pin = gets.chomp
67
+
68
+ OAuth::RequestToken.new(oauth_consumer, rtoken, rsecret)
69
+ access_token = request_token.get_access_token(:oauth_verifier => pin)
70
+
71
+ return access_token.token, access_token.secret
72
+ end
73
+ end
74
+
75
+ end
@@ -1,3 +1,3 @@
1
1
  module Tweetskim
2
- VERSION = "0.6.0"
2
+ VERSION = "0.7.0"
3
3
  end
@@ -14,16 +14,6 @@ class TestTweetskim < Test::Unit::TestCase
14
14
  status.stubs(:user).returns user
15
15
  return status
16
16
  end
17
-
18
- def test_column_creation
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
-
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"
22
-
23
- actual = @f.column(tweets, {:width => 40})
24
-
25
- assert_equal expected, actual
26
- end
27
17
 
28
18
  def test_line_creation
29
19
  tweets = [t("Ut enimad minim veniam, quis nostrud."), t("Duis aute irure dolor in reprehenderit"), t("Excepteur sint occaecat cupidatat non proident")]
@@ -38,40 +28,6 @@ LINES
38
28
 
39
29
  assert_equal expected, actual
40
30
  end
41
-
42
-
43
- def test_whitespace_padding
44
-
45
- col = <<COL
46
- aaaaaa
47
- aaaaa
48
- aaaa
49
- aaa
50
- aa
51
- a
52
-
53
- COL
54
-
55
- expected = <<COL
56
- aaaaaa
57
- aaaaa
58
- aaaa
59
- aaa
60
- aa
61
- a
62
-
63
- COL
64
-
65
- assert_equal expected, @f.pad(col, 6)
66
- end
67
-
68
- def test_settings_persistence
69
-
70
-
71
-
72
- end
73
-
74
-
75
31
 
76
32
  end
77
33
 
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.6.0
4
+ version: 0.7.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-07 00:00:00.000000000Z
12
+ date: 2012-03-30 00:00:00.000000000Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: twitter
16
- requirement: &9038620 !ruby/object:Gem::Requirement
16
+ requirement: &18714980 !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: *9038620
24
+ version_requirements: *18714980
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: oauth
27
- requirement: &9038200 !ruby/object:Gem::Requirement
27
+ requirement: &18714560 !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: *9038200
35
+ version_requirements: *18714560
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: OptionParser
38
- requirement: &9037780 !ruby/object:Gem::Requirement
38
+ requirement: &18714140 !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: *9037780
46
+ version_requirements: *18714140
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: mocha
49
- requirement: &9037360 !ruby/object:Gem::Requirement
49
+ requirement: &18713720 !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: *9037360
57
+ version_requirements: *18713720
58
58
  description: ! 'Usage: tweetskim [options]'
59
59
  email:
60
60
  - thomas@kjeldahlnilsson.net
@@ -70,6 +70,9 @@ files:
70
70
  - bin/tweetskim
71
71
  - lib/tweetskim.rb
72
72
  - lib/tweetskim/core.rb
73
+ - lib/tweetskim/formatter.rb
74
+ - lib/tweetskim/settings.rb
75
+ - lib/tweetskim/twitter_adapter.rb
73
76
  - lib/tweetskim/version.rb
74
77
  - test/test_helper.rb
75
78
  - test/test_tweetskim.rb