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.
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 %>