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.
Files changed (44) hide show
  1. checksums.yaml +5 -5
  2. data/.rubocop.yml +3 -2
  3. data/.travis.yml +1 -3
  4. data/CHANGELOG.md +37 -0
  5. data/Gemfile.lock +53 -48
  6. data/README.md +1 -1
  7. data/at_coder_friends.gemspec +5 -7
  8. data/config/default.yml +146 -72
  9. data/docs/CONFIGURATION.md +222 -136
  10. data/lib/at_coder_friends.rb +1 -0
  11. data/lib/at_coder_friends/cli.rb +8 -0
  12. data/lib/at_coder_friends/config_loader.rb +11 -3
  13. data/lib/at_coder_friends/context.rb +10 -6
  14. data/lib/at_coder_friends/emitter.rb +2 -2
  15. data/lib/at_coder_friends/generator/base.rb +3 -2
  16. data/lib/at_coder_friends/generator/main.rb +2 -1
  17. data/lib/at_coder_friends/parser/constraints.rb +1 -0
  18. data/lib/at_coder_friends/parser/input_format.rb +2 -0
  19. data/lib/at_coder_friends/parser/input_type.rb +3 -2
  20. data/lib/at_coder_friends/parser/modulo.rb +1 -1
  21. data/lib/at_coder_friends/parser/sections.rb +3 -3
  22. data/lib/at_coder_friends/path_info.rb +51 -0
  23. data/lib/at_coder_friends/path_util.rb +0 -31
  24. data/lib/at_coder_friends/scraping/agent.rb +11 -2
  25. data/lib/at_coder_friends/scraping/custom_test.rb +5 -6
  26. data/lib/at_coder_friends/scraping/submission.rb +6 -7
  27. data/lib/at_coder_friends/scraping/tasks.rb +8 -3
  28. data/lib/at_coder_friends/test_runner/base.rb +17 -4
  29. data/lib/at_coder_friends/test_runner/judge.rb +7 -9
  30. data/lib/at_coder_friends/test_runner/sample.rb +2 -4
  31. data/lib/at_coder_friends/verifier.rb +2 -3
  32. data/lib/at_coder_friends/version.rb +1 -1
  33. data/templates/cxx_builtin.cxx.erb +26 -35
  34. data/templates/ruby_builtin.rb.erb +17 -18
  35. metadata +7 -16
  36. data/tasks/regression/check_const.rake +0 -137
  37. data/tasks/regression/check_diff.rake +0 -30
  38. data/tasks/regression/check_fmt.rake +0 -45
  39. data/tasks/regression/check_parse.rake +0 -69
  40. data/tasks/regression/list_handler.rb +0 -46
  41. data/tasks/regression/regression.rb +0 -38
  42. data/tasks/regression/report_handler.rb +0 -20
  43. data/tasks/regression/section_list.rake +0 -53
  44. 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
@@ -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