usaidwat 1.4.5 → 1.5.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 81fff9eeb3cb27fb171c0e765857245b69a7cfa6
4
- data.tar.gz: 0e8665fd1c0b68b607fd0354624ea089e0e9015d
3
+ metadata.gz: f691290d3941259d0b2cfdfaa0ac6f256df6bfba
4
+ data.tar.gz: 4e943e27e1d55d4c3fb08b10c1d8298b24303312
5
5
  SHA512:
6
- metadata.gz: e00710b0a337b430c7fa576dc4ca58e847e402b060d316df87561fb555133c41b0d7a7247208d1ff6d3773330c5aee481aeb69f3ab833e3ecaf97151f3aefedb
7
- data.tar.gz: 80415d6345702d01eb5d4bc5df197e09ed4b308bf1ed657e25cf4fc4300eba3653ecb5c3dfa5e36667c9f6888504af28e1a0341a4e893810a1c345f384c2df87
6
+ metadata.gz: 568babcb320e2cbddbd18ee4bfb1a3f8a6f33e3a014abe65992d1bfebad0fe5fb9d4199e2df85d8054da83ee36fc80c49087d7d0825ea72cc0a5fc3c2730ef35
7
+ data.tar.gz: b8532c9d3210713253e8f9a7fd9cf9f5b01bd37babbac633c16454b40bdef0290cdfec2840620acae013958d380e8a46efd512e107801dccc0e67d06a4429783
data/Rakefile CHANGED
@@ -31,6 +31,13 @@ task :release => [:tag, :build] do
31
31
  system "gem", "push", GEM
32
32
  end
33
33
 
34
+ desc "Run the test suite"
35
+ task :test do
36
+ ok = system "bundle", "exec", "rspec"
37
+ fail if !ok
38
+ system "bundle", "exec", "cucumber", "-f", "progress"
39
+ end
40
+
34
41
  desc "Clean built products"
35
42
  task :clean do
36
43
  rm Dir.glob("*.gem"), :verbose => true
data/bin/usaidwat CHANGED
@@ -5,7 +5,9 @@ require 'usaidwat'
5
5
  require 'usaidwat/ext/mercenary'
6
6
 
7
7
  Mercenary.program(:usaidwat) do |p|
8
- p.version USaidWat::VERSION
8
+ version = USaidWat::VERSION
9
+ version += " (#{USaidWat::commit_hash})" if USaidWat::VERSION.end_with?('.dev')
10
+ p.version version
9
11
  p.description 'Answers the age-old question, "Where does a Redditor comment the most?"'
10
12
  p.syntax 'usaidwat <command> [options] <args>'
11
13
 
@@ -0,0 +1,46 @@
1
+ Feature: Show timeline of comments
2
+
3
+ As a Redditor
4
+ I want to visualize when another Redditor comments most often
5
+ In order to see what time they like to comment
6
+
7
+ Scenario: Show timeline data for user
8
+ Given the Reddit service returns comments for the user "mipadi"
9
+ When I run `usaidwat timeline mipadi`
10
+ Then it should pass with:
11
+ """
12
+ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
13
+ S * * *
14
+ M * * * * * * * * *
15
+ T * * * * * * * * *
16
+ W * * * * * *
17
+ T * * * * * * * *
18
+ F * * * * * * *
19
+ S * *
20
+ """
21
+
22
+ Scenario: Show timeline data for a user with no comments
23
+ Given the Reddit service returns comments for the user "blank"
24
+ When I run `usaidwat timeline blank`
25
+ Then it should pass with:
26
+ """
27
+ blank has no comments.
28
+ """
29
+
30
+ Scenario: Show timeline data without specifying a user
31
+ Given the Reddit service returns comments for the user "mipadi"
32
+ When I run `usaidwat timeline testuser`
33
+ Then the exit status should not be 0
34
+ And stderr should contain exactly:
35
+ """
36
+ No such user: testuser
37
+ """
38
+
39
+ Scenario: Show timeline without specifying a user
40
+ Given the Reddit service returns comments for the user "mipadi"
41
+ When I run `usaidwat timeline`
42
+ Then the exit status should not be 0
43
+ And stderr should contain exactly:
44
+ """
45
+ You must specify a username
46
+ """
data/lib/usaidwat.rb CHANGED
@@ -9,6 +9,7 @@ require "usaidwat/algo"
9
9
  require "usaidwat/client"
10
10
  require "usaidwat/command"
11
11
  require "usaidwat/formatter"
12
+ require "usaidwat/thing"
12
13
  require "usaidwat/version"
13
14
 
14
15
  require_all "usaidwat/commands"
@@ -1,11 +1,13 @@
1
- require 'snooby'
2
1
  require 'usaidwat/service'
3
- require 'usaidwat/ext/snooby'
4
2
  require 'usaidwat/ext/time'
5
3
 
6
4
  module USaidWat
7
5
  module Client
8
- class ReachabilityError < RuntimeError; end
6
+ class ReachabilityError < RuntimeError
7
+ def initialize(msg = nil)
8
+ super(msg || 'Reddit unreachable')
9
+ end
10
+ end
9
11
 
10
12
  class NoSuchUserError < StandardError; end
11
13
 
@@ -20,20 +22,20 @@ module USaidWat
20
22
  user.comments(100)
21
23
  rescue NoMethodError
22
24
  raise NoSuchUserError, username
23
- rescue TypeError, Net::HTTP::Persistent::Error
24
- raise ReachabilityError, "Reddit unreachable"
25
+ rescue RuntimeError
26
+ raise ReachabilityError
25
27
  end
26
28
 
27
29
  def link_karma
28
- about('link_karma')
30
+ about.link_karma
29
31
  end
30
32
 
31
33
  def comment_karma
32
- about('comment_karma')
34
+ about.comment_karma
33
35
  end
34
36
 
35
37
  def created_at
36
- Time.at(about('created_utc'))
38
+ about.created_utc
37
39
  end
38
40
 
39
41
  def age
@@ -48,8 +50,8 @@ module USaidWat
48
50
  user.posts
49
51
  rescue NoMethodError
50
52
  raise NoSuchUserError, username
51
- rescue TypeError, Net::HTTP::Persistent::Error
52
- raise ReachabilityError, "Reddit unreachable"
53
+ rescue RuntimeError
54
+ raise ReachabilityError
53
55
  end
54
56
 
55
57
  private
@@ -58,18 +60,16 @@ module USaidWat
58
60
  @service.user(username)
59
61
  end
60
62
 
61
- def about(key)
62
- user.about[key]
63
+ def about
64
+ user.about
63
65
  rescue NoMethodError
64
66
  raise NoSuchUserError, username
65
- rescue TypeError, Net::HTTP::Persistent::Error
66
- raise ReachabilityError, "Reddit unreachable"
67
67
  end
68
68
  end
69
69
 
70
70
  class Redditor < BaseRedditor
71
71
  def initialize(username)
72
- @service = Snooby::Client.new("usaidwat v#{USaidWat::VERSION}")
72
+ @service = USaidWat::Service::RedditService.new
73
73
  super
74
74
  end
75
75
  end
@@ -0,0 +1,42 @@
1
+ module USaidWat
2
+ module Application
3
+ class Timeline < Command
4
+ def initialize(prog)
5
+ prog.command(:timeline) do |c|
6
+ c.action do |args, options|
7
+ process(options, args)
8
+ end
9
+ end
10
+ super
11
+ end
12
+
13
+ def process(options, args)
14
+ raise ArgumentError.new('You must specify a username') if args.empty?
15
+ username = args.shift
16
+
17
+ redditor = client.new(username)
18
+ comments = redditor.comments
19
+
20
+ quit "#{username} has no comments." if comments.empty?
21
+
22
+ buckets = comments_by_days_and_hours(comments)
23
+ times = Array.new(7) { Array.new(24, 0) }
24
+ buckets.each do |v|
25
+ d, h = v
26
+ times[d][h] += 1
27
+ end
28
+
29
+ formatter = USaidWat::CLI::TimelineFormatter.new
30
+ puts formatter.format(times)
31
+ rescue USaidWat::Client::NoSuchUserError
32
+ quit "No such user: #{username}", :no_such_user
33
+ end
34
+
35
+ private
36
+
37
+ def comments_by_days_and_hours(comments)
38
+ comments.map { |c| [c.created_utc.wday, c.created_utc.hour] }
39
+ end
40
+ end
41
+ end
42
+ end
@@ -1,187 +1,7 @@
1
- require 'date'
2
- require 'downterm'
3
- require 'rainbow/ext/string'
4
- require 'redcarpet'
5
- require 'set'
6
- require 'stringio'
7
- require 'ttycaca'
8
- require 'usaidwat/ext/string'
9
- require 'usaidwat/ext/time'
1
+ require 'usaidwat/formatter/base'
2
+ require 'usaidwat/formatter/comment'
3
+ require 'usaidwat/formatter/count'
4
+ require 'usaidwat/formatter/post'
5
+ require 'usaidwat/formatter/timeline'
10
6
 
11
7
  Rainbow.enabled = true unless ENV['USAIDWAT_ENV'] == 'cucumber'
12
-
13
- module USaidWat
14
- module CLI
15
- class BaseFormatter
16
- def initialize(options = {})
17
- @options = options
18
- @count = 0
19
- end
20
-
21
- def pattern
22
- @options[:pattern]
23
- end
24
-
25
- def pattern?
26
- !!@options[:pattern]
27
- end
28
-
29
- def raw?
30
- !!@options[:raw]
31
- end
32
-
33
- def relative_dates?
34
- @options[:date_format].nil? || @options[:date_format].to_sym != :absolute
35
- end
36
-
37
- protected
38
-
39
- def tty
40
- @tty ||= Ttycaca::Terminal.new
41
- end
42
- end
43
-
44
- class PostFormatter < BaseFormatter
45
- def format(post)
46
- cols = tty.width
47
- out = StringIO.new
48
- out.write("\n\n\n") unless @count == 0
49
- out.write("#{post.subreddit}\n".color(:green))
50
- out.write("#{post_link(post)}\n".color(:yellow))
51
- out.write("#{post.title.strip.unescape_html.truncate(cols)}\n".color(:magenta))
52
- out.write("#{post_date(post)}".color(:blue))
53
- out.write("\n#{post.url}") unless post.url.end_with?(post.permalink)
54
- @count += 1
55
- out.rewind
56
- out.read
57
- end
58
-
59
- private
60
-
61
- def post_link(post)
62
- "https://www.reddit.com#{post.permalink.split('/')[0..-2].join('/')}"
63
- end
64
-
65
- def post_date(post)
66
- Time.at(post.created_utc).ago
67
- end
68
- end
69
-
70
- class CompactPostFormatter < BaseFormatter
71
- def format(post)
72
- cols = tty.width
73
- out = StringIO.new
74
- subreddit = post.subreddit
75
- cols -= subreddit.length + 1
76
- title = post.title.strip.unescape_html.truncate(cols)
77
- out.write(subreddit.color(:green))
78
- out.write(" #{title}\n")
79
- out.rewind
80
- out.read
81
- end
82
- end
83
-
84
- class CommentFormatter < BaseFormatter
85
- def format(comment)
86
- cols = tty.width
87
- out = StringIO.new
88
- out.write("\n\n") unless @count == 0
89
- out.write("#{comment.subreddit}\n".color(:green))
90
- out.write("#{comment_link(comment)}\n".color(:yellow))
91
- out.write("#{comment.link_title.strip.unescape_html.truncate(cols)}\n".color(:magenta))
92
- out.write("#{comment_date(comment)}".color(:blue))
93
- out.write(" \u2022 ".color(:cyan))
94
- out.write(sprintf("%+d\n", comment_karma(comment)).color(:blue))
95
- out.write("\n")
96
- out.write("#{comment_body(comment)}\n")
97
- @count += 1
98
- out.rewind
99
- out.read
100
- end
101
-
102
- private
103
- def markdown
104
- @markdown ||= Redcarpet::Markdown.new(Downterm::Render::Terminal, :autolink => true,
105
- :strikethrough => true,
106
- :superscript => true)
107
- end
108
-
109
- def comment_body(comment)
110
- body = comment.body.strip.unescape_html
111
- body = markdown.render(body) unless raw?
112
- if pattern?
113
- body.highlight(pattern)
114
- else
115
- body
116
- end
117
- end
118
-
119
- def comment_link(comment)
120
- link = comment.link_id.split("_")[-1]
121
- "http://www.reddit.com/r/#{comment.subreddit}/comments/#{link}/z/#{comment.id}"
122
- end
123
-
124
- def comment_date(comment)
125
- d = DateTime.strptime(comment.created_utc.to_s, "%s").to_time.localtime
126
- if relative_dates?
127
- d.ago
128
- else
129
- d_part = d.strftime("%a, %-d %b %Y")
130
- t_part = d.strftime("%l:%M %p").strip
131
- "#{d_part}, #{t_part}"
132
- end
133
- end
134
-
135
- def comment_karma(comment)
136
- comment.ups - comment.downs
137
- end
138
- end
139
-
140
- class CompactCommentFormatter < BaseFormatter
141
- def format(comment)
142
- cols = tty.width
143
- out = StringIO.new
144
- subreddit = comment.subreddit
145
- cols -= subreddit.length + 1
146
- title = comment.link_title.strip.unescape_html.truncate(cols)
147
- key = "#{subreddit} #{title}"
148
- if !seen?(key)
149
- out.write("#{subreddit}".color(:green))
150
- out.write(" #{title}\n")
151
- end
152
- mark_seen(key)
153
- out.rewind
154
- out.read
155
- end
156
-
157
- private
158
-
159
- def comments
160
- @comments ||= Set.new
161
- end
162
-
163
- def mark_seen(comment)
164
- comments << comment
165
- end
166
-
167
- def seen?(comment)
168
- comments.include?(comment)
169
- end
170
- end
171
-
172
- class TallyFormatter < BaseFormatter
173
- def format(partition_data)
174
- out = StringIO.new
175
- longest_subreddit = partition_data.longest
176
- subreddits = partition_data.counts
177
- subreddits.each do |subreddit_count|
178
- subreddit, tally = subreddit_count
179
- line = sprintf("%-*s %3d\n", longest_subreddit, subreddit, tally)
180
- out.write(line)
181
- end
182
- out.rewind
183
- out.read
184
- end
185
- end
186
- end
187
- end
@@ -0,0 +1,39 @@
1
+ require 'downterm'
2
+ require 'rainbow/ext/string'
3
+ require 'redcarpet'
4
+ require 'ttycaca'
5
+
6
+ module USaidWat
7
+ module CLI
8
+ module TTYFormatter
9
+ def tty
10
+ @tty ||= Ttycaca::Terminal.new
11
+ end
12
+ end
13
+
14
+ class BaseFormatter
15
+ include TTYFormatter
16
+
17
+ def initialize(options = {})
18
+ @options = options
19
+ @count = 0
20
+ end
21
+
22
+ def pattern
23
+ @options[:pattern]
24
+ end
25
+
26
+ def pattern?
27
+ !!@options[:pattern]
28
+ end
29
+
30
+ def raw?
31
+ !!@options[:raw]
32
+ end
33
+
34
+ def relative_dates?
35
+ @options[:date_format].nil? || @options[:date_format].to_sym != :absolute
36
+ end
37
+ end
38
+ end
39
+ end