ojsubmitter 0.4.1 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +14 -9
- data/exe/ojsubmitter +2 -0
- data/lib/ojsubmitter.rb +1 -0
- data/lib/ojsubmitter/cli.rb +5 -0
- data/lib/ojsubmitter/judge.rb +4 -1
- data/lib/ojsubmitter/judge/atcoder.rb +106 -0
- data/lib/ojsubmitter/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3525ee90ceff005c0e0bd6417eb44b6cda07515c
|
4
|
+
data.tar.gz: 2061c12ddf318c3dbedf9ec48d62651cb803bb9a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3fb69b0aea4f371cbea9b415c60e6fbf6fe315c169613f156b8cd5509fd43cb4abf0f75c83c77d370cd273709c9ebc4a0aaef3284ed8e7145c638742a165a0b5
|
7
|
+
data.tar.gz: 0b7657ab8067283d63885906c0d21fdf29265741a966b42f0fd2346af5c388f680681c79e0ea1621fe31ff1e874f7483a5ff6ea4543b603bfc8692a7ad2d9a31
|
data/README.md
CHANGED
@@ -13,6 +13,7 @@ This gem helps you submit source code to online judges from command line interfa
|
|
13
13
|
- [PKU JudgeOnline](http://poj.org)
|
14
14
|
- [Sphere online judge](http://www.spoj.com)
|
15
15
|
- [Codeforces](http://codeforces.com)
|
16
|
+
- [AtCoder](http://atcoder.jp)
|
16
17
|
|
17
18
|
You can also get this list from `ojsubmitter list` command.
|
18
19
|
|
@@ -32,7 +33,7 @@ You can set the default options of ojsubmitter command.
|
|
32
33
|
|
33
34
|
#### Submit
|
34
35
|
|
35
|
-
$ ojsubmitter -j [JUDGE_NAME] -u [USER_NAME] -p [PASSWORD] -l [LANGUAGE] -f [SOURCE_FILE] -i [PROBLEM_ID]
|
36
|
+
$ ojsubmitter -j [JUDGE_NAME] -u [USER_NAME] -p [PASSWORD] -l [LANGUAGE] -f [SOURCE_FILE] -i [PROBLEM_ID] -c [CONTEST_ID]
|
36
37
|
|
37
38
|
This command has too many options, so you can use `.ojsconf.yml` to set default options.
|
38
39
|
After submitting, this will open the submission status page with web browser. If you don't want to open browser, please use `-n` option.
|
@@ -40,16 +41,17 @@ If you don't specify the problem id, this tool assume the problem id from file n
|
|
40
41
|
|
41
42
|
#### Available judges and options to submit.
|
42
43
|
|
43
|
-
| online judge | problem | judge (-j) | problem_id (-i) | file name (-f) |
|
44
|
-
|
45
|
-
| Aizu Online Judge | [0000](http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=0000) | aoj | 0000 | 0000.cpp |
|
46
|
-
| PKU Judge Online | [1000](http://poj.org/problem?id=1000) | poj | 1000 | 1000.cpp |
|
47
|
-
| Sphere Online Judge | [PRIME1](http://www.spoj.com/problems/PRIME1/) | spoj | PRIME1 | prime1.cpp |
|
48
|
-
| Codeforces | [1A](http://codeforces.com/problemset/problem/1/A) | cf, codeforces | 1A | 1A.cpp |
|
49
|
-
|
50
|
-
When you submit to Codeforces and your file name is like `A.cpp`, this tool assume contest id from your current directory. For example, if your current directory is `/path/to/cf/1` and file name is `A.cpp`, problem id will be `1A`.
|
44
|
+
| online judge | problem | judge (-j) | problem_id (-i) | file name (-f) | contest_id (-c) |
|
45
|
+
|:--|:--:|:--:|:--:|:--:|:--:|
|
46
|
+
| Aizu Online Judge | [0000](http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=0000) | aoj | 0000 | 0000.cpp | |
|
47
|
+
| PKU Judge Online | [1000](http://poj.org/problem?id=1000) | poj | 1000 | 1000.cpp | |
|
48
|
+
| Sphere Online Judge | [PRIME1](http://www.spoj.com/problems/PRIME1/) | spoj | PRIME1 | prime1.cpp | |
|
49
|
+
| Codeforces | [1A](http://codeforces.com/problemset/problem/1/A) | cf, codeforces | 1A | 1A.cpp | |
|
50
|
+
| AtCoder | [abc001 A](http://abc001.contest.atcoder.jp/tasks/abc001_1) | atcoder | A | a.cpp | abc001 |
|
51
51
|
|
52
52
|
|
53
|
+
When you submit to Codeforces and your file name is like `A.cpp`, this tool assume contest id from your current directory. For example, if your current directory is `/path/to/cf/1` and file name is `A.cpp`, problem id will be `1A`.
|
54
|
+
|
53
55
|
#### Available languages
|
54
56
|
|
55
57
|
All languages are case-insensitive.
|
@@ -183,6 +185,9 @@ Version infomation of Codeforces is [here](http://codeforces.com/blog/entry/79).
|
|
183
185
|
| Scala 2.11.7 | Scala |
|
184
186
|
| JavaScript V8 4.8.0 | JavaScript |
|
185
187
|
|
188
|
+
#### AtCoder
|
189
|
+
|
190
|
+
When you use this for submitting to atcoder, this tool will get languages list from atcoder and submit with matched language. If two more languages are matched, you have to select one.
|
186
191
|
|
187
192
|
#### Help
|
188
193
|
|
data/exe/ojsubmitter
CHANGED
data/lib/ojsubmitter.rb
CHANGED
data/lib/ojsubmitter/cli.rb
CHANGED
@@ -40,6 +40,9 @@ module OJS
|
|
40
40
|
aliases: "-n",
|
41
41
|
type: :boolean,
|
42
42
|
desc: "Don't show status page after submitting."
|
43
|
+
option :contest_id,
|
44
|
+
aliases: "-c",
|
45
|
+
desc: "Specify a contest id of AtCoder"
|
43
46
|
def submit
|
44
47
|
@config = set_options_from_config_file(options.to_h)
|
45
48
|
judge_class.submit @config
|
@@ -78,6 +81,8 @@ module OJS
|
|
78
81
|
OJS.const_get @config['judge'].upcase
|
79
82
|
when 'codeforces', 'cf'
|
80
83
|
OJS::Codeforces
|
84
|
+
when 'atcoder'
|
85
|
+
OJS::AtCoder
|
81
86
|
else
|
82
87
|
raise UnknownJudgeError
|
83
88
|
end
|
data/lib/ojsubmitter/judge.rb
CHANGED
@@ -5,10 +5,11 @@ module OJS
|
|
5
5
|
class Judge
|
6
6
|
class LoginFailedError < StandardError; end
|
7
7
|
class SubmissionError < StandardError; end
|
8
|
+
class UnknownLanguageError < StandardError; end
|
8
9
|
|
9
10
|
class << self
|
10
11
|
def valid_judges
|
11
|
-
%w[AOJ POJ SPOJ Codeforces]
|
12
|
+
%w[AOJ POJ SPOJ Codeforces AtCoder]
|
12
13
|
end
|
13
14
|
|
14
15
|
def login
|
@@ -26,6 +27,8 @@ module OJS
|
|
26
27
|
Logger.error "Login failed!"
|
27
28
|
rescue SubmissionError => err
|
28
29
|
Logger.error "Failed to submit. Check your config."
|
30
|
+
rescue UnknownLanguageError => err
|
31
|
+
Logger.error "No languages are matched."
|
29
32
|
end
|
30
33
|
|
31
34
|
def post
|
@@ -0,0 +1,106 @@
|
|
1
|
+
require 'ojsubmitter/judge'
|
2
|
+
require 'nokogiri'
|
3
|
+
|
4
|
+
module OJS
|
5
|
+
class AtCoder < Judge
|
6
|
+
class << self
|
7
|
+
def login
|
8
|
+
res = hclient.post(
|
9
|
+
"https://#{contest_url}/login",
|
10
|
+
{ name: user,
|
11
|
+
password: password,
|
12
|
+
submit: 'Login' }
|
13
|
+
)
|
14
|
+
hclient.cookies.each do |ck|
|
15
|
+
ck.domain = contest_url if ck.domain == 'atcoder.jp'
|
16
|
+
end
|
17
|
+
raise Judge::LoginFailedError unless hclient.cookies.any? { |ck| ck.name == '_user_id' }
|
18
|
+
Logger.info "Logged in successfully."
|
19
|
+
end
|
20
|
+
|
21
|
+
def post
|
22
|
+
res = hclient.post(
|
23
|
+
"https://#{contest_url}/submit",
|
24
|
+
{ __session: session,
|
25
|
+
task_id: task_id,
|
26
|
+
:"language_id_#{task_id}" => language,
|
27
|
+
source_code: code,
|
28
|
+
submit: 'submit',
|
29
|
+
}
|
30
|
+
)
|
31
|
+
raise Judge::SubmissionError if res.body =~ /Error/
|
32
|
+
end
|
33
|
+
|
34
|
+
def contest_url
|
35
|
+
"#{contest_id}.contest.atcoder.jp"
|
36
|
+
end
|
37
|
+
|
38
|
+
def status_url
|
39
|
+
"https://#{contest_url}/submissions/me"
|
40
|
+
end
|
41
|
+
|
42
|
+
def language
|
43
|
+
set_extra_values unless @languages
|
44
|
+
cands = []
|
45
|
+
@languages.each do |id, name|
|
46
|
+
cands << [id,name] if name.downcase.match Regexp.escape(@config['language'].downcase)
|
47
|
+
end
|
48
|
+
raise Judge::UnknownLanguageError if cands.empty?
|
49
|
+
return cands[0][0] if cands.size == 1
|
50
|
+
select_language cands
|
51
|
+
end
|
52
|
+
|
53
|
+
def select_language(cands)
|
54
|
+
Logger.info "Two more languages are matched. Please select one."
|
55
|
+
cands.each_with_index do |cand, idx|
|
56
|
+
Logger.info "#{idx} : #{cand[1]}"
|
57
|
+
end
|
58
|
+
while true
|
59
|
+
inp = STDIN.gets.chomp
|
60
|
+
next Logger.info "Please input number." unless inp =~ /\A\d+\z/
|
61
|
+
idx = inp.to_i
|
62
|
+
next Logger.info "Please input valid number." unless cands[idx]
|
63
|
+
return cands[idx][0]
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def contest_id
|
68
|
+
unless @config['contest_id']
|
69
|
+
@config['contest_id'] = Dir.pwd.split('/').last
|
70
|
+
end
|
71
|
+
@config['contest_id'].downcase
|
72
|
+
end
|
73
|
+
|
74
|
+
def task_id
|
75
|
+
unless @task_id
|
76
|
+
set_extra_values
|
77
|
+
end
|
78
|
+
@task_id
|
79
|
+
end
|
80
|
+
|
81
|
+
def problem_id
|
82
|
+
unless @config['problem_id']
|
83
|
+
@config['problem_id'] = File.basename(file).split('.')[0]
|
84
|
+
end
|
85
|
+
@config['problem_id'].upcase
|
86
|
+
end
|
87
|
+
|
88
|
+
def session
|
89
|
+
unless @session
|
90
|
+
set_extra_values
|
91
|
+
end
|
92
|
+
@session
|
93
|
+
end
|
94
|
+
|
95
|
+
def set_extra_values
|
96
|
+
res = @hclient.get("https://#{contest_url}/submit")
|
97
|
+
html = Nokogiri::HTML.parse(res.body)
|
98
|
+
@session = html.xpath('//input[@name="__session"]/@value').first.value
|
99
|
+
@task_id = html.xpath('//select[@name="task_id"]/option').first.attribute('value').value.to_i + problem_id.ord - 'A'.ord
|
100
|
+
@languages = html.xpath("//select[@name=\"language_id_#{@task_id}\"]/option").map { |lang|
|
101
|
+
[lang.attribute('value').value, lang.content]
|
102
|
+
}
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
data/lib/ojsubmitter/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ojsubmitter
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- hadrori
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-03-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -188,6 +188,7 @@ files:
|
|
188
188
|
- lib/ojsubmitter/cli.rb
|
189
189
|
- lib/ojsubmitter/judge.rb
|
190
190
|
- lib/ojsubmitter/judge/aoj.rb
|
191
|
+
- lib/ojsubmitter/judge/atcoder.rb
|
191
192
|
- lib/ojsubmitter/judge/codeforces.rb
|
192
193
|
- lib/ojsubmitter/judge/poj.rb
|
193
194
|
- lib/ojsubmitter/judge/spoj.rb
|