at_coder_friends 0.6.3 → 0.6.8
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.rubocop.yml +3 -2
- data/.travis.yml +1 -3
- data/CHANGELOG.md +37 -0
- data/Gemfile.lock +53 -48
- data/README.md +1 -1
- data/at_coder_friends.gemspec +5 -7
- data/config/default.yml +146 -72
- data/docs/CONFIGURATION.md +222 -136
- data/lib/at_coder_friends.rb +1 -0
- data/lib/at_coder_friends/cli.rb +8 -0
- data/lib/at_coder_friends/config_loader.rb +11 -3
- data/lib/at_coder_friends/context.rb +10 -6
- data/lib/at_coder_friends/emitter.rb +2 -2
- data/lib/at_coder_friends/generator/base.rb +3 -2
- data/lib/at_coder_friends/generator/main.rb +2 -1
- data/lib/at_coder_friends/parser/constraints.rb +1 -0
- data/lib/at_coder_friends/parser/input_format.rb +2 -0
- data/lib/at_coder_friends/parser/input_type.rb +3 -2
- data/lib/at_coder_friends/parser/modulo.rb +1 -1
- data/lib/at_coder_friends/parser/sections.rb +3 -3
- data/lib/at_coder_friends/path_info.rb +51 -0
- data/lib/at_coder_friends/path_util.rb +0 -31
- data/lib/at_coder_friends/scraping/agent.rb +11 -2
- data/lib/at_coder_friends/scraping/custom_test.rb +5 -6
- data/lib/at_coder_friends/scraping/submission.rb +6 -7
- data/lib/at_coder_friends/scraping/tasks.rb +8 -3
- data/lib/at_coder_friends/test_runner/base.rb +17 -4
- data/lib/at_coder_friends/test_runner/judge.rb +7 -9
- data/lib/at_coder_friends/test_runner/sample.rb +2 -4
- data/lib/at_coder_friends/verifier.rb +2 -3
- data/lib/at_coder_friends/version.rb +1 -1
- data/templates/cxx_builtin.cxx.erb +26 -35
- data/templates/ruby_builtin.rb.erb +17 -18
- metadata +7 -16
- data/tasks/regression/check_const.rake +0 -137
- data/tasks/regression/check_diff.rake +0 -30
- data/tasks/regression/check_fmt.rake +0 -45
- data/tasks/regression/check_parse.rake +0 -69
- data/tasks/regression/list_handler.rb +0 -46
- data/tasks/regression/regression.rb +0 -38
- data/tasks/regression/report_handler.rb +0 -20
- data/tasks/regression/section_list.rake +0 -53
- data/tasks/regression/setup.rake +0 -48
@@ -1,45 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_relative 'regression'
|
4
|
-
|
5
|
-
module AtCoderFriends
|
6
|
-
# tasks for regression
|
7
|
-
module Regression
|
8
|
-
module_function
|
9
|
-
|
10
|
-
def check_fmt
|
11
|
-
open_report('check_fmt.txt') do |f|
|
12
|
-
local_pbm_list.each do |contest, q, url|
|
13
|
-
next unless (res = process_fmt(contest, q, url))
|
14
|
-
|
15
|
-
f.puts [
|
16
|
-
contest, q, *res.map { |s| tsv_escape(s) }
|
17
|
-
].join("\t")
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
def process_fmt(contest, q, url)
|
23
|
-
pbm = local_scraping_agent(nil, contest).fetch_problem(q, url)
|
24
|
-
Parser::Sections.process(pbm)
|
25
|
-
Parser::SampleData.process(pbm)
|
26
|
-
fmt1 = Parser::InputFormat.find_fmt(pbm)
|
27
|
-
return unless fmt1 && !fmt1.empty?
|
28
|
-
|
29
|
-
fmt2 = Parser::InputFormat.normalize_fmt(fmt1).join("\n")
|
30
|
-
Parser::InputFormat.process(pbm)
|
31
|
-
Parser::InputType.process(pbm)
|
32
|
-
inpdefs = pbm.formats_src
|
33
|
-
fmt3 = inpdefs.map(&:to_s).join("\n")
|
34
|
-
fmt4 = inpdefs.any? { |inpdef| inpdef.cols.empty? } ? '○' : ''
|
35
|
-
[fmt1, fmt2, fmt3, fmt4]
|
36
|
-
end
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
namespace :regression do
|
41
|
-
desc 'checks input format patterns'
|
42
|
-
task :check_fmt do
|
43
|
-
AtCoderFriends::Regression.check_fmt
|
44
|
-
end
|
45
|
-
end
|
@@ -1,69 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_relative 'regression'
|
4
|
-
require 'at_coder_friends'
|
5
|
-
|
6
|
-
module AtCoderFriends
|
7
|
-
# tasks for regression
|
8
|
-
module Regression
|
9
|
-
module_function
|
10
|
-
|
11
|
-
def check_parse
|
12
|
-
list = local_pbm_list.map do |contest, q, url|
|
13
|
-
pbm = local_scraping_agent(nil, contest).fetch_problem(q, url)
|
14
|
-
Parser::Main.process(pbm)
|
15
|
-
flags = [
|
16
|
-
!fmt?(pbm),
|
17
|
-
pbm.samples.all? { |smp| smp.txt.empty? },
|
18
|
-
pbm.options.interactive
|
19
|
-
]
|
20
|
-
[contest, q, flags]
|
21
|
-
end
|
22
|
-
report(list, 'check_parse.txt')
|
23
|
-
end
|
24
|
-
|
25
|
-
def check_bin
|
26
|
-
list = local_pbm_list.map do |contest, q, url|
|
27
|
-
pbm = local_scraping_agent(nil, contest).fetch_problem(q, url)
|
28
|
-
Parser::Main.process(pbm)
|
29
|
-
flags = [pbm.options.binary_values]
|
30
|
-
[contest, q, flags]
|
31
|
-
end
|
32
|
-
report(list, 'check_bin.txt')
|
33
|
-
end
|
34
|
-
|
35
|
-
def fmt?(pbm)
|
36
|
-
fmt = Parser::InputFormat.find_fmt(pbm)
|
37
|
-
fmt && !fmt.empty?
|
38
|
-
end
|
39
|
-
|
40
|
-
def report(list, file)
|
41
|
-
open_report(file) do |f|
|
42
|
-
list
|
43
|
-
.select { |_, _, flags| flags.any? }
|
44
|
-
.map { |c, q, flags| [c, q, flags.map { |flg| f_to_s(flg) }] }
|
45
|
-
.each { |args| f.puts args.flatten.join("\t") }
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
def f_to_s(f)
|
50
|
-
if f.is_a?(Array)
|
51
|
-
f
|
52
|
-
else
|
53
|
-
f ? '◯' : '-'
|
54
|
-
end
|
55
|
-
end
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
namespace :regression do
|
60
|
-
desc 'checks page parse result'
|
61
|
-
task :check_parse do
|
62
|
-
AtCoderFriends::Regression.check_parse
|
63
|
-
end
|
64
|
-
|
65
|
-
desc 'checks binary problem parse result'
|
66
|
-
task :check_bin do
|
67
|
-
AtCoderFriends::Regression.check_bin
|
68
|
-
end
|
69
|
-
end
|
@@ -1,46 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'net/http'
|
4
|
-
require 'uri'
|
5
|
-
require 'json'
|
6
|
-
require 'csv'
|
7
|
-
|
8
|
-
module AtCoderFriends
|
9
|
-
# tasks for regression
|
10
|
-
module Regression
|
11
|
-
module_function
|
12
|
-
|
13
|
-
CONTEST_LIST_URL = 'https://kenkoooo.com/atcoder/resources/contests.json'
|
14
|
-
ACF_HOME = File.expand_path(File.join(__dir__, '..', '..'))
|
15
|
-
REGRESSION_HOME = File.join(ACF_HOME, 'regression')
|
16
|
-
PAGES_DIR = File.join(REGRESSION_HOME, 'pages')
|
17
|
-
EMIT_ORG_DIR = File.join(REGRESSION_HOME, 'emit_org')
|
18
|
-
EMIT_DIR_FMT = File.join(REGRESSION_HOME, 'emit_%<now>s')
|
19
|
-
|
20
|
-
def contest_id_list
|
21
|
-
uri = URI.parse(CONTEST_LIST_URL)
|
22
|
-
json = Net::HTTP.get(uri)
|
23
|
-
contests = JSON.parse(json)
|
24
|
-
puts "Total #{contests.size} contests"
|
25
|
-
contests.map { |h| h['id'] }
|
26
|
-
end
|
27
|
-
|
28
|
-
def local_pbm_list
|
29
|
-
Dir.glob(PAGES_DIR + '/**/*.html').map do |pbm_path|
|
30
|
-
contest = File.basename(File.dirname(pbm_path))
|
31
|
-
q = File.basename(pbm_path, '.html')
|
32
|
-
url = "file://#{pbm_path}"
|
33
|
-
[contest, q, url]
|
34
|
-
end.sort # .take(10)
|
35
|
-
end
|
36
|
-
|
37
|
-
def pbm_list_from_file(file)
|
38
|
-
dat = File.join(REGRESSION_HOME, file)
|
39
|
-
CSV.read(dat, col_sep: "\t", headers: false).map do |contest, q|
|
40
|
-
pbm_path = File.join(PAGES_DIR, contest, "#{q}.html")
|
41
|
-
url = "file://#{pbm_path}"
|
42
|
-
[contest, q, url]
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end
|
@@ -1,38 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'mechanize'
|
4
|
-
require 'at_coder_friends'
|
5
|
-
require_relative 'list_handler'
|
6
|
-
require_relative 'report_handler'
|
7
|
-
|
8
|
-
module AtCoderFriends
|
9
|
-
# tasks for regression
|
10
|
-
module Regression
|
11
|
-
module_function
|
12
|
-
|
13
|
-
def scraping_agent(root, contest)
|
14
|
-
root ||= REGRESSION_HOME
|
15
|
-
@ctx = Context.new({}, File.join(root, contest))
|
16
|
-
@ctx.scraping_agent
|
17
|
-
end
|
18
|
-
|
19
|
-
def local_scraping_agent(root, contest)
|
20
|
-
scraping_agent(root, contest)
|
21
|
-
.tap { |sa| sa.agent.pre_connect_hooks.clear }
|
22
|
-
end
|
23
|
-
|
24
|
-
def agent
|
25
|
-
@agent ||= Mechanize.new
|
26
|
-
end
|
27
|
-
|
28
|
-
def pipeline(pbm)
|
29
|
-
Parser::Main.process(pbm)
|
30
|
-
@ctx.generator.process(pbm)
|
31
|
-
@ctx.emitter.emit(pbm)
|
32
|
-
end
|
33
|
-
|
34
|
-
def rmdir_force(dir)
|
35
|
-
FileUtils.rm_r(dir) if Dir.exist?(dir)
|
36
|
-
end
|
37
|
-
end
|
38
|
-
end
|
@@ -1,20 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module AtCoderFriends
|
4
|
-
# tasks for regression
|
5
|
-
module Regression
|
6
|
-
module_function
|
7
|
-
|
8
|
-
def open_report(file)
|
9
|
-
File.open(report_path(file), 'wb') { |f| yield f }
|
10
|
-
end
|
11
|
-
|
12
|
-
def report_path(file)
|
13
|
-
File.join(REGRESSION_HOME, file)
|
14
|
-
end
|
15
|
-
|
16
|
-
def tsv_escape(str)
|
17
|
-
'"' + str.gsub('"', '""').gsub("\t", ' ') + '"'
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
@@ -1,53 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_relative 'regression'
|
4
|
-
|
5
|
-
module AtCoderFriends
|
6
|
-
# tasks for regression
|
7
|
-
module Regression
|
8
|
-
module_function
|
9
|
-
|
10
|
-
SectionInfo = Struct.new(:contest, :q, :title)
|
11
|
-
|
12
|
-
def section_list
|
13
|
-
list = load_section_list
|
14
|
-
save_section_list(list)
|
15
|
-
end
|
16
|
-
|
17
|
-
def load_section_list
|
18
|
-
local_pbm_list.flat_map do |contest, q, url|
|
19
|
-
page = agent.get(url)
|
20
|
-
%w[h2 h3].flat_map do |tag|
|
21
|
-
page.search(tag).map do |h|
|
22
|
-
SectionInfo.new(contest, q, normalize(h.content))
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
def save_section_list(list)
|
29
|
-
open_report('section_list.txt') do |f|
|
30
|
-
list.group_by(&:title).each do |k, vs|
|
31
|
-
f.puts [k, vs.size, vs[0].contest, vs[0].q].join("\t")
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
def normalize(s)
|
37
|
-
s
|
38
|
-
.tr('0-9A-Za-z', '0-9A-Za-z')
|
39
|
-
.gsub(/[[:space:]]/, '')
|
40
|
-
.gsub(/[^一-龠_ぁ-ん_ァ-ヶーa-zA-Z0-9 ]/, '')
|
41
|
-
.downcase
|
42
|
-
.gsub(/\d+/, '{N}')
|
43
|
-
.strip
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
namespace :regression do
|
49
|
-
desc 'list all section titles'
|
50
|
-
task :section_list do
|
51
|
-
AtCoderFriends::Regression.section_list
|
52
|
-
end
|
53
|
-
end
|
data/tasks/regression/setup.rake
DELETED
@@ -1,48 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_relative 'regression'
|
4
|
-
|
5
|
-
module AtCoderFriends
|
6
|
-
# tasks for regression
|
7
|
-
module Regression
|
8
|
-
module_function
|
9
|
-
|
10
|
-
def setup
|
11
|
-
rmdir_force(PAGES_DIR)
|
12
|
-
rmdir_force(EMIT_ORG_DIR)
|
13
|
-
contest_id_list.each do |contest|
|
14
|
-
setup_by_contest(contest)
|
15
|
-
sleep 3
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
def setup_by_contest(contest)
|
20
|
-
scraping_agent(EMIT_ORG_DIR, contest).fetch_all do |pbm|
|
21
|
-
setup_by_pbm(contest, pbm)
|
22
|
-
end
|
23
|
-
rescue StandardError => e
|
24
|
-
p e
|
25
|
-
end
|
26
|
-
|
27
|
-
def setup_by_pbm(contest, pbm)
|
28
|
-
html_path = File.join(PAGES_DIR, contest, "#{pbm.q}.html")
|
29
|
-
save_file(html_path, pbm.page.body)
|
30
|
-
pipeline(pbm)
|
31
|
-
rescue StandardError => e
|
32
|
-
p e
|
33
|
-
end
|
34
|
-
|
35
|
-
def save_file(path, content)
|
36
|
-
dir = File.dirname(path)
|
37
|
-
FileUtils.makedirs(dir) unless Dir.exist?(dir)
|
38
|
-
File.binwrite(path, content)
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
namespace :regression do
|
44
|
-
desc 'setup regression environment'
|
45
|
-
task :setup do
|
46
|
-
AtCoderFriends::Regression.setup
|
47
|
-
end
|
48
|
-
end
|