Class: HackerNews

Inherits:
Object
  • Object
show all
Defined in:
lib/hackernews.rb

Defined Under Namespace

Classes: LoginError

Constant Summary

VERSION =
'0.2.1'
BASE_URL =
"http://news.ycombinator.com"
ITEM_URL =
"#{BASE_URL}/item?id=%s"
USER_URL =
"#{BASE_URL}/user?id=%s"
LOGIN_SUBMIT_URL =
"#{BASE_URL}/y"
COMMENT_SUBMIT_URL =
"#{BASE_URL}/r"

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(username = nil, password = nil) ⇒ HackerNews

Creates a new HackerNews object. If username and password are provided, login is called.



24
25
26
# File 'lib/hackernews.rb', line 24

def initialize(username=nil, password=nil)
  (username, password) if username and password
end

Class Method Details

.versionObject

Returns the version string for the library.



10
11
12
# File 'lib/hackernews.rb', line 10

def self.version
  VERSION
end

Instance Method Details

#average_karmaObject

Retrieves the average karma per post for the logged in user (must be logged in).



47
48
49
50
# File 'lib/hackernews.rb', line 47

def average_karma
  require_login!
  user_page.match(/<td valign=top>avg:<\/td><td>([\d\.]+)<\/td>/)[1]
end

#comment(id, text) ⇒ Object

Post a comment on a posted item or on another comment.



69
70
71
72
73
# File 'lib/hackernews.rb', line 69

def comment(id, text)
  require_login!
  fnid = get(ITEM_URL % id).match(/<input type=hidden name="fnid" value="([^"]+)"/)[1]
  post(COMMENT_SUBMIT_URL, 'fnid' => fnid, 'text' => text)
end

#karma(username = nil) ⇒ Object

Retrieves the karma for the logged in user, or for the specified username (if given).



42
43
44
# File 'lib/hackernews.rb', line 42

def karma(username=nil)
  user_page(username).match(/<td valign=top>karma\:<\/td><td>(\d+)<\/td>/)[1]
end

#login(username, password) ⇒ Object

Log into Hacker News with the specified username and password.



29
30
31
32
33
34
35
36
37
38
39
# File 'lib/hackernews.rb', line 29

def (username, password)
   = get(BASE_URL).match(/href="([^"]+)">login<\/a>/)[1]
  form_html = get(BASE_URL + )
  fnid = form_html.match(/<input type=hidden name="fnid" value="([^"]+)"/)[1]
  response = post(LOGIN_SUBMIT_URL, 'fnid' => fnid, 'u' => username, 'p' => password)
  @username = username
  @password = password
  unless @cookie = response.header['set-cookie']
    raise LoginError, "Login credentials did not work."
  end
end

#parse_story_comments(id) ⇒ Object

Parse the comment tree for a story. I used regex so as to not impose library requirements on a library that is not my own.

Returns an array of hashes. E.G for ret-val. [{:id=>1, :poster=>:chasing_sparks, :text=>'.', :children=>



81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
# File 'lib/hackernews.rb', line 81

def parse_story_comments(id)
  source = get(BASE_URL + "/item?id=#{id}")

  # The following regexp will break
  indentation  = '<img src="http:\/\/ycombinator.com\/images\/s.gif" height=1 width=(\d+)><\/td>'
  score        = '<span id=score_([0-9]+)>([0-9]+) point'
  user_id      = '<a href="user\\?id=([^"]+)">'
  time_ago     = '<\/a>([^\|]+)\|'
  comment_body = '<span class=\\"comment\\"><font color=#000000>(.*?)<\\/font>'    
  regexp_str  = "#{indentation}.*?#{score}.*?#{user_id}.*?#{time_ago}.*?#{comment_body}"

  comment_regexp = Regexp.new(regexp_str, Regexp::MULTILINE)
  comments = source.scan(comment_regexp)

  commenter_stack = []
  comments.collect! do |comment| 
    comment_hash = {
      :indentation => comment[0].to_i,
      :id          => comment[1], 
      :points      => comment[2], 
      :user_id     => comment[3], 
      :post_date   => comment[4].lstrip.rstrip,:text=>comment[5],
      :children    => []
    }
    
    commenter_stack.pop until commenter_stack.empty? || commenter_stack.last[:indentation] < comment_hash[:indentation]
    commenter_stack.last[:children].push(comment_hash) if commenter_stack.length > 0
    commenter_stack.push(comment_hash)

    (commenter_stack.size == 1) ? comment_hash : nil
  end

  comments.compact
end

#user_page(username = nil) ⇒ Object

Retrieves the user page html for the specified username (or the current logged in user if none is specified).



53
54
55
56
57
58
59
# File 'lib/hackernews.rb', line 53

def user_page(username=nil)
  username ||= @username
  @user_pages ||= {}
  @user_pages[username] ||= begin
    get(USER_URL % username)
  end
end

#vote(id) ⇒ Object

Up-vote a post or a comment by passing in the id number.



62
63
64
65
66
# File 'lib/hackernews.rb', line 62

def vote(id)
  require_login!
  url = get(ITEM_URL % id).match(/<a id=up_\d+ onclick="return vote\(this\)" href="(vote\?[^"]+)">/)[1]
  get(BASE_URL + '/' + url)
end