at_coder_friends 0.5.0 → 0.5.1
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/.gitignore +5 -2
- data/.rubocop.yml +1 -0
- data/.rubocop_todo.yml +4 -1
- data/Gemfile.lock +16 -14
- data/Rakefile +2 -0
- data/at_coder_friends.gemspec +1 -0
- data/lib/at_coder_friends.rb +13 -5
- data/lib/at_coder_friends/cli.rb +1 -2
- data/lib/at_coder_friends/config_loader.rb +2 -2
- data/lib/at_coder_friends/context.rb +3 -3
- data/lib/at_coder_friends/cxx_generator.rb +7 -13
- data/lib/at_coder_friends/emitter.rb +0 -4
- data/lib/at_coder_friends/parser/constraints_parser.rb +26 -0
- data/lib/at_coder_friends/parser/format_parser.rb +154 -0
- data/lib/at_coder_friends/parser/main.rb +16 -0
- data/lib/at_coder_friends/parser/page_parser.rb +119 -0
- data/lib/at_coder_friends/path_util.rb +10 -0
- data/lib/at_coder_friends/problem.rb +11 -14
- data/lib/at_coder_friends/scraping/agent.rb +77 -0
- data/lib/at_coder_friends/scraping/authentication.rb +71 -0
- data/lib/at_coder_friends/scraping/custom_test.rb +53 -0
- data/lib/at_coder_friends/scraping/session.rb +26 -0
- data/lib/at_coder_friends/scraping/submission.rb +31 -0
- data/lib/at_coder_friends/scraping/tasks.rb +39 -0
- data/lib/at_coder_friends/test_runner/base.rb +123 -0
- data/lib/at_coder_friends/test_runner/judge.rb +44 -0
- data/lib/at_coder_friends/test_runner/sample.rb +35 -0
- data/lib/at_coder_friends/verifier.rb +4 -2
- data/lib/at_coder_friends/version.rb +1 -1
- data/tasks/regression.rake +163 -0
- metadata +30 -7
- data/lib/at_coder_friends/format_parser.rb +0 -151
- data/lib/at_coder_friends/judge_test_runner.rb +0 -34
- data/lib/at_coder_friends/sample_test_runner.rb +0 -31
- data/lib/at_coder_friends/scraping_agent.rb +0 -265
- data/lib/at_coder_friends/test_runner.rb +0 -104
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 24142f8aee41542925cca00a32b8bc857c012625
|
4
|
+
data.tar.gz: 31511f4cde2547fe046b202981888691d070231a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c6eab79caf8682d95758978e90ee04bbd687a66f302e4ecec3e1dbd73ce8bb2c4b5208411b76c319b992eabc01970e3b5e8c77d6d4fda9f88eb1ff617ff00d06
|
7
|
+
data.tar.gz: 87a88e30c96d63452044c56e5dad00981fecbac8a956e24f99b411709dae015b3046ee5be735ca5d707907da8cb6dd38f86eec0e2285ffeee83b03ba26c75fd4
|
data/.gitignore
CHANGED
data/.rubocop.yml
CHANGED
data/.rubocop_todo.yml
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
at_coder_friends (0.5.
|
4
|
+
at_coder_friends (0.5.1)
|
5
|
+
colorize (~> 0.8.1)
|
5
6
|
launchy (~> 2.4.3)
|
6
7
|
mechanize (~> 2.0)
|
7
8
|
|
@@ -10,6 +11,7 @@ GEM
|
|
10
11
|
specs:
|
11
12
|
addressable (2.7.0)
|
12
13
|
public_suffix (>= 2.0.2, < 5.0)
|
14
|
+
colorize (0.8.1)
|
13
15
|
connection_pool (2.2.2)
|
14
16
|
crack (0.4.3)
|
15
17
|
safe_yaml (~> 1.0.0)
|
@@ -32,9 +34,9 @@ GEM
|
|
32
34
|
nokogiri (~> 1.6)
|
33
35
|
ntlm-http (~> 0.1, >= 0.1.1)
|
34
36
|
webrobots (>= 0.0.9, < 0.2)
|
35
|
-
mime-types (3.
|
37
|
+
mime-types (3.3)
|
36
38
|
mime-types-data (~> 3.2015)
|
37
|
-
mime-types-data (3.2019.
|
39
|
+
mime-types-data (3.2019.0904)
|
38
40
|
mini_portile2 (2.4.0)
|
39
41
|
net-http-digest_auth (1.4.1)
|
40
42
|
net-http-persistent (3.1.0)
|
@@ -44,19 +46,19 @@ GEM
|
|
44
46
|
ntlm-http (0.1.1)
|
45
47
|
public_suffix (4.0.1)
|
46
48
|
rake (13.0.0)
|
47
|
-
rspec (3.
|
48
|
-
rspec-core (~> 3.
|
49
|
-
rspec-expectations (~> 3.
|
50
|
-
rspec-mocks (~> 3.
|
51
|
-
rspec-core (3.
|
52
|
-
rspec-support (~> 3.
|
53
|
-
rspec-expectations (3.
|
49
|
+
rspec (3.9.0)
|
50
|
+
rspec-core (~> 3.9.0)
|
51
|
+
rspec-expectations (~> 3.9.0)
|
52
|
+
rspec-mocks (~> 3.9.0)
|
53
|
+
rspec-core (3.9.0)
|
54
|
+
rspec-support (~> 3.9.0)
|
55
|
+
rspec-expectations (3.9.0)
|
54
56
|
diff-lcs (>= 1.2.0, < 2.0)
|
55
|
-
rspec-support (~> 3.
|
56
|
-
rspec-mocks (3.
|
57
|
+
rspec-support (~> 3.9.0)
|
58
|
+
rspec-mocks (3.9.0)
|
57
59
|
diff-lcs (>= 1.2.0, < 2.0)
|
58
|
-
rspec-support (~> 3.
|
59
|
-
rspec-support (3.
|
60
|
+
rspec-support (~> 3.9.0)
|
61
|
+
rspec-support (3.9.0)
|
60
62
|
safe_yaml (1.0.5)
|
61
63
|
simplecov (0.17.1)
|
62
64
|
docile (~> 1.1)
|
data/Rakefile
CHANGED
data/at_coder_friends.gemspec
CHANGED
data/lib/at_coder_friends.rb
CHANGED
@@ -5,12 +5,20 @@ require 'at_coder_friends/errors'
|
|
5
5
|
require 'at_coder_friends/path_util'
|
6
6
|
require 'at_coder_friends/config_loader'
|
7
7
|
require 'at_coder_friends/verifier'
|
8
|
-
require 'at_coder_friends/test_runner'
|
9
|
-
require 'at_coder_friends/
|
10
|
-
require 'at_coder_friends/
|
8
|
+
require 'at_coder_friends/test_runner/base'
|
9
|
+
require 'at_coder_friends/test_runner/sample'
|
10
|
+
require 'at_coder_friends/test_runner/judge'
|
11
11
|
require 'at_coder_friends/problem'
|
12
|
-
require 'at_coder_friends/
|
13
|
-
require 'at_coder_friends/
|
12
|
+
require 'at_coder_friends/scraping/session'
|
13
|
+
require 'at_coder_friends/scraping/authentication'
|
14
|
+
require 'at_coder_friends/scraping/custom_test'
|
15
|
+
require 'at_coder_friends/scraping/submission'
|
16
|
+
require 'at_coder_friends/scraping/tasks'
|
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'
|
21
|
+
require 'at_coder_friends/parser/main'
|
14
22
|
require 'at_coder_friends/ruby_generator'
|
15
23
|
require 'at_coder_friends/cxx_generator'
|
16
24
|
require 'at_coder_friends/emitter'
|
data/lib/at_coder_friends/cli.rb
CHANGED
@@ -92,11 +92,10 @@ module AtCoderFriends
|
|
92
92
|
raise AppError, "#{path} is not empty." \
|
93
93
|
if Dir.exist?(path) && !Dir["#{path}/*"].empty?
|
94
94
|
|
95
|
-
parser = FormatParser.new
|
96
95
|
rb_gen = RubyGenerator.new
|
97
96
|
cxx_gen = CxxGenerator.new
|
98
97
|
ctx.scraping_agent.fetch_all do |pbm|
|
99
|
-
|
98
|
+
Parser::Main.process(pbm)
|
100
99
|
rb_gen.process(pbm)
|
101
100
|
cxx_gen.process(pbm)
|
102
101
|
ctx.emitter.emit(pbm)
|
@@ -43,7 +43,7 @@ module AtCoderFriends
|
|
43
43
|
end
|
44
44
|
|
45
45
|
def merge(base_hash, derived_hash)
|
46
|
-
res = base_hash.merge(derived_hash
|
46
|
+
res = base_hash.merge(derived_hash) do |_, base_val, derived_val|
|
47
47
|
if base_val.is_a?(Hash) && derived_val.is_a?(Hash)
|
48
48
|
merge(base_val, derived_val)
|
49
49
|
else
|
@@ -55,7 +55,7 @@ module AtCoderFriends
|
|
55
55
|
|
56
56
|
def load_yaml(path)
|
57
57
|
yaml = IO.read(path, encoding: Encoding::UTF_8)
|
58
|
-
YAML.safe_load(yaml, [], [], false, path)
|
58
|
+
YAML.safe_load(yaml, [], [], false, path) || {}
|
59
59
|
rescue Errno::ENOENT
|
60
60
|
raise ConfigNotFoundError,
|
61
61
|
"Configuration file not found: #{path}"
|
@@ -19,15 +19,15 @@ module AtCoderFriends
|
|
19
19
|
end
|
20
20
|
|
21
21
|
def scraping_agent
|
22
|
-
@scraping_agent ||=
|
22
|
+
@scraping_agent ||= Scraping::Agent.new(self)
|
23
23
|
end
|
24
24
|
|
25
25
|
def sample_test_runner
|
26
|
-
@sample_test_runner ||=
|
26
|
+
@sample_test_runner ||= TestRunner::Sample.new(self)
|
27
27
|
end
|
28
28
|
|
29
29
|
def judge_test_runner
|
30
|
-
@judge_test_runner ||=
|
30
|
+
@judge_test_runner ||= TestRunner::Judge.new(self)
|
31
31
|
end
|
32
32
|
|
33
33
|
def verifier
|
@@ -61,12 +61,12 @@ module AtCoderFriends
|
|
61
61
|
}.freeze
|
62
62
|
|
63
63
|
def process(pbm)
|
64
|
-
src = generate(pbm.defs, pbm.
|
64
|
+
src = generate(pbm.defs, pbm.constraints)
|
65
65
|
pbm.add_src(:cxx, src)
|
66
66
|
end
|
67
67
|
|
68
|
-
def generate(defs,
|
69
|
-
consts = gen_consts(
|
68
|
+
def generate(defs, constraints)
|
69
|
+
consts = gen_consts(constraints)
|
70
70
|
dcls = gen_decls(defs)
|
71
71
|
reads = gen_reads(defs)
|
72
72
|
TEMPLATE
|
@@ -75,16 +75,10 @@ module AtCoderFriends
|
|
75
75
|
.sub('/*** READS ***/', reads.map { |s| ' ' + s }.join("\n"))
|
76
76
|
end
|
77
77
|
|
78
|
-
def gen_consts(
|
79
|
-
|
80
|
-
.
|
81
|
-
.
|
82
|
-
.scan(/([\da-z_]+)\s*≦\s*(\d+)(?:\^(\d+))?/i)
|
83
|
-
.map do |v, sz, k|
|
84
|
-
sz = sz.to_i
|
85
|
-
sz **= k.to_i if k
|
86
|
-
"const int #{v.upcase}_MAX = #{sz};"
|
87
|
-
end
|
78
|
+
def gen_consts(constraints)
|
79
|
+
constraints
|
80
|
+
.select { |c| c.type == :max }
|
81
|
+
.map { |c| "const int #{c.name.upcase}_MAX = #{c.value};" }
|
88
82
|
end
|
89
83
|
|
90
84
|
def gen_decls(defs)
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AtCoderFriends
|
4
|
+
module Parser
|
5
|
+
# parses constraints
|
6
|
+
module ConstraintsParser
|
7
|
+
module_function
|
8
|
+
|
9
|
+
def process(pbm)
|
10
|
+
pbm.constraints = parse(pbm.desc)
|
11
|
+
end
|
12
|
+
|
13
|
+
def parse(desc)
|
14
|
+
desc
|
15
|
+
.gsub(/[,\\(){}|]/, '')
|
16
|
+
.gsub(/(≤|leq?)/i, '≦')
|
17
|
+
.scan(/([\da-z_]+)\s*≦\s*(\d+)(?:\^(\d+))?/i)
|
18
|
+
.map do |v, sz, k|
|
19
|
+
sz = sz.to_i
|
20
|
+
sz **= k.to_i if k
|
21
|
+
Constraint.new(v, :max, sz)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,154 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AtCoderFriends
|
4
|
+
module Parser
|
5
|
+
# parses input data format and generates input definitons
|
6
|
+
module FormatParser
|
7
|
+
module_function
|
8
|
+
|
9
|
+
# Iterates through elements of an array
|
10
|
+
class Iterator
|
11
|
+
def initialize(array)
|
12
|
+
@array = array
|
13
|
+
@i = 0
|
14
|
+
end
|
15
|
+
|
16
|
+
def next?
|
17
|
+
@i < @array.size
|
18
|
+
end
|
19
|
+
|
20
|
+
def next
|
21
|
+
ret = @array[@i]
|
22
|
+
@i += 1
|
23
|
+
ret
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
PARSERS = [
|
28
|
+
{
|
29
|
+
container: :harray,
|
30
|
+
item: :number,
|
31
|
+
pat: /^(?<v>[a-z]+)[01](\s+\k<v>.)*(\s+\.+)?(\s+\k<v>.)+$/i,
|
32
|
+
names: ->(m) { [m[:v]] },
|
33
|
+
pat2: ->(_) { nil },
|
34
|
+
size: ->(f) { [f[-1]] }
|
35
|
+
},
|
36
|
+
{
|
37
|
+
container: :harray,
|
38
|
+
item: :char,
|
39
|
+
pat: /^(?<v>[a-z]+)[01](\k<v>.)*(\s*\.+\s*)?(\k<v>.)+$/i,
|
40
|
+
names: ->(m) { [m[:v]] },
|
41
|
+
pat2: ->(_) { nil },
|
42
|
+
size: ->(f) { [f[-1]] }
|
43
|
+
},
|
44
|
+
{
|
45
|
+
container: :matrix,
|
46
|
+
item: :number,
|
47
|
+
pat: /^(?<v>[a-z]+)[01][01](\s+\k<v>..)*(\s+\.+)?(\s+\k<v>..)+$/i,
|
48
|
+
names: ->(m) { [m[:v]] },
|
49
|
+
pat2: ->(v) { /(^#{v}..(\s+#{v}..)*(\s+\.+)?(\s+#{v}..)+|\.+)$/ },
|
50
|
+
size: ->(f) { f[-2..-1].chars.to_a }
|
51
|
+
},
|
52
|
+
{
|
53
|
+
container: :matrix,
|
54
|
+
item: :char,
|
55
|
+
pat: /^(?<v>[a-z]+)[01][01](\k<v>..)*(\s*\.+\s*)?(\k<v>..)+$/i,
|
56
|
+
names: ->(m) { [m[:v]] },
|
57
|
+
pat2: ->(v) { /(^#{v}..(#{v}..)*(\s*\.+\s*)?(#{v}..)+|\.+)$/ },
|
58
|
+
size: ->(f) { f[-2..-1].chars.to_a }
|
59
|
+
},
|
60
|
+
{
|
61
|
+
container: :varray,
|
62
|
+
item: :number,
|
63
|
+
pat: /^[a-z]+(?<i>[0-9])(\s+[a-z]+\k<i>)*$/i,
|
64
|
+
names: ->(m) { m[0].split.map { |w| w[0..-2] } },
|
65
|
+
pat2: lambda { |vs|
|
66
|
+
pat = vs.map { |v| v + '.+' }.join('\s+')
|
67
|
+
/^(#{pat}|\.+)$/
|
68
|
+
},
|
69
|
+
size: ->(f) { /(?<sz>\d+)$/ =~ f ? [sz] : [f[-1]] }
|
70
|
+
},
|
71
|
+
{
|
72
|
+
container: :single,
|
73
|
+
item: :number,
|
74
|
+
pat: /^[a-z]+(\s+[a-z]+)*$/i,
|
75
|
+
names: ->(m) { m[0].split },
|
76
|
+
pat2: ->(_) { nil },
|
77
|
+
size: ->(_) { [] }
|
78
|
+
}
|
79
|
+
].freeze
|
80
|
+
|
81
|
+
def process(pbm)
|
82
|
+
defs = parse(pbm.fmt, pbm.smps)
|
83
|
+
pbm.defs = defs
|
84
|
+
end
|
85
|
+
|
86
|
+
def parse(fmt, smps)
|
87
|
+
lines = normalize(fmt)
|
88
|
+
defs = parse_fmt(lines)
|
89
|
+
smpx = max_smp(smps)
|
90
|
+
smpx && match_smp!(defs, smpx)
|
91
|
+
defs
|
92
|
+
end
|
93
|
+
|
94
|
+
def normalize(fmt)
|
95
|
+
fmt
|
96
|
+
.gsub(/[+*-]\d+/, '') # N-1, N+1 -> N
|
97
|
+
.gsub(%r{[-/ ]}, ' ') # a-b, a/b -> a b
|
98
|
+
.gsub(/\{.*?\}/) { |w| w.delete(' ') } # {1, 1}->{1,1} shortest match
|
99
|
+
.gsub(/[_,'\\(){}|$]/, '')
|
100
|
+
.gsub(/[・::…‥]+/, '..')
|
101
|
+
.gsub(/[clv]?dots/, '..')
|
102
|
+
.gsub(/^[.\s]+$/, '..')
|
103
|
+
.split("\n")
|
104
|
+
.map(&:strip)
|
105
|
+
end
|
106
|
+
|
107
|
+
# rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
108
|
+
def parse_fmt(lines)
|
109
|
+
it = Iterator.new(lines + ['']) # sentinel
|
110
|
+
prv = nil
|
111
|
+
cur = it.next
|
112
|
+
Enumerator.new do |y|
|
113
|
+
loop do
|
114
|
+
unless (parser = PARSERS.find { |ps| ps[:pat] =~ cur })
|
115
|
+
puts "unknown format: #{cur}" unless cur.empty?
|
116
|
+
(cur = it.next) ? next : break
|
117
|
+
end
|
118
|
+
container, item = parser.values_at(:container, :item)
|
119
|
+
m = parser[:pat].match(cur)
|
120
|
+
names = parser[:names].call(m)
|
121
|
+
pat2 = parser[:pat2].call(names)
|
122
|
+
loop do
|
123
|
+
prv = cur
|
124
|
+
cur = it.next
|
125
|
+
break unless pat2 && pat2 =~ cur
|
126
|
+
end
|
127
|
+
size = parser[:size].call(prv)
|
128
|
+
y << InputDef.new(container, item, names, size)
|
129
|
+
end
|
130
|
+
end.to_a
|
131
|
+
end
|
132
|
+
# rubocop:enable Metrics/MethodLength, Metrics/AbcSize
|
133
|
+
|
134
|
+
def max_smp(smps)
|
135
|
+
smps
|
136
|
+
.select { |smp| smp.ext == :in }
|
137
|
+
.max_by { |smp| smp.txt.size }
|
138
|
+
&.txt
|
139
|
+
end
|
140
|
+
|
141
|
+
def match_smp!(inpdefs, smp)
|
142
|
+
lines = smp.split("\n")
|
143
|
+
inpdefs.each_with_index do |inpdef, i|
|
144
|
+
break if i >= lines.size
|
145
|
+
next if inpdef.item != :number
|
146
|
+
|
147
|
+
inpdef.item = :string if lines[i].split[0] =~ /[^\-0-9]/
|
148
|
+
break if %i[varray matrix].include?(inpdef.container)
|
149
|
+
end
|
150
|
+
inpdefs
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AtCoderFriends
|
4
|
+
module Parser
|
5
|
+
# entry point for parsing problem description
|
6
|
+
module Main
|
7
|
+
module_function
|
8
|
+
|
9
|
+
def process(pbm)
|
10
|
+
PageParser.process(pbm)
|
11
|
+
FormatParser.process(pbm)
|
12
|
+
ConstraintsParser.process(pbm)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|