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.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/.gitattributes +1 -0
  3. data/.github/workflows/codeql-analysis.yml +70 -0
  4. data/.github/workflows/ruby.yml +38 -0
  5. data/.gitignore +3 -0
  6. data/.rubocop.yml +8 -1
  7. data/CHANGELOG.md +23 -4
  8. data/Gemfile.lock +43 -43
  9. data/README.md +15 -92
  10. data/at_coder_friends.gemspec +4 -3
  11. data/lib/at_coder_friends/cli.rb +13 -28
  12. data/lib/at_coder_friends/config_loader.rb +2 -4
  13. data/lib/at_coder_friends/generator/any_builtin.rb +22 -0
  14. data/lib/at_coder_friends/generator/base.rb +55 -6
  15. data/lib/at_coder_friends/generator/c_builtin.rb +22 -0
  16. data/lib/at_coder_friends/generator/cxx_builtin.rb +9 -241
  17. data/lib/at_coder_friends/generator/fragment.rb +106 -0
  18. data/lib/at_coder_friends/generator/main.rb +20 -14
  19. data/lib/at_coder_friends/generator/ruby_builtin.rb +13 -166
  20. data/lib/at_coder_friends/parser/binary.rb +12 -5
  21. data/lib/at_coder_friends/parser/constraints.rb +8 -8
  22. data/lib/at_coder_friends/parser/input_format.rb +19 -15
  23. data/lib/at_coder_friends/parser/modulo.rb +5 -7
  24. data/lib/at_coder_friends/parser/section_wrapper.rb +3 -5
  25. data/lib/at_coder_friends/parser/sections.rb +2 -2
  26. data/lib/at_coder_friends/path_util.rb +1 -1
  27. data/lib/at_coder_friends/problem.rb +5 -5
  28. data/lib/at_coder_friends/scraping/agent.rb +1 -1
  29. data/lib/at_coder_friends/scraping/authentication.rb +3 -3
  30. data/lib/at_coder_friends/scraping/session.rb +1 -1
  31. data/lib/at_coder_friends/scraping/tasks.rb +6 -8
  32. data/lib/at_coder_friends/test_runner/base.rb +1 -2
  33. data/lib/at_coder_friends/test_runner/judge.rb +3 -3
  34. data/lib/at_coder_friends/version.rb +1 -1
  35. data/lib/at_coder_friends.rb +3 -0
  36. data/templates/any_builtin.md.erb +30 -0
  37. data/templates/any_builtin_fragments.yml +5 -0
  38. data/templates/c_builtin.c.erb +36 -0
  39. data/templates/c_builtin_fragments.yml +127 -0
  40. data/templates/csharp_sample.cs.erb +29 -0
  41. data/templates/csharp_sample_fragments.yml +159 -0
  42. data/templates/java_sample.java.erb +25 -0
  43. data/templates/java_sample_fragments.yml +98 -0
  44. data/templates/ruby_builtin_fragments.yml +93 -0
  45. metadata +26 -6
  46. data/.travis.yml +0 -16
  47. 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
- DEFAULT_TMPL = File.join(TMPL_DIR, 'ruby_builtin.rb.erb')
10
- ATTRS = Attributes.new(:rb, DEFAULT_TMPL)
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 render(src)
17
- src = embed_lines(src, '### CONSTS ###', gen_consts)
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| gen_mod(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
- def gen_decl(inpdef)
38
- case inpdef.container
39
- when :single
40
- gen_single_decl(inpdef)
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.size == 2
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
- if out_fmt =~ /#{re1}.+#{re2}/m
17
+ case out_fmt
18
+ when /#{re1}.+#{re2}/m
20
19
  vs
21
- elsif out_fmt =~ /#{re2}.+#{re1}/m
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
- .scan(MAX_PATTERN)
39
- .map(&:compact)
40
- .map { |k, v| [normalize_names(k), normalize_value(v)] }
41
- .select { |_, v| v && !v.empty? }
42
- .flat_map { |ks, v| ks.map { |k| [k, v] } }
43
- .uniq
44
- .map { |k, v| Problem::Constant.new(k, :max, v) }
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('&gt;', '>')
57
57
  .gsub('&lt;', '<')
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..-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
- attr_reader :names, :pat2, :size, :delim, :ix0
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..-1].map { |v| v + RE_IX.source }.join('\s+')
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..-1]&.map { |v| v + RE_IX.source }
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..-1]&.map { |v| v + RE_IX.source }
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..-1]&.map { |v| v + RE_IX.source }
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.select { |w| w =~ /\A#{RE_SINGLE}\z/ } }
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
- if (matcher = MATCHERS.find { |m| m.match(line) })
473
- elsif !line.empty?
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|divided\s*by|dividing\s*by)\s*#{VALUE_PATTERN}
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{[^一-龠_ぁ-ん_ァ-ヶーa-zA-Z0-9 -/:-@\[-`\{-~]}, '')
63
- .gsub(/{\\rm\s*mod\s*}\\?/i, 'mod') # {\rm mod} -> mod
64
- .gsub(/\\rm\s*{\s*mod\s*}\\?/i, 'mod') # \rm{mod}\ -> mod
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 ||= begin
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 ||= begin
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(/[^一-龠_ぁ-ん_ァ-ヶーa-zA-Z0-9 ]/, '')
143
+ .gsub(/[^一-龠_ぁ-んァ-ヶーa-zA-Z0-9 ]/, '')
144
144
  .strip
145
145
  end
146
146
  end
@@ -4,7 +4,7 @@ module AtCoderFriends
4
4
  # Common methods and behaviors for dealing with paths.
5
5
  module PathUtil
6
6
  def makedirs_unless(dir)
7
- FileUtils.makedirs(dir) unless Dir.exist?(dir)
7
+ FileUtils.makedirs(dir)
8
8
  end
9
9
  end
10
10
  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..-1], size: size,
81
- delim: delim, cols: cols[-1..-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..-1], size: size[0..0],
96
- delim: delim, cols: cols[1..-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(STDERR) if ctx.options[:debug]
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') + '?continue=' + CGI.escape(url))
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 = STDIN.gets.chomp
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 = STDIN.noecho(&:gets).chomp
49
+ pass = $stdin.noecho(&:gets).chomp
50
50
  puts
51
51
  end
52
52
  [user, pass]
@@ -14,7 +14,7 @@ module AtCoderFriends
14
14
 
15
15
  def save_session
16
16
  dir = File.dirname(session_store)
17
- Dir.mkdir(dir) unless Dir.exist?(dir)
17
+ FileUtils.mkdir_p(dir)
18
18
  agent.cookie_jar.save_as(session_store)
19
19
  end
20
20
 
@@ -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
- begin
11
- pbm = fetch_problem(q, url)
12
- yield pbm if block_given?
13
- pbm
14
- rescue StandardError => e
15
- puts e.to_s
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 ||= begin
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 = true)
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}"
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module AtCoderFriends
4
- VERSION = '0.6.8'
4
+ VERSION = '0.7.0'
5
5
  end
@@ -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 -%>
@@ -0,0 +1,5 @@
1
+ constant:
2
+ mod: type=<%= type %> name=<%= name %> value=<%= value %>
3
+ max: type=<%= type %> name=<%= name %> value=<%= value %>
4
+ declaration:
5
+ main: <%= to_s %>