ruby-hackernews 1.3.3 → 1.3.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +15 -0
- data/.gitignore +21 -0
- data/Gemfile +10 -0
- data/README.rdoc +4 -0
- data/Rakefile +5 -25
- data/lib/ruby-hackernews.rb +2 -0
- data/lib/ruby-hackernews/domain/comment/comment.rb +22 -3
- data/lib/ruby-hackernews/domain/entry/entry.rb +14 -0
- data/lib/ruby-hackernews/domain/entry/time_info.rb +3 -2
- data/lib/ruby-hackernews/services/comment_service.rb +16 -8
- data/lib/ruby-hackernews/services/configuration_service.rb +8 -0
- data/lib/ruby-hackernews/services/entry_service.rb +16 -3
- data/lib/ruby-hackernews/version.rb +3 -0
- data/ruby-hackernews.gemspec +27 -0
- data/spec/HNAPI/domain/time_info_spec.rb +47 -0
- data/spec/HNAPI/services/entries/entry_service_spec.rb +50 -0
- data/spec/HNAPI/services/entries/parsers/comments_info_parser_spec.rb +42 -0
- data/spec/HNAPI/services/entries/parsers/entry_page_parser_spec.rb +26 -0
- data/spec/HNAPI/services/entries/parsers/entry_parser_spec.rb +53 -0
- data/spec/HNAPI/services/entries/parsers/hn_test_page.html +36 -0
- data/spec/HNAPI/services/entries/parsers/link_info_parser_spec.rb +44 -0
- data/spec/HNAPI/services/entries/parsers/parser_helper.rb +77 -0
- data/spec/HNAPI/services/entries/parsers/time_info_parser_spec.rb +25 -0
- data/spec/HNAPI/services/entries/parsers/user_info_parser_spec.rb +26 -0
- data/spec/HNAPI/services/entries/parsers/voting_info_parser_spec.rb +48 -0
- data/spec/HNAPI/services/mechanize_context_spec.rb +67 -0
- data/spec/spec_helper.rb +7 -0
- metadata +82 -29
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
NDk5ZmI0Zjc1YzU2M2Y5NTA1NTM4YmEwZTFjYWJjODMyMWViMjVlYQ==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
NGMyOTJiN2U3ZGJlNjEzNzUzZGNlOTIzZjQ2ZDRiNWNmZWRhN2MwYw==
|
7
|
+
!binary "U0hBNTEy":
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
NTk4NTUzMWVkYmRhYzdmZDA3OGRjZTY2MDE3MmFhNTZkYmUxM2FjMWVmMDlh
|
10
|
+
MTJiYTZlNWU5YmE3ZmI2MTY3NzBkNGMzODA2ODczYTViYzQ0YWNhMzZmOTNi
|
11
|
+
NDllMWRmN2RhMGM4NTQ5NzViZjQyZjFiNjhmM2I0NTYxNTRkOTM=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
ZmRjM2E4Y2Q5MDFiODliY2JmMzA1YzVlYTUzM2FhMzBhYWIyMTRhMWM1MjRh
|
14
|
+
ZGQzYmIwNDBiNzViZmQ2YTk3MjczZTE0YzhkMDEzZWRjNjAxOWQ4NDVkMDg5
|
15
|
+
NTliZDI2Y2UwMmU3MDBhOTUzNmUzYzJjMmVhMGRlNWU5MDY1YzA=
|
data/.gitignore
ADDED
data/Gemfile
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
source 'https://rubygems.org'
|
2
|
+
|
3
|
+
group :development do
|
4
|
+
# rspec is here and not in gemspec, because :require is not supported there
|
5
|
+
# put every other gem in gemspec
|
6
|
+
gem 'rspec', :require => "spec"
|
7
|
+
end
|
8
|
+
|
9
|
+
# Specify your gem's dependencies in ruby-hackernews.gemspec
|
10
|
+
gemspec
|
data/README.rdoc
CHANGED
@@ -38,6 +38,8 @@ There are methods for getting specific entry types:
|
|
38
38
|
Entry.questions # gets the first page of questions (ask NH)
|
39
39
|
Entry.newest # gets the first page of new links (new)
|
40
40
|
Entry.jobs # gets the first page of job offerts (jobs)
|
41
|
+
Entry.shows # gets the first page of shows (show HN)
|
42
|
+
Entry.new_shows # gets the first page of new shows (show HN new)
|
41
43
|
|
42
44
|
You can also get a single entry by its ID:
|
43
45
|
|
@@ -160,6 +162,7 @@ Will return the HN comment url of the last submitted story of that user
|
|
160
162
|
|
161
163
|
== THANKS TO
|
162
164
|
|
165
|
+
- Anton Katunin ( https://github.com/antulik ) for adding the gemfile and putting all specs into modules
|
163
166
|
- Mike Kelly ( https://github.com/mikekelly ) for fixing a bug in TimeInfo.time
|
164
167
|
- Marc Köhlbrugge ( http://github.com/marckohlbrugge ) fox fixing and formatting the documentation
|
165
168
|
- Peter Cooper ( http://github.com/peterc ) for bug reports
|
@@ -168,3 +171,4 @@ Will return the HN comment url of the last submitted story of that user
|
|
168
171
|
- Wayne ( http://github.com/BlissOfBeing ) for adding User.submissions, Entry.comments_url and cleaning up the Rakefile
|
169
172
|
- Daniel Da Cunha ( http://github.com/ddacunha ) for a fix on Entry#comments_count
|
170
173
|
- Nathan Campos ( http://github.com/nathanpc) for adding #text to Entry
|
174
|
+
- Girish Sonawane ( https://github.com/girishso) for adding Entry#shows and Entry#new_shows methods
|
data/Rakefile
CHANGED
@@ -1,28 +1,8 @@
|
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
require "bundler/gem_tasks"
|
1
3
|
|
2
|
-
require '
|
3
|
-
require 'rake'
|
4
|
-
require 'rake/clean'
|
5
|
-
require 'rubygems/package_task'
|
6
|
-
require 'rdoc/task'
|
7
|
-
require 'rake/testtask'
|
4
|
+
require 'rspec/core/rake_task'
|
8
5
|
|
9
|
-
|
10
|
-
s.name = 'ruby-hackernews'
|
11
|
-
s.version = '1.3.3'
|
12
|
-
s.add_dependency('require_all', '>= 1.1.0')
|
13
|
-
s.add_dependency('mechanize', '>= 1.0.0')
|
14
|
-
s.has_rdoc = false
|
15
|
-
s.homepage = "http://github.com/bolthar/ruby-hackernews"
|
16
|
-
s.summary = 'An interface to Hacker News'
|
17
|
-
s.description = s.summary
|
18
|
-
s.author = 'Andrea Dallera'
|
19
|
-
s.email = 'andrea@andreadallera.com'
|
20
|
-
s.files = %w(README.rdoc Rakefile) + Dir.glob("{lib}/**/*")
|
21
|
-
s.require_path = "lib"
|
22
|
-
end
|
6
|
+
RSpec::Core::RakeTask.new('spec')
|
23
7
|
|
24
|
-
|
25
|
-
p.gem_spec = spec
|
26
|
-
p.need_tar = true
|
27
|
-
p.need_zip = true
|
28
|
-
end
|
8
|
+
task :default => :spec
|
data/lib/ruby-hackernews.rb
CHANGED
@@ -3,18 +3,19 @@ module RubyHackernews
|
|
3
3
|
class Comment
|
4
4
|
include Enumerable
|
5
5
|
|
6
|
-
attr_reader :
|
6
|
+
attr_reader :text_html
|
7
7
|
attr_reader :voting
|
8
8
|
attr_reader :user
|
9
9
|
|
10
10
|
attr_accessor :parent
|
11
11
|
|
12
|
-
def initialize(
|
13
|
-
@
|
12
|
+
def initialize(text_html, voting, user_info, reply_link, absolute_link, parent_link)
|
13
|
+
@text_html = text_html
|
14
14
|
@voting = voting
|
15
15
|
@user = user_info
|
16
16
|
@reply_link = reply_link
|
17
17
|
@absolute_link = absolute_link
|
18
|
+
@parent_link = parent_link
|
18
19
|
@children = []
|
19
20
|
end
|
20
21
|
|
@@ -22,6 +23,18 @@ module RubyHackernews
|
|
22
23
|
return @absolute_link.split("=")[1].to_i
|
23
24
|
end
|
24
25
|
|
26
|
+
def parent_id
|
27
|
+
if parent
|
28
|
+
parent.id
|
29
|
+
elsif @parent_link
|
30
|
+
@parent_link[/\d+/].to_i
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def text
|
35
|
+
@text ||= text_html.gsub(/<.{1,2}>/, "")
|
36
|
+
end
|
37
|
+
|
25
38
|
def <<(comment)
|
26
39
|
comment.parent = self
|
27
40
|
@children << comment
|
@@ -43,6 +56,12 @@ module RubyHackernews
|
|
43
56
|
return CommentService.new.get_new_comments(pages)
|
44
57
|
end
|
45
58
|
|
59
|
+
def self.newest_with_extra(pages = 1, url = nil)
|
60
|
+
args = [pages]
|
61
|
+
args << url unless url.nil?
|
62
|
+
return CommentService.new.get_new_comments_with_extra *args
|
63
|
+
end
|
64
|
+
|
46
65
|
def self.find(id)
|
47
66
|
return CommentService.new.find_by_id(id)
|
48
67
|
end
|
@@ -39,6 +39,12 @@ module RubyHackernews
|
|
39
39
|
return EntryService.new.get_new_entries(pages)
|
40
40
|
end
|
41
41
|
|
42
|
+
def self.newest_with_extra(pages = 1, url = nil)
|
43
|
+
args = [pages]
|
44
|
+
args << url unless url.nil?
|
45
|
+
return EntryService.new.get_entries_with_extra *args
|
46
|
+
end
|
47
|
+
|
42
48
|
def self.questions(pages = 1)
|
43
49
|
return EntryService.new.get_questions(pages)
|
44
50
|
end
|
@@ -47,6 +53,14 @@ module RubyHackernews
|
|
47
53
|
return EntryService.new.get_jobs(pages)
|
48
54
|
end
|
49
55
|
|
56
|
+
def self.shows(pages = 1)
|
57
|
+
return EntryService.new.get_shows(pages)
|
58
|
+
end
|
59
|
+
|
60
|
+
def self.new_shows(pages = 1)
|
61
|
+
return EntryService.new.get_new_shows(pages)
|
62
|
+
end
|
63
|
+
|
50
64
|
def self.find(id)
|
51
65
|
return EntryService.new.find_by_id(id)
|
52
66
|
end
|
@@ -11,10 +11,11 @@ module RubyHackernews
|
|
11
11
|
return Time.now - @unit_of_measure * @value
|
12
12
|
end
|
13
13
|
|
14
|
-
def initialize(value, unit_of_measure)
|
14
|
+
def initialize(value, unit_of_measure)
|
15
15
|
@value = value
|
16
16
|
if(unit_of_measure)
|
17
|
-
descriptor = unit_of_measure
|
17
|
+
descriptor = unit_of_measure
|
18
|
+
descriptor = unit_of_measure[0..-2] if unit_of_measure[-1].chr == 's'
|
18
19
|
@unit_of_measure = self.class.const_get(descriptor.upcase)
|
19
20
|
end
|
20
21
|
end
|
@@ -28,11 +28,12 @@ module RubyHackernews
|
|
28
28
|
comments = []
|
29
29
|
target = comments
|
30
30
|
current_level = 0
|
31
|
-
table.search("table/tr").select do |tr|
|
31
|
+
trs = table.search("table/tr").select do |tr|
|
32
32
|
tr.search("span.comment").inner_html != "[deleted]"
|
33
|
-
end
|
33
|
+
end
|
34
|
+
trs.each do |tr|
|
34
35
|
comment = parse_comment(tr)
|
35
|
-
level = tr.search("img[@src='
|
36
|
+
level = tr.search("img[@src='s.gif']").first['width'].to_i / 40
|
36
37
|
difference = current_level - level
|
37
38
|
(difference + 1).times do
|
38
39
|
target = target.kind_of?(Comment) && target.parent ? target.parent : comments
|
@@ -45,8 +46,13 @@ module RubyHackernews
|
|
45
46
|
end
|
46
47
|
|
47
48
|
def get_new_comments(pages = 1, url = ConfigurationService.comments_url)
|
49
|
+
get_new_comments_with_extra(pages,url)[:comments]
|
50
|
+
end
|
51
|
+
|
52
|
+
def get_new_comments_with_extra(pages = 1, url = ConfigurationService.comments_url)
|
48
53
|
parser = EntryPageParser.new(agent.get(url))
|
49
54
|
comments = []
|
55
|
+
next_url = nil
|
50
56
|
pages.times do
|
51
57
|
lines = parser.get_lines
|
52
58
|
lines.each do |line|
|
@@ -55,22 +61,24 @@ module RubyHackernews
|
|
55
61
|
next_url = parser.get_next_url || break
|
56
62
|
parser = EntryPageParser.new(agent.get(next_url))
|
57
63
|
end
|
58
|
-
return comments
|
64
|
+
return {:comments => comments, :next_url => next_url}
|
59
65
|
end
|
60
66
|
|
61
67
|
def parse_comment(element)
|
62
|
-
|
68
|
+
text_html = ""
|
63
69
|
element.search("span.comment").first.children.each do |ch|
|
64
|
-
|
70
|
+
text_html = ch.inner_html
|
65
71
|
end
|
66
72
|
header = element.search("span.comhead").first
|
67
73
|
voting = VotingInfoParser.new(element.search("td/center/a"), header).parse
|
68
74
|
user_info = UserInfoParser.new(header).parse
|
69
75
|
reply_link = element.search("td[@class='default']/p//u//a").first
|
70
|
-
reply_url = reply_link['href'] if reply_link
|
76
|
+
reply_url = reply_link['href'] if reply_link
|
71
77
|
absolute_link_group = header.search("a")
|
72
78
|
absolute_url = absolute_link_group.count == 2 ? absolute_link_group[1]['href'] : nil
|
73
|
-
|
79
|
+
parent_link = header.search("a[text()*='parent']").first
|
80
|
+
parent_url = parent_link['href'] if parent_link
|
81
|
+
return Comment.new(text_html, voting, user_info, reply_url, absolute_url, parent_url)
|
74
82
|
end
|
75
83
|
|
76
84
|
def write_comment(page_url, comment)
|
@@ -22,6 +22,14 @@ module RubyHackernews
|
|
22
22
|
return File.join(self.base_url, "jobs")
|
23
23
|
end
|
24
24
|
|
25
|
+
def self.show_url
|
26
|
+
return File.join(self.base_url, "show")
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.new_shows_url
|
30
|
+
return File.join(self.base_url, "shownew")
|
31
|
+
end
|
32
|
+
|
25
33
|
def self.comments_url
|
26
34
|
return File.join(self.base_url, "newcomments")
|
27
35
|
end
|
@@ -4,8 +4,13 @@ module RubyHackernews
|
|
4
4
|
include MechanizeContext
|
5
5
|
|
6
6
|
def get_entries(pages = 1, url = ConfigurationService.base_url)
|
7
|
+
get_entries_with_extra(pages, url)[:entries]
|
8
|
+
end
|
9
|
+
|
10
|
+
def get_entries_with_extra(pages = 1, url = ConfigurationService.base_url)
|
7
11
|
parser = EntryPageParser.new(agent.get(url))
|
8
12
|
entry_infos = []
|
13
|
+
next_url = nil
|
9
14
|
pages.times do
|
10
15
|
lines = parser.get_lines
|
11
16
|
(lines.length / 2).times do
|
@@ -14,7 +19,7 @@ module RubyHackernews
|
|
14
19
|
next_url = parser.get_next_url || break
|
15
20
|
parser = EntryPageParser.new(agent.get(next_url))
|
16
21
|
end
|
17
|
-
return entry_infos
|
22
|
+
return {:entries => entry_infos, :next_url => next_url}
|
18
23
|
end
|
19
24
|
|
20
25
|
def find_by_id(id)
|
@@ -34,7 +39,15 @@ module RubyHackernews
|
|
34
39
|
def get_jobs(pages = 1)
|
35
40
|
return get_entries(pages, ConfigurationService.jobs_url)
|
36
41
|
end
|
37
|
-
|
42
|
+
|
43
|
+
def get_shows(pages = 1)
|
44
|
+
return get_entries(pages, ConfigurationService.show_url)
|
45
|
+
end
|
46
|
+
|
47
|
+
def get_new_shows(pages = 1)
|
48
|
+
return get_entries(pages, ConfigurationService.new_shows_url)
|
49
|
+
end
|
50
|
+
|
38
51
|
def submit(title, url)
|
39
52
|
require_authentication
|
40
53
|
form = agent.get(ConfigurationService.submit_url).forms.first
|
@@ -61,7 +74,7 @@ module RubyHackernews
|
|
61
74
|
form.x = text
|
62
75
|
form.submit
|
63
76
|
end
|
64
|
-
|
77
|
+
|
65
78
|
end
|
66
79
|
|
67
80
|
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'ruby-hackernews/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "ruby-hackernews"
|
8
|
+
spec.version = RubyHackernews::VERSION
|
9
|
+
spec.authors = ["Andrea Dallera"]
|
10
|
+
spec.email = ["andrea@andreadallera.com"]
|
11
|
+
spec.description = %q{An interface to Hacker News}
|
12
|
+
spec.summary = %q{An interface to Hacker News}
|
13
|
+
spec.homepage = "http://github.com/blissofbeing/ruby-hackernews"
|
14
|
+
|
15
|
+
spec.files = `git ls-files`.split($/)
|
16
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
17
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
18
|
+
spec.require_paths = ["lib"]
|
19
|
+
|
20
|
+
spec.has_rdoc = false
|
21
|
+
|
22
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
23
|
+
spec.add_development_dependency "rake"
|
24
|
+
|
25
|
+
spec.add_dependency('require_all', '>= 1.1.0')
|
26
|
+
spec.add_dependency('mechanize', '>= 1.0.0')
|
27
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module RubyHackernews
|
4
|
+
describe TimeInfo do
|
5
|
+
|
6
|
+
before :all do
|
7
|
+
class RubyHackernews::TimeInfo
|
8
|
+
DUMMY = 10
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
describe :initialize do
|
13
|
+
|
14
|
+
it "should set unit_of_measure as uppercase descriptor const if singular" do
|
15
|
+
timeinfo = TimeInfo.new(5, "dummy")
|
16
|
+
timeinfo.instance_variable_get(:@unit_of_measure).should == 10
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should set unit_of_measure as uppercase minus last s descriptor const if plural" do
|
20
|
+
timeinfo = TimeInfo.new(5, "dummys")
|
21
|
+
timeinfo.instance_variable_get(:@unit_of_measure).should == 10
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
describe :time do
|
27
|
+
|
28
|
+
it "should return right amount when passed seconds" do
|
29
|
+
TimeInfo.new(15, "seconds").time.round.should == (Time.now - 15).round
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should return right amount when passed minutes" do
|
33
|
+
TimeInfo.new(24, "minutes").time.round.should == (Time.now - 24*60).round
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should return right amount when passed hours" do
|
37
|
+
TimeInfo.new(3, "hours").time.round.should == (Time.now - 3*3600).round
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should return right amount when passed days" do
|
41
|
+
TimeInfo.new(16, "days").time.round.should == (Time.now - 16*86400).round
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
#useless purely integration tests... remove?
|
4
|
+
module RubyHackernews
|
5
|
+
describe EntryService do
|
6
|
+
|
7
|
+
describe :get_entries do
|
8
|
+
|
9
|
+
it "should always call EntryPageParser with current agent" do
|
10
|
+
parser = stub()
|
11
|
+
parser.should_receive(:get_lines).and_return([])
|
12
|
+
parser.should_receive(:get_next_url).and_return(nil)
|
13
|
+
agent = stub()
|
14
|
+
agent.should_receive(:get).any_number_of_times.and_return(:page)
|
15
|
+
MechanizeContext.create(:default, agent)
|
16
|
+
service = EntryService.new
|
17
|
+
EntryPageParser.should_receive(:new).any_number_of_times.with(:page).and_return(parser)
|
18
|
+
service.get_entries
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should always call get_lines 'pages' number of times" do
|
22
|
+
pages = 5
|
23
|
+
parser = stub()
|
24
|
+
parser.should_receive(:get_lines).exactly(pages).times.and_return([])
|
25
|
+
parser.should_receive(:get_next_url).any_number_of_times.and_return(nil)
|
26
|
+
agent = stub()
|
27
|
+
agent.should_receive(:get).any_number_of_times.and_return(:page)
|
28
|
+
MechanizeContext.create(:default, agent)
|
29
|
+
service = EntryService.new
|
30
|
+
EntryPageParser.should_receive(:new).any_number_of_times.with(:page).and_return(parser)
|
31
|
+
service.get_entries(pages)
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should always call get_next_url 'pages' number of times" do
|
35
|
+
pages = 5
|
36
|
+
parser = stub()
|
37
|
+
parser.should_receive(:get_lines).any_number_of_times.and_return([])
|
38
|
+
parser.should_receive(:get_next_url).exactly(pages).times.and_return(nil)
|
39
|
+
agent = stub()
|
40
|
+
agent.should_receive(:get).any_number_of_times.and_return(:page)
|
41
|
+
MechanizeContext.create(:default, agent)
|
42
|
+
service = EntryService.new
|
43
|
+
EntryPageParser.should_receive(:new).any_number_of_times.with(:page).and_return(parser)
|
44
|
+
service.get_entries(pages)
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require File.expand_path(File.dirname(__FILE__) + '/parser_helper')
|
3
|
+
|
4
|
+
module RubyHackernews
|
5
|
+
describe CommentsInfoParser do
|
6
|
+
|
7
|
+
before(:each) do
|
8
|
+
@line = ParserHelper.second_line
|
9
|
+
@comment_link = "item?id=1645686"
|
10
|
+
end
|
11
|
+
|
12
|
+
describe :parse do
|
13
|
+
|
14
|
+
it "should not call CommentsInfo.new if comment tag is missing" do
|
15
|
+
parser = CommentsInfoParser.new(ParserHelper.second_line_comments_tag_missing)
|
16
|
+
CommentsInfo.should_not_receive(:new)
|
17
|
+
parser.parse
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should call CommentsInfo.new with comments count if not 'discuss'" do
|
21
|
+
parser = CommentsInfoParser.new(@line)
|
22
|
+
CommentsInfo.should_receive(:new).with(2, anything)
|
23
|
+
parser.parse
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should call CommentsInfo.new with 0 if is 'discuss'" do
|
27
|
+
parser = CommentsInfoParser.new(ParserHelper.second_line_no_comments_yet)
|
28
|
+
CommentsInfo.should_receive(:new).with(0, anything)
|
29
|
+
parser.parse
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should call CommentsInfo.new with comment link" do
|
33
|
+
parser = CommentsInfoParser.new(@line)
|
34
|
+
CommentsInfo.should_receive(:new).with(anything, @comment_link)
|
35
|
+
parser.parse
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require File.expand_path(File.dirname(__FILE__) + '/parser_helper')
|
3
|
+
|
4
|
+
module RubyHackernews
|
5
|
+
describe EntryPageParser do
|
6
|
+
|
7
|
+
before :each do
|
8
|
+
@page = ParserHelper.full_page
|
9
|
+
end
|
10
|
+
|
11
|
+
describe :get_lines do
|
12
|
+
it "should always return 60 elements" do
|
13
|
+
lines = EntryPageParser.new(@page).get_lines
|
14
|
+
lines.length.should == 60
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
describe :get_next_url do
|
19
|
+
it "should get the url in 'More' element" do
|
20
|
+
url = EntryPageParser.new(@page).get_next_url
|
21
|
+
url.should == "/x?fnid=9LO1ba1swy"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require File.expand_path(File.dirname(__FILE__) + '/parser_helper')
|
3
|
+
|
4
|
+
module RubyHackernews
|
5
|
+
describe EntryParser do
|
6
|
+
|
7
|
+
before(:each) do
|
8
|
+
@first_line = ParserHelper.first_line_full
|
9
|
+
@second_line = ParserHelper.second_line_full
|
10
|
+
end
|
11
|
+
|
12
|
+
describe :parse do
|
13
|
+
|
14
|
+
it "should call Entry.new with the right number" do
|
15
|
+
parser = EntryParser.new(@first_line, @second_line)
|
16
|
+
Entry.should_receive(:new).with(2, anything, anything, anything, anything, anything)
|
17
|
+
parser.parse
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should return an entry with correct link" do
|
21
|
+
parser = EntryParser.new(@first_line, @second_line)
|
22
|
+
entry = parser.parse
|
23
|
+
entry.link.title.should == "The Tragic Death of Practically Everything"
|
24
|
+
entry.link.href.should == "http://technologizer.com/2010/08/18/the-tragic-death-of-practically-everything/"
|
25
|
+
entry.link.site.should == "technologizer.com"
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should return an entry with correct voting" do
|
29
|
+
parser = EntryParser.new(@first_line, @second_line)
|
30
|
+
entry = parser.parse
|
31
|
+
entry.voting.upvote.should == "vote?for=1645745&dir=up&whence=%6e%65%77%73"
|
32
|
+
entry.voting.downvote.should be_nil
|
33
|
+
entry.voting.score.should == 59
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should return an entry with correct user" do
|
37
|
+
parser = EntryParser.new(@first_line, @second_line)
|
38
|
+
entry = parser.parse
|
39
|
+
entry.user.name.should == "dhotson"
|
40
|
+
entry.user.page.should == "user?id=dhotson"
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should return an entry with correct time" do
|
44
|
+
parser = EntryParser.new(@first_line, @second_line)
|
45
|
+
entry = parser.parse
|
46
|
+
entry.time.round.should == (Time.now - 3600*4).round
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
@@ -0,0 +1,36 @@
|
|
1
|
+
<html><head><link rel="stylesheet" type="text/css" href="http://ycombinator.com/news.css">
|
2
|
+
<link rel="shortcut icon" href="http://ycombinator.com/favicon.ico">
|
3
|
+
<script>
|
4
|
+
function byId(id) {
|
5
|
+
return document.getElementById(id);
|
6
|
+
}
|
7
|
+
|
8
|
+
function vote(node) {
|
9
|
+
var v = node.id.split(/_/); // {'up', '123'}
|
10
|
+
var item = v[1];
|
11
|
+
|
12
|
+
// adjust score
|
13
|
+
var score = byId('score_' + item);
|
14
|
+
var newscore = parseInt(score.innerHTML) + (v[0] == 'up' ? 1 : -1);
|
15
|
+
score.innerHTML = newscore + (newscore == 1 ? ' point' : ' points');
|
16
|
+
|
17
|
+
// hide arrows
|
18
|
+
byId('up_' + item).style.visibility = 'hidden';
|
19
|
+
byId('down_' + item).style.visibility = 'hidden';
|
20
|
+
|
21
|
+
// ping server
|
22
|
+
var ping = new Image();
|
23
|
+
ping.src = node.href;
|
24
|
+
|
25
|
+
return false; // cancel browser nav
|
26
|
+
} </script><title>Hacker News</title></head><body><center><table border=0 cellpadding=0 cellspacing=0 width="85%" bgcolor=#f6f6ef><tr><td bgcolor=#ff6600><table border=0 cellpadding=0 cellspacing=0 width="100%" style="padding:2px"><tr><td style="width:18px;padding-right:4px"><a href="http://ycombinator.com"><img src="http://ycombinator.com/images/y18.gif" width=18 height=18 style="border:1px #ffffff solid;"></img></a></td><td style="line-height:12pt; height:10px;"><span class="pagetop"><b><a href="news">Hacker News</a></b><img src="http://ycombinator.com/images/s.gif" height=1 width=10><a href="newest">new</a> | <a href="newcomments">comments</a> | <a href="ask">ask</a> | <a href="jobs">jobs</a> | <a href="submit">submit</a></span></td><td style="text-align:right;padding-right:4px;"><span class="pagetop"><a href="/x?fnid=aGDlLvxj45">login</a></span></td></tr></table></td></tr><tr style="height:10px"></tr><tr><td><table border=0 cellpadding=0 cellspacing=0><tr><td align=right valign=top class="title">1.</td><td><center><a id=up_1645934 href="vote?for=1645934&dir=up&whence=%6e%65%77%73"><img src="http://ycombinator.com/images/grayarrow.gif" border=0 vspace=3 hspace=2></a><span id=down_1645934></span></center></td><td class="title"><a href="http://hackaday.com/2010/08/29/seaswarm-we-can-clean-up-the-gulf-in-a-month/">Seaswarm: we can clean up the Gulf in a month</a><span class="comhead"> (hackaday.com) </span></td></tr><tr><td colspan=2></td><td class="subtext"><span id=score_1645934>30 points</span> by <a href="user?id=IgorPartola">IgorPartola</a> 1 hour ago | <a href="item?id=1645934">10 comments</a></td></tr><tr style="height:5px"></tr><tr><td align=right valign=top class="title">2.</td><td><center><a id=up_1645745 href="vote?for=1645745&dir=up&whence=%6e%65%77%73"><img src="http://ycombinator.com/images/grayarrow.gif" border=0 vspace=3 hspace=2></a><span id=down_1645745></span></center></td><td class="title"><a href="http://technologizer.com/2010/08/18/the-tragic-death-of-practically-everything/">The Tragic Death of Practically Everything</a><span class="comhead"> (technologizer.com) </span></td></tr><tr><td colspan=2></td><td class="subtext"><span id=score_1645745>59 points</span> by <a href="user?id=dhotson">dhotson</a> 4 hours ago | <a href="item?id=1645745">5 comments</a></td></tr><tr style="height:5px"></tr><tr><td align=right valign=top class="title">3.</td><td><center><a id=up_1645820 href="vote?for=1645820&dir=up&whence=%6e%65%77%73"><img src="http://ycombinator.com/images/grayarrow.gif" border=0 vspace=3 hspace=2></a><span id=down_1645820></span></center></td><td class="title"><a href="http://github.com/resistor/BrainFTracing">I wrote an LLVM-powered trace-based JIT for Brainf**k</a><span class="comhead"> (github.com) </span></td></tr><tr><td colspan=2></td><td class="subtext"><span id=score_1645820>31 points</span> by <a href="user?id=Halienja">Halienja</a> 3 hours ago | <a href="item?id=1645820">21 comments</a></td></tr><tr style="height:5px"></tr><tr><td align=right valign=top class="title">4.</td><td><center><a id=up_1646087 href="vote?for=1646087&dir=up&whence=%6e%65%77%73"><img src="http://ycombinator.com/images/grayarrow.gif" border=0 vspace=3 hspace=2></a><span id=down_1646087></span></center></td><td class="title"><a href="http://www.inc.com/magazine/20100901/the-truth-about-real-estate.html">Jason Fried: The Truth About Real Estate</a><span class="comhead"> (inc.com) </span></td></tr><tr><td colspan=2></td><td class="subtext"><span id=score_1646087>6 points</span> by <a href="user?id=slater">slater</a> 27 minutes ago | <a href="item?id=1646087">discuss</a></td></tr><tr style="height:5px"></tr><tr><td align=right valign=top class="title">5.</td><td><center><a id=up_1644876 href="vote?for=1644876&dir=up&whence=%6e%65%77%73"><img src="http://ycombinator.com/images/grayarrow.gif" border=0 vspace=3 hspace=2></a><span id=down_1644876></span></center></td><td class="title"><a href="http://weblog.rubyonrails.org/2010/8/29/rails-3-0-it-s-done">Rails 3.0: It's ready</a><span class="comhead"> (rubyonrails.org) </span></td></tr><tr><td colspan=2></td><td class="subtext"><span id=score_1644876>313 points</span> by <a href="user?id=steveklabnik">steveklabnik</a> 14 hours ago | <a href="item?id=1644876">51 comments</a></td></tr><tr style="height:5px"></tr><tr><td align=right valign=top class="title">6.</td><td><center><a id=up_1646096 href="vote?for=1646096&dir=up&whence=%6e%65%77%73"><img src="http://ycombinator.com/images/grayarrow.gif" border=0 vspace=3 hspace=2></a><span id=down_1646096></span></center></td><td class="title"><a href="http://people.csail.mit.edu/pgbovine/python/" rel="nofollow">Python Visual Tutorial</a><span class="comhead"> (mit.edu) </span></td></tr><tr><td colspan=2></td><td class="subtext"><span id=score_1646096>5 points</span> by <a href="user?id=prog">prog</a> 23 minutes ago | <a href="item?id=1646096">discuss</a></td></tr><tr style="height:5px"></tr><tr><td align=right valign=top class="title">7.</td><td><center><a id=up_1645911 href="vote?for=1645911&dir=up&whence=%6e%65%77%73"><img src="http://ycombinator.com/images/grayarrow.gif" border=0 vspace=3 hspace=2></a><span id=down_1645911></span></center></td><td class="title"><a href="http://mortenjust.com/2010/08/30/finding-out-which-things-to-throw-out/">Flow chart: How to find out which things to throw out</a><span class="comhead"> (mortenjust.com) </span></td></tr><tr><td colspan=2></td><td class="subtext"><span id=score_1645911>14 points</span> by <a href="user?id=mortenjust">mortenjust</a> 2 hours ago | <a href="item?id=1645911">6 comments</a></td></tr><tr style="height:5px"></tr><tr><td align=right valign=top class="title">8.</td><td><center><a id=up_1645929 href="vote?for=1645929&dir=up&whence=%6e%65%77%73"><img src="http://ycombinator.com/images/grayarrow.gif" border=0 vspace=3 hspace=2></a><span id=down_1645929></span></center></td><td class="title"><a href="http://www.nytimes.com/2010/08/30/business/media/30link.html?_r=1&src=twr">A Hit Song on YouTube, Unnameable on the Radio</a><span class="comhead"> (nytimes.com) </span></td></tr><tr><td colspan=2></td><td class="subtext"><span id=score_1645929>17 points</span> by <a href="user?id=donohoe">donohoe</a> 2 hours ago | <a href="item?id=1645929">10 comments</a></td></tr><tr style="height:5px"></tr><tr><td align=right valign=top class="title">9.</td><td><center><a id=up_1644915 href="vote?for=1644915&dir=up&whence=%6e%65%77%73"><img src="http://ycombinator.com/images/grayarrow.gif" border=0 vspace=3 hspace=2></a><span id=down_1644915></span></center></td><td class="title"><a href="http://swarmation.com/">Swarmation: like musical chairs for pixels</a><span class="comhead"> (swarmation.com) </span></td></tr><tr><td colspan=2></td><td class="subtext"><span id=score_1644915>162 points</span> by <a href="user?id=mcantelon">mcantelon</a> 13 hours ago | <a href="item?id=1644915">59 comments</a></td></tr><tr style="height:5px"></tr><tr><td align=right valign=top class="title">10.</td><td><center><a id=up_1645686 href="vote?for=1645686&dir=up&whence=%6e%65%77%73"><img src="http://ycombinator.com/images/grayarrow.gif" border=0 vspace=3 hspace=2></a><span id=down_1645686></span></center></td><td class="title"><a href="http://djangodash.com/judging/results/">Django Dash 2010 Results</a><span class="comhead"> (djangodash.com) </span></td></tr><tr><td colspan=2></td><td class="subtext"><span id=score_1645686>21 points</span> by <a href="user?id=johnthedebs">johnthedebs</a> 5 hours ago | <a href="item?id=1645686">5 comments</a></td></tr><tr style="height:5px"></tr><tr><td align=right valign=top class="title">11.</td><td><center><a id=up_1645417 href="vote?for=1645417&dir=up&whence=%6e%65%77%73"><img src="http://ycombinator.com/images/grayarrow.gif" border=0 vspace=3 hspace=2></a><span id=down_1645417></span></center></td><td class="title"><a href="http://www.anandtech.com/show/3878/farewell-to-ati-amd-to-retire-the-ati-brand-later-this-year">AMD to Retire the ATI Brand Later this Year</a><span class="comhead"> (anandtech.com) </span></td></tr><tr><td colspan=2></td><td class="subtext"><span id=score_1645417>50 points</span> by <a href="user?id=spcmnspff">spcmnspff</a> 8 hours ago | <a href="item?id=1645417">9 comments</a></td></tr><tr style="height:5px"></tr><tr><td align=right valign=top class="title">12.</td><td><center><a id=up_1645291 href="vote?for=1645291&dir=up&whence=%6e%65%77%73"><img src="http://ycombinator.com/images/grayarrow.gif" border=0 vspace=3 hspace=2></a><span id=down_1645291></span></center></td><td class="title"><a href="http://www.nycresistor.com/2010/08/29/finally-finished/">Hacker builds working 1/10th scale Cray 1</a><span class="comhead"> (nycresistor.com) </span></td></tr><tr><td colspan=2></td><td class="subtext"><span id=score_1645291>61 points</span> by <a href="user?id=henning">henning</a> 10 hours ago | <a href="item?id=1645291">13 comments</a></td></tr><tr style="height:5px"></tr><tr><td align=right valign=top class="title">13.</td><td><center><a id=up_1645885 href="vote?for=1645885&dir=up&whence=%6e%65%77%73"><img src="http://ycombinator.com/images/grayarrow.gif" border=0 vspace=3 hspace=2></a><span id=down_1645885></span></center></td><td class="title"><a href="http://online.wsj.com/article_email/SB10001424052748703418004575455911922562120-lMyQjAxMTAwMDIwNzEyNDcyWj.html">Spreading Hayek, Spurning Keynes</a><span class="comhead"> (wsj.com) </span></td></tr><tr><td colspan=2></td><td class="subtext"><span id=score_1645885>7 points</span> by <a href="user?id=DanielBMarkham">DanielBMarkham</a> 2 hours ago | <a href="item?id=1645885">8 comments</a></td></tr><tr style="height:5px"></tr><tr><td align=right valign=top class="title">14.</td><td><center><a id=up_1645799 href="vote?for=1645799&dir=up&whence=%6e%65%77%73"><img src="http://ycombinator.com/images/grayarrow.gif" border=0 vspace=3 hspace=2></a><span id=down_1645799></span></center></td><td class="title"><a href="http://blog.ianbicking.org/2008/05/06/the-gpl-and-principles/">The GPL and Principles</a><span class="comhead"> (ianbicking.org) </span></td></tr><tr><td colspan=2></td><td class="subtext"><span id=score_1645799>10 points</span> by <a href="user?id=dhotson">dhotson</a> 3 hours ago | <a href="item?id=1645799">discuss</a></td></tr><tr style="height:5px"></tr><tr><td align=right valign=top class="title">15.</td><td><center><a id=up_1645129 href="vote?for=1645129&dir=up&whence=%6e%65%77%73"><img src="http://ycombinator.com/images/grayarrow.gif" border=0 vspace=3 hspace=2></a><span id=down_1645129></span></center></td><td class="title"><a href="http://karaten.posterous.com/ageism-in-silicon-valley-a-foreign-perspectiv">Ageism in silicon valley: a foreign perspective</a><span class="comhead"> (karaten.posterous.com) </span></td></tr><tr><td colspan=2></td><td class="subtext"><span id=score_1645129>73 points</span> by <a href="user?id=karaten">karaten</a> 11 hours ago | <a href="item?id=1645129">20 comments</a></td></tr><tr style="height:5px"></tr><tr><td align=right valign=top class="title">16.</td><td><center><a id=up_1645376 href="vote?for=1645376&dir=up&whence=%6e%65%77%73"><img src="http://ycombinator.com/images/grayarrow.gif" border=0 vspace=3 hspace=2></a><span id=down_1645376></span></center></td><td class="title"><a href="http://www.ryanallis.com/most-important-business-lessons-learned/">The Most Important Business Lessons I’ve Learned </a><span class="comhead"> (ryanallis.com) </span></td></tr><tr><td colspan=2></td><td class="subtext"><span id=score_1645376>42 points</span> by <a href="user?id=zaidf">zaidf</a> 9 hours ago | <a href="item?id=1645376">8 comments</a></td></tr><tr style="height:5px"></tr><tr><td align=right valign=top class="title">17.</td><td><center><a id=up_1645258 href="vote?for=1645258&dir=up&whence=%6e%65%77%73"><img src="http://ycombinator.com/images/grayarrow.gif" border=0 vspace=3 hspace=2></a><span id=down_1645258></span></center></td><td class="title"><a href="http://rubydoc.info">RubyDoc.info: Auto-generated RubyGems and GitHub library docs</a><span class="comhead"> (rubydoc.info) </span></td></tr><tr><td colspan=2></td><td class="subtext"><span id=score_1645258>41 points</span> by <a href="user?id=zapnap">zapnap</a> 10 hours ago | <a href="item?id=1645258">3 comments</a></td></tr><tr style="height:5px"></tr><tr><td align=right valign=top class="title">18.</td><td><center><a id=up_1643318 href="vote?for=1643318&dir=up&whence=%6e%65%77%73"><img src="http://ycombinator.com/images/grayarrow.gif" border=0 vspace=3 hspace=2></a><span id=down_1643318></span></center></td><td class="title"><a href="http://www.thestar.com/news/gta/article/854018--how-panhandlers-use-free-credit-cards?bn=1">What happens when you give homeless people a prepaid credit card. </a><span class="comhead"> (thestar.com) </span></td></tr><tr><td colspan=2></td><td class="subtext"><span id=score_1643318>330 points</span> by <a href="user?id=pavs">pavs</a> 1 day ago | <a href="item?id=1643318">219 comments</a></td></tr><tr style="height:5px"></tr><tr><td align=right valign=top class="title">19.</td><td><center><a id=up_1645202 href="vote?for=1645202&dir=up&whence=%6e%65%77%73"><img src="http://ycombinator.com/images/grayarrow.gif" border=0 vspace=3 hspace=2></a><span id=down_1645202></span></center></td><td class="title"><a href="http://academic.research.microsoft.com/">Microsoft Academic Search</a><span class="comhead"> (microsoft.com) </span></td></tr><tr><td colspan=2></td><td class="subtext"><span id=score_1645202>40 points</span> by <a href="user?id=brisance">brisance</a> 11 hours ago | <a href="item?id=1645202">12 comments</a></td></tr><tr style="height:5px"></tr><tr><td align=right valign=top class="title">20.</td><td><center><a id=up_1645520 href="vote?for=1645520&dir=up&whence=%6e%65%77%73"><img src="http://ycombinator.com/images/grayarrow.gif" border=0 vspace=3 hspace=2></a><span id=down_1645520></span></center></td><td class="title"><a href="http://nodeknockout.com/teams/anansi">MapRejuice - Distributed Client Side Computing (Node Knockout Entry)</a><span class="comhead"> (nodeknockout.com) </span></td></tr><tr><td colspan=2></td><td class="subtext"><span id=score_1645520>19 points</span> by <a href="user?id=Klonoar">Klonoar</a> 7 hours ago | <a href="item?id=1645520">14 comments</a></td></tr><tr style="height:5px"></tr><tr><td align=right valign=top class="title">21.</td><td><center><a id=up_1643239 href="vote?for=1643239&dir=up&whence=%6e%65%77%73"><img src="http://ycombinator.com/images/grayarrow.gif" border=0 vspace=3 hspace=2></a><span id=down_1643239></span></center></td><td class="title"><a href="http://www.inspirationandchai.com/Regrets-of-the-Dying.html">Regrets of the Dying</a><span class="comhead"> (inspirationandchai.com) </span></td></tr><tr><td colspan=2></td><td class="subtext"><span id=score_1643239>304 points</span> by <a href="user?id=vijaydev">vijaydev</a> 1 day ago | <a href="item?id=1643239">78 comments</a></td></tr><tr style="height:5px"></tr><tr><td align=right valign=top class="title">22.</td><td><center><a id=up_1645115 href="vote?for=1645115&dir=up&whence=%6e%65%77%73"><img src="http://ycombinator.com/images/grayarrow.gif" border=0 vspace=3 hspace=2></a><span id=down_1645115></span></center></td><td class="title"><a href="http://archiver.mailfighter.net/nnsquad/2010/August/29/0002.html">Net Neutrality is now law in Chile</a><span class="comhead"> (mailfighter.net) </span></td></tr><tr><td colspan=2></td><td class="subtext"><span id=score_1645115>42 points</span> by <a href="user?id=nfriedly">nfriedly</a> 12 hours ago | <a href="item?id=1645115">6 comments</a></td></tr><tr style="height:5px"></tr><tr><td align=right valign=top class="title">23.</td><td><center><a id=up_1644481 href="vote?for=1644481&dir=up&whence=%6e%65%77%73"><img src="http://ycombinator.com/images/grayarrow.gif" border=0 vspace=3 hspace=2></a><span id=down_1644481></span></center></td><td class="title"><a href="http://nodelay.no.de/">Realtime monitoring of Wikipedia edits via node.js</a><span class="comhead"> (no.de) </span></td></tr><tr><td colspan=2></td><td class="subtext"><span id=score_1644481>83 points</span> by <a href="user?id=mcantelon">mcantelon</a> 17 hours ago | <a href="item?id=1644481">11 comments</a></td></tr><tr style="height:5px"></tr><tr><td align=right valign=top class="title">24.</td><td><center><a id=up_1644094 href="vote?for=1644094&dir=up&whence=%6e%65%77%73"><img src="http://ycombinator.com/images/grayarrow.gif" border=0 vspace=3 hspace=2></a><span id=down_1644094></span></center></td><td class="title"><a href="http://www.economist.com/node/16881791">Obesity: Drink till you drop</a><span class="comhead"> (economist.com) </span></td></tr><tr><td colspan=2></td><td class="subtext"><span id=score_1644094>110 points</span> by <a href="user?id=jsyedidia">jsyedidia</a> 20 hours ago | <a href="item?id=1644094">81 comments</a></td></tr><tr style="height:5px"></tr><tr><td align=right valign=top class="title">25.</td><td><center><a id=up_1643936 href="vote?for=1643936&dir=up&whence=%6e%65%77%73"><img src="http://ycombinator.com/images/grayarrow.gif" border=0 vspace=3 hspace=2></a><span id=down_1643936></span></center></td><td class="title"><a href="http://lessframework.com/">Less Framework 2.0 Released</a><span class="comhead"> (lessframework.com) </span></td></tr><tr><td colspan=2></td><td class="subtext"><span id=score_1643936>141 points</span> by <a href="user?id=alexkiwi">alexkiwi</a> 22 hours ago | <a href="item?id=1643936">26 comments</a></td></tr><tr style="height:5px"></tr><tr><td align=right valign=top class="title">26.</td><td><center><a id=up_1644859 href="vote?for=1644859&dir=up&whence=%6e%65%77%73"><img src="http://ycombinator.com/images/grayarrow.gif" border=0 vspace=3 hspace=2></a><span id=down_1644859></span></center></td><td class="title"><a href="http://symkat.com/1/five-text-processing-tools-you-should-know/">Basic Command-Line Data Processing in Linux</a><span class="comhead"> (symkat.com) </span></td></tr><tr><td colspan=2></td><td class="subtext"><span id=score_1644859>55 points</span> by <a href="user?id=symkat">symkat</a> 14 hours ago | <a href="item?id=1644859">17 comments</a></td></tr><tr style="height:5px"></tr><tr><td align=right valign=top class="title">27.</td><td><center><a id=up_1645200 href="vote?for=1645200&dir=up&whence=%6e%65%77%73"><img src="http://ycombinator.com/images/grayarrow.gif" border=0 vspace=3 hspace=2></a><span id=down_1645200></span></center></td><td class="title"><a href="http://techcrunch.com/2010/08/29/cisco-may-be-making-a-run-for-skype/">Cisco May Be Making A Run For Skype</a><span class="comhead"> (techcrunch.com) </span></td></tr><tr><td colspan=2></td><td class="subtext"><span id=score_1645200>27 points</span> by <a href="user?id=mjfern">mjfern</a> 11 hours ago | <a href="item?id=1645200">13 comments</a></td></tr><tr style="height:5px"></tr><tr><td align=right valign=top class="title">28.</td><td><center><a id=up_1645004 href="vote?for=1645004&dir=up&whence=%6e%65%77%73"><img src="http://ycombinator.com/images/grayarrow.gif" border=0 vspace=3 hspace=2></a><span id=down_1645004></span></center></td><td class="title"><a href="http://bhorowitz.com/2010/08/29/the-right-kind-of-ambition-2/">The Right Kind of Ambition</a><span class="comhead"> (bhorowitz.com) </span></td></tr><tr><td colspan=2></td><td class="subtext"><span id=score_1645004>39 points</span> by <a href="user?id=dwynings">dwynings</a> 12 hours ago | <a href="item?id=1645004">20 comments</a></td></tr><tr style="height:5px"></tr><tr><td align=right valign=top class="title">29.</td><td><center><a id=up_1644772 href="vote?for=1644772&dir=up&whence=%6e%65%77%73"><img src="http://ycombinator.com/images/grayarrow.gif" border=0 vspace=3 hspace=2></a><span id=down_1644772></span></center></td><td class="title"><a href="http://www.scribd.com/doc/36582231/CrunchPad-Interserve-v-Fusion-Garage-Denial-of-Preliminary-Injunction">Arrington Is Denied Injunction Against Fusion Garage Over CrunchPad</a><span class="comhead"> (scribd.com) </span></td></tr><tr><td colspan=2></td><td class="subtext"><span id=score_1644772>40 points</span> by <a href="user?id=tptacek">tptacek</a> 14 hours ago | <a href="item?id=1644772">12 comments</a></td></tr><tr style="height:5px"></tr><tr><td align=right valign=top class="title">30.</td><td><center><a id=up_1643920 href="vote?for=1643920&dir=up&whence=%6e%65%77%73"><img src="http://ycombinator.com/images/grayarrow.gif" border=0 vspace=3 hspace=2></a><span id=down_1643920></span></center></td><td class="title"><a href="http://www.makikoitoh.com/journal/satoshi-kons-last-words">Satoshi Kon's last words</a><span class="comhead"> (makikoitoh.com) </span></td></tr><tr><td colspan=2></td><td class="subtext"><span id=score_1643920>79 points</span> by <a href="user?id=wallflower">wallflower</a> 22 hours ago | <a href="item?id=1643920">10 comments</a></td></tr><tr style="height:5px"></tr><tr style="height:10px"></tr><tr><td colspan=2></td><td class="title"><a href="/x?fnid=9LO1ba1swy" rel="nofollow">More</a></td></tr></table></td></tr><tr><td><img src="http://ycombinator.com/images/s.gif" height=10 width=0><table width="100%" cellspacing=0 cellpadding=1><tr><td bgcolor=#ff6600></td></tr></table><br>
|
27
|
+
<center><span class="yclinks"><a href="lists">Lists</a> | <a href="rss">RSS</a> | <a href="http://google.com/search?q=site%3Anews.ycombinator.com">Search</a> | <a href="http://ycombinator.com/bookmarklet.html">Bookmarklet</a> | <a href="http://ycombinator.com/newsguidelines.html">Guidelines</a> | <a href="http://ycombinator.com/newsfaq.html">FAQ</a> | <a href="http://ycombinator.com/newsnews.html">News News</a> | <a href="item?id=363">Feature Requests</a> | <a href="http://ycombinator.com">Y Combinator</a> | <a href="http://ycombinator.com/apply.html">Apply</a> | <a href="http://ycombinator.com/lib.html">Library</a></span><br><br>
|
28
|
+
<script type="text/javascript"
|
29
|
+
src="http://www.co2stats.com/propres.php?s=1138"></script><img src="http://ycombinator.com/images/s.gif" height=1 width=15><a href="http://www.webmynd.com/html/hackernews.html"><img
|
30
|
+
src="http://ycombinator.com/images/hnsearch.png" border=0
|
31
|
+
style="padding-bottom:12px"></a><img src="http://ycombinator.com/images/s.gif" height=1 width=25><a href="http://mixpanel.com/?from=yc"><img border=0
|
32
|
+
src="http://mixpanel.com/site_media/images/mixpanel_partner_logo_borderless.gif"
|
33
|
+
alt="Analytics by Mixpanel"
|
34
|
+
style="padding-bottom:8px"
|
35
|
+
/></a><br>
|
36
|
+
</center></td></tr></table></center></body></html>
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require File.expand_path(File.dirname(__FILE__) + '/parser_helper')
|
3
|
+
|
4
|
+
module RubyHackernews
|
5
|
+
describe LinkInfoParser do
|
6
|
+
|
7
|
+
before :each do
|
8
|
+
@line = ParserHelper.link_line
|
9
|
+
@correct_title = "Flow chart: How to find out which things to throw out"
|
10
|
+
@correct_link = "http://mortenjust.com/2010/08/30/finding-out-which-things-to-throw-out/"
|
11
|
+
@correct_site = "mortenjust.com"
|
12
|
+
end
|
13
|
+
|
14
|
+
describe :parse do
|
15
|
+
|
16
|
+
it "should call LinkInfo.new with correct title" do
|
17
|
+
parser = LinkInfoParser.new(@line)
|
18
|
+
LinkInfo.should_receive(:new).with(@correct_title, anything, anything)
|
19
|
+
parser.parse
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should call LinkInfo.new with correct link" do
|
23
|
+
parser = LinkInfoParser.new(@line)
|
24
|
+
LinkInfo.should_receive(:new).with(anything, @correct_link, anything)
|
25
|
+
parser.parse
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should call LinkInfo.new with correct site if site is present" do
|
29
|
+
parser = LinkInfoParser.new(@line)
|
30
|
+
LinkInfo.should_receive(:new).with(anything, anything, @correct_site)
|
31
|
+
parser.parse
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should call LinkInfo.new with nil if site is not present" do
|
35
|
+
parser = LinkInfoParser.new(ParserHelper.link_line_no_site)
|
36
|
+
LinkInfo.should_receive(:new).with(anything, anything, nil)
|
37
|
+
parser.parse
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
@@ -0,0 +1,77 @@
|
|
1
|
+
|
2
|
+
class ParserHelper
|
3
|
+
|
4
|
+
#upvote: vote?for=1645686&dir=up&whence=%6e%65%77%73
|
5
|
+
#downvote: nil
|
6
|
+
def self.voting_node_no_downvote
|
7
|
+
return Nokogiri::HTML.fragment('<a id=up_1645686 href="vote?for=1645686&dir=up&whence=%6e%65%77%73"><img src="http://ycombinator.com/images/grayarrow.gif" border=0 vspace=3 hspace=2></a><span id=down_1645686></span>'
|
8
|
+
).children
|
9
|
+
end
|
10
|
+
|
11
|
+
#upvote: nil
|
12
|
+
#downvote: vote?for=1645686&dir=up&whence=%6e%65%77%73
|
13
|
+
def self.voting_node_no_upvote
|
14
|
+
return Nokogiri::HTML.fragment('<span id=up_1645686></span><a id=down_1645686 href="vote?for=1645686&dir=up&whence=%6e%65%77%73"><img src="http://ycombinator.com/images/grayarrow.gif" border=0 vspace=3 hspace=2></a>'
|
15
|
+
).children
|
16
|
+
end
|
17
|
+
|
18
|
+
#upvote: vote?for=1645686&dir=up&whence=%6e%65%77%73
|
19
|
+
#downvote: vote?for=1645686&dir=up&whence=%6e%65%77%73
|
20
|
+
def self.voting_node
|
21
|
+
return Nokogiri::HTML.fragment('<a id=up_1645686 href="vote?for=1645686&dir=up&whence=%6e%65%77%73"><img src="http://ycombinator.com/images/grayarrow.gif" border=0 vspace=3 hspace=2></a><a id=down_1645686 href="vote?for=1645686&dir=up&whence=%6e%65%77%73"><img src="http://ycombinator.com/images/grayarrow.gif" border=0 vspace=3 hspace=2></a>'
|
22
|
+
).children
|
23
|
+
end
|
24
|
+
|
25
|
+
#username : johnthedebs
|
26
|
+
#user page : user?id=johnthedebs
|
27
|
+
#score : 17
|
28
|
+
#comments : 2
|
29
|
+
#comment_page : item?id=1645686
|
30
|
+
def self.second_line
|
31
|
+
return Nokogiri::HTML.fragment('<td class="subtext"><span id=score_1645686>17 points</span> by <a href="user?id=johnthedebs">johnthedebs</a> 4 hours ago | <a href="item?id=1645686">2 comments</a></td>')
|
32
|
+
end
|
33
|
+
|
34
|
+
#username : johnthedebs
|
35
|
+
#user page : user?id=johnthedebs
|
36
|
+
#score : 17
|
37
|
+
#comment_page : item?id=1645686
|
38
|
+
def self.second_line_no_comments_yet
|
39
|
+
return Nokogiri::HTML.fragment('<td class="subtext"><span id=score_1645686>17 points</span> by <a href="user?id=johnthedebs">johnthedebs</a> 4 hours ago | <a href="item?id=1645686">discuss</a></td>')
|
40
|
+
end
|
41
|
+
|
42
|
+
#username : johnthedebs
|
43
|
+
#user page : user?id=johnthedebs
|
44
|
+
#score : 17
|
45
|
+
def self.second_line_comments_tag_missing
|
46
|
+
return Nokogiri::HTML.fragment('<td class="subtext"><span id=score_1645686>17 points</span> by <a href="user?id=johnthedebs">johnthedebs</a> 4 hours ago</td>')
|
47
|
+
end
|
48
|
+
|
49
|
+
#title : Flow chart: How to find out which things to throw out
|
50
|
+
#link : http://mortenjust.com/2010/08/30/finding-out-which-things-to-throw-out/
|
51
|
+
#site : (mortenjust.com)
|
52
|
+
def self.link_line
|
53
|
+
return Nokogiri::HTML('<td class="title"><a href="http://mortenjust.com/2010/08/30/finding-out-which-things-to-throw-out/" rel="nofollow">Flow chart: How to find out which things to throw out</a><span class="comhead"> (mortenjust.com) </span></td>')
|
54
|
+
end
|
55
|
+
|
56
|
+
#title : Flow chart: How to find out which things to throw out
|
57
|
+
#link : http://mortenjust.com/2010/08/30/finding-out-which-things-to-throw-out/
|
58
|
+
def self.link_line_no_site
|
59
|
+
return Nokogiri::HTML('<td class="title"><a href="http://mortenjust.com/2010/08/30/finding-out-which-things-to-throw-out/" rel="nofollow">Flow chart: How to find out which things to throw out</a></td>')
|
60
|
+
end
|
61
|
+
|
62
|
+
def self.first_line_full
|
63
|
+
return Nokogiri::HTML('<tr><td align=right valign=top class="title">2.</td><td><center><a id=up_1645745 href="vote?for=1645745&dir=up&whence=%6e%65%77%73"><img src="http://ycombinator.com/images/grayarrow.gif" border=0 vspace=3 hspace=2></a><span id=down_1645745></span></center></td><td class="title"><a href="http://technologizer.com/2010/08/18/the-tragic-death-of-practically-everything/">The Tragic Death of Practically Everything</a><span class="comhead"> (technologizer.com) </span></td></tr>')
|
64
|
+
end
|
65
|
+
|
66
|
+
def self.second_line_full
|
67
|
+
return Nokogiri::HTML('<tr><td colspan=2></td><td class="subtext"><span id=score_1645745>59 points</span> by <a href="user?id=dhotson">dhotson</a> 4 hours ago | <a href="item?id=1645745">5 comments</a></td></tr>')
|
68
|
+
end
|
69
|
+
|
70
|
+
def self.full_page
|
71
|
+
File.open(File.join(File.dirname(__FILE__), 'hn_test_page.html'), 'r') do |file|
|
72
|
+
return Nokogiri::HTML(file)
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module RubyHackernews
|
4
|
+
describe TimeInfoParser do
|
5
|
+
|
6
|
+
before :each do
|
7
|
+
@parser = TimeInfoParser.new(stub(:text => " 4 hours ago | "))
|
8
|
+
end
|
9
|
+
|
10
|
+
describe :parse do
|
11
|
+
|
12
|
+
it "should pass the right value as the first parameter" do
|
13
|
+
TimeInfo.should_receive(:new).with(4, anything)
|
14
|
+
@parser.parse
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should pass the right UoM descriptor as the second parameter" do
|
18
|
+
TimeInfo.should_receive(:new).with(anything, "hours")
|
19
|
+
@parser.parse
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require File.expand_path(File.dirname(__FILE__) + '/parser_helper')
|
3
|
+
|
4
|
+
module RubyHackernews
|
5
|
+
describe UserInfoParser do
|
6
|
+
|
7
|
+
before :each do
|
8
|
+
@parser = UserInfoParser.new(ParserHelper.second_line)
|
9
|
+
end
|
10
|
+
|
11
|
+
describe :parse do
|
12
|
+
|
13
|
+
it "should pass the right user name" do
|
14
|
+
UserInfo.should_receive(:new).with("johnthedebs", anything)
|
15
|
+
@parser.parse
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should pass the right user page" do
|
19
|
+
UserInfo.should_receive(:new).with(anything, "user?id=johnthedebs")
|
20
|
+
@parser.parse
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require File.expand_path(File.dirname(__FILE__) + '/parser_helper')
|
3
|
+
|
4
|
+
module RubyHackernews
|
5
|
+
describe VotingInfoParser do
|
6
|
+
|
7
|
+
before :each do
|
8
|
+
@voting_element = ParserHelper.voting_node
|
9
|
+
@score_element = ParserHelper.second_line
|
10
|
+
@correct_vote_link = "vote?for=1645686&dir=up&whence=%6e%65%77%73"
|
11
|
+
end
|
12
|
+
|
13
|
+
describe :parse do
|
14
|
+
|
15
|
+
it "should assign link.href to upvote if element not nil" do
|
16
|
+
parser = VotingInfoParser.new(@voting_element, @score_element)
|
17
|
+
VotingInfo.should_receive(:new).with(anything, @correct_vote_link, anything)
|
18
|
+
parser.parse
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should assing nil to upvote if element nil" do
|
22
|
+
parser = VotingInfoParser.new(ParserHelper.voting_node_no_upvote, @score_element)
|
23
|
+
VotingInfo.should_receive(:new).with(anything, nil, anything)
|
24
|
+
parser.parse
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should assing link.href to downvote if element not nil" do
|
28
|
+
parser = VotingInfoParser.new(@voting_element, @score_element)
|
29
|
+
VotingInfo.should_receive(:new).with(anything, anything, @correct_vote_link)
|
30
|
+
parser.parse
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should assing nil to downvote if element nil" do
|
34
|
+
parser = VotingInfoParser.new(ParserHelper.voting_node_no_downvote, @score_element)
|
35
|
+
VotingInfo.should_receive(:new).with(anything, anything, nil)
|
36
|
+
parser.parse
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should assing correct score to score" do
|
40
|
+
parser = VotingInfoParser.new(@voting_element, @score_element)
|
41
|
+
VotingInfo.should_receive(:new).with(17, anything, anything)
|
42
|
+
parser.parse
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module RubyHackernews
|
4
|
+
describe MechanizeContext do
|
5
|
+
|
6
|
+
before :each do
|
7
|
+
MechanizeContext.send(:class_variable_set, :@@contexts, nil)
|
8
|
+
MechanizeContext.send(:class_variable_set, :@@default, nil)
|
9
|
+
end
|
10
|
+
|
11
|
+
describe "create" do
|
12
|
+
|
13
|
+
it "should instantiate class variable on use" do
|
14
|
+
MechanizeContext.create()
|
15
|
+
MechanizeContext.send(:class_variable_get, :@@contexts).should_not be_nil
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should assign new agent to hash[key]" do
|
19
|
+
MechanizeContext.create(:test_key)
|
20
|
+
MechanizeContext.send(:class_variable_get, :@@contexts)[:test_key].should be_kind_of Mechanize
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should assign new agent to default if no key passed" do
|
24
|
+
MechanizeContext.create
|
25
|
+
MechanizeContext.send(:class_variable_get, :@@contexts)[:default].should be_kind_of Mechanize
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
describe "agent=" do
|
31
|
+
|
32
|
+
it "should set @@default as passed key" do
|
33
|
+
MechanizeContext.agent = :test_agent
|
34
|
+
MechanizeContext.send(:class_variable_get, :@@default).should == :test_agent
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
describe "agent" do
|
40
|
+
|
41
|
+
it "should return the @@default agent" do
|
42
|
+
MechanizeContext.send(:class_variable_set, :@@default, :test_value)
|
43
|
+
MechanizeContext.send(:class_variable_set, :@@contexts, {:test_value => :target})
|
44
|
+
klass = Class.new
|
45
|
+
klass.instance_eval do
|
46
|
+
include MechanizeContext
|
47
|
+
end
|
48
|
+
klass.new.agent.should == :target
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
|
53
|
+
describe "[]" do
|
54
|
+
|
55
|
+
it "should return the [key] agent" do
|
56
|
+
MechanizeContext.send(:class_variable_set, :@@contexts, {:test_value => :target})
|
57
|
+
klass = Class.new
|
58
|
+
klass.instance_eval do
|
59
|
+
include MechanizeContext
|
60
|
+
end
|
61
|
+
klass.new[:test_value].should == :target
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
data/spec/spec_helper.rb
ADDED
metadata
CHANGED
@@ -1,20 +1,46 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruby-hackernews
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.3.
|
5
|
-
prerelease:
|
4
|
+
version: 1.3.5
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Andrea Dallera
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date:
|
11
|
+
date: 2014-08-04 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.3'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.3'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ! '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ! '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
14
41
|
- !ruby/object:Gem::Dependency
|
15
42
|
name: require_all
|
16
43
|
requirement: !ruby/object:Gem::Requirement
|
17
|
-
none: false
|
18
44
|
requirements:
|
19
45
|
- - ! '>='
|
20
46
|
- !ruby/object:Gem::Version
|
@@ -22,7 +48,6 @@ dependencies:
|
|
22
48
|
type: :runtime
|
23
49
|
prerelease: false
|
24
50
|
version_requirements: !ruby/object:Gem::Requirement
|
25
|
-
none: false
|
26
51
|
requirements:
|
27
52
|
- - ! '>='
|
28
53
|
- !ruby/object:Gem::Version
|
@@ -30,7 +55,6 @@ dependencies:
|
|
30
55
|
- !ruby/object:Gem::Dependency
|
31
56
|
name: mechanize
|
32
57
|
requirement: !ruby/object:Gem::Requirement
|
33
|
-
none: false
|
34
58
|
requirements:
|
35
59
|
- - ! '>='
|
36
60
|
- !ruby/object:Gem::Version
|
@@ -38,69 +62,98 @@ dependencies:
|
|
38
62
|
type: :runtime
|
39
63
|
prerelease: false
|
40
64
|
version_requirements: !ruby/object:Gem::Requirement
|
41
|
-
none: false
|
42
65
|
requirements:
|
43
66
|
- - ! '>='
|
44
67
|
- !ruby/object:Gem::Version
|
45
68
|
version: 1.0.0
|
46
69
|
description: An interface to Hacker News
|
47
|
-
email:
|
70
|
+
email:
|
71
|
+
- andrea@andreadallera.com
|
48
72
|
executables: []
|
49
73
|
extensions: []
|
50
74
|
extra_rdoc_files: []
|
51
75
|
files:
|
76
|
+
- .gitignore
|
77
|
+
- Gemfile
|
52
78
|
- README.rdoc
|
53
79
|
- Rakefile
|
54
80
|
- lib/ruby-hackernews.rb
|
81
|
+
- lib/ruby-hackernews/domain/comment/comment.rb
|
55
82
|
- lib/ruby-hackernews/domain/entry/comments_info.rb
|
56
|
-
- lib/ruby-hackernews/domain/entry/time_info.rb
|
57
|
-
- lib/ruby-hackernews/domain/entry/voting_info.rb
|
58
|
-
- lib/ruby-hackernews/domain/entry/link_info.rb
|
59
83
|
- lib/ruby-hackernews/domain/entry/entry.rb
|
84
|
+
- lib/ruby-hackernews/domain/entry/link_info.rb
|
85
|
+
- lib/ruby-hackernews/domain/entry/time_info.rb
|
60
86
|
- lib/ruby-hackernews/domain/entry/user_info.rb
|
87
|
+
- lib/ruby-hackernews/domain/entry/voting_info.rb
|
61
88
|
- lib/ruby-hackernews/domain/user.rb
|
62
|
-
- lib/ruby-hackernews/
|
89
|
+
- lib/ruby-hackernews/services/comment_service.rb
|
63
90
|
- lib/ruby-hackernews/services/configuration_service.rb
|
64
|
-
- lib/ruby-hackernews/services/
|
91
|
+
- lib/ruby-hackernews/services/entry_service.rb
|
65
92
|
- lib/ruby-hackernews/services/login_service.rb
|
66
93
|
- lib/ruby-hackernews/services/mechanize_context.rb
|
67
94
|
- lib/ruby-hackernews/services/not_authenticated_error.rb
|
68
|
-
- lib/ruby-hackernews/services/
|
69
|
-
- lib/ruby-hackernews/services/
|
70
|
-
- lib/ruby-hackernews/services/
|
71
|
-
- lib/ruby-hackernews/services/comment_service.rb
|
72
|
-
- lib/ruby-hackernews/services/voting_service.rb
|
73
|
-
- lib/ruby-hackernews/services/text_service.rb
|
74
|
-
- lib/ruby-hackernews/services/parsers/text_parser.rb
|
75
|
-
- lib/ruby-hackernews/services/parsers/user_info_parser.rb
|
95
|
+
- lib/ruby-hackernews/services/page_fetcher.rb
|
96
|
+
- lib/ruby-hackernews/services/parsers/comments_info_parser.rb
|
97
|
+
- lib/ruby-hackernews/services/parsers/entry_page_parser.rb
|
76
98
|
- lib/ruby-hackernews/services/parsers/entry_parser.rb
|
77
99
|
- lib/ruby-hackernews/services/parsers/link_info_parser.rb
|
100
|
+
- lib/ruby-hackernews/services/parsers/text_parser.rb
|
78
101
|
- lib/ruby-hackernews/services/parsers/time_info_parser.rb
|
102
|
+
- lib/ruby-hackernews/services/parsers/user_info_parser.rb
|
79
103
|
- lib/ruby-hackernews/services/parsers/voting_info_parser.rb
|
80
|
-
- lib/ruby-hackernews/services/
|
81
|
-
- lib/ruby-hackernews/services/
|
82
|
-
|
104
|
+
- lib/ruby-hackernews/services/signup_service.rb
|
105
|
+
- lib/ruby-hackernews/services/text_service.rb
|
106
|
+
- lib/ruby-hackernews/services/user_info_service.rb
|
107
|
+
- lib/ruby-hackernews/services/voting_service.rb
|
108
|
+
- lib/ruby-hackernews/version.rb
|
109
|
+
- ruby-hackernews.gemspec
|
110
|
+
- spec/HNAPI/domain/time_info_spec.rb
|
111
|
+
- spec/HNAPI/services/entries/entry_service_spec.rb
|
112
|
+
- spec/HNAPI/services/entries/parsers/comments_info_parser_spec.rb
|
113
|
+
- spec/HNAPI/services/entries/parsers/entry_page_parser_spec.rb
|
114
|
+
- spec/HNAPI/services/entries/parsers/entry_parser_spec.rb
|
115
|
+
- spec/HNAPI/services/entries/parsers/hn_test_page.html
|
116
|
+
- spec/HNAPI/services/entries/parsers/link_info_parser_spec.rb
|
117
|
+
- spec/HNAPI/services/entries/parsers/parser_helper.rb
|
118
|
+
- spec/HNAPI/services/entries/parsers/time_info_parser_spec.rb
|
119
|
+
- spec/HNAPI/services/entries/parsers/user_info_parser_spec.rb
|
120
|
+
- spec/HNAPI/services/entries/parsers/voting_info_parser_spec.rb
|
121
|
+
- spec/HNAPI/services/mechanize_context_spec.rb
|
122
|
+
- spec/spec_helper.rb
|
123
|
+
homepage: http://github.com/blissofbeing/ruby-hackernews
|
83
124
|
licenses: []
|
125
|
+
metadata: {}
|
84
126
|
post_install_message:
|
85
127
|
rdoc_options: []
|
86
128
|
require_paths:
|
87
129
|
- lib
|
88
130
|
required_ruby_version: !ruby/object:Gem::Requirement
|
89
|
-
none: false
|
90
131
|
requirements:
|
91
132
|
- - ! '>='
|
92
133
|
- !ruby/object:Gem::Version
|
93
134
|
version: '0'
|
94
135
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
95
|
-
none: false
|
96
136
|
requirements:
|
97
137
|
- - ! '>='
|
98
138
|
- !ruby/object:Gem::Version
|
99
139
|
version: '0'
|
100
140
|
requirements: []
|
101
141
|
rubyforge_project:
|
102
|
-
rubygems_version:
|
142
|
+
rubygems_version: 2.0.3
|
103
143
|
signing_key:
|
104
|
-
specification_version:
|
144
|
+
specification_version: 4
|
105
145
|
summary: An interface to Hacker News
|
106
|
-
test_files:
|
146
|
+
test_files:
|
147
|
+
- spec/HNAPI/domain/time_info_spec.rb
|
148
|
+
- spec/HNAPI/services/entries/entry_service_spec.rb
|
149
|
+
- spec/HNAPI/services/entries/parsers/comments_info_parser_spec.rb
|
150
|
+
- spec/HNAPI/services/entries/parsers/entry_page_parser_spec.rb
|
151
|
+
- spec/HNAPI/services/entries/parsers/entry_parser_spec.rb
|
152
|
+
- spec/HNAPI/services/entries/parsers/hn_test_page.html
|
153
|
+
- spec/HNAPI/services/entries/parsers/link_info_parser_spec.rb
|
154
|
+
- spec/HNAPI/services/entries/parsers/parser_helper.rb
|
155
|
+
- spec/HNAPI/services/entries/parsers/time_info_parser_spec.rb
|
156
|
+
- spec/HNAPI/services/entries/parsers/user_info_parser_spec.rb
|
157
|
+
- spec/HNAPI/services/entries/parsers/voting_info_parser_spec.rb
|
158
|
+
- spec/HNAPI/services/mechanize_context_spec.rb
|
159
|
+
- spec/spec_helper.rb
|