judges 0.60.3 → 0.60.4
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/Gemfile +4 -3
- data/Gemfile.lock +34 -30
- data/README.md +3 -3
- data/Rakefile +1 -1
- data/features/step_definitions/steps.rb +6 -6
- data/features/test.feature +2 -2
- data/fixtures/repeat/repeat.rb +0 -2
- data/judges.gemspec +20 -20
- data/lib/judges/ascii_loog.rb +1 -2
- data/lib/judges/commands/download.rb +5 -6
- data/lib/judges/commands/eval.rb +5 -6
- data/lib/judges/commands/import.rb +6 -6
- data/lib/judges/commands/inspect.rb +2 -2
- data/lib/judges/commands/join.rb +3 -3
- data/lib/judges/commands/print.rb +19 -19
- data/lib/judges/commands/pull.rb +15 -12
- data/lib/judges/commands/push.rb +5 -5
- data/lib/judges/commands/test.rb +115 -83
- data/lib/judges/commands/trim.rb +5 -5
- data/lib/judges/commands/update.rb +102 -74
- data/lib/judges/commands/upload.rb +8 -8
- data/lib/judges/impex.rb +6 -6
- data/lib/judges/judge.rb +14 -12
- data/lib/judges/judges.rb +30 -25
- data/lib/judges/options.rb +32 -41
- data/lib/judges/pretty_exception.rb +1 -1
- data/lib/judges/statistics.rb +5 -8
- data/lib/judges.rb +1 -1
- data/package-lock.json +106 -295
- data/package.json +2 -2
- metadata +1 -1
data/lib/judges/commands/pull.rb
CHANGED
|
@@ -3,16 +3,16 @@
|
|
|
3
3
|
# SPDX-FileCopyrightText: Copyright (c) 2024-2026 Yegor Bugayenko
|
|
4
4
|
# SPDX-License-Identifier: MIT
|
|
5
5
|
|
|
6
|
-
require 'typhoeus'
|
|
7
|
-
require 'iri'
|
|
8
6
|
require 'baza-rb'
|
|
9
7
|
require 'elapsed'
|
|
8
|
+
require 'iri'
|
|
9
|
+
require 'typhoeus'
|
|
10
10
|
require_relative '../../judges'
|
|
11
11
|
require_relative '../../judges/impex'
|
|
12
12
|
|
|
13
13
|
# The +pull+ command.
|
|
14
14
|
#
|
|
15
|
-
# This class is instantiated by the +bin/
|
|
15
|
+
# This class is instantiated by the +bin/judges+ command line interface. You
|
|
16
16
|
# are not supposed to instantiate it yourself.
|
|
17
17
|
#
|
|
18
18
|
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
|
@@ -30,7 +30,7 @@ class Judges::Pull
|
|
|
30
30
|
# @param [Array] args List of command line arguments
|
|
31
31
|
# @raise [RuntimeError] If not exactly two arguments provided
|
|
32
32
|
def run(opts, args)
|
|
33
|
-
raise 'Exactly two arguments required' unless args.size == 2
|
|
33
|
+
raise(ArgumentError, 'Exactly two arguments required') unless args.size == 2
|
|
34
34
|
fb = Factbase.new
|
|
35
35
|
baza = BazaRb.new(
|
|
36
36
|
opts['host'], opts['port'].to_i, opts['token'],
|
|
@@ -47,16 +47,16 @@ class Judges::Pull
|
|
|
47
47
|
jid = baza.recent(name)
|
|
48
48
|
unless baza.exit_code(jid).zero?
|
|
49
49
|
@loog.warn("STDOUT of the job ##{jid} (from the server):\n#{baza.stdout(jid)}")
|
|
50
|
-
raise "The job ##{jid} ('#{name}') is broken, maybe you should expire it"
|
|
50
|
+
raise(StandardError, "The job ##{jid} ('#{name}') is broken, maybe you should expire it")
|
|
51
51
|
end
|
|
52
52
|
fb.import(baza.pull(wait(name, baza, jid, opts['wait'])))
|
|
53
53
|
Judges::Impex.new(@loog, args[1]).export(fb)
|
|
54
54
|
ensure
|
|
55
55
|
baza.unlock(name, opts['owner'])
|
|
56
56
|
end
|
|
57
|
-
throw
|
|
57
|
+
throw(:"👍 Pulled #{fb.size} facts by name '#{name}'")
|
|
58
58
|
else
|
|
59
|
-
throw
|
|
59
|
+
throw(:"⚠️ Nothing to pull - name '#{name}' not found on server")
|
|
60
60
|
end
|
|
61
61
|
end
|
|
62
62
|
end
|
|
@@ -64,14 +64,17 @@ class Judges::Pull
|
|
|
64
64
|
private
|
|
65
65
|
|
|
66
66
|
def wait(name, baza, id, limit)
|
|
67
|
-
raise 'Waiting time is nil' if limit.nil?
|
|
67
|
+
raise(StandardError, 'Waiting time is nil') if limit.nil?
|
|
68
68
|
start = Time.now
|
|
69
69
|
loop do
|
|
70
70
|
break if baza.finished?(id)
|
|
71
|
-
sleep
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
71
|
+
sleep(1)
|
|
72
|
+
if Time.now - start > limit
|
|
73
|
+
raise(StandardError, "Time is over, the job ##{id} ('#{name}') is still not completed")
|
|
74
|
+
end
|
|
75
|
+
@loog.debug(
|
|
76
|
+
"Still waiting for the job ##{id} ('#{name}') to finish... (#{format('%.2f', Time.now - start)}s already)"
|
|
77
|
+
)
|
|
75
78
|
end
|
|
76
79
|
id
|
|
77
80
|
end
|
data/lib/judges/commands/push.rb
CHANGED
|
@@ -3,16 +3,16 @@
|
|
|
3
3
|
# SPDX-FileCopyrightText: Copyright (c) 2024-2026 Yegor Bugayenko
|
|
4
4
|
# SPDX-License-Identifier: MIT
|
|
5
5
|
|
|
6
|
-
require 'typhoeus'
|
|
7
|
-
require 'iri'
|
|
8
6
|
require 'baza-rb'
|
|
9
7
|
require 'elapsed'
|
|
8
|
+
require 'iri'
|
|
9
|
+
require 'typhoeus'
|
|
10
10
|
require_relative '../../judges'
|
|
11
11
|
require_relative '../../judges/impex'
|
|
12
12
|
|
|
13
13
|
# The +push+ command.
|
|
14
14
|
#
|
|
15
|
-
# This class is instantiated by the +bin/
|
|
15
|
+
# This class is instantiated by the +bin/judges+ command line interface. You
|
|
16
16
|
# are not supposed to instantiate it yourself.
|
|
17
17
|
#
|
|
18
18
|
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
|
@@ -30,7 +30,7 @@ class Judges::Push
|
|
|
30
30
|
# @param [Array] args List of command line arguments
|
|
31
31
|
# @raise [RuntimeError] If not exactly two arguments provided
|
|
32
32
|
def run(opts, args)
|
|
33
|
-
raise 'Exactly two arguments required: <name> and <path>' unless args.size == 2
|
|
33
|
+
raise(ArgumentError, 'Exactly two arguments required: <name> and <path>') unless args.size == 2
|
|
34
34
|
name = args[0]
|
|
35
35
|
fb = Judges::Impex.new(@loog, args[1]).import
|
|
36
36
|
baza = BazaRb.new(
|
|
@@ -45,7 +45,7 @@ class Judges::Push
|
|
|
45
45
|
baza.lock(name, opts['owner'])
|
|
46
46
|
begin
|
|
47
47
|
baza.push(name, fb.export, opts['meta'] || [])
|
|
48
|
-
throw
|
|
48
|
+
throw(:"👍 Pushed #{fb.size} facts to baza")
|
|
49
49
|
ensure
|
|
50
50
|
baza.unlock(name, opts['owner'])
|
|
51
51
|
end
|
data/lib/judges/commands/test.rb
CHANGED
|
@@ -2,22 +2,23 @@
|
|
|
2
2
|
|
|
3
3
|
# SPDX-FileCopyrightText: Copyright (c) 2024-2026 Yegor Bugayenko
|
|
4
4
|
# SPDX-License-Identifier: MIT
|
|
5
|
-
|
|
6
|
-
require 'factbase'
|
|
5
|
+
|
|
7
6
|
require 'backtrace'
|
|
8
|
-
require 'factbase/to_xml'
|
|
9
7
|
require 'elapsed'
|
|
10
8
|
require 'ellipsized'
|
|
9
|
+
require 'factbase'
|
|
10
|
+
require 'factbase/to_xml'
|
|
11
|
+
require 'nokogiri'
|
|
11
12
|
require 'timeout'
|
|
12
13
|
require_relative '../../judges'
|
|
13
|
-
require_relative '../../judges/
|
|
14
|
+
require_relative '../../judges/categories'
|
|
14
15
|
require_relative '../../judges/judges'
|
|
15
16
|
require_relative '../../judges/options'
|
|
16
|
-
require_relative '../../judges/
|
|
17
|
+
require_relative '../../judges/to_rel'
|
|
17
18
|
|
|
18
19
|
# The +test+ command.
|
|
19
20
|
#
|
|
20
|
-
# This class is instantiated by the +bin/
|
|
21
|
+
# This class is instantiated by the +bin/judges+ command line interface. You
|
|
21
22
|
# are not supposed to instantiate it yourself.
|
|
22
23
|
#
|
|
23
24
|
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
|
@@ -34,8 +35,9 @@ class Judges::Test
|
|
|
34
35
|
# @param [Hash] opts Command line options (start with '--')
|
|
35
36
|
# @param [Array] args List of command line arguments
|
|
36
37
|
# @raise [RuntimeError] If not exactly one argument provided
|
|
38
|
+
# rubocop:disable Metrics/MethodLength
|
|
37
39
|
def run(opts, args)
|
|
38
|
-
raise 'Exactly one argument required' unless args.size == 1
|
|
40
|
+
raise(ArgumentError, 'Exactly one argument required') unless args.size == 1
|
|
39
41
|
dir = args[0]
|
|
40
42
|
@loog.info("Testing judges in #{dir.to_rel}...")
|
|
41
43
|
errors = []
|
|
@@ -51,87 +53,112 @@ class Judges::Test
|
|
|
51
53
|
@loog.info("👉 Testing #{judge.script} (##{i}) in #{judge.dir.to_rel}...")
|
|
52
54
|
buf = Loog::Buffer.new
|
|
53
55
|
judge = judge.with_loog(buf)
|
|
54
|
-
|
|
55
|
-
tname = File.basename(f).gsub(/\.yml$/, '')
|
|
56
|
-
visible << " #{judge.name}/#{tname}"
|
|
57
|
-
next unless include?(opts, judge.name, tname)
|
|
58
|
-
yaml = YAML.load_file(f, permitted_classes: [Time])
|
|
59
|
-
if yaml['skip']
|
|
60
|
-
buf.info("Skipped #{f.to_rel}")
|
|
61
|
-
next
|
|
62
|
-
end
|
|
63
|
-
unless Judges::Categories.new(opts['enable'], opts['disable']).ok?(yaml['category'])
|
|
64
|
-
buf.info("Skipped #{f.to_rel} because of its category")
|
|
65
|
-
next
|
|
66
|
-
end
|
|
67
|
-
buf.info("🛠️ Testing #{f.to_rel}:")
|
|
68
|
-
start = Time.now
|
|
69
|
-
badge = "#{judge.name}/#{tname}"
|
|
70
|
-
begin
|
|
71
|
-
fb = Factbase.new
|
|
72
|
-
prepare(fb, yaml)
|
|
73
|
-
yaml['before']&.each do |n|
|
|
74
|
-
j = judges.get(n).with_loog(buf)
|
|
75
|
-
buf.info("Running #{j.script} judge as a pre-condition...")
|
|
76
|
-
test_one(fb, opts, j, n, yaml, assert: false)
|
|
77
|
-
end
|
|
78
|
-
test_one(fb, opts, judge, tname, yaml)
|
|
79
|
-
yaml['after']&.each do |rb|
|
|
80
|
-
buf.info("Running #{rb} assertion script...")
|
|
81
|
-
$fb = fb
|
|
82
|
-
$loog = buf
|
|
83
|
-
if yaml['timeout']
|
|
84
|
-
Timeout.timeout(yaml['timeout']) do
|
|
85
|
-
load(File.join(judge.dir, rb), true)
|
|
86
|
-
end
|
|
87
|
-
else
|
|
88
|
-
load(File.join(judge.dir, rb), true)
|
|
89
|
-
end
|
|
90
|
-
end
|
|
91
|
-
tests += 1
|
|
92
|
-
rescue StandardError => e
|
|
93
|
-
@loog.info(buf.to_s)
|
|
94
|
-
@loog.warn(Backtrace.new(e))
|
|
95
|
-
errors << badge
|
|
96
|
-
end
|
|
97
|
-
times[badge] = Time.now - start
|
|
98
|
-
end
|
|
56
|
+
tests += run_judge_tests(judge, buf, opts, judges, visible, times, errors)
|
|
99
57
|
tested += 1
|
|
100
58
|
end
|
|
101
|
-
|
|
102
|
-
fmt = "%-60s\t%9s\t%-9s"
|
|
103
|
-
@loog.info(
|
|
104
|
-
[
|
|
105
|
-
'Test summary:',
|
|
106
|
-
format(fmt, 'Script', 'Seconds', 'Result'),
|
|
107
|
-
format(fmt, '---', '---', '---'),
|
|
108
|
-
times.sort_by { |_, v| v }.reverse.map do |script, sec|
|
|
109
|
-
format(fmt, script.ellipsized(50), format('%.3f', sec), errors.include?(script) ? 'ERROR' : 'OK')
|
|
110
|
-
end.join("\n ")
|
|
111
|
-
].join("\n ")
|
|
112
|
-
)
|
|
113
|
-
end
|
|
114
|
-
throw :'👍 No judges tested' if tested.zero?
|
|
115
|
-
throw :"👍 All #{tested} judge(s) but no tests passed" if tests.zero?
|
|
116
|
-
throw :"👍 All #{tested} judge(s) and #{tests} tests passed" if errors.empty?
|
|
117
|
-
throw :"❌ #{tested} judge(s) tested, #{errors.size} of them failed"
|
|
59
|
+
print_test_summary(times, errors, tested, tests)
|
|
118
60
|
end
|
|
119
61
|
unless errors.empty?
|
|
120
|
-
raise "#{errors.size} tests failed" unless opts['quiet']
|
|
121
|
-
@loog.debug('Not failing the build with
|
|
62
|
+
raise(StandardError, "#{errors.size} tests failed") unless opts['quiet']
|
|
63
|
+
@loog.debug('Not failing the build with test failures, due to the --quiet option')
|
|
122
64
|
end
|
|
123
65
|
return unless tested.zero? || tests.zero?
|
|
124
66
|
if opts['judge'].nil?
|
|
125
|
-
raise 'There
|
|
67
|
+
raise(StandardError, 'There seem to be no judges') unless opts['quiet']
|
|
126
68
|
@loog.debug('Not failing the build with no judges tested, due to the --quiet option')
|
|
127
69
|
else
|
|
128
|
-
raise 'There
|
|
70
|
+
raise(StandardError, 'There seem to be no judges') if visible.empty?
|
|
129
71
|
@loog.info("The following judges are available to use with the --judge option:\n #{visible.join("\n ")}")
|
|
130
72
|
end
|
|
131
73
|
end
|
|
74
|
+
# rubocop:enable Metrics/MethodLength
|
|
132
75
|
|
|
133
76
|
private
|
|
134
77
|
|
|
78
|
+
def run_judge_tests(judge, buf, opts, judges, visible, times, errors)
|
|
79
|
+
count = 0
|
|
80
|
+
judge.tests.each do |f|
|
|
81
|
+
tname = File.basename(f).gsub(/\.yml$/, '')
|
|
82
|
+
visible << " #{judge.name}/#{tname}"
|
|
83
|
+
next unless include?(opts, judge.name, tname)
|
|
84
|
+
yaml = YAML.load_file(f, permitted_classes: [Time])
|
|
85
|
+
next if skip_test?(buf, f, yaml, opts)
|
|
86
|
+
buf.info("🛠️ Testing #{f.to_rel}:")
|
|
87
|
+
badge = "#{judge.name}/#{tname}"
|
|
88
|
+
start = Time.now
|
|
89
|
+
begin
|
|
90
|
+
count += run_single_test(judge, buf, opts, judges, yaml, badge)
|
|
91
|
+
rescue StandardError => e
|
|
92
|
+
@loog.info(buf.to_s)
|
|
93
|
+
@loog.warn(Backtrace.new(e))
|
|
94
|
+
errors << badge
|
|
95
|
+
end
|
|
96
|
+
times[badge] = Time.now - start
|
|
97
|
+
end
|
|
98
|
+
count
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def skip_test?(buf, path, yaml, opts)
|
|
102
|
+
if yaml['skip']
|
|
103
|
+
buf.info("Skipped #{path.to_rel}")
|
|
104
|
+
return true
|
|
105
|
+
end
|
|
106
|
+
unless Judges::Categories.new(opts['enable'], opts['disable']).ok?(yaml['category'])
|
|
107
|
+
buf.info("Skipped #{path.to_rel} because of its category")
|
|
108
|
+
return true
|
|
109
|
+
end
|
|
110
|
+
false
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def run_single_test(judge, buf, opts, judges, yaml, badge)
|
|
114
|
+
fb = Factbase.new
|
|
115
|
+
prepare(fb, yaml)
|
|
116
|
+
yaml['before']&.each do |n|
|
|
117
|
+
j = judges.get(n).with_loog(buf)
|
|
118
|
+
buf.info("Running #{j.script} judge as a pre-condition...")
|
|
119
|
+
test_one(fb, opts, j, n, yaml, assert: false)
|
|
120
|
+
end
|
|
121
|
+
tname = badge.split('/').last
|
|
122
|
+
test_one(fb, opts, judge, tname, yaml)
|
|
123
|
+
run_after_assertions(judge, buf, fb, yaml)
|
|
124
|
+
1
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def run_after_assertions(judge, buf, fb, yaml)
|
|
128
|
+
yaml['after']&.each do |rb|
|
|
129
|
+
buf.info("Running #{rb} assertion script...")
|
|
130
|
+
$fb = fb
|
|
131
|
+
$loog = buf
|
|
132
|
+
if yaml['timeout']
|
|
133
|
+
Timeout.timeout(yaml['timeout']) do
|
|
134
|
+
load(File.join(judge.dir, rb), true)
|
|
135
|
+
end
|
|
136
|
+
else
|
|
137
|
+
load(File.join(judge.dir, rb), true)
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
def print_test_summary(times, errors, tested, tests)
|
|
143
|
+
unless times.empty?
|
|
144
|
+
fmt = "%-60s\t%9s\t%-9s"
|
|
145
|
+
@loog.info(
|
|
146
|
+
[
|
|
147
|
+
'Test summary:',
|
|
148
|
+
format(fmt, 'Script', 'Seconds', 'Result'),
|
|
149
|
+
format(fmt, '---', '---', '---'),
|
|
150
|
+
times.sort_by { |_, v| v }.reverse.map do |script, sec|
|
|
151
|
+
format(fmt, script.ellipsized(50), format('%.3f', sec), errors.include?(script) ? 'ERROR' : 'OK')
|
|
152
|
+
end.join("\n ")
|
|
153
|
+
].join("\n ")
|
|
154
|
+
)
|
|
155
|
+
end
|
|
156
|
+
throw(:'👍 No judges tested') if tested.zero?
|
|
157
|
+
throw(:"👍 All #{tested} judge(s) but no tests passed") if tests.zero?
|
|
158
|
+
throw(:"👍 All #{tested} judge(s) and #{tests} tests passed") if errors.empty?
|
|
159
|
+
throw(:"❌ #{tested} judge(s) tested, #{errors.size} of them failed")
|
|
160
|
+
end
|
|
161
|
+
|
|
135
162
|
def include?(opts, name, tname = nil)
|
|
136
163
|
judges = opts['judge'] || []
|
|
137
164
|
return true if judges.empty?
|
|
@@ -148,14 +175,14 @@ class Judges::Test
|
|
|
148
175
|
i.each do |k, vv|
|
|
149
176
|
if vv.is_a?(Array)
|
|
150
177
|
vv.each do |v|
|
|
151
|
-
f.
|
|
178
|
+
f.public_send(:"#{k}=", v)
|
|
152
179
|
end
|
|
153
180
|
else
|
|
154
181
|
if k == '_id'
|
|
155
182
|
vv = id
|
|
156
183
|
id += 1
|
|
157
184
|
end
|
|
158
|
-
f.
|
|
185
|
+
f.public_send(:"#{k}=", vv)
|
|
159
186
|
end
|
|
160
187
|
end
|
|
161
188
|
end
|
|
@@ -170,6 +197,7 @@ class Judges::Test
|
|
|
170
197
|
# @param [Hash] yaml The YAML to be tested
|
|
171
198
|
# @param [Boolean] assert Should we assert (TRUE) or simply skip (FALSE)?
|
|
172
199
|
# @return [nil] Always NIL
|
|
200
|
+
# rubocop:disable Metrics/MethodLength
|
|
173
201
|
def test_one(fb, opts, judge, tname, yaml, assert: true)
|
|
174
202
|
options = Judges::Options.new(opts['option']) + Judges::Options.new(yaml['options'])
|
|
175
203
|
runs = opts['runs'] || yaml['runs'] || 1
|
|
@@ -177,10 +205,10 @@ class Judges::Test
|
|
|
177
205
|
(1..runs).each do |r|
|
|
178
206
|
fbx = fb
|
|
179
207
|
if opts['log']
|
|
180
|
-
require
|
|
208
|
+
require('factbase/logged')
|
|
181
209
|
fbx = Factbase::Logged.new(fb, @loog)
|
|
182
210
|
end
|
|
183
|
-
|
|
211
|
+
failure = yaml['expected_failure']
|
|
184
212
|
begin
|
|
185
213
|
if timeout
|
|
186
214
|
Timeout.timeout(timeout) do
|
|
@@ -189,28 +217,32 @@ class Judges::Test
|
|
|
189
217
|
else
|
|
190
218
|
judge.run(fbx, {}, {}, options)
|
|
191
219
|
end
|
|
192
|
-
raise 'Exception expected but not raised' if
|
|
220
|
+
raise(StandardError, 'Exception expected but not raised') if failure
|
|
193
221
|
rescue Timeout::Error => e
|
|
194
|
-
raise "Test timed out after #{timeout} seconds"
|
|
222
|
+
raise(StandardError, "Test timed out after #{timeout} seconds")
|
|
195
223
|
# rubocop:disable Lint/RescueException
|
|
196
224
|
rescue Exception => e
|
|
197
225
|
# rubocop:enable Lint/RescueException
|
|
198
|
-
raise
|
|
199
|
-
if
|
|
200
|
-
raise
|
|
226
|
+
raise(e) unless failure
|
|
227
|
+
if failure.is_a?(Array) && failure.none? { |s| e.message.include?(s) }
|
|
228
|
+
raise(
|
|
229
|
+
StandardError,
|
|
230
|
+
"Exception #{e.class} raised with #{e.message.inspect}, but this is not what was expected"
|
|
231
|
+
)
|
|
201
232
|
end
|
|
202
233
|
end
|
|
203
234
|
next unless assert
|
|
204
235
|
assert(judge, tname, fb, yaml) if r == runs || opts['assert_once'].is_a?(FalseClass)
|
|
205
236
|
end
|
|
206
237
|
end
|
|
238
|
+
# rubocop:enable Metrics/MethodLength
|
|
207
239
|
|
|
208
240
|
def assert(judge, tname, fb, yaml)
|
|
209
241
|
xpaths = yaml['expected']
|
|
210
242
|
return if xpaths.nil?
|
|
211
243
|
xml = Nokogiri::XML.parse(Factbase::ToXML.new(fb).xml)
|
|
212
244
|
xpaths.each do |xp|
|
|
213
|
-
raise "#{judge.name}/#{tname} doesn't match '#{xp}':\n#{xml}" if xml.xpath(xp).empty?
|
|
245
|
+
raise(StandardError, "#{judge.name}/#{tname} doesn't match '#{xp}':\n#{xml}") if xml.xpath(xp).empty?
|
|
214
246
|
end
|
|
215
247
|
end
|
|
216
248
|
end
|
data/lib/judges/commands/trim.rb
CHANGED
|
@@ -3,14 +3,14 @@
|
|
|
3
3
|
# SPDX-FileCopyrightText: Copyright (c) 2024-2026 Yegor Bugayenko
|
|
4
4
|
# SPDX-License-Identifier: MIT
|
|
5
5
|
|
|
6
|
-
require 'time'
|
|
7
6
|
require 'elapsed'
|
|
7
|
+
require 'time'
|
|
8
8
|
require_relative '../../judges'
|
|
9
9
|
require_relative '../../judges/impex'
|
|
10
10
|
|
|
11
11
|
# The +trim+ command.
|
|
12
12
|
#
|
|
13
|
-
# This class is instantiated by the +bin/
|
|
13
|
+
# This class is instantiated by the +bin/judges+ command line interface. You
|
|
14
14
|
# are not supposed to instantiate it yourself.
|
|
15
15
|
#
|
|
16
16
|
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
|
@@ -28,14 +28,14 @@ class Judges::Trim
|
|
|
28
28
|
# @param [Array] args List of command line arguments
|
|
29
29
|
# @raise [RuntimeError] If not exactly one argument provided
|
|
30
30
|
def run(opts, args)
|
|
31
|
-
raise 'Exactly one argument required' unless args.size == 1
|
|
31
|
+
raise(ArgumentError, 'Exactly one argument required') unless args.size == 1
|
|
32
32
|
impex = Judges::Impex.new(@loog, args[0])
|
|
33
33
|
fb = impex.import
|
|
34
34
|
elapsed(@loog, level: Logger::INFO) do
|
|
35
35
|
deleted = fb.query(opts['query']).delete!
|
|
36
|
-
throw
|
|
36
|
+
throw(:'⚠️ No facts deleted') if deleted.zero?
|
|
37
37
|
impex.export(fb)
|
|
38
|
-
throw
|
|
38
|
+
throw(:"👍 #{deleted} fact(s) deleted")
|
|
39
39
|
end
|
|
40
40
|
end
|
|
41
41
|
end
|