ruby-hackernews 1.3.3 → 1.3.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|