poj_org 0.3.0 → 0.4.4
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.
- data/lib/poj_org/code.rb +47 -0
- data/lib/poj_org/errors.rb +9 -0
- data/lib/poj_org/problem.rb +22 -0
- data/lib/poj_org/user.rb +70 -0
- data/lib/poj_org.rb +4 -119
- metadata +24 -4
data/lib/poj_org/code.rb
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
require 'cgi'
|
|
2
|
+
require 'open-uri'
|
|
3
|
+
require 'nokogiri'
|
|
4
|
+
require 'poj_org/errors'
|
|
5
|
+
require 'poj_org/user'
|
|
6
|
+
|
|
7
|
+
module PojOrg
|
|
8
|
+
class Code
|
|
9
|
+
attr_reader :id, :username, :problem_id, :result, :memory_in_kb, :time_in_ms, :language, :length_in_byte, :submitted_at, :content
|
|
10
|
+
|
|
11
|
+
def initialize(id)
|
|
12
|
+
@id = id
|
|
13
|
+
fetch_details
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def url
|
|
17
|
+
"http://poj.org/showsource?solution_id=#{id}"
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def fetch_content(user)
|
|
21
|
+
user.login do |cookie|
|
|
22
|
+
html = Nokogiri::HTML(open(url, 'Cookie' => cookie))
|
|
23
|
+
if html.xpath('/html/head/title').text == 'Error'
|
|
24
|
+
raise PojOrg::Errors::CodeNotFound if html.xpath('/html/body/ul/li').text.include?('No such solution')
|
|
25
|
+
raise PojOrg::Errors::AccessDenied if html.xpath('/html/body/ul/li').text.include?('Source request declined')
|
|
26
|
+
raise PojOrg::Errors::Error
|
|
27
|
+
end
|
|
28
|
+
@content = html.xpath('/html/body/pre').text
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
private
|
|
33
|
+
|
|
34
|
+
def fetch_details
|
|
35
|
+
html = Nokogiri::HTML(open("http://poj.org/status?top=#{@id+1}"))
|
|
36
|
+
raise PojOrg::Errors::CodeNotFound if html.xpath('/html/body/table[2]/tr[2]/td[1]').text.to_i != @id
|
|
37
|
+
@username = html.xpath('/html/body/table[2]/tr[2]/td[2]').text
|
|
38
|
+
@problem_id = html.xpath('/html/body/table[2]/tr[2]/td[3]').text.to_i
|
|
39
|
+
@result = html.xpath('/html/body/table[2]/tr[2]/td[4]').text
|
|
40
|
+
@memory_in_kb = html.xpath('/html/body/table[2]/tr[2]/td[5]').text.to_i
|
|
41
|
+
@time_in_ms = html.xpath('/html/body/table[2]/tr[2]/td[6]').text.to_i
|
|
42
|
+
@language = html.xpath('/html/body/table[2]/tr[2]/td[7]').text
|
|
43
|
+
@length_in_byte = html.xpath('/html/body/table[2]/tr[2]/td[8]').text.to_i
|
|
44
|
+
@submitted_at = html.xpath('/html/body/table[2]/tr[2]/td[9]').text
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
require 'open-uri'
|
|
2
|
+
require 'nokogiri'
|
|
3
|
+
require 'poj_org/errors'
|
|
4
|
+
|
|
5
|
+
module PojOrg
|
|
6
|
+
class Problem
|
|
7
|
+
attr_reader :id, :title, :time_limit_in_ms, :memory_limit_in_kb
|
|
8
|
+
|
|
9
|
+
def initialize(id)
|
|
10
|
+
@id = id
|
|
11
|
+
html = Nokogiri::HTML(open(url))
|
|
12
|
+
raise PojOrg::Errors::ProblemNotFound if html.xpath('/html/head/title').text == 'Error'
|
|
13
|
+
@title = html.xpath('/html/body/table[2]/tr/td/div[2]').text
|
|
14
|
+
@time_limit_in_ms = html.xpath('/html/body/table[2]/tr/td/div[3]/table/tr[1]/td[1]').text[/\d+/].to_i
|
|
15
|
+
@memory_limit_in_kb = html.xpath('/html/body/table[2]/tr/td/div[3]/table/tr[1]/td[3]').text[/\d+/].to_i
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def url
|
|
19
|
+
"http://poj.org/problem?id=#{id}"
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
data/lib/poj_org/user.rb
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
require 'net/http'
|
|
2
|
+
require 'open-uri'
|
|
3
|
+
require 'poj_org/errors'
|
|
4
|
+
|
|
5
|
+
module PojOrg
|
|
6
|
+
class User
|
|
7
|
+
attr_reader :username
|
|
8
|
+
|
|
9
|
+
def initialize(username, password)
|
|
10
|
+
@username = username
|
|
11
|
+
@password = password
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def authenticated?
|
|
15
|
+
login
|
|
16
|
+
true
|
|
17
|
+
rescue
|
|
18
|
+
false
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def login
|
|
22
|
+
response = Net::HTTP.post_form(
|
|
23
|
+
URI('http://poj.org/login'),
|
|
24
|
+
'user_id1' => username,
|
|
25
|
+
'password1' => @password
|
|
26
|
+
)
|
|
27
|
+
raise PojOrg::Errors::Unauthorized if response.body['failed']
|
|
28
|
+
yield response['set-cookie'] if block_given?
|
|
29
|
+
open('http://poj.org/login?action=logout')
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def code(id)
|
|
33
|
+
code = Code.new(id)
|
|
34
|
+
code.fetch_content(self)
|
|
35
|
+
code
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def code_ids(options = {})
|
|
39
|
+
html = Nokogiri::HTML(open(status_url(options)))
|
|
40
|
+
ids = []
|
|
41
|
+
2.upto(Float::INFINITY) do |row|
|
|
42
|
+
element = html.xpath("/html/body/table[2]/tr[#{row}]/td[1]").text
|
|
43
|
+
break if element.empty?
|
|
44
|
+
ids << element.to_i
|
|
45
|
+
end
|
|
46
|
+
ids += code_ids(options.merge(top: ids.last)) unless ids.empty?
|
|
47
|
+
ids
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def codes(options = {})
|
|
51
|
+
code_ids.map do |id|
|
|
52
|
+
code(id)
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def url
|
|
57
|
+
"http://poj.org/userstatus?user_id=#{@username}"
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
private
|
|
61
|
+
|
|
62
|
+
def status_url(options)
|
|
63
|
+
options.merge!(user_id: @username)
|
|
64
|
+
params = options.map { |key, value|
|
|
65
|
+
"&#{key}=#{value}"
|
|
66
|
+
}.join('&')
|
|
67
|
+
"http://poj.org/status?#{params}"
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
data/lib/poj_org.rb
CHANGED
|
@@ -1,119 +1,4 @@
|
|
|
1
|
-
require '
|
|
2
|
-
require '
|
|
3
|
-
require '
|
|
4
|
-
|
|
5
|
-
# This class provides authetication methods
|
|
6
|
-
class PojOrg
|
|
7
|
-
# Stored user name
|
|
8
|
-
@@user = nil
|
|
9
|
-
|
|
10
|
-
# Stored password
|
|
11
|
-
@@password = nil
|
|
12
|
-
|
|
13
|
-
# Status of last authentication
|
|
14
|
-
@@authenticated = false
|
|
15
|
-
|
|
16
|
-
# Autheticate and store user name and password
|
|
17
|
-
#
|
|
18
|
-
# @example
|
|
19
|
-
# >> PojOrg::authenticate('poj_library', 'secret')
|
|
20
|
-
# => true
|
|
21
|
-
# >> PojOrg::authenticate('poj_library', 'wrong_password')
|
|
22
|
-
# => false
|
|
23
|
-
#
|
|
24
|
-
# @param [String] user user name of poj.org
|
|
25
|
-
# @param [String] password password of poj.org
|
|
26
|
-
#
|
|
27
|
-
# @return [Boolean] whether authenticated or not
|
|
28
|
-
def self.authenticate(user, password)
|
|
29
|
-
if login(user, password)
|
|
30
|
-
@@user = user
|
|
31
|
-
@@password = password
|
|
32
|
-
@@authenticated = true
|
|
33
|
-
else
|
|
34
|
-
@@authenticated = false
|
|
35
|
-
end
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
# Unauthenticate and erase user name and password
|
|
39
|
-
def self.unauthenticate
|
|
40
|
-
@@user = nil
|
|
41
|
-
@@password = nil
|
|
42
|
-
@@authenticated = false
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
# Status of last authentication
|
|
46
|
-
#
|
|
47
|
-
# @return [Boolean] Whether the last authentication success or not
|
|
48
|
-
def self.authenticated?
|
|
49
|
-
@@authenticated
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
# Url of problem
|
|
53
|
-
#
|
|
54
|
-
# @param [Integer] ID of problem
|
|
55
|
-
#
|
|
56
|
-
# @return [String] Url of problem
|
|
57
|
-
def self.problem_url(id)
|
|
58
|
-
"http://poj.org/problem?id=#{id}"
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
# Details of problem
|
|
62
|
-
#
|
|
63
|
-
# @param [Integer] ID of problem
|
|
64
|
-
#
|
|
65
|
-
# @return [Hash] Details of problem or Nil if any error occured
|
|
66
|
-
def self.problem(id)
|
|
67
|
-
html = open(problem_url(id)).read
|
|
68
|
-
return nil if html.include? '<title>Error</title>'
|
|
69
|
-
{
|
|
70
|
-
id: id,
|
|
71
|
-
url: problem_url(id),
|
|
72
|
-
title: html[/(?<=<div class="ptt" lang="en-US">).+?(?=<\/div>)/],
|
|
73
|
-
time_limit_in_ms: html[/(?<=<b>Time Limit:<\/b>)\s*\d+/].to_i,
|
|
74
|
-
memory_limit_in_kb: html[/(?<=<b>Memory Limit:<\/b>)\s*\d+/].to_i
|
|
75
|
-
}
|
|
76
|
-
end
|
|
77
|
-
|
|
78
|
-
# Url of code
|
|
79
|
-
#
|
|
80
|
-
# @param [Integer] ID of code
|
|
81
|
-
#
|
|
82
|
-
# @return [String] Url of code
|
|
83
|
-
def self.code_url(id)
|
|
84
|
-
"http://poj.org/showsource?solution_id=#{id}"
|
|
85
|
-
end
|
|
86
|
-
|
|
87
|
-
# Details of code
|
|
88
|
-
# Need to be autheticated
|
|
89
|
-
#
|
|
90
|
-
# @param [Integer] ID of code
|
|
91
|
-
#
|
|
92
|
-
# @return [Hash] Details of code or Nil if any error occured
|
|
93
|
-
def self.code(id)
|
|
94
|
-
return nil unless authenticated?
|
|
95
|
-
html = open(code_url(id), 'Cookie' => login).read
|
|
96
|
-
return nil if html.include? '<title>Error</title>'
|
|
97
|
-
{
|
|
98
|
-
id: id,
|
|
99
|
-
url: code_url(id),
|
|
100
|
-
problem_id: (/<td><b>Problem:.+?<a.+?>(.+?)<\/a><\/td>/).match(html)[1].to_i,
|
|
101
|
-
user: (/<td><b>User:.+?<a.+?>(.+?)<\/a><\/td>/).match(html)[1],
|
|
102
|
-
time_in_ms: (/<td><b>Time:.+?(\d+)MS<\/td>/).match(html)[1].to_i,
|
|
103
|
-
memory_in_kb: (/<td><b>Memory:.+?(\d+)K<\/td>/).match(html)[1].to_i,
|
|
104
|
-
language: (/<td><b>Language:<\/b>\s*(.+?)<\/td>/).match(html)[1],
|
|
105
|
-
content: CGI.unescapeHTML((/<pre.+?>(.+)<\/pre>/m).match(html)[1])
|
|
106
|
-
}
|
|
107
|
-
end
|
|
108
|
-
|
|
109
|
-
private
|
|
110
|
-
|
|
111
|
-
def self.login(user = nil, password = nil)
|
|
112
|
-
login = Net::HTTP.post_form(
|
|
113
|
-
URI('http://poj.org/login'),
|
|
114
|
-
'user_id1' => user || @@user,
|
|
115
|
-
'password1' => password || @@password
|
|
116
|
-
)
|
|
117
|
-
login.body['failed'] ? false : login['set-cookie']
|
|
118
|
-
end
|
|
119
|
-
end
|
|
1
|
+
require 'poj_org/errors'
|
|
2
|
+
require 'poj_org/problem'
|
|
3
|
+
require 'poj_org/user'
|
|
4
|
+
require 'poj_org/code'
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: poj_org
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.4.4
|
|
5
5
|
prerelease:
|
|
6
6
|
platform: ruby
|
|
7
7
|
authors:
|
|
@@ -9,15 +9,35 @@ authors:
|
|
|
9
9
|
autorequire:
|
|
10
10
|
bindir: bin
|
|
11
11
|
cert_chain: []
|
|
12
|
-
date: 2013-
|
|
13
|
-
dependencies:
|
|
14
|
-
|
|
12
|
+
date: 2013-03-15 00:00:00.000000000 Z
|
|
13
|
+
dependencies:
|
|
14
|
+
- !ruby/object:Gem::Dependency
|
|
15
|
+
name: nokogiri
|
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
|
17
|
+
none: false
|
|
18
|
+
requirements:
|
|
19
|
+
- - ! '>='
|
|
20
|
+
- !ruby/object:Gem::Version
|
|
21
|
+
version: '0'
|
|
22
|
+
type: :runtime
|
|
23
|
+
prerelease: false
|
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
25
|
+
none: false
|
|
26
|
+
requirements:
|
|
27
|
+
- - ! '>='
|
|
28
|
+
- !ruby/object:Gem::Version
|
|
29
|
+
version: '0'
|
|
30
|
+
description: Fetch details of problems, codes and users from poj.org
|
|
15
31
|
email: pinepara@gmail.com
|
|
16
32
|
executables: []
|
|
17
33
|
extensions: []
|
|
18
34
|
extra_rdoc_files: []
|
|
19
35
|
files:
|
|
20
36
|
- ./lib/poj_org.rb
|
|
37
|
+
- ./lib/poj_org/problem.rb
|
|
38
|
+
- ./lib/poj_org/errors.rb
|
|
39
|
+
- ./lib/poj_org/code.rb
|
|
40
|
+
- ./lib/poj_org/user.rb
|
|
21
41
|
homepage: https://github.com/pinepara/poj_org
|
|
22
42
|
licenses: []
|
|
23
43
|
post_install_message:
|