stars 0.4.0 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +2 -0
- data/Gemfile.lock +26 -0
- data/README.markdown +48 -62
- data/Rakefile +130 -35
- data/bin/stars +1 -3
- data/lib/stars/client.rb +79 -62
- data/lib/stars/config.rb +41 -0
- data/lib/stars/core_ext/string.rb +6 -0
- data/lib/stars/post.rb +57 -0
- data/lib/stars/services/convore.rb +40 -0
- data/lib/stars/services/favstar.rb +79 -0
- data/lib/stars/services/service.rb +32 -0
- data/lib/stars.rb +37 -6
- data/stars.gemspec +85 -65
- data/test/examples/stars.yml +1 -0
- data/test/helper.rb +10 -27
- data/test/test_client.rb +18 -35
- data/test/test_config.rb +29 -0
- data/test/test_favstar.rb +19 -7
- data/test/test_post.rb +30 -0
- metadata +57 -22
- data/.document +0 -5
- data/.gitignore +0 -21
- data/VERSION +0 -1
- data/lib/stars/favstar.rb +0 -33
- data/lib/stars/formatter.rb +0 -70
- data/test/test_formatter.rb +0 -66
- data/test/test_stars.rb +0 -9
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
stars (0.5.0)
|
5
|
+
httparty
|
6
|
+
keep (~> 0.0.3)
|
7
|
+
nokogiri
|
8
|
+
terminal-table
|
9
|
+
|
10
|
+
GEM
|
11
|
+
remote: http://rubygems.org/
|
12
|
+
specs:
|
13
|
+
crack (0.1.8)
|
14
|
+
httparty (0.7.6)
|
15
|
+
crack (= 0.1.8)
|
16
|
+
keep (0.0.3)
|
17
|
+
mocha (0.9.12)
|
18
|
+
nokogiri (1.4.4)
|
19
|
+
terminal-table (1.4.2)
|
20
|
+
|
21
|
+
PLATFORMS
|
22
|
+
ruby
|
23
|
+
|
24
|
+
DEPENDENCIES
|
25
|
+
mocha (~> 0.9.9)
|
26
|
+
stars!
|
data/README.markdown
CHANGED
@@ -3,72 +3,58 @@
|
|
3
3
|
|
4
4
|
## why
|
5
5
|
|
6
|
-
|
6
|
+
Stars are a global currency. You tweet something, you write something, you
|
7
|
+
otherwise put yourself out there. Sure, you feel a warm sense of accomplishment
|
8
|
+
when you do this, but how do you *really* know if the people like you?
|
7
9
|
|
8
|
-
|
10
|
+
**FUCKING STARS, THAT'S HOW**
|
9
11
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
★ by @holman
|
15
|
-
+----+-----------+--------------+--------------------------------------------------------+
|
16
|
-
| # | Stars | Time | Your Funnies |
|
17
|
-
+----+-----------+--------------+--------------------------------------------------------+
|
18
|
-
| 1 | * | 12 hours ago | Today's GitHub todo list: put cupholders in the for... |
|
19
|
-
| 2 | * * * | 1 day ago | This bus is going so slowly that my AT&T 3G coverag... |
|
20
|
-
| 3 | * * * * * | 2 days ago | Every now and then I bust out that I'm from North D... |
|
21
|
-
| 4 | * * * | 3 days ago | Was told that "y'alls be stupid" by an adamant stre... |
|
22
|
-
| 5 | * * | 4 days ago | Now that we've fixed healthcare forever, who wants ... |
|
23
|
-
| 6 | * * * * | 4 days ago | Just wikipedia'd "Justin Bieber" and I still don't ... |
|
24
|
-
| 7 | * * * * | 5 days ago | Look. I'm not saying David Copperfield is a little ... |
|
25
|
-
| 8 | * | 6 days ago | SFO. Guys, we're at TERROR ALERT ORANGE. I don't t... |
|
26
|
-
| 9 | * | 7 days ago | Dammit. 2012 looks like garbage so far, but if a mo... |
|
27
|
-
| 10 | * | 10 days ago | At the MySQL + Rails combined meetup. I don't want ... |
|
28
|
-
| 11 | * | 10 days ago | Oh, they're doing a MacGruber movie. This makes sen... |
|
29
|
-
| 12 | * * * | 10 days ago | Just got my third free replacement earbuds from the... |
|
30
|
-
| 13 | * x 13 | 11 days ago | So for the seven of us that are both nerdy *and* va... |
|
31
|
-
| 14 | * * * * * | 11 days ago | I wouldn't say I'm "saving daylight" as much as I'm... |
|
32
|
-
| 15 | * * * | 13 days ago | I pre-ordered an iPad, checked into lunch, and now ... |
|
33
|
-
| 16 | * * | 13 days ago | In another life I want to be a pop star heartthrob ... |
|
34
|
-
| 17 | * | 14 days ago | Oh hey, a year or so of my beer consumption: http:/... |
|
35
|
-
| 18 | * | 14 days ago | Going to totally refork and rework my dotfiles soon... |
|
36
|
-
| 19 | * * * | 15 days ago | You change your Facebook pic, that syncs to my iPho... |
|
37
|
-
| 20 | * * | 17 days ago | just about finished my thesis on generating free en... |
|
38
|
-
+----+-----------+--------------+--------------------------------------------------------+
|
39
|
-
|
40
|
-
|
41
|
-
You can tell from the relative dearth of stars that I'm in my *screw followers I'm important so here's what I had for lunch* phase. Don't worry; I'll become a star whore again and tweet pop culture references in relation to presidential penile size soon enough.
|
42
|
-
|
43
|
-
You can also specify which user you want to run the query against by passing it in as your one argument. This value is saved for the future, too. For example:
|
12
|
+
`stars` is a command-line client to check your precious stars at fine
|
13
|
+
establishments like [Twitter](http://twitter.com) (via the exquisite
|
14
|
+
[Favstar](http://favstar.fm)) and [Convore](http://convore.com). More services
|
15
|
+
will be added as they get added.
|
44
16
|
|
45
|
-
|
46
|
-
stars # generates @holman's stars
|
47
|
-
stars goodtutorials # generates @goodtutorials' stars
|
48
|
-
stars # generates @goodtutorials' stars
|
49
|
-
|
50
|
-
You can also get some knowledge dropped all over your face about a specific toot:
|
51
|
-
|
52
|
-
Type the number of the toot that you want to learn about
|
53
|
-
(or hit return to view all again, you ego-maniac) >>
|
54
|
-
14
|
55
|
-
|
56
|
-
5 stars: I wouldn't say I'm "saving daylight" as much as
|
57
|
-
I'm sequestering it in a small room underneath my stairs so
|
58
|
-
its screams can't be heard.
|
59
|
-
|
60
|
-
★ twilighteyes08
|
61
|
-
★ itsjustEm
|
62
|
-
★ aklw
|
63
|
-
★ shariv67
|
64
|
-
★ IsJonas
|
65
|
-
RT kneath
|
66
|
-
|
67
|
-
|
68
|
-
## state of affairs
|
17
|
+
## how
|
69
18
|
|
70
|
-
|
19
|
+
Install with `gem install stars`, then do a quick `stars`, fill in your
|
20
|
+
username for your service, and let it do its sultry magic. This is me lately:
|
21
|
+
|
22
|
+
★ stars
|
23
|
+
+----+---------+-------+-----------------------------------------+
|
24
|
+
| | Service | Stars | The Hotness |
|
25
|
+
+----+---------+-------+-----------------------------------------+
|
26
|
+
| 1 | Convore | 29 | Number of stars received |
|
27
|
+
| 2 | Favstar | 5 | we're flawed because we want so much... |
|
28
|
+
| 3 | Favstar | 3 | Cherish your drunken coworker moment... |
|
29
|
+
| 4 | Favstar | 5 | Usually @kneath teaches me that a li... |
|
30
|
+
| 5 | Favstar | 2 | Whew. Done with cohosting #codeconf.... |
|
31
|
+
| 6 | Favstar | 2 | 1) Guys do lightning talk 2) Mention... |
|
32
|
+
| 7 | Favstar | 1 | I am in a suit, and I'm addressing t... |
|
33
|
+
| 8 | Favstar | 3 | @kneath you have to take a picture o... |
|
34
|
+
| 9 | Favstar | 3 | I won't work until GitHub defunds fr... |
|
35
|
+
| 10 | Favstar | 1 | Coordinating my attire for @codeconf... |
|
36
|
+
| 11 | Favstar | 1 | You are the wind beneath my wings! I... |
|
37
|
+
| 12 | Favstar | 1 | One of those rare San Francisco nigh... |
|
38
|
+
| 13 | Favstar | 1 | @GavinStark Me too! |
|
39
|
+
| 14 | Favstar | 30 | Why @github hacks on side projects: ... |
|
40
|
+
| 15 | Favstar | 1 | @luckiestmonkey all the borg would g... |
|
41
|
+
+----+---------+-------+-----------------------------------------+
|
42
|
+
|
43
|
+
## BONUS ROUND
|
44
|
+
|
45
|
+
Plopped a whopper of a comparison on Convore between Python's whitespacing and
|
46
|
+
the piddly lawyer in Jurassic Park, and want to see the results *right now,
|
47
|
+
dammit??!??!?!?!*? Have no fear! Check your service stars directly with `stars
|
48
|
+
<service>`:
|
49
|
+
|
50
|
+
stars convore
|
51
|
+
|
52
|
+
## whip it out
|
53
|
+
|
54
|
+
`stars` is kind of a silly little project. It's not as well-tested or
|
55
|
+
well-documented as I'd like, but so it goes. Fork, send me a pull request, and
|
56
|
+
we'll all be friends.
|
71
57
|
|
72
58
|
## who
|
73
59
|
|
74
|
-
[@holman](http://twitter.com/holman) did this.
|
60
|
+
[@holman](http://twitter.com/holman) did this. I look great in a Speedo.
|
data/Rakefile
CHANGED
@@ -1,25 +1,50 @@
|
|
1
1
|
require 'rubygems'
|
2
2
|
require 'rake'
|
3
|
+
require 'date'
|
3
4
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
5
|
+
#############################################################################
|
6
|
+
#
|
7
|
+
# Helper functions
|
8
|
+
#
|
9
|
+
#############################################################################
|
10
|
+
|
11
|
+
def name
|
12
|
+
@name ||= Dir['*.gemspec'].first.split('.').first
|
13
|
+
end
|
14
|
+
|
15
|
+
def version
|
16
|
+
line = File.read("lib/#{name}.rb")[/^\s*VERSION\s*=\s*.*/]
|
17
|
+
line.match(/.*VERSION\s*=\s*['"](.*)['"]/)[1]
|
18
|
+
end
|
19
|
+
|
20
|
+
def date
|
21
|
+
Date.today.to_s
|
22
|
+
end
|
23
|
+
|
24
|
+
def rubyforge_project
|
25
|
+
name
|
26
|
+
end
|
27
|
+
|
28
|
+
def gemspec_file
|
29
|
+
"#{name}.gemspec"
|
30
|
+
end
|
31
|
+
|
32
|
+
def gem_file
|
33
|
+
"#{name}-#{version}.gem"
|
34
|
+
end
|
35
|
+
|
36
|
+
def replace_header(head, header_name)
|
37
|
+
head.sub!(/(\.#{header_name}\s*= ').*'/) { "#{$1}#{send(header_name)}'"}
|
21
38
|
end
|
22
39
|
|
40
|
+
#############################################################################
|
41
|
+
#
|
42
|
+
# Standard tasks
|
43
|
+
#
|
44
|
+
#############################################################################
|
45
|
+
|
46
|
+
task :default => :test
|
47
|
+
|
23
48
|
require 'rake/testtask'
|
24
49
|
Rake::TestTask.new(:test) do |test|
|
25
50
|
test.libs << 'lib' << 'test'
|
@@ -27,29 +52,99 @@ Rake::TestTask.new(:test) do |test|
|
|
27
52
|
test.verbose = true
|
28
53
|
end
|
29
54
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
end
|
37
|
-
rescue LoadError
|
38
|
-
task :rcov do
|
39
|
-
abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
|
40
|
-
end
|
55
|
+
desc "Generate RCov test coverage and open in your browser"
|
56
|
+
task :coverage do
|
57
|
+
require 'rcov'
|
58
|
+
sh "rm -fr coverage"
|
59
|
+
sh "rcov test/test_*.rb"
|
60
|
+
sh "open coverage/index.html"
|
41
61
|
end
|
42
62
|
|
43
|
-
task :test => :check_dependencies
|
44
|
-
|
45
|
-
task :default => :test
|
46
|
-
|
47
63
|
require 'rake/rdoctask'
|
48
64
|
Rake::RDocTask.new do |rdoc|
|
49
|
-
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
50
|
-
|
51
65
|
rdoc.rdoc_dir = 'rdoc'
|
52
|
-
rdoc.title = "
|
66
|
+
rdoc.title = "#{name} #{version}"
|
53
67
|
rdoc.rdoc_files.include('README*')
|
54
68
|
rdoc.rdoc_files.include('lib/**/*.rb')
|
55
69
|
end
|
70
|
+
|
71
|
+
desc "Open an irb session preloaded with this library"
|
72
|
+
task :console do
|
73
|
+
sh "irb -rubygems -r ./lib/#{name}.rb"
|
74
|
+
end
|
75
|
+
|
76
|
+
#############################################################################
|
77
|
+
#
|
78
|
+
# Custom tasks (add your own tasks here)
|
79
|
+
#
|
80
|
+
#############################################################################
|
81
|
+
|
82
|
+
|
83
|
+
|
84
|
+
#############################################################################
|
85
|
+
#
|
86
|
+
# Packaging tasks
|
87
|
+
#
|
88
|
+
#############################################################################
|
89
|
+
|
90
|
+
desc "Create tag v#{version} and build and push #{gem_file} to Rubygems"
|
91
|
+
task :release => :build do
|
92
|
+
unless `git branch` =~ /^\* master$/
|
93
|
+
puts "You must be on the master branch to release!"
|
94
|
+
exit!
|
95
|
+
end
|
96
|
+
sh "git commit --allow-empty -a -m 'Release #{version}'"
|
97
|
+
sh "git tag v#{version}"
|
98
|
+
sh "git push origin master"
|
99
|
+
sh "git push origin v#{version}"
|
100
|
+
sh "gem push pkg/#{name}-#{version}.gem"
|
101
|
+
end
|
102
|
+
|
103
|
+
desc "Build #{gem_file} into the pkg directory"
|
104
|
+
task :build => :gemspec do
|
105
|
+
sh "mkdir -p pkg"
|
106
|
+
sh "gem build #{gemspec_file}"
|
107
|
+
sh "mv #{gem_file} pkg"
|
108
|
+
end
|
109
|
+
|
110
|
+
desc "Generate #{gemspec_file}"
|
111
|
+
task :gemspec => :validate do
|
112
|
+
# read spec file and split out manifest section
|
113
|
+
spec = File.read(gemspec_file)
|
114
|
+
head, manifest, tail = spec.split(" # = MANIFEST =\n")
|
115
|
+
|
116
|
+
# replace name version and date
|
117
|
+
replace_header(head, :name)
|
118
|
+
replace_header(head, :version)
|
119
|
+
replace_header(head, :date)
|
120
|
+
#comment this out if your rubyforge_project has a different name
|
121
|
+
replace_header(head, :rubyforge_project)
|
122
|
+
|
123
|
+
# determine file list from git ls-files
|
124
|
+
files = `git ls-files`.
|
125
|
+
split("\n").
|
126
|
+
sort.
|
127
|
+
reject { |file| file =~ /^\./ }.
|
128
|
+
reject { |file| file =~ /^(rdoc|pkg)/ }.
|
129
|
+
map { |file| " #{file}" }.
|
130
|
+
join("\n")
|
131
|
+
|
132
|
+
# piece file back together and write
|
133
|
+
manifest = " s.files = %w[\n#{files}\n ]\n"
|
134
|
+
spec = [head, manifest, tail].join(" # = MANIFEST =\n")
|
135
|
+
File.open(gemspec_file, 'w') { |io| io.write(spec) }
|
136
|
+
puts "Updated #{gemspec_file}"
|
137
|
+
end
|
138
|
+
|
139
|
+
desc "Validate #{gemspec_file}"
|
140
|
+
task :validate do
|
141
|
+
libfiles = Dir['lib/*'] - ["lib/#{name}.rb", "lib/#{name}"]
|
142
|
+
unless libfiles.empty?
|
143
|
+
puts "Directory `lib` should only contain a `#{name}.rb` file and `#{name}` dir."
|
144
|
+
exit!
|
145
|
+
end
|
146
|
+
unless Dir['VERSION*'].empty?
|
147
|
+
puts "A `VERSION` file at root level violates Gem best practices."
|
148
|
+
exit!
|
149
|
+
end
|
150
|
+
end
|
data/bin/stars
CHANGED
data/lib/stars/client.rb
CHANGED
@@ -1,81 +1,98 @@
|
|
1
|
-
#
|
2
|
-
|
1
|
+
# Client is our interface between user and terminal prompt. This does all of
|
2
|
+
# the heavy-lifting for formatting.
|
3
|
+
#
|
3
4
|
module Stars
|
4
5
|
class Client
|
5
|
-
|
6
|
-
def self.load!(new_username=nil)
|
7
|
-
remember_username(new_username) if new_username
|
8
|
-
@recent = Stars::Favstar.new.recent(username)
|
9
|
-
display
|
10
|
-
end
|
11
6
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
7
|
+
attr_reader :posts
|
8
|
+
attr_writer :posts
|
9
|
+
|
10
|
+
# Initializes a new Client.
|
11
|
+
#
|
12
|
+
# Returns nothing.
|
13
|
+
def initialize(cmd)
|
14
|
+
Stars.config.prompt_for_username(cmd[1]) if cmd[0] == 'add'
|
18
15
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
File.exists?(config_path) ? File.read(config_path) : prompt_for_username
|
25
|
-
end
|
26
|
-
|
27
|
-
def self.prompt_for_username
|
28
|
-
puts ""
|
29
|
-
puts ""
|
30
|
-
puts " ★ stars"
|
31
|
-
puts ""
|
32
|
-
puts "Type your Twitter username:"
|
33
|
-
remember_username(self.input.chomp)
|
34
|
-
end
|
35
|
-
|
36
|
-
def self.remember_username(username)
|
37
|
-
File.open(config_path, 'w') {|f| f.write(username) }
|
38
|
-
username
|
39
|
-
end
|
40
|
-
|
41
|
-
def self.config_path
|
42
|
-
File.join(ENV['HOME'], '.stars')
|
16
|
+
system "clear"
|
17
|
+
puts "★ stars"
|
18
|
+
|
19
|
+
display(cmd[0])
|
20
|
+
star_loop
|
43
21
|
end
|
44
|
-
|
45
|
-
|
22
|
+
|
23
|
+
# Run a loop FOREVER until we kill it or we make a selection.
|
24
|
+
#
|
25
|
+
# Returns nothing.
|
26
|
+
def star_loop
|
46
27
|
selection = ''
|
47
28
|
while true
|
48
|
-
puts "Type the number of the
|
29
|
+
puts "Type the number of the post that you want to learn about"
|
49
30
|
print " (or hit return to view all again, you ego-maniac) >> "
|
50
|
-
selection =
|
31
|
+
selection = $stdin.gets.chomp
|
51
32
|
break if ['','q','quit','exit','fuckthis'].include?(selection.downcase)
|
52
|
-
|
33
|
+
show(selection)
|
53
34
|
end
|
54
35
|
display if selection == ''
|
55
36
|
end
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
37
|
+
|
38
|
+
# Displays all of the star tables and information we have.
|
39
|
+
#
|
40
|
+
# Returns nothing.
|
41
|
+
def display(service=nil)
|
42
|
+
Stars.config.prompt_for_service if Stars.installed_services.empty?
|
43
|
+
|
44
|
+
if service
|
45
|
+
posts = service.constantize.posts
|
64
46
|
else
|
65
|
-
|
66
|
-
|
67
|
-
puts ''
|
47
|
+
posts = Stars.installed_services.collect{ |service|
|
48
|
+
service.constantize.posts }.flatten
|
68
49
|
end
|
50
|
+
@posts = Post.filter(posts)
|
51
|
+
puts print_posts(@posts)
|
69
52
|
end
|
70
|
-
|
71
|
-
|
72
|
-
|
53
|
+
|
54
|
+
# Show more information about a particular post.
|
55
|
+
#
|
56
|
+
# id - the Integer id entered by the user, which we map to a Post
|
57
|
+
#
|
58
|
+
# Returns nothing (although does delegate to the Post to show #more).
|
59
|
+
def show(id)
|
60
|
+
post = @posts[id.to_i-1]
|
61
|
+
return puts("\nMake a valid selection. Pretty please?\n") unless post
|
62
|
+
puts post.more
|
63
|
+
display
|
73
64
|
end
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
65
|
+
|
66
|
+
# This does the actual printing of posts.
|
67
|
+
#
|
68
|
+
# posts - an Array of Post objects
|
69
|
+
#
|
70
|
+
# It loops through the Array of posts and sends them to `terminal-table`.
|
71
|
+
def print_posts(posts)
|
72
|
+
table do |t|
|
73
|
+
t.headings = headings
|
74
|
+
posts.each_with_index do |post,i|
|
75
|
+
t << [
|
76
|
+
{ :value => i+1, :alignment => :right },
|
77
|
+
post.service.capitalize,
|
78
|
+
{ :value => post.stars_count, :alignment => :center },
|
79
|
+
post.short_name
|
80
|
+
]
|
81
|
+
end
|
82
|
+
end
|
78
83
|
end
|
79
|
-
|
84
|
+
|
85
|
+
# The headings used in the resulting printed table.
|
86
|
+
#
|
87
|
+
# This returns an Array of headings.
|
88
|
+
def headings
|
89
|
+
[
|
90
|
+
'',
|
91
|
+
'Service',
|
92
|
+
'Stars',
|
93
|
+
{:value => 'The Hotness', :alignment => :center }
|
94
|
+
]
|
95
|
+
end
|
96
|
+
|
80
97
|
end
|
81
98
|
end
|
data/lib/stars/config.rb
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
module Stars
|
2
|
+
class Config
|
3
|
+
|
4
|
+
attr_reader :keep
|
5
|
+
|
6
|
+
attr_writer :keep
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
@keep = Keep.new(config_path)
|
10
|
+
end
|
11
|
+
|
12
|
+
def config_path
|
13
|
+
"#{File.expand_path('~')}/.stars.yml"
|
14
|
+
end
|
15
|
+
|
16
|
+
def username(service)
|
17
|
+
prompt_for_username(service)
|
18
|
+
end
|
19
|
+
|
20
|
+
def prompt_for_service
|
21
|
+
puts "What service do you want to track?"
|
22
|
+
puts "Your options: #{Stars.uninstalled_services.join(', ')}"
|
23
|
+
service = $stdin.gets.chomp.downcase
|
24
|
+
prompt_for_username(service)
|
25
|
+
end
|
26
|
+
|
27
|
+
def prompt_for_username(service)
|
28
|
+
return @keep.get(service) if @keep.present?(service)
|
29
|
+
|
30
|
+
if !Stars.uninstalled_services.empty? and !Stars.uninstalled_services.include?(service.downcase)
|
31
|
+
puts("You need to pick something from: #{Stars.uninstalled_services.join(', ')}")
|
32
|
+
return exit
|
33
|
+
end
|
34
|
+
|
35
|
+
puts "What's your username for #{service}?"
|
36
|
+
username = $stdin.gets.chomp
|
37
|
+
@keep.set(service,username)
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
end
|
data/lib/stars/post.rb
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
module Stars
|
2
|
+
class Post
|
3
|
+
attr_reader :url
|
4
|
+
attr_reader :service
|
5
|
+
attr_reader :stars_count
|
6
|
+
attr_reader :date
|
7
|
+
|
8
|
+
attr_writer :name
|
9
|
+
attr_writer :service
|
10
|
+
attr_writer :url
|
11
|
+
attr_writer :stars
|
12
|
+
attr_writer :stars_count
|
13
|
+
attr_writer :date
|
14
|
+
|
15
|
+
def initialize(attributes)
|
16
|
+
@name = attributes[:name]
|
17
|
+
@url = attributes[:url]
|
18
|
+
@stars = attributes[:stars]
|
19
|
+
@stars_count = attributes[:stars_count]
|
20
|
+
@service = attributes[:service]
|
21
|
+
@date = attributes[:date]
|
22
|
+
end
|
23
|
+
|
24
|
+
# The String name of the Post.
|
25
|
+
#
|
26
|
+
# This returns the String of the content of the Post (which we just call
|
27
|
+
# "name"). We also strip whitespace, since it tends to screw up things on
|
28
|
+
# the command line.
|
29
|
+
def name
|
30
|
+
@name.gsub("\n",' ')
|
31
|
+
end
|
32
|
+
|
33
|
+
# The shorted String version of `name`.
|
34
|
+
#
|
35
|
+
# Returns a String of the name truncated at 35 characters.
|
36
|
+
def short_name
|
37
|
+
name.size > 35 ? "#{name[0..35]}..." : name
|
38
|
+
end
|
39
|
+
|
40
|
+
def stars
|
41
|
+
@stars
|
42
|
+
end
|
43
|
+
|
44
|
+
def more
|
45
|
+
service.constantize.more(self)
|
46
|
+
end
|
47
|
+
|
48
|
+
# Filter an Array of Post objects.
|
49
|
+
#
|
50
|
+
# posts - an Array of Post objects to filter
|
51
|
+
#
|
52
|
+
# This returns the Array sorted by the 15 most recent stars.
|
53
|
+
def self.filter(posts)
|
54
|
+
posts.sort{ |a,b| b.date <=> a.date }[0..14]
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Stars
|
2
|
+
class Convore < Service
|
3
|
+
|
4
|
+
attr_reader :posts
|
5
|
+
|
6
|
+
def name
|
7
|
+
"convore"
|
8
|
+
end
|
9
|
+
|
10
|
+
def posts
|
11
|
+
[Post.new(:name => "Number of stars received",
|
12
|
+
:stars_count => stars,
|
13
|
+
:service => name,
|
14
|
+
:date => DateTime.now,
|
15
|
+
:url => "https://convore.com/users/#{Stars.config.username('convore')}")]
|
16
|
+
end
|
17
|
+
|
18
|
+
def html
|
19
|
+
Nokogiri::HTML(open("https://convore.com/users/#{username}"))
|
20
|
+
end
|
21
|
+
|
22
|
+
def stars
|
23
|
+
html.css('.stars-received strong').first.content.to_i
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.more(post)
|
27
|
+
return <<-CONVORE
|
28
|
+
|
29
|
+
Convore doesn't have a stars API yet. So we're just scraping your total stars
|
30
|
+
for now. Kind of a bummer, isn't it? You should probably send @ericflo a tweet
|
31
|
+
and complain about it. Tell him I didn't send you.
|
32
|
+
|
33
|
+
Anyway, you have #{post.stars_count} stars with Convore right now. Check it:
|
34
|
+
#{post.url}
|
35
|
+
|
36
|
+
CONVORE
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
end
|