at_coder_friends 0.6.8 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- 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 -%>
|