at_coder_friends 0.6.8 → 0.7.0
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 +4 -4
- data/.gitattributes +1 -0
- data/.github/workflows/codeql-analysis.yml +70 -0
- data/.github/workflows/ruby.yml +38 -0
- data/.gitignore +3 -0
- data/.rubocop.yml +8 -1
- data/CHANGELOG.md +23 -4
- data/Gemfile.lock +43 -43
- data/README.md +15 -92
- data/at_coder_friends.gemspec +4 -3
- data/lib/at_coder_friends/cli.rb +13 -28
- data/lib/at_coder_friends/config_loader.rb +2 -4
- data/lib/at_coder_friends/generator/any_builtin.rb +22 -0
- data/lib/at_coder_friends/generator/base.rb +55 -6
- data/lib/at_coder_friends/generator/c_builtin.rb +22 -0
- data/lib/at_coder_friends/generator/cxx_builtin.rb +9 -241
- data/lib/at_coder_friends/generator/fragment.rb +106 -0
- data/lib/at_coder_friends/generator/main.rb +20 -14
- data/lib/at_coder_friends/generator/ruby_builtin.rb +13 -166
- data/lib/at_coder_friends/parser/binary.rb +12 -5
- data/lib/at_coder_friends/parser/constraints.rb +8 -8
- data/lib/at_coder_friends/parser/input_format.rb +19 -15
- data/lib/at_coder_friends/parser/modulo.rb +5 -7
- data/lib/at_coder_friends/parser/section_wrapper.rb +3 -5
- data/lib/at_coder_friends/parser/sections.rb +2 -2
- data/lib/at_coder_friends/path_util.rb +1 -1
- data/lib/at_coder_friends/problem.rb +5 -5
- data/lib/at_coder_friends/scraping/agent.rb +1 -1
- data/lib/at_coder_friends/scraping/authentication.rb +3 -3
- data/lib/at_coder_friends/scraping/session.rb +1 -1
- data/lib/at_coder_friends/scraping/tasks.rb +6 -8
- data/lib/at_coder_friends/test_runner/base.rb +1 -2
- data/lib/at_coder_friends/test_runner/judge.rb +3 -3
- data/lib/at_coder_friends/version.rb +1 -1
- data/lib/at_coder_friends.rb +3 -0
- data/templates/any_builtin.md.erb +30 -0
- data/templates/any_builtin_fragments.yml +5 -0
- data/templates/c_builtin.c.erb +36 -0
- data/templates/c_builtin_fragments.yml +127 -0
- data/templates/csharp_sample.cs.erb +29 -0
- data/templates/csharp_sample_fragments.yml +159 -0
- data/templates/java_sample.java.erb +25 -0
- data/templates/java_sample_fragments.yml +98 -0
- data/templates/ruby_builtin_fragments.yml +93 -0
- metadata +26 -6
- data/.travis.yml +0 -16
- data/docs/CONFIGURATION.md +0 -421
@@ -4,182 +4,29 @@ module AtCoderFriends
|
|
4
4
|
module Generator
|
5
5
|
# generates Ruby source from problem description
|
6
6
|
class RubyBuiltin < Base
|
7
|
+
include ConstFragmentMixin
|
8
|
+
include DeclFragmentMixin
|
9
|
+
|
7
10
|
ACF_HOME = File.realpath(File.join(__dir__, '..', '..', '..'))
|
8
11
|
TMPL_DIR = File.join(ACF_HOME, 'templates')
|
9
|
-
|
10
|
-
|
12
|
+
TEMPLATE = File.join(TMPL_DIR, 'ruby_builtin.rb.erb')
|
13
|
+
FRAGMENTS = File.realpath(File.join(TMPL_DIR, 'ruby_builtin_fragments.yml'))
|
14
|
+
ATTRS = Attributes.new(:rb, TEMPLATE, FRAGMENTS)
|
11
15
|
|
12
16
|
def attrs
|
13
17
|
ATTRS
|
14
18
|
end
|
15
19
|
|
16
|
-
def
|
17
|
-
|
18
|
-
src = embed_lines(src, '### DCLS ###', gen_decls)
|
19
|
-
src
|
20
|
-
end
|
21
|
-
|
22
|
-
def gen_consts(constants = pbm.constants)
|
23
|
-
constants
|
20
|
+
def gen_consts
|
21
|
+
pbm.constants
|
24
22
|
.select { |c| c.type == :mod }
|
25
|
-
.map { |c|
|
26
|
-
end
|
27
|
-
|
28
|
-
def gen_mod(c)
|
29
|
-
v = c.value.gsub('^', '**').gsub(',', '_')
|
30
|
-
"MOD = #{v}"
|
31
|
-
end
|
32
|
-
|
33
|
-
def gen_decls(inpdefs = pbm.formats)
|
34
|
-
inpdefs.map { |inpdef| gen_decl(inpdef) }.flatten
|
23
|
+
.map { |c| gen_const(c) }
|
35
24
|
end
|
36
25
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
when :harray
|
42
|
-
gen_harray_decl(inpdef)
|
43
|
-
when :varray
|
44
|
-
gen_varray_decl(inpdef)
|
45
|
-
when :matrix
|
46
|
-
gen_matrix_decl(inpdef)
|
47
|
-
when :varray_matrix, :matrix_varray
|
48
|
-
gen_cmb_decl(inpdef)
|
49
|
-
when :vmatrix
|
50
|
-
gen_vmatrix_decl(inpdef)
|
51
|
-
when :hmatrix
|
52
|
-
gen_hmatrix_decl(inpdef)
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
|
-
def gen_single_decl(inpdef)
|
57
|
-
names = inpdef.names
|
58
|
-
dcl = names.join(', ')
|
59
|
-
expr = gen_expr(inpdef, names.size > 1)
|
60
|
-
"#{dcl} = #{expr}"
|
61
|
-
end
|
62
|
-
|
63
|
-
def gen_harray_decl(inpdef)
|
64
|
-
v = inpdef.names[0]
|
65
|
-
dcl = "#{v}s"
|
66
|
-
expr = gen_expr(inpdef, true)
|
67
|
-
"#{dcl} = #{expr}"
|
68
|
-
end
|
69
|
-
|
70
|
-
def gen_varray_decl(inpdef)
|
71
|
-
if inpdef.names.size == 1
|
72
|
-
gen_varray_1_decl(inpdef)
|
73
|
-
else
|
74
|
-
gen_varray_n_decl(inpdef)
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
|
-
def gen_varray_1_decl(inpdef)
|
79
|
-
v = inpdef.names[0]
|
80
|
-
sz = inpdef.size[0]
|
81
|
-
dcl = "#{v}s"
|
82
|
-
expr = gen_expr(inpdef, false)
|
83
|
-
"#{dcl} = Array.new(#{sz}) { #{expr} }"
|
84
|
-
end
|
85
|
-
|
86
|
-
def gen_varray_n_decl(inpdef)
|
87
|
-
names = inpdef.names
|
88
|
-
sz = inpdef.size[0]
|
89
|
-
dcl = names.map { |v| "#{v}s[i]" }.join(', ')
|
90
|
-
expr = gen_expr(inpdef, true)
|
91
|
-
ret = []
|
92
|
-
ret += names.map { |v| "#{v}s = Array.new(#{sz})" }
|
93
|
-
ret << "#{sz}.times do |i|"
|
94
|
-
ret << " #{dcl} = #{expr}"
|
95
|
-
ret << 'end'
|
96
|
-
ret
|
97
|
-
end
|
98
|
-
|
99
|
-
def gen_matrix_decl(inpdef)
|
100
|
-
v = inpdef.names[0]
|
101
|
-
sz = inpdef.size[0]
|
102
|
-
decl = "#{v}ss"
|
103
|
-
expr = gen_expr(inpdef, true)
|
104
|
-
"#{decl} = Array.new(#{sz}) { #{expr} }"
|
105
|
-
end
|
106
|
-
|
107
|
-
def gen_cmb_decl(inpdef)
|
108
|
-
mx = inpdef.container == :varray_matrix ? -1 : 0
|
109
|
-
vs = inpdef.names.map { |v| "#{v}s" }
|
110
|
-
vs[mx] += 's'
|
111
|
-
sz = inpdef.size[0]
|
112
|
-
dcls = vs.map { |v| "#{v}[i]" }
|
113
|
-
dcls[mx] = '*' + dcls[mx] unless inpdef.item == :char
|
114
|
-
dcl = dcls.join(', ')
|
115
|
-
expr = gen_cmb_expr(inpdef)
|
116
|
-
ret = []
|
117
|
-
ret += vs.map { |v| "#{v} = Array.new(#{sz})" }
|
118
|
-
ret << "#{sz}.times do |i|"
|
119
|
-
ret << " #{dcl} = #{expr}"
|
120
|
-
ret << 'end'
|
121
|
-
ret
|
122
|
-
end
|
123
|
-
|
124
|
-
def gen_vmatrix_decl(inpdef)
|
125
|
-
names = inpdef.names
|
126
|
-
sz1, sz2 = inpdef.size
|
127
|
-
dcl = names.map { |v| "#{v}ss[i][j]" }.join(', ')
|
128
|
-
expr = gen_expr(inpdef, true)
|
129
|
-
ret = []
|
130
|
-
ret += names.map do |v|
|
131
|
-
"#{v}ss = Array.new(#{sz1}) { Array.new(#{sz2}) }"
|
132
|
-
end
|
133
|
-
ret << "#{sz1}.times do |i|"
|
134
|
-
ret << " #{sz2}.times do |j|"
|
135
|
-
ret << " #{dcl} = #{expr}"
|
136
|
-
ret << ' end'
|
137
|
-
ret << 'end'
|
138
|
-
ret
|
139
|
-
end
|
140
|
-
|
141
|
-
def gen_hmatrix_decl(inpdef)
|
142
|
-
names = inpdef.names
|
143
|
-
sz = inpdef.size[0]
|
144
|
-
dcl = names.map { |v| "#{v}ss[i]" }.join(', ')
|
145
|
-
expr = gen_expr(inpdef, true)
|
146
|
-
ret = []
|
147
|
-
ret += names.map { |v| "#{v}ss = Array.new(#{sz})" }
|
148
|
-
ret << "#{sz}.times do |i|"
|
149
|
-
ret << " #{dcl} = #{expr}.each_slice(#{names.size}).to_a.transpose"
|
150
|
-
ret << 'end'
|
151
|
-
ret
|
152
|
-
end
|
153
|
-
|
154
|
-
def gen_expr(inpdef, split)
|
155
|
-
read = gen_read(inpdef.delim)
|
156
|
-
case inpdef.item
|
157
|
-
when :number
|
158
|
-
split ? "#{read}.split.map(&:to_i)" : "#{read}.to_i"
|
159
|
-
when :decimal
|
160
|
-
split ? "#{read}.split.map(&:to_f)" : "#{read}.to_f"
|
161
|
-
when :string
|
162
|
-
split ? "#{read}.chomp.split" : "#{read}.chomp"
|
163
|
-
when :char
|
164
|
-
'gets.chomp'
|
165
|
-
end
|
166
|
-
end
|
167
|
-
|
168
|
-
def gen_cmb_expr(inpdef)
|
169
|
-
read = gen_read(inpdef.delim)
|
170
|
-
case inpdef.item
|
171
|
-
when :number
|
172
|
-
"#{read}.split.map(&:to_i)"
|
173
|
-
when :decimal
|
174
|
-
"#{read}.split.map(&:to_f)"
|
175
|
-
when :string, :char
|
176
|
-
"#{read}.chomp.split"
|
177
|
-
end
|
178
|
-
end
|
179
|
-
|
180
|
-
def gen_read(delim)
|
181
|
-
sub = delim.chars.map { |d| ".gsub('#{d}', ' ')" }.join
|
182
|
-
"gets#{sub}"
|
26
|
+
# deprecated, use ERB syntax
|
27
|
+
def render(src)
|
28
|
+
src = embed_lines(src, '### CONSTS ###', gen_consts)
|
29
|
+
embed_lines(src, '### DCLS ###', gen_decls)
|
183
30
|
end
|
184
31
|
end
|
185
32
|
end
|
@@ -8,17 +8,16 @@ module AtCoderFriends
|
|
8
8
|
|
9
9
|
def process(pbm)
|
10
10
|
vs = exp_values(pbm)
|
11
|
-
return unless vs
|
12
|
-
return if vs.any? { |v| v.include?("\n") }
|
13
|
-
return if vs.any? { |v| v =~ /\A[0-9\s]*\z/ }
|
11
|
+
return unless binary_values?(vs)
|
14
12
|
|
15
13
|
out_fmt = output_format(pbm)
|
16
14
|
re1, re2 = vs.map { |v| Regexp.escape(v) }
|
17
15
|
|
18
16
|
pbm.options.binary_values =
|
19
|
-
|
17
|
+
case out_fmt
|
18
|
+
when /#{re1}.+#{re2}/m
|
20
19
|
vs
|
21
|
-
|
20
|
+
when /#{re2}.+#{re1}/m
|
22
21
|
vs.reverse
|
23
22
|
end
|
24
23
|
end
|
@@ -31,6 +30,14 @@ module AtCoderFriends
|
|
31
30
|
.uniq
|
32
31
|
end
|
33
32
|
|
33
|
+
def binary_values?(vs)
|
34
|
+
return false unless vs.size == 2
|
35
|
+
return false if vs.any? { |v| v.include?("\n") }
|
36
|
+
return false if vs.any? { |v| v =~ /\A[0-9\s]*\z/ }
|
37
|
+
|
38
|
+
true
|
39
|
+
end
|
40
|
+
|
34
41
|
def output_format(pbm)
|
35
42
|
pbm.sections[Problem::SECTION_OUT_FMT]&.content || ''
|
36
43
|
end
|
@@ -34,14 +34,14 @@ module AtCoderFriends
|
|
34
34
|
|
35
35
|
def parse(str)
|
36
36
|
str = normalize_content(str)
|
37
|
-
str
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
.
|
43
|
-
|
44
|
-
|
37
|
+
pats = str.scan(MAX_PATTERN).map(&:compact)
|
38
|
+
pairs = pats.each_with_object([]) do |(k, v), result|
|
39
|
+
value = normalize_value(v)
|
40
|
+
next unless value && !value.empty?
|
41
|
+
|
42
|
+
normalize_names(k).each { |name| result << [name, value] }
|
43
|
+
end
|
44
|
+
pairs.uniq.map { |k, v| Problem::Constant.new(k, :max, v) }
|
45
45
|
end
|
46
46
|
|
47
47
|
def normalize_content(s)
|
@@ -56,16 +56,20 @@ module AtCoderFriends
|
|
56
56
|
.gsub('>', '>')
|
57
57
|
.gsub('<', '<')
|
58
58
|
.gsub('\\ ', ' ')
|
59
|
-
.gsub(/\\hspace\{\d+pt\}/, ' ')
|
60
59
|
.gsub('\\(', '')
|
61
60
|
.gsub('\\)', '')
|
62
61
|
.gsub('\\lvert', '|')
|
63
62
|
.gsub('\\rvert', '|')
|
64
|
-
.gsub('\\mathit', '')
|
65
|
-
.gsub('\\mathrm', '')
|
66
63
|
.gsub('\\times', '*')
|
67
64
|
.gsub(/\\begin(\{[^{}]*\})*/, '')
|
68
65
|
.gsub(/\\end(\{[^{}]*\})*/, '')
|
66
|
+
.gsub(/\\hspace(\{[^{}]*\})*/, ' ')
|
67
|
+
.gsub(/\\mathrm\{([^{}]*)\}/, '\1')
|
68
|
+
.gsub(/\\mathit\{([^{}]*)\}/, '\1')
|
69
|
+
.gsub(/\\textrm\{([^{}]*)\}/, '\1')
|
70
|
+
.gsub(/\\text\{([^{}]*)\}/, '\1')
|
71
|
+
.gsub(/\\rm\{([^{}]*)\}/, '\1')
|
72
|
+
.gsub('\\rm ', ' ')
|
69
73
|
.gsub(/\\[cdlv]?dots/, '..')
|
70
74
|
.gsub(/\{\}/, ' ')
|
71
75
|
.gsub('−', '-') # full width hyphen
|
@@ -140,7 +144,7 @@ module AtCoderFriends
|
|
140
144
|
sz = str.split('_')
|
141
145
|
return sz if sz.size == 2
|
142
146
|
|
143
|
-
[str[0] || '_', str[1
|
147
|
+
[str[0] || '_', str[1..] || '_']
|
144
148
|
end
|
145
149
|
end
|
146
150
|
|
@@ -148,8 +152,8 @@ module AtCoderFriends
|
|
148
152
|
class InputFormatMatcher
|
149
153
|
include InputFormatUtils
|
150
154
|
|
151
|
-
attr_reader :container, :item, :pat, :gen_names, :gen_pat2
|
152
|
-
|
155
|
+
attr_reader :container, :item, :pat, :gen_names, :gen_pat2,
|
156
|
+
:names, :pat2, :size, :delim, :ix0
|
153
157
|
|
154
158
|
def initialize(
|
155
159
|
container: nil, item: nil,
|
@@ -168,8 +172,8 @@ module AtCoderFriends
|
|
168
172
|
|
169
173
|
@names = gen_names.call(m1)
|
170
174
|
@pat2 = gen_pat2&.call(names)
|
171
|
-
@size = m1.names.include?('sz') && m1['sz'] || ''
|
172
|
-
@ix0 = m1.names.include?('ix0') && m1['ix0'] || size
|
175
|
+
@size = (m1.names.include?('sz') && m1['sz']) || ''
|
176
|
+
@ix0 = (m1.names.include?('ix0') && m1['ix0']) || size
|
173
177
|
@delim = dlm
|
174
178
|
true
|
175
179
|
end
|
@@ -339,7 +343,7 @@ module AtCoderFriends
|
|
339
343
|
gen_pat2:
|
340
344
|
lambda { |vs|
|
341
345
|
m = vs[0]
|
342
|
-
ws = vs[1
|
346
|
+
ws = vs[1..].map { |v| v + RE_IX.source }.join('\s+')
|
343
347
|
/
|
344
348
|
\A
|
345
349
|
#{m}#{RE_IX}
|
@@ -363,7 +367,7 @@ module AtCoderFriends
|
|
363
367
|
lambda { |vs|
|
364
368
|
ws = [
|
365
369
|
vs[0] + RE_SZ.source,
|
366
|
-
*vs[1
|
370
|
+
*vs[1..]&.map { |v| v + RE_IX.source }
|
367
371
|
].join('\s+')
|
368
372
|
/\A#{ws}\z/
|
369
373
|
}
|
@@ -385,7 +389,7 @@ module AtCoderFriends
|
|
385
389
|
ws1 = vs.map { |v| v + RE_IX.source }.join('\s+')
|
386
390
|
ws2 = [
|
387
391
|
vs[0] + RE_SZ.source,
|
388
|
-
*vs[1
|
392
|
+
*vs[1..]&.map { |v| v + RE_IX.source }
|
389
393
|
].join('\s+')
|
390
394
|
/
|
391
395
|
\A
|
@@ -408,7 +412,7 @@ module AtCoderFriends
|
|
408
412
|
lambda { |vs|
|
409
413
|
ws = [
|
410
414
|
vs[0] + RE_SZ.source,
|
411
|
-
*vs[1
|
415
|
+
*vs[1..]&.map { |v| v + RE_IX.source }
|
412
416
|
].join('\s+')
|
413
417
|
/\A#{ws}\z/
|
414
418
|
}
|
@@ -416,7 +420,7 @@ module AtCoderFriends
|
|
416
420
|
SINGLE_MATCHER = InputFormatMatcher.new(
|
417
421
|
container: :single,
|
418
422
|
pat: /\A(.*\s)?#{RE_SINGLE}(\s.*)?\z/,
|
419
|
-
gen_names: ->(m) { m[0].split.
|
423
|
+
gen_names: ->(m) { m[0].split.grep(/\A#{RE_SINGLE}\z/) }
|
420
424
|
)
|
421
425
|
MATCHERS = [
|
422
426
|
MATRIX_MATCHER,
|
@@ -469,8 +473,8 @@ module AtCoderFriends
|
|
469
473
|
|
470
474
|
ret << matcher.to_inpdef
|
471
475
|
end
|
472
|
-
|
473
|
-
|
476
|
+
matcher = MATCHERS.find { |m| m.match(line) }
|
477
|
+
if !line.empty? && matcher.nil?
|
474
478
|
puts "unknown format: #{line}"
|
475
479
|
ret << unknown_fmt(line)
|
476
480
|
end
|
@@ -6,7 +6,6 @@ module AtCoderFriends
|
|
6
6
|
module Modulo
|
7
7
|
module_function
|
8
8
|
|
9
|
-
# rubocop:disable Style/AsciiComments
|
10
9
|
SECTIONS = [
|
11
10
|
Problem::SECTION_OUT_FMT,
|
12
11
|
Problem::SECTION_STATEMENT,
|
@@ -18,6 +17,7 @@ module AtCoderFriends
|
|
18
17
|
VALUE_PATTERN = %r{
|
19
18
|
(?:
|
20
19
|
<var>([^<>]+)</var>
|
20
|
+
|\(([^()]+)\)
|
21
21
|
|\\\(([^()]+)\\\)
|
22
22
|
|\$([^$]+)\$
|
23
23
|
|\{([^{}]+)\}
|
@@ -29,10 +29,9 @@ module AtCoderFriends
|
|
29
29
|
MOD_PATTERN = /
|
30
30
|
(?:
|
31
31
|
#{VALUE_PATTERN}\s*(?:\([^()]+\)\s*)?で割った(?:剰余|余り|あまり)
|
32
|
-
|(?:modulo|mod|
|
32
|
+
|(?:modulo|mod|divid(?:ed|ing)\s*by)\s*#{VALUE_PATTERN}
|
33
33
|
)
|
34
34
|
/xi.freeze
|
35
|
-
# rubocop:enable Style/AsciiComments
|
36
35
|
|
37
36
|
def process(pbm)
|
38
37
|
mods = []
|
@@ -59,10 +58,9 @@ module AtCoderFriends
|
|
59
58
|
s
|
60
59
|
.tr('0-9A-Za-z', '0-9A-Za-z')
|
61
60
|
.gsub(/[[:space:]]/, ' ')
|
62
|
-
.gsub(%r{[^一-龠_
|
63
|
-
.gsub(/{\\
|
64
|
-
.gsub(/\\
|
65
|
-
.gsub(/\\mbox\s*{\s*mod\s*}/i, 'mod') # \mbox{mod} -> mod
|
61
|
+
.gsub(%r{[^一-龠_ぁ-んァ-ヶーa-zA-Z0-9 -/:-@\[-`\{-~]}, '')
|
62
|
+
.gsub(/{\\[a-z]+\s*mod\s*}\\?/i, 'mod') # {\rm mod}, {\bmod} -> mod
|
63
|
+
.gsub(/\\[a-z]+\s*{\s*mod\s*}\\?/i, 'mod') # \text{mod} -> mod
|
66
64
|
.gsub(%r{<var>\s*mod\s*</var>}i, 'mod') # <var>mod</var> -> mod
|
67
65
|
end
|
68
66
|
|
@@ -23,15 +23,13 @@ module AtCoderFriends
|
|
23
23
|
end
|
24
24
|
|
25
25
|
def content
|
26
|
-
@content ||=
|
26
|
+
@content ||=
|
27
27
|
siblings.reduce('') { |m, node| m + node.content }.gsub("\r\n", "\n")
|
28
|
-
end
|
29
28
|
end
|
30
29
|
|
31
30
|
def html
|
32
|
-
@html ||=
|
31
|
+
@html ||=
|
33
32
|
siblings.reduce('') { |m, node| m + node.to_html }.gsub("\r\n", "\n")
|
34
|
-
end
|
35
33
|
end
|
36
34
|
|
37
35
|
def find_element(tags)
|
@@ -54,7 +52,7 @@ module AtCoderFriends
|
|
54
52
|
|
55
53
|
def code_block(mtd)
|
56
54
|
elem = find_element(%w[pre blockquote])
|
57
|
-
elem && elem.send(mtd).lstrip.gsub("\r\n", "\n") || ''
|
55
|
+
(elem && elem.send(mtd).lstrip.gsub("\r\n", "\n")) || ''
|
58
56
|
end
|
59
57
|
end
|
60
58
|
end
|
@@ -129,7 +129,7 @@ module AtCoderFriends
|
|
129
129
|
key = nil
|
130
130
|
SECTION_DEFS.any? do |grp|
|
131
131
|
if (m = title.match(grp[:pattern]))
|
132
|
-
no = m.names.include?('no') && m['no'] || '1'
|
132
|
+
no = (m.names.include?('no') && m['no']) || '1'
|
133
133
|
key = format(grp[:key], no: no)
|
134
134
|
end
|
135
135
|
end
|
@@ -140,7 +140,7 @@ module AtCoderFriends
|
|
140
140
|
s
|
141
141
|
.tr('0-9A-Za-z', '0-9A-Za-z')
|
142
142
|
.gsub(/[[:space:]]/, ' ') # &npsp; full-width space
|
143
|
-
.gsub(/[^一-龠_
|
143
|
+
.gsub(/[^一-龠_ぁ-んァ-ヶーa-zA-Z0-9 ]/, '')
|
144
144
|
.strip
|
145
145
|
end
|
146
146
|
end
|
@@ -54,7 +54,7 @@ module AtCoderFriends
|
|
54
54
|
end
|
55
55
|
|
56
56
|
def vars
|
57
|
-
tmp = @item && [@item] || cols
|
57
|
+
tmp = (@item && [@item]) || cols
|
58
58
|
names.zip(tmp).map { |(name, col)| [name, col || :number] }
|
59
59
|
end
|
60
60
|
|
@@ -77,8 +77,8 @@ module AtCoderFriends
|
|
77
77
|
),
|
78
78
|
self.class.new(
|
79
79
|
container: :matrix, item: @item,
|
80
|
-
names: names[-1
|
81
|
-
delim: delim, cols: cols[-1
|
80
|
+
names: names[-1..], size: size,
|
81
|
+
delim: delim, cols: cols[-1..] || []
|
82
82
|
)
|
83
83
|
]
|
84
84
|
end
|
@@ -92,8 +92,8 @@ module AtCoderFriends
|
|
92
92
|
),
|
93
93
|
self.class.new(
|
94
94
|
container: :varray,
|
95
|
-
names: names[1
|
96
|
-
delim: delim, cols: cols[1
|
95
|
+
names: names[1..], size: size[0..0],
|
96
|
+
delim: delim, cols: cols[1..] || []
|
97
97
|
)
|
98
98
|
]
|
99
99
|
end
|
@@ -23,7 +23,7 @@ module AtCoderFriends
|
|
23
23
|
@agent = Mechanize.new
|
24
24
|
agent.user_agent = "AtCoderFriends/#{VERSION} (#{CONTACT})"
|
25
25
|
agent.pre_connect_hooks << proc { sleep 0.1 }
|
26
|
-
agent.log = Logger.new(
|
26
|
+
agent.log = Logger.new($stderr) if ctx.options[:debug]
|
27
27
|
load_session
|
28
28
|
end
|
29
29
|
|
@@ -25,7 +25,7 @@ module AtCoderFriends
|
|
25
25
|
raise e if username_link(e.page)
|
26
26
|
end
|
27
27
|
|
28
|
-
agent.get(common_url('login')
|
28
|
+
agent.get("#{common_url('login')}?continue=#{CGI.escape(url)}")
|
29
29
|
end
|
30
30
|
|
31
31
|
def post_login(page)
|
@@ -40,13 +40,13 @@ module AtCoderFriends
|
|
40
40
|
user = ctx.config['user'].to_s
|
41
41
|
if user.empty?
|
42
42
|
print('enter username:')
|
43
|
-
user =
|
43
|
+
user = $stdin.gets.chomp
|
44
44
|
end
|
45
45
|
|
46
46
|
pass = ctx.config['password'].to_s
|
47
47
|
if pass.empty?
|
48
48
|
print("enter password for #{user}:")
|
49
|
-
pass =
|
49
|
+
pass = $stdin.noecho(&:gets).chomp
|
50
50
|
puts
|
51
51
|
end
|
52
52
|
[user, pass]
|
@@ -7,14 +7,12 @@ module AtCoderFriends
|
|
7
7
|
def fetch_all
|
8
8
|
puts "***** fetch_all #{contest} *****"
|
9
9
|
fetch_assignments.map do |q, url|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
puts e.backtrace
|
17
|
-
end
|
10
|
+
pbm = fetch_problem(q, url)
|
11
|
+
yield pbm if block_given?
|
12
|
+
pbm
|
13
|
+
rescue StandardError => e
|
14
|
+
puts e
|
15
|
+
puts e.backtrace
|
18
16
|
end
|
19
17
|
end
|
20
18
|
|
@@ -121,7 +121,7 @@ module AtCoderFriends
|
|
121
121
|
end
|
122
122
|
|
123
123
|
def which_os
|
124
|
-
@which_os ||=
|
124
|
+
@which_os ||=
|
125
125
|
case RbConfig::CONFIG['host_os']
|
126
126
|
when /mswin|msys|mingw|cygwin|bccwin|wince|emc/
|
127
127
|
:windows
|
@@ -134,7 +134,6 @@ module AtCoderFriends
|
|
134
134
|
else
|
135
135
|
:unknown
|
136
136
|
end
|
137
|
-
end
|
138
137
|
end
|
139
138
|
end
|
140
139
|
end
|
@@ -16,17 +16,17 @@ module AtCoderFriends
|
|
16
16
|
puts "***** judge_all #{prg} (#{test_loc}) *****"
|
17
17
|
results = Dir["#{data_dir}/#{q}/in/*"].sort.map do |infile|
|
18
18
|
id = File.basename(infile)
|
19
|
-
judge(id, false)
|
19
|
+
judge(id, detail: false)
|
20
20
|
end
|
21
21
|
!results.empty? && results.all?
|
22
22
|
end
|
23
23
|
|
24
24
|
def judge_one(id)
|
25
25
|
puts "***** judge_one #{prg} (#{test_loc}) *****"
|
26
|
-
judge(id, true)
|
26
|
+
judge(id, detail: true)
|
27
27
|
end
|
28
28
|
|
29
|
-
def judge(id, detail
|
29
|
+
def judge(id, detail: true)
|
30
30
|
@detail = detail
|
31
31
|
infile = "#{data_dir}/#{q}/in/#{id}"
|
32
32
|
outfile = "#{result_dir}/#{q}/result/#{id}"
|
data/lib/at_coder_friends.rb
CHANGED
@@ -28,6 +28,9 @@ require 'at_coder_friends/parser/interactive'
|
|
28
28
|
require 'at_coder_friends/parser/binary'
|
29
29
|
require 'at_coder_friends/parser/main'
|
30
30
|
require 'at_coder_friends/generator/base'
|
31
|
+
require 'at_coder_friends/generator/fragment'
|
32
|
+
require 'at_coder_friends/generator/any_builtin'
|
33
|
+
require 'at_coder_friends/generator/c_builtin'
|
31
34
|
require 'at_coder_friends/generator/cxx_builtin'
|
32
35
|
require 'at_coder_friends/generator/ruby_builtin'
|
33
36
|
require 'at_coder_friends/generator/main'
|
@@ -0,0 +1,30 @@
|
|
1
|
+
AnyBuiltin Generator
|
2
|
+
====================
|
3
|
+
|
4
|
+
## Usage
|
5
|
+
- Prepare a source template file.
|
6
|
+
- Specify the path to the template file
|
7
|
+
and file extension for the generated file (here we use 'js')
|
8
|
+
in `.at_coder_friends.yml` as follows:
|
9
|
+
|
10
|
+
```
|
11
|
+
generators:
|
12
|
+
- AnyBuiltin
|
13
|
+
generator_settings:
|
14
|
+
AnyBuiltin:
|
15
|
+
file_ext: js
|
16
|
+
template: /path/to/template
|
17
|
+
```
|
18
|
+
|
19
|
+
## Problem URL
|
20
|
+
<%= pbm.url %>
|
21
|
+
|
22
|
+
## Constants
|
23
|
+
<% gen_consts.each do |line| -%>
|
24
|
+
- [<%= line %>]
|
25
|
+
<% end -%>
|
26
|
+
|
27
|
+
## Variables
|
28
|
+
<% gen_decls.each do |line| -%>
|
29
|
+
- [<%= line %>]
|
30
|
+
<% end -%>
|