at_coder_friends 0.5.2 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +1 -0
  3. data/.rubocop_todo.yml +1 -4
  4. data/Gemfile.lock +1 -1
  5. data/README.md +1 -1
  6. data/config/default.yml +3 -0
  7. data/docs/CONFIGURATION.md +74 -9
  8. data/lib/at_coder_friends.rb +10 -5
  9. data/lib/at_coder_friends/cli.rb +2 -5
  10. data/lib/at_coder_friends/context.rb +4 -0
  11. data/lib/at_coder_friends/emitter.rb +2 -2
  12. data/lib/at_coder_friends/generator/cxx_builtin.rb +191 -0
  13. data/lib/at_coder_friends/generator/main.rb +53 -0
  14. data/lib/at_coder_friends/generator/ruby_builtin.rb +128 -0
  15. data/lib/at_coder_friends/parser/binary.rb +39 -0
  16. data/lib/at_coder_friends/parser/constraints.rb +36 -0
  17. data/lib/at_coder_friends/parser/{format_parser.rb → input_format.rb} +42 -30
  18. data/lib/at_coder_friends/parser/interactive.rb +29 -0
  19. data/lib/at_coder_friends/parser/main.rb +6 -3
  20. data/lib/at_coder_friends/parser/sample_data.rb +24 -0
  21. data/lib/at_coder_friends/parser/section_wrapper.rb +49 -0
  22. data/lib/at_coder_friends/parser/{page_parser.rb → sections.rb} +44 -50
  23. data/lib/at_coder_friends/problem.rb +40 -24
  24. data/lib/at_coder_friends/scraping/agent.rb +1 -5
  25. data/lib/at_coder_friends/scraping/authentication.rb +2 -2
  26. data/lib/at_coder_friends/scraping/session.rb +1 -1
  27. data/lib/at_coder_friends/scraping/tasks.rb +2 -6
  28. data/lib/at_coder_friends/test_runner/base.rb +36 -31
  29. data/lib/at_coder_friends/test_runner/judge.rb +2 -6
  30. data/lib/at_coder_friends/test_runner/sample.rb +8 -6
  31. data/lib/at_coder_friends/version.rb +1 -1
  32. data/tasks/regression/check_diff.rake +29 -0
  33. data/tasks/regression/check_parse.rake +56 -0
  34. data/tasks/regression/regression.rb +67 -0
  35. data/tasks/regression/section_list.rake +41 -0
  36. data/tasks/regression/setup.rake +48 -0
  37. data/templates/cxx_builtin_default.cxx +26 -0
  38. data/templates/cxx_builtin_interactive.cxx +61 -0
  39. data/templates/ruby_builtin_default.rb +5 -0
  40. data/templates/ruby_builtin_interactive.rb +32 -0
  41. metadata +21 -8
  42. data/lib/at_coder_friends/cxx_generator.rb +0 -169
  43. data/lib/at_coder_friends/parser/constraints_parser.rb +0 -26
  44. data/lib/at_coder_friends/ruby_generator.rb +0 -97
  45. data/tasks/regression.rake +0 -163
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c37cfc3181ae4abcc3d837e5a312987af2e9758e
4
- data.tar.gz: b6573770d47b1d73cf94b4a048cb9b7cbcd49b26
3
+ metadata.gz: cfcd8c547d0916bc1db5c76b5c698e410ddb3541
4
+ data.tar.gz: 03e06ac13b32c2d55166cf1cefa83ad9cfbe3fa2
5
5
  SHA512:
6
- metadata.gz: 5a21187eab2ff6217744414daa64251e8b1602bbc5e2d8c5e05d6f9b1dff6f9cfd209a5d8136900e9ab65f03289d3338743e01f7eb4043b94908956b09b4863b
7
- data.tar.gz: a3557e02966c8189d06c1133cbc519cb1a53dd31e385d433eba628232d3557ae1c1f9e96d2edcbf406c92954e8c358adb3e4ee9c2e4d1c4a041a87b52da95e58
6
+ metadata.gz: d73018f888e13b7a37a19b8945b879513caf4952ff5bdcbe9412c413a84d05c4c055fb00166e97fe3b5420637b0c87c767796f9c2835e82c879451f854b2fc9d
7
+ data.tar.gz: 602aa37bf5f315a9bccfbd3e676f19b0651c4687fbe351e65d670359c956b74e230ebcedade158928cd1486092947af1bfb34c1504632b7389d1029da2afb70a
@@ -2,6 +2,7 @@ inherit_from: .rubocop_todo.yml
2
2
 
3
3
  AllCops:
4
4
  Exclude:
5
+ - 'templates/**/*'
5
6
  - 'spec/fixtures/**/*'
6
7
  - 'regression/**/*'
7
8
  TargetRubyVersion: 2.3
@@ -2,10 +2,7 @@ Metrics/AbcSize:
2
2
  Max: 20
3
3
 
4
4
  Metrics/ClassLength:
5
- Max: 135
6
-
7
- Metrics/ModuleLength:
8
- Max: 120
5
+ Max: 125
9
6
 
10
7
  Metrics/MethodLength:
11
8
  Max: 15
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- at_coder_friends (0.5.2)
4
+ at_coder_friends (0.6.0)
5
5
  colorize (~> 0.8.1)
6
6
  launchy (~> 2.4.3)
7
7
  mechanize (~> 2.0)
data/README.md CHANGED
@@ -87,7 +87,7 @@ See [CONFIGURATION.md](docs/CONFIGURATION.md) for details.
87
87
  ## Notes
88
88
 
89
89
  - Compilation is not supported.
90
- - Source generator supports only ruby and C++.
90
+ - Source generator supports only Ruby and C++ in default.
91
91
 
92
92
  ## For Sublime Text user
93
93
 
@@ -1,5 +1,8 @@
1
1
  user: ~
2
2
  password: ~
3
+ generators:
4
+ - RubyBuiltin
5
+ - CxxBuiltin
3
6
  ext_settings:
4
7
  'awk':
5
8
  submit_lang: '3506' # Awk (mawk)
@@ -20,9 +20,14 @@ Its contents are merged with the default settings.
20
20
  ```.at_coder_friends.yml```で新しい設定項目の追加や、既存の設定項目の変更をすると、
21
21
  その内容がデフォルト設定にマージされます。
22
22
 
23
+ [/config/default.yml](/config/default.yml)
24
+
23
25
  ```YAML
24
26
  user: ~
25
27
  password: ~
28
+ generators:
29
+ - RubyBuiltin
30
+ - CxxBuiltin
26
31
  ext_settings:
27
32
  'awk':
28
33
  submit_lang: '3506' # Awk (mawk)
@@ -115,15 +120,43 @@ ext_settings:
115
120
 
116
121
  - user
117
122
  AtCoder username
118
- If omitted, you are prompted to enter it on the first run.
123
+ If omitted, you are prompted to enter it on the first login.
119
124
  AtCoderのユーザ名
120
- 省略した場合、初回の実行時に入力を求められます
125
+ 省略した場合、初回のログイン時に入力を求められます
121
126
 
122
127
  - password
123
128
  AtCoder password
124
- If omitted, you are prompted to enter it on the first run.
129
+ If omitted, you are prompted to enter it on the first login.
125
130
  AtCoderのパスワード
126
- 省略した場合、初回の実行時に入力を求められます
131
+ 省略した場合、初回のログイン時に入力を求められます
132
+
133
+ - generators
134
+ List of source generator class names
135
+ In default, ```RubyBuiltin``` and ```CxxBuiltin``` are available.
136
+ For those other than above, corresponding plugin will be used
137
+ if it has been installed (?).
138
+ ソーススケルトンを生成するジェネレータのクラス名(リスト形式)
139
+ 既定の状態では「RubyBuiltin」と「CxxBuiltin」が利用でき、
140
+ 上記以外については、対応するプラグインがインストールされていれば
141
+ それが使われます(?)
142
+
143
+ For example, if ```RubyAlt``` is specified as generator name,
144
+ following plugin will be used:
145
+
146
+ | | |
147
+ |-----------------|---------------------------------------------------|
148
+ |Gem Name |```at_coder_friends-generator-ruby_alt``` |
149
+ |Require Statement|```require 'at_coder_friends/generator/ruby_alt'```|
150
+ |Main Class Name |```AtCoderFriends::Generator::RubyAlt``` |
151
+
152
+ - generator_settings
153
+ - _(generator name)_
154
+ Settings for each generator
155
+ For details, see the manual of each generator.
156
+ [Settings for built-in generators](#builtin-generator-settings)
157
+ ジェネレータ毎の設定
158
+ 詳細は各ジェネレータのマニュアルを参照してください
159
+ [組込ジェネレータの設定](#builtin-generator-settings)
127
160
 
128
161
  - ext_settings
129
162
  Extension specific settings
@@ -159,10 +192,23 @@ ext_settings:
159
192
  Execution command for Linux(optional)
160
193
  Linux専用実行コマンド(あれば設定)
161
194
 
195
+ <a id="builtin-generator-settings"></a>
196
+ ### Settings for RubyBuiltin generator
197
+ | Setting | Description | Default |
198
+ |---------|-------------|---------|
199
+ |default_template|Source template file path|[/templates/ruby_builtin_default.rb](/templates/ruby_builtin_default.rb)|
200
+ |interactive_template|Source template file path for interactive problems|[/templates/ruby_builtin_interactive.rb](/templates/ruby_builtin_interactive.rb)|
201
+
202
+ ### Settings for CxxBuiltin generator
203
+ | Setting | Description | Default |
204
+ |---------|-------------|---------|
205
+ |default_template|Source template file path|[/templates/cxx_builtin_default.cxx](/templates/cxx_builtin_default.cxx)|
206
+ |interactive_template|Source template file path for interactive problems|[/templates/cxx_builtin_interactive.cxx](/templates/cxx_builtin_interactive.cxx)|
207
+
162
208
  ### Language ID list (2019/09/16)
163
209
 
164
210
  | Language ID | Description |
165
- |---|---|
211
+ |-------------|-------------|
166
212
  |3003|C++14 (GCC 5.4.1)|
167
213
  |3001|Bash (GNU bash v4.3.11)|
168
214
  |3002|C (GCC 5.4.1)|
@@ -229,13 +275,32 @@ during execution.
229
275
  test_cmd 文字列中の以下の変数には、
230
276
  実行時に対象ファイルのパス情報が展開されます。
231
277
 
232
- | Variable | Descripton |
233
- |---|---|
234
- |{dir}|the directory name of the file<br>ファイルの置かれているディレクトリ名|
235
- |{base}|the file name excluding the extension<br>拡張子を除いたファイル名|
278
+ | Variable | Descripton |
279
+ |----------|----------------------------------------------------------------|
280
+ |{dir} |the directory name of the file<br>ファイルの置かれているディレクトリ名|
281
+ |{base} |the file name excluding the extension<br>拡張子を除いたファイル名 |
236
282
 
237
283
  ## Examples of overwriting settings
238
284
 
285
+ - Use only Ruby source generator
286
+ Rubyのソースジェネレータのみ使用
287
+ ```YAML
288
+ generators:
289
+ - RubyBuiltin
290
+ ```
291
+ - Do not use source generator
292
+ ソースジェネレータを使用しない
293
+ ```YAML
294
+ generators: ~
295
+ ```
296
+ - change C++ source template
297
+ C++のソース雛型を変更
298
+ ```YAML
299
+ generator_settings:
300
+ CxxBuiltin:
301
+ default_template: /path/to/template
302
+ ```
303
+
239
304
  - Test .py with local Python
240
305
  .pyをローカル環境のPythonでテスト
241
306
  ```YAML
@@ -15,12 +15,17 @@ require 'at_coder_friends/scraping/custom_test'
15
15
  require 'at_coder_friends/scraping/submission'
16
16
  require 'at_coder_friends/scraping/tasks'
17
17
  require 'at_coder_friends/scraping/agent'
18
- require 'at_coder_friends/parser/page_parser'
19
- require 'at_coder_friends/parser/format_parser'
20
- require 'at_coder_friends/parser/constraints_parser'
18
+ require 'at_coder_friends/parser/section_wrapper'
19
+ require 'at_coder_friends/parser/sections'
20
+ require 'at_coder_friends/parser/sample_data'
21
+ require 'at_coder_friends/parser/input_format'
22
+ require 'at_coder_friends/parser/constraints'
23
+ require 'at_coder_friends/parser/interactive'
24
+ require 'at_coder_friends/parser/binary'
21
25
  require 'at_coder_friends/parser/main'
22
- require 'at_coder_friends/ruby_generator'
23
- require 'at_coder_friends/cxx_generator'
26
+ require 'at_coder_friends/generator/cxx_builtin'
27
+ require 'at_coder_friends/generator/ruby_builtin'
28
+ require 'at_coder_friends/generator/main'
24
29
  require 'at_coder_friends/emitter'
25
30
  require 'at_coder_friends/context'
26
31
  require 'at_coder_friends/cli'
@@ -92,17 +92,14 @@ module AtCoderFriends
92
92
  raise AppError, "#{path} is not empty." \
93
93
  if Dir.exist?(path) && !Dir["#{path}/*"].empty?
94
94
 
95
- rb_gen = RubyGenerator.new
96
- cxx_gen = CxxGenerator.new
97
95
  ctx.scraping_agent.fetch_all do |pbm|
98
96
  Parser::Main.process(pbm)
99
- rb_gen.process(pbm)
100
- cxx_gen.process(pbm)
97
+ ctx.generator.process(pbm)
101
98
  ctx.emitter.emit(pbm)
102
99
  end
103
100
  end
104
101
 
105
- def test_one(id = 1)
102
+ def test_one(id = '001')
106
103
  ctx.sample_test_runner.test_one(id)
107
104
  end
108
105
 
@@ -22,6 +22,10 @@ module AtCoderFriends
22
22
  @scraping_agent ||= Scraping::Agent.new(self)
23
23
  end
24
24
 
25
+ def generator
26
+ @generator ||= Generator::Main.new(self)
27
+ end
28
+
25
29
  def sample_test_runner
26
30
  @sample_test_runner ||= TestRunner::Sample.new(self)
27
31
  end
@@ -14,8 +14,8 @@ module AtCoderFriends
14
14
  end
15
15
 
16
16
  def emit(pbm)
17
- pbm.smps.each { |smp| emit_sample(pbm, smp) }
18
- pbm.srcs.each { |src| emit_source(pbm, src) }
17
+ pbm.samples.each { |smp| emit_sample(pbm, smp) }
18
+ pbm.sources.each { |src| emit_source(pbm, src) }
19
19
  end
20
20
 
21
21
  def emit_sample(pbm, smp)
@@ -0,0 +1,191 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AtCoderFriends
4
+ module Generator
5
+ module CxxBuiltinConstants
6
+ ACF_HOME = File.realpath(File.join(__dir__, '..', '..', '..'))
7
+ TMPL_DIR = File.join(ACF_HOME, 'templates')
8
+ DEFAULT_TMPL = File.join(TMPL_DIR, 'cxx_builtin_default.cxx')
9
+ INTERACTIVE_TMPL = File.join(TMPL_DIR, 'cxx_builtin_interactive.cxx')
10
+ SCANF_FMTS = [
11
+ 'scanf("%<fmt>s", %<addr>s);',
12
+ 'REP(i, %<sz1>s) scanf("%<fmt>s", %<addr>s);',
13
+ 'REP(i, %<sz1>s) REP(j, %<sz2>s) scanf("%<fmt>s", %<addr>s);'
14
+ ].freeze
15
+ FMT_FMTS = { number: '%d', string: '%s', char: '%s' }.freeze
16
+ ADDR_FMTS = {
17
+ single: {
18
+ number: '&%<v>s',
19
+ string: '%<v>s'
20
+ },
21
+ harray: {
22
+ number: '%<v>s + i',
23
+ string: '%<v>s[i]',
24
+ char: '%<v>s'
25
+ },
26
+ varray: {
27
+ number: '%<v>s + i',
28
+ string: '%<v>s[i]'
29
+ },
30
+ matrix: {
31
+ number: '&%<v>s[i][j]',
32
+ string: '%<v>s[i][j]',
33
+ char: '%<v>s[i]'
34
+ }
35
+ }.freeze
36
+ DEFAULT_OUTPUT = <<~TEXT
37
+ int ans = 0;
38
+ printf("%d\\n", ans);
39
+ TEXT
40
+ BINARY_OUTPUT_FMT = <<~TEXT
41
+ bool cond = false;
42
+ puts(cond ? "%s" : "%s");
43
+ TEXT
44
+ end
45
+
46
+ # generates C++ source code from problem description
47
+ class CxxBuiltin
48
+ include CxxBuiltinConstants
49
+
50
+ attr_reader :cfg, :pbm
51
+
52
+ def initialize(cfg = nil)
53
+ @cfg = cfg || {}
54
+ end
55
+
56
+ def process(pbm)
57
+ src = generate(pbm)
58
+ pbm.add_src(:cxx, src)
59
+ end
60
+
61
+ def generate(pbm)
62
+ @pbm = pbm
63
+ src = File.read(select_template)
64
+ src = embed_lines(src, '/*** URL ***/', [pbm.url])
65
+ src = embed_lines(src, '/*** CONSTS ***/', gen_consts)
66
+ src = embed_lines(src, '/*** DCLS ***/', gen_decls)
67
+ src = embed_lines(src, '/*** INPUTS ***/', gen_inputs)
68
+ embed_lines(src, '/*** OUTPUT ***/', gen_output.split("\n"))
69
+ end
70
+
71
+ def embed_lines(src, pat, lines)
72
+ re = Regexp.escape(pat)
73
+ src.gsub(
74
+ /^(.*)#{re}(.*)$/,
75
+ lines.map { |s| '\1' + s + '\2' }.join("\n")
76
+ )
77
+ end
78
+
79
+ def select_template(interactive = pbm.options.interactive)
80
+ interactive ? interactive_template : default_template
81
+ end
82
+
83
+ def default_template
84
+ cfg['default_template'] || DEFAULT_TMPL
85
+ end
86
+
87
+ def interactive_template
88
+ cfg['interactive_template'] || INTERACTIVE_TMPL
89
+ end
90
+
91
+ def gen_consts(constraints = pbm.constraints)
92
+ constraints
93
+ .select { |c| c.type == :max }
94
+ .map { |c| "const int #{c.name.upcase}_MAX = #{c.value};" }
95
+ end
96
+
97
+ def gen_decls(inpdefs = pbm.formats)
98
+ inpdefs.map { |inpdef| gen_decl(inpdef) }.flatten
99
+ end
100
+
101
+ def gen_decl(inpdef)
102
+ case inpdef.container
103
+ when :single
104
+ gen_single_decl(inpdef)
105
+ when :harray
106
+ gen_harray_decl(inpdef)
107
+ when :varray
108
+ gen_varray_decl(inpdef)
109
+ when :matrix
110
+ gen_matrix_decl(inpdef)
111
+ end
112
+ end
113
+
114
+ def gen_single_decl(inpdef)
115
+ names = inpdef.names
116
+ case inpdef.item
117
+ when :number
118
+ dcl = names.join(', ')
119
+ "int #{dcl};"
120
+ when :string
121
+ names.map { |v| "char #{v}[#{v.upcase}_MAX + 1];" }
122
+ end
123
+ end
124
+
125
+ def gen_harray_decl(inpdef)
126
+ v = inpdef.names[0]
127
+ sz = gen_arr_size(inpdef.size)[0]
128
+ case inpdef.item
129
+ when :number
130
+ "int #{v}[#{sz}];"
131
+ when :string
132
+ "char #{v}[#{sz}][#{v.upcase}_MAX + 1];"
133
+ when :char
134
+ "char #{v}[#{sz} + 1];"
135
+ end
136
+ end
137
+
138
+ def gen_varray_decl(inpdef)
139
+ names = inpdef.names
140
+ sz = gen_arr_size(inpdef.size)[0]
141
+ case inpdef.item
142
+ when :number
143
+ names.map { |v| "int #{v}[#{sz}];" }
144
+ when :string
145
+ names.map { |v| "char #{v}[#{sz}][#{v.upcase}_MAX + 1];" }
146
+ end
147
+ end
148
+
149
+ def gen_matrix_decl(inpdef)
150
+ v = inpdef.names[0]
151
+ sz1, sz2 = gen_arr_size(inpdef.size)
152
+ case inpdef.item
153
+ when :number
154
+ "int #{v}[#{sz1}][#{sz2}];"
155
+ when :string
156
+ "char #{v}[#{sz1}][#{sz2}][#{v.upcase}_MAX + 1];"
157
+ when :char
158
+ "char #{v}[#{sz1}][#{sz2} + 1];"
159
+ end
160
+ end
161
+
162
+ def gen_arr_size(szs)
163
+ szs.map { |sz| sz =~ /\D/ ? "#{sz.upcase}_MAX" : sz }
164
+ end
165
+
166
+ def gen_inputs(inpdefs = pbm.formats)
167
+ inpdefs.map { |inpdef| gen_input(inpdef) }.flatten
168
+ end
169
+
170
+ # rubocop:disable Metrics/AbcSize
171
+ def gen_input(inpdef)
172
+ dim = inpdef.size.size - (inpdef.item == :char ? 1 : 0)
173
+ scanf = SCANF_FMTS[dim]
174
+ sz1, sz2 = inpdef.size
175
+ fmt = FMT_FMTS[inpdef.item] * inpdef.names.size
176
+ addr_fmt = ADDR_FMTS[inpdef.container][inpdef.item]
177
+ addr = inpdef.names.map { |v| format(addr_fmt, v: v) }.join(', ')
178
+ format(scanf, sz1: sz1, sz2: sz2, fmt: fmt, addr: addr)
179
+ end
180
+ # rubocop:enable Metrics/AbcSize
181
+
182
+ def gen_output(vs = pbm.options.binary_values)
183
+ if vs
184
+ format(BINARY_OUTPUT_FMT, *vs)
185
+ else
186
+ DEFAULT_OUTPUT
187
+ end
188
+ end
189
+ end
190
+ end
191
+ end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AtCoderFriends
4
+ module Generator
5
+ # entry point of source generation
6
+ class Main
7
+ attr_reader :ctx
8
+
9
+ def initialize(ctx)
10
+ @ctx = ctx
11
+ @cache = {}
12
+ end
13
+
14
+ def process(pbm)
15
+ generators = ctx.config.dig('generators') || []
16
+ generators.each do |gen_name|
17
+ gen_obj = load_obj(gen_name)
18
+ gen_obj.process(pbm)
19
+ end
20
+ end
21
+
22
+ def load_obj(gen_name)
23
+ @cache[gen_name] ||= begin
24
+ gen_class = load_class(gen_name)
25
+ gen_cnf = config_for(gen_name)
26
+ gen_class.new(gen_cnf)
27
+ end
28
+ end
29
+
30
+ def load_class(gen_name)
31
+ unless AtCoderFriends::Generator.const_defined?(gen_name)
32
+ require "at_coder_friends/generator/#{to_snake(gen_name)}"
33
+ end
34
+ AtCoderFriends::Generator.const_get(gen_name)
35
+ rescue LoadError
36
+ raise AppError, "plugin load error : generator #{gen_name} not found."
37
+ end
38
+
39
+ def config_for(gen_name)
40
+ ctx.config.dig('generator_settings', gen_name) || {}
41
+ end
42
+
43
+ def to_snake(str)
44
+ str
45
+ .gsub(/::/, '/')
46
+ .gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
47
+ .gsub(/([a-z\d])([A-Z])/, '\1_\2')
48
+ .tr('-', '_')
49
+ .downcase
50
+ end
51
+ end
52
+ end
53
+ end