at_coder_friends 0.6.3 → 0.6.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 9a7432316e843545fb879309e242139dc2c0405c
4
- data.tar.gz: 9e22a2dcde9e98a171ed393365de8fd308957996
3
+ metadata.gz: ac22f93d26dc92de38a01ed67b2fa1a8465380c2
4
+ data.tar.gz: 28e89a872bcc0825b5a4f53019fd43a7dea07511
5
5
  SHA512:
6
- metadata.gz: 70e350831761899ee4178e65f8563cbd328a0b8e70971e4620015d623484c0297fa60a6a5ce447bb349d3b2fa06799b336fb270913a34b8efb857dc97e9dfaa3
7
- data.tar.gz: ff84c2c7fb80dda6105561d82d94c697c7e5133e91219c9f6530f8e7db083192a5ac8a5148a204fd5740c3cf470d53fd56ac5026b908738f12ccb671d824dd39
6
+ metadata.gz: dee4b060fbd70915fa8e59c170a9d02e9d2ae8af925251d89e4fb3f5b1a9d7d33e20f71ffb39de4ea54190ff50011ac0ad8795149c576134a12f876448831cf8
7
+ data.tar.gz: 02a32cd3a62047c90cd8dd30269a8d5d6c82d443bc1f7e7adebfddc4c78742a6d4bd3ff6f53a24ec71f10da5bdd74a34ce9107cd7463d6b1b575adc317714bf5
data/.travis.yml CHANGED
@@ -7,7 +7,7 @@ env:
7
7
  - CC_TEST_REPORTER_ID=cb942bcc168feb78c43c506364d5344c5ec9a46a0b68dc66acb581e77c981ff1
8
8
  - COVERAGE=true
9
9
  before_install:
10
- - gem install bundler -v '2.0.2'
10
+ - gem install bundler -v '2.1.4'
11
11
  before_script:
12
12
  - curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
13
13
  - chmod +x ./cc-test-reporter
data/CHANGELOG.md CHANGED
@@ -1,6 +1,9 @@
1
1
  # Change log
2
2
 
3
3
  ## master (unreleased)
4
+ ### Changed
5
+ - Modulo RegExp pattern.
6
+ - Minor changes in ERBs.
4
7
 
5
8
  ## 0.6.3 (2020-01-05)
6
9
  ### Added
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- at_coder_friends (0.6.3)
4
+ at_coder_friends (0.6.4)
5
5
  colorize (~> 0.8.1)
6
6
  launchy (~> 2.4.3)
7
7
  mechanize (~> 2.0)
@@ -19,10 +19,10 @@ GEM
19
19
  docile (1.3.2)
20
20
  domain_name (0.5.20190701)
21
21
  unf (>= 0.0.5, < 1.0.0)
22
- hashdiff (1.0.0)
22
+ hashdiff (1.0.1)
23
23
  http-cookie (1.0.3)
24
24
  domain_name (~> 0.5)
25
- json (2.2.0)
25
+ json (2.3.0)
26
26
  launchy (2.4.3)
27
27
  addressable (~> 2.3)
28
28
  mechanize (2.7.6)
@@ -34,31 +34,31 @@ GEM
34
34
  nokogiri (~> 1.6)
35
35
  ntlm-http (~> 0.1, >= 0.1.1)
36
36
  webrobots (>= 0.0.9, < 0.2)
37
- mime-types (3.3)
37
+ mime-types (3.3.1)
38
38
  mime-types-data (~> 3.2015)
39
39
  mime-types-data (3.2019.1009)
40
40
  mini_portile2 (2.4.0)
41
41
  net-http-digest_auth (1.4.1)
42
42
  net-http-persistent (3.1.0)
43
43
  connection_pool (~> 2.2)
44
- nokogiri (1.10.5)
44
+ nokogiri (1.10.9)
45
45
  mini_portile2 (~> 2.4.0)
46
46
  ntlm-http (0.1.1)
47
- public_suffix (4.0.1)
47
+ public_suffix (4.0.3)
48
48
  rake (13.0.1)
49
49
  rspec (3.9.0)
50
50
  rspec-core (~> 3.9.0)
51
51
  rspec-expectations (~> 3.9.0)
52
52
  rspec-mocks (~> 3.9.0)
53
- rspec-core (3.9.0)
54
- rspec-support (~> 3.9.0)
53
+ rspec-core (3.9.1)
54
+ rspec-support (~> 3.9.1)
55
55
  rspec-expectations (3.9.0)
56
56
  diff-lcs (>= 1.2.0, < 2.0)
57
57
  rspec-support (~> 3.9.0)
58
- rspec-mocks (3.9.0)
58
+ rspec-mocks (3.9.1)
59
59
  diff-lcs (>= 1.2.0, < 2.0)
60
60
  rspec-support (~> 3.9.0)
61
- rspec-support (3.9.0)
61
+ rspec-support (3.9.2)
62
62
  safe_yaml (1.0.5)
63
63
  simplecov (0.17.1)
64
64
  docile (~> 1.1)
@@ -68,7 +68,7 @@ GEM
68
68
  unf (0.1.4)
69
69
  unf_ext
70
70
  unf_ext (0.0.7.6)
71
- webmock (3.7.6)
71
+ webmock (3.8.2)
72
72
  addressable (>= 2.3.6)
73
73
  crack (>= 0.3.2)
74
74
  hashdiff (>= 0.4.0, < 2.0.0)
@@ -87,4 +87,4 @@ DEPENDENCIES
87
87
  webmock (~> 3.0)
88
88
 
89
89
  BUNDLED WITH
90
- 2.0.2
90
+ 2.1.4
@@ -23,7 +23,7 @@ Gem::Specification.new do |spec|
23
23
 
24
24
  spec.files = Dir.chdir(File.expand_path(__dir__)) do
25
25
  `git ls-files -z`.split("\x0").reject do |f|
26
- f.match(%r{^(test|spec|features)/})
26
+ f.match(%r{^(test|spec|features|tasks)/})
27
27
  end
28
28
  end
29
29
  spec.bindir = 'exe'
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'optparse'
4
- require 'launchy'
5
4
 
6
5
  module AtCoderFriends
7
6
  # command line interface
@@ -140,6 +139,7 @@ module AtCoderFriends
140
139
  end
141
140
 
142
141
  def open_contest
142
+ require 'launchy'
143
143
  Launchy.open(ctx.scraping_agent.contest_url)
144
144
  end
145
145
  end
@@ -11,20 +11,28 @@ module AtCoderFriends
11
11
  DEFAULT_FILE = File.join(ACF_HOME, 'config', 'default.yml')
12
12
 
13
13
  class << self
14
+ def dotfile
15
+ DOTFILE
16
+ end
17
+
18
+ def default_file
19
+ DEFAULT_FILE
20
+ end
21
+
14
22
  def load_config(ctx)
15
23
  path = config_file_for(ctx.path)
16
24
  config = load_yaml(path)
17
- return config if path == DEFAULT_FILE
25
+ return config if path == default_file
18
26
 
19
27
  merge_with_default(config)
20
28
  end
21
29
 
22
30
  def config_file_for(target_dir)
23
- find_project_dotfile(target_dir) || DEFAULT_FILE
31
+ find_project_dotfile(target_dir) || default_file
24
32
  end
25
33
 
26
34
  def find_project_dotfile(target_dir)
27
- find_file_upwards(DOTFILE, target_dir)
35
+ find_file_upwards(dotfile, target_dir)
28
36
  end
29
37
 
30
38
  def find_file_upwards(filename, start_dir)
@@ -7,11 +7,15 @@ module AtCoderFriends
7
7
  # - configuration
8
8
  # - application modules
9
9
  class Context
10
- attr_reader :options, :path
10
+ attr_reader :options, :path_info
11
11
 
12
12
  def initialize(options, path)
13
13
  @options = options
14
- @path = File.expand_path(path)
14
+ @path_info = PathInfo.new(File.expand_path(path))
15
+ end
16
+
17
+ def path
18
+ path_info.path
15
19
  end
16
20
 
17
21
  def config
@@ -26,6 +30,10 @@ module AtCoderFriends
26
30
  @generator ||= Generator::Main.new(self)
27
31
  end
28
32
 
33
+ def emitter
34
+ @emitter ||= Emitter.new(self)
35
+ end
36
+
29
37
  def sample_test_runner
30
38
  @sample_test_runner ||= TestRunner::Sample.new(self)
31
39
  end
@@ -38,10 +46,6 @@ module AtCoderFriends
38
46
  @verifier ||= Verifier.new(self)
39
47
  end
40
48
 
41
- def emitter
42
- @emitter ||= Emitter.new(self)
43
- end
44
-
45
49
  def post_process
46
50
  @scraping_agent&.save_session
47
51
  end
@@ -9,8 +9,8 @@ module AtCoderFriends
9
9
  include PathUtil
10
10
 
11
11
  def initialize(ctx)
12
- @src_dir = ctx.path
13
- @smp_dir = smp_dir(@src_dir)
12
+ @src_dir = ctx.path_info.src_dir
13
+ @smp_dir = ctx.path_info.smp_dir
14
14
  end
15
15
 
16
16
  def emit(pbm)
@@ -22,7 +22,8 @@ module AtCoderFriends
22
22
  @pbm = pbm
23
23
  src = File.read(select_template)
24
24
  src = ERB.new(src).result(binding)
25
- render(src)
25
+ src = render(src) if respond_to?(:render)
26
+ src
26
27
  end
27
28
 
28
29
  def select_template
@@ -21,7 +21,7 @@ module AtCoderFriends
21
21
  |\\\(([^()]+)\\\)
22
22
  |\$([^$]+)\$
23
23
  |\{([^{}]+)\}
24
- |([\d,]+)
24
+ |([\d,^+]+)
25
25
  |([一二三四五六七八九十百千万億]+)
26
26
  )
27
27
  }x.freeze
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AtCoderFriends
4
+ # holds target path information
5
+ class PathInfo
6
+ SMP_DIR = 'data'
7
+ CASES_DIR = 'cases'
8
+ TMP_DIR = '.tmp'
9
+
10
+ attr_reader :path, :dir
11
+
12
+ def initialize(path)
13
+ @path = path
14
+ # in setup command, path is directory name (existent/non-existent)
15
+ # in other commands(test, submit, verify), path is existent file name
16
+ @dir = File.file?(path) ? File.dirname(path) : path
17
+ end
18
+
19
+ def contest_name
20
+ File.basename(dir).delete('#').downcase
21
+ end
22
+
23
+ def components
24
+ # overwrites @dir here for non-existent files (test purpose)
25
+ @dir, prg = File.split(path)
26
+ base, ext = prg.split('.')
27
+ q = base.gsub(/_[^#_]+\z/, '')
28
+ [path, dir, prg, base, ext, q]
29
+ end
30
+
31
+ def src_dir
32
+ dir
33
+ end
34
+
35
+ def smp_dir
36
+ File.join(dir, SMP_DIR)
37
+ end
38
+
39
+ def cases_dir
40
+ File.join(dir, CASES_DIR)
41
+ end
42
+
43
+ def cases_out_dir
44
+ File.join(dir, TMP_DIR, CASES_DIR)
45
+ end
46
+
47
+ def tmp_dir
48
+ File.join(dir, TMP_DIR)
49
+ end
50
+ end
51
+ end
@@ -3,37 +3,6 @@
3
3
  module AtCoderFriends
4
4
  # Common methods and behaviors for dealing with paths.
5
5
  module PathUtil
6
- module_function
7
-
8
- SMP_DIR = 'data'
9
- CASES_DIR = 'cases'
10
- TMP_DIR = '.tmp'
11
-
12
- def contest_name(path)
13
- dir = File.file?(path) ? File.dirname(path) : path
14
- File.basename(dir).delete('#').downcase
15
- end
16
-
17
- def split_prg_path(path)
18
- dir, prg = File.split(path)
19
- base, ext = prg.split('.')
20
- q = base.split('_')[0]
21
- [path, dir, prg, base, ext, q]
22
- end
23
-
24
- def smp_dir(dir)
25
- File.join(dir, SMP_DIR)
26
- end
27
-
28
- def cases_dir(dir)
29
- File.join(dir, CASES_DIR)
30
- end
31
-
32
- def tmp_dir(path)
33
- dir = File.dirname(path)
34
- File.join(dir, '.tmp')
35
- end
36
-
37
6
  def makedirs_unless(dir)
38
7
  FileUtils.makedirs(dir) unless Dir.exist?(dir)
39
8
  end
@@ -7,7 +7,6 @@ module AtCoderFriends
7
7
  module Scraping
8
8
  # common functions for scraping
9
9
  class Agent
10
- include AtCoderFriends::PathUtil
11
10
  include Session
12
11
  include Authentication
13
12
  include Tasks
@@ -29,7 +28,7 @@ module AtCoderFriends
29
28
  end
30
29
 
31
30
  def contest
32
- @contest ||= contest_name(ctx.path)
31
+ @contest ||= ctx.path_info.contest_name
33
32
  end
34
33
 
35
34
  def common_url(path)
@@ -6,10 +6,8 @@ module AtCoderFriends
6
6
  module Scraping
7
7
  # run tests on custom_test page
8
8
  module CustomTest
9
- include AtCoderFriends::PathUtil
10
-
11
9
  def code_test(infile)
12
- path, _dir, _prg, _base, ext, _q = split_prg_path(ctx.path)
10
+ path, _dir, _prg, _base, ext, _q = ctx.path_info.components
13
11
  lang = lang_id(ext)
14
12
  src = File.read(path, encoding: Encoding::UTF_8)
15
13
  data = File.read(infile)
@@ -4,10 +4,8 @@ module AtCoderFriends
4
4
  module Scraping
5
5
  # submit sources on submit page
6
6
  module Submission
7
- include AtCoderFriends::PathUtil
8
-
9
7
  def submit
10
- path, _dir, prg, _base, ext, q = split_prg_path(ctx.path)
8
+ path, _dir, prg, _base, ext, q = ctx.path_info.components
11
9
  puts "***** submit #{prg} *****"
12
10
  lang = lang_id(ext)
13
11
  src = File.read(path, encoding: Encoding::UTF_8)
@@ -8,6 +8,7 @@ module AtCoderFriends
8
8
  # run tests for the specified program.
9
9
  class Base
10
10
  include PathUtil
11
+
11
12
  STATUS_STR = {
12
13
  OK: '<< OK >>'.green,
13
14
  WA: '!!!!! WA !!!!!'.red,
@@ -19,7 +20,7 @@ module AtCoderFriends
19
20
 
20
21
  def initialize(ctx)
21
22
  @ctx = ctx
22
- @path, @dir, @prg, @base, @ext, @q = split_prg_path(ctx.path)
23
+ @path, @dir, @prg, @base, @ext, @q = ctx.path_info.components
23
24
  @detail = true
24
25
  end
25
26
 
@@ -32,11 +33,23 @@ module AtCoderFriends
32
33
  end
33
34
 
34
35
  def test_loc
35
- test_cmd ? 'local' : 'remote'
36
+ if test_cmd
37
+ 'local'
38
+ elsif ctx.scraping_agent.respond_to?(:code_test)
39
+ 'remote'
40
+ else
41
+ raise AppError, "test_cmd for .#{ext} is not specified."
42
+ end
36
43
  end
37
44
 
38
45
  def test_mtd
39
- test_cmd ? :local_test : :remote_test
46
+ if test_cmd
47
+ :local_test
48
+ elsif ctx.scraping_agent.respond_to?(:code_test)
49
+ :remote_test
50
+ else
51
+ raise AppError, "test_cmd for .#{ext} is not specified."
52
+ end
40
53
  end
41
54
 
42
55
  def run_test(id, infile, outfile, expfile)
@@ -63,7 +76,7 @@ module AtCoderFriends
63
76
  end
64
77
 
65
78
  def local_test(infile, outfile)
66
- system("#{test_cmd} < #{infile} > #{outfile}")
79
+ system("#{test_cmd} < \"#{infile}\" > \"#{outfile}\"")
67
80
  end
68
81
 
69
82
  def remote_test(infile, outfile)
@@ -4,20 +4,18 @@ module AtCoderFriends
4
4
  module TestRunner
5
5
  # run test cases for the specified program with judge input/output.
6
6
  class Judge < Base
7
- include PathUtil
8
-
9
7
  attr_reader :data_dir, :result_dir
10
8
 
11
9
  def initialize(ctx)
12
10
  super(ctx)
13
- @data_dir = cases_dir(dir)
14
- @result_dir = cases_dir(tmp_dir(path))
11
+ @data_dir = ctx.path_info.cases_dir
12
+ @result_dir = ctx.path_info.cases_out_dir
15
13
  end
16
14
 
17
15
  def judge_all
18
16
  puts "***** judge_all #{prg} (#{test_loc}) *****"
19
- results = Dir["#{data_dir}/#{q}/in/*.txt"].sort.map do |infile|
20
- id = File.basename(infile, '.txt')
17
+ results = Dir["#{data_dir}/#{q}/in/*"].sort.map do |infile|
18
+ id = File.basename(infile)
21
19
  judge(id, false)
22
20
  end
23
21
  !results.empty? && results.all?
@@ -30,9 +28,9 @@ module AtCoderFriends
30
28
 
31
29
  def judge(id, detail = true)
32
30
  @detail = detail
33
- infile = "#{data_dir}/#{q}/in/#{id}.txt"
34
- outfile = "#{result_dir}/#{q}/result/#{id}.txt"
35
- expfile = "#{data_dir}/#{q}/out/#{id}.txt"
31
+ infile = "#{data_dir}/#{q}/in/#{id}"
32
+ outfile = "#{result_dir}/#{q}/result/#{id}"
33
+ expfile = "#{data_dir}/#{q}/out/#{id}"
36
34
  run_test(id, infile, outfile, expfile)
37
35
  end
38
36
  end
@@ -4,19 +4,17 @@ module AtCoderFriends
4
4
  module TestRunner
5
5
  # run test cases for the specified program with sample input/output.
6
6
  class Sample < Base
7
- include PathUtil
8
-
9
7
  attr_reader :data_dir
10
8
 
11
9
  def initialize(ctx)
12
10
  super(ctx)
13
- @data_dir = smp_dir(dir)
11
+ @data_dir = ctx.path_info.smp_dir
14
12
  end
15
13
 
16
14
  def test_all
17
15
  puts "***** test_all #{prg} (#{test_loc}) *****"
18
16
  results = Dir["#{data_dir}/#{q}_*.in"].sort.map do |infile|
19
- id = File.basename(infile, '.in').sub(/[^_]+_/, '')
17
+ id = File.basename(infile, '.in').sub(/\A#{q}_/, '')
20
18
  test(id)
21
19
  end
22
20
  !results.empty? && results.all?
@@ -10,9 +10,8 @@ module AtCoderFriends
10
10
  attr_reader :path, :file, :vdir, :vpath
11
11
 
12
12
  def initialize(ctx)
13
- @path = ctx.path
14
- @file = File.basename(path)
15
- @vdir = tmp_dir(path)
13
+ @path, _dir, @file = ctx.path_info.components
14
+ @vdir = ctx.path_info.tmp_dir
16
15
  @vpath = File.join(vdir, "#{file}.verified")
17
16
  end
18
17
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module AtCoderFriends
4
- VERSION = '0.6.3'
4
+ VERSION = '0.6.4'
5
5
  end
@@ -4,6 +4,7 @@ require 'at_coder_friends/version'
4
4
  require 'at_coder_friends/errors'
5
5
  require 'at_coder_friends/path_util'
6
6
  require 'at_coder_friends/config_loader'
7
+ require 'at_coder_friends/path_info'
7
8
  require 'at_coder_friends/verifier'
8
9
  require 'at_coder_friends/test_runner/base'
9
10
  require 'at_coder_friends/test_runner/sample'
@@ -1,8 +1,8 @@
1
1
  // <%= pbm.url %>
2
-
3
2
  <%
4
3
  if pbm.options.interactive
5
- %>#include <cstdio>
4
+ %>
5
+ #include <cstdio>
6
6
  #include <vector>
7
7
  #include <string>
8
8
 
@@ -33,10 +33,10 @@ void query() {
33
33
  }
34
34
 
35
35
  //------------------------------------------------------------------------------
36
- /*** CONSTS ***/
37
-
38
- /*** DCLS ***/
39
-
36
+ <% gen_consts.each do |const| %><%= const %>
37
+ <% end %>
38
+ <% gen_decls.each do |dcl| %><%= dcl %>
39
+ <% end %>
40
40
  void solve() {
41
41
  printf("! %s\n", ans);
42
42
  fflush(stdout);
@@ -50,23 +50,26 @@ void solve() {
50
50
  }
51
51
 
52
52
  void input() {
53
- /*** INPUTS ***/
54
- #ifdef DEBUG
53
+ <% gen_inputs.each do |input| %> <%= input %>
54
+ <% end
55
+ %>#ifdef DEBUG
55
56
  scanf("%s", source);
56
57
  #endif
57
- }<%
58
+ }
59
+ <%
58
60
  else
59
- %>#include <cstdio>
61
+ %>
62
+ #include <cstdio>
60
63
 
61
64
  using namespace std;
62
65
 
63
66
  #define REP(i,n) for(int i=0; i<(int)(n); i++)
64
67
  #define FOR(i,b,e) for(int i=(b); i<=(int)(e); i++)
65
68
 
66
- /*** CONSTS ***/
67
-
68
- /*** DCLS ***/
69
-
69
+ <% gen_consts.each do |const| %><%= const %>
70
+ <% end %>
71
+ <% gen_decls.each do |dcl| %><%= dcl %>
72
+ <% end %>
70
73
  void solve() {
71
74
  <%
72
75
  if (vs = pbm.options.binary_values)
@@ -80,11 +83,12 @@ end
80
83
  }
81
84
 
82
85
  void input() {
83
- /*** INPUTS ***/
84
- }<%
86
+ <% gen_inputs.each do |input| %> <%= input %>
87
+ <% end
88
+ %>}
89
+ <%
85
90
  end
86
91
  %>
87
-
88
92
  int main() {
89
93
  input();
90
94
  solve();
@@ -1,8 +1,8 @@
1
1
  # <%= pbm.url %>
2
-
3
2
  <%
4
3
  if pbm.options.interactive
5
- %>def query(*args)
4
+ %>
5
+ def query(*args)
6
6
  puts "? #{args.join(' ')}"
7
7
  STDOUT.flush
8
8
  if $DEBUG
@@ -15,10 +15,10 @@ end
15
15
 
16
16
  $DEBUG = true
17
17
 
18
- ### CONSTS ###
19
-
20
- ### DCLS ###
21
-
18
+ <% gen_consts.each do |const| %><%= const %>
19
+ <% end %>
20
+ <% gen_decls.each do |dcl| %><%= dcl %>
21
+ <% end %>
22
22
  if $DEBUG
23
23
  @responses = []
24
24
  @source = gets.chomp
@@ -35,10 +35,11 @@ if $DEBUG
35
35
  puts "----------------------------------------"
36
36
  end<%
37
37
  else
38
- %>### CONSTS ###
39
-
40
- ### DCLS ###
41
-
38
+ %>
39
+ <% gen_consts.each do |const| %><%= const %>
40
+ <% end %>
41
+ <% gen_decls.each do |dcl| %><%= dcl %>
42
+ <% end %>
42
43
  <%
43
44
  if (vs = pbm.options.binary_values)
44
45
  %>puts cond ? '<%= vs[0] %>' : '<%= vs[1] %>'<%
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: at_coder_friends
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.3
4
+ version: 0.6.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - nejiko96
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-01-04 00:00:00.000000000 Z
11
+ date: 2020-03-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: colorize
@@ -174,6 +174,7 @@ files:
174
174
  - lib/at_coder_friends/parser/sample_data.rb
175
175
  - lib/at_coder_friends/parser/section_wrapper.rb
176
176
  - lib/at_coder_friends/parser/sections.rb
177
+ - lib/at_coder_friends/path_info.rb
177
178
  - lib/at_coder_friends/path_util.rb
178
179
  - lib/at_coder_friends/problem.rb
179
180
  - lib/at_coder_friends/scraping/agent.rb
@@ -187,15 +188,6 @@ files:
187
188
  - lib/at_coder_friends/test_runner/sample.rb
188
189
  - lib/at_coder_friends/verifier.rb
189
190
  - lib/at_coder_friends/version.rb
190
- - tasks/regression/check_const.rake
191
- - tasks/regression/check_diff.rake
192
- - tasks/regression/check_fmt.rake
193
- - tasks/regression/check_parse.rake
194
- - tasks/regression/list_handler.rb
195
- - tasks/regression/regression.rb
196
- - tasks/regression/report_handler.rb
197
- - tasks/regression/section_list.rake
198
- - tasks/regression/setup.rake
199
191
  - templates/cxx_builtin.cxx.erb
200
192
  - templates/ruby_builtin.rb.erb
201
193
  homepage: https://github.com/nejiko96/at_coder_friends
@@ -1,137 +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
- CONST_PAT = {
11
- mod: /
12
- (.{,30}(?:
13
- で割った|modulo|mod\b|divided\s+by|dividing\s+by
14
- ).{,30})
15
- /xmi,
16
- max: /
17
- (.{,30}(?:
18
- ≦|≤|\\le|&leq?;
19
- |<|\\lt|&lt;
20
- |以上.{1,25}以下の整数
21
- ).{,30})
22
- /xmi
23
- }.freeze
24
-
25
- def collect(tgt)
26
- open_const_report('collect', tgt) do |f|
27
- local_pbm_list.each do |contest, q, url|
28
- page = agent.get(url)
29
- body = page.body.force_encoding('utf-8')
30
- ms = body.scan(CONST_PAT[tgt.to_sym])
31
- ms.each do |m|
32
- s = m[0].delete("\r\n")
33
- f.puts [contest, q, tsv_escape(s)].join("\t")
34
- end
35
- end
36
- end
37
- end
38
-
39
- def check_mod
40
- open_const_report('check', 'mod') do |f|
41
- local_pbm_list.each do |contest, q, url|
42
- pbm = local_scraping_agent(nil, contest).fetch_problem(q, url)
43
- Parser::Sections.process(pbm)
44
- Parser::Modulo.process(pbm)
45
- pbm.constants.each do |cnst|
46
- f.puts [contest, q, cnst.value].join("\t")
47
- end
48
- end
49
- end
50
- end
51
-
52
- def check_max
53
- open_const_report('check', 'max') do |f|
54
- local_pbm_list.each do |contest, q, url|
55
- pbm = local_scraping_agent(nil, contest).fetch_problem(q, url)
56
- Parser::Sections.process(pbm)
57
- Parser::Constraints.process(pbm)
58
- pbm.constants.each do |cns|
59
- f.puts [contest, q, "#{cns.name}:#{cns.value}"].join("\t")
60
- end
61
- end
62
- end
63
- end
64
-
65
- def merge_list(tgt)
66
- tbl = load_merge_list(tgt)
67
- save_merge_list(tgt, tbl)
68
- end
69
-
70
- def load_merge_list(tgt)
71
- tbl = {}
72
- %w[collect check]
73
- .map { |act| load_const_report(act, tgt) }
74
- .each
75
- .with_index(1) do |data, n|
76
- data
77
- .group_by { |contest, q, _| "#{contest}\t#{q}" }
78
- .map { |key, grp| [key, grp.map { |row| row[2] }.join("\n")] }
79
- .each do |key, txt|
80
- tbl[key] ||= { 'v1' => '', 'v2' => '' }
81
- tbl[key]["v#{n}"] = '"' + txt + '"'
82
- end
83
- end
84
- tbl
85
- end
86
-
87
- def save_merge_list(tgt, tbl)
88
- open_const_report('merge', tgt) do |f|
89
- tbl.sort.each do |k, h|
90
- f.puts [k, h['v1'], h['v2']].join("\t")
91
- end
92
- end
93
- end
94
-
95
- def open_const_report(act, tgt)
96
- open_report("#{act}_#{tgt}.txt") { |f| yield f }
97
- end
98
-
99
- def load_const_report(act, tgt)
100
- file = report_path("#{act}_#{tgt}.txt")
101
- Encoding.default_external = 'utf-8'
102
- CSV.read(file, col_sep: "\t", headers: false)
103
- end
104
- end
105
- end
106
-
107
- namespace :regression do
108
- desc 'list all mod values'
109
- task :collect_mod do
110
- AtCoderFriends::Regression.collect('mod')
111
- end
112
-
113
- desc 'check extracted mod values'
114
- task :check_mod do
115
- AtCoderFriends::Regression.check_mod
116
- end
117
-
118
- desc 'merge mod values list'
119
- task :merge_mod do
120
- AtCoderFriends::Regression.merge_list('mod')
121
- end
122
-
123
- desc 'list all max values'
124
- task :collect_max do
125
- AtCoderFriends::Regression.collect('max')
126
- end
127
-
128
- desc 'check extracted max values'
129
- task :check_max do
130
- AtCoderFriends::Regression.check_max
131
- end
132
-
133
- desc 'merge max values list'
134
- task :merge_max do
135
- AtCoderFriends::Regression.merge_list('max')
136
- end
137
- end
@@ -1,30 +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_diff
11
- emit_dir = format(EMIT_DIR_FMT, now: Time.now.strftime('%Y%m%d%H%M%S'))
12
- rmdir_force(emit_dir)
13
-
14
- local_pbm_list.each do |contest, q, url|
15
- pbm = local_scraping_agent(emit_dir, contest).fetch_problem(q, url)
16
- pipeline(pbm)
17
- end
18
-
19
- diff_log = report_path('check_diff.txt')
20
- system("diff -r --exclude=.git #{EMIT_ORG_DIR} #{emit_dir} > #{diff_log}")
21
- end
22
- end
23
- end
24
-
25
- namespace :regression do
26
- desc 'run regression check'
27
- task :check_diff do
28
- AtCoderFriends::Regression.check_diff
29
- end
30
- end
@@ -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