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.
@@ -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,9 @@
1
+ module PojOrg
2
+ module Errors
3
+ class Error < StandardError; end
4
+ class Unauthorized < StandardError; end
5
+ class ProblemNotFound < StandardError; end
6
+ class CodeNotFound < StandardError; end
7
+ class AccessDenied < StandardError; end
8
+ end
9
+ 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
@@ -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 'net/http'
2
- require 'open-uri'
3
- require 'cgi'
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.3.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-01-25 00:00:00.000000000 Z
13
- dependencies: []
14
- description: Fetch details of problems and codes from poj.org
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: