judges 0.44.0 → 0.44.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bc9d8bdc800247520e9f42a07f90143c7c3fcf505a4a993221d7aa8437b11611
4
- data.tar.gz: 21d88232ebe5299cf672945ab83c702a3c942d984f233bd9f714fb2cdb846609
3
+ metadata.gz: 4791985ccc60d62edaf96e7fdf59912d4f5c53bfe21cfedd5d5554087c006324
4
+ data.tar.gz: e49a5acd43f2c9722e36233d7ed228f00dbbb63df3a7259c03e9b9f224e7b3c3
5
5
  SHA512:
6
- metadata.gz: eb1ac7d1219d4f901c5856e8c2698c4e77eaf5a3b0f8f0658bc94e1304f5597b3cada4a9c1ba85660bbaebd81a2e03cea58a92b7ba8e1a2c820e3403ea269a60
7
- data.tar.gz: a9937c3f3d031d3d2c6e1265d8ccc2bf0365ffcda171d539bdf03a22d68d6a3d887a6010beb876c17fd1f2a31cd38d06d0e7473861bc3e6cb2a21b62857041a3
6
+ metadata.gz: 3571c3740ed87fd99a5e56f482f297f1ecec20440c7a924122a1a0bd43d26aa5e492d986adf0de8bd65d2931d2a345af84afb469766ab2ce8a025e4c9014e424
7
+ data.tar.gz: 61e06fba2897f2fa04214372ee646029134cfd7f9877c2c92afdbe113d9665158da79b5c5257bf3a64dd880d276f26b81984c8b6b8240a166f81c16197f55b01
@@ -16,4 +16,4 @@ jobs:
16
16
  runs-on: ubuntu-24.04
17
17
  steps:
18
18
  - uses: actions/checkout@v4
19
- - uses: yegor256/copyrights-action@0.0.8
19
+ - uses: yegor256/copyrights-action@0.0.10
data/bin/judges CHANGED
@@ -61,6 +61,13 @@ class JudgesGLI extend GLI::App
61
61
  true
62
62
  end
63
63
 
64
+ desc 'Print version of the tool'
65
+ command :version do |c|
66
+ c.action do
67
+ @@loog.info(Judges::VERSION)
68
+ end
69
+ end
70
+
64
71
  desc 'Update the factbase by executing all judges sequentially'
65
72
  command :update do |c|
66
73
  c.desc 'Options to pass to each judge'
@@ -0,0 +1,10 @@
1
+ # SPDX-FileCopyrightText: Copyright (c) 2024-2025 Yegor Bugayenko
2
+ # SPDX-License-Identifier: MIT
3
+
4
+ Feature: Version
5
+ I want to know the version of the gem
6
+
7
+ Scenario: Print the version
8
+ Given I make a temp directory
9
+ Then I run bin/judges with "version"
10
+ And Exit code is zero
data/judges.gemspec CHANGED
@@ -9,7 +9,7 @@ Gem::Specification.new do |s|
9
9
  s.required_rubygems_version = Gem::Requirement.new('>= 0') if s.respond_to? :required_rubygems_version=
10
10
  s.required_ruby_version = '>=3.2'
11
11
  s.name = 'judges'
12
- s.version = '0.44.0'
12
+ s.version = '0.44.1'
13
13
  s.license = 'MIT'
14
14
  s.summary = 'Command-Line Tool for a Factbase'
15
15
  s.description =
@@ -6,21 +6,51 @@
6
6
  require_relative '../judges'
7
7
 
8
8
  # Categories of tests.
9
+ #
10
+ # This class manages test categories, allowing you to enable or disable
11
+ # specific categories of tests. It provides a mechanism to filter which
12
+ # tests should be executed based on their associated categories.
13
+ #
9
14
  # Author:: Yegor Bugayenko (yegor256@gmail.com)
10
15
  # Copyright:: Copyright (c) 2024-2025 Yegor Bugayenko
11
16
  # License:: MIT
12
17
  class Judges::Categories
13
- # Ctor.
18
+ # Initialize a new Categories instance.
19
+ #
20
+ # Creates a categories filter with lists of enabled and disabled categories.
21
+ # The filter logic works as follows:
22
+ # - If a category is in the disable list, the test is rejected
23
+ # - If a category is in the enable list, the test is accepted
24
+ # - If no categories are enabled (empty enable list), all tests are accepted
25
+ # unless explicitly disabled
26
+ #
14
27
  # @param [Array<String>] enable List of categories to enable
15
- # @param [Array<String>] disable List of categories to enable
28
+ # @param [Array<String>] disable List of categories to disable
16
29
  def initialize(enable, disable)
17
30
  @enable = enable.is_a?(Array) ? enable : []
18
31
  @disable = disable.is_a?(Array) ? disable : []
19
32
  end
20
33
 
21
- # This test is good to go, with this list of categories?
22
- # @param [Array<String>] cats List of them
23
- # @return [Boolean] True if yes
34
+ # Check if a test with given categories should be executed.
35
+ #
36
+ # Determines whether a test associated with the provided categories
37
+ # should be executed based on the enable/disable lists configured
38
+ # during initialization.
39
+ #
40
+ # The evaluation logic:
41
+ # 1. If any category is in the disable list, returns false
42
+ # 2. If any category is in the enable list, returns true
43
+ # 3. If the enable list is empty, returns true (all tests allowed)
44
+ # 4. Otherwise, returns false
45
+ #
46
+ # @param [Array<String>, String, nil] cats List of categories associated with the test,
47
+ # can be a single string or nil
48
+ # @return [Boolean] true if the test should be executed, false otherwise
49
+ # @example Check if a test with categories should run
50
+ # categories = Judges::Categories.new(['important'], ['experimental'])
51
+ # categories.ok?(['important', 'slow']) # => true
52
+ # categories.ok?(['experimental']) # => false
53
+ # categories.ok?(nil) # => true (if enable list is empty)
24
54
  def ok?(cats)
25
55
  cats = [] if cats.nil?
26
56
  cats = [cats] unless cats.is_a?(Array)
@@ -159,7 +159,8 @@ class Judges::Update
159
159
  elapsed(@loog, level: Logger::INFO) do
160
160
  c = one_judge(opts, fb, judge, global, options, errors)
161
161
  churn += c
162
- throw :"👍 The '#{judge.name}' judge #{c} out of #{fb.size}"
162
+ throw :"👍 The '#{judge.name}' judge made zero changes to #{fb.size} facts" if c.zero?
163
+ throw :"👍 The '#{judge.name}' judge #{c} out of #{fb.size} facts"
163
164
  end
164
165
  rescue StandardError, SyntaxError => e
165
166
  @loog.warn(Backtrace.new(e))
@@ -187,7 +188,7 @@ class Judges::Update
187
188
  # @param [Hash] global Global options
188
189
  # @param [Judges::Options] options The options
189
190
  # @param [Array<String>] errors List of errors
190
- # @return [Churn] How many modifications have been made
191
+ # @return [Factbase::Churn] How many modifications have been made
191
192
  def one_judge(opts, fb, judge, global, options, errors)
192
193
  local = {}
193
194
  start = Time.now
data/lib/judges/impex.rb CHANGED
@@ -10,21 +10,42 @@ require_relative '../judges'
10
10
  require_relative '../judges/to_rel'
11
11
 
12
12
  # Import/Export of factbases.
13
+ #
14
+ # This class provides functionality for importing and exporting Factbase
15
+ # objects to and from binary files. It handles file I/O operations with
16
+ # proper logging and error handling.
17
+ #
13
18
  # Author:: Yegor Bugayenko (yegor256@gmail.com)
14
19
  # Copyright:: Copyright (c) 2024-2025 Yegor Bugayenko
15
20
  # License:: MIT
16
21
  class Judges::Impex
17
- # Initialize.
18
- # @param [Loog] loog Logging facility
22
+ # Initialize a new Impex instance.
23
+ #
24
+ # @param [Loog] loog Logging facility for recording import/export operations
19
25
  # @param [String] file File path for import/export operations
26
+ # @example Create an Impex instance
27
+ # impex = Judges::Impex.new(logger, '/path/to/factbase.fb')
20
28
  def initialize(loog, file)
21
29
  @loog = loog
22
30
  @file = file
23
31
  end
24
32
 
25
33
  # Import factbase from file.
26
- # @param [Boolean] strict Whether to raise error if file doesn't exist
27
- # @return [Factbase] The imported factbase
34
+ #
35
+ # Creates a new Factbase instance and imports data from the file specified
36
+ # during initialization. The operation is timed and logged. If the file
37
+ # doesn't exist, behavior depends on the strict parameter.
38
+ #
39
+ # @param [Boolean] strict Whether to raise error if file doesn't exist.
40
+ # When true (default), raises an error if file is missing.
41
+ # When false, logs a message and returns an empty factbase.
42
+ # @return [Factbase] The imported factbase, or empty factbase if file
43
+ # doesn't exist and strict is false
44
+ # @raise [RuntimeError] If file doesn't exist and strict is true
45
+ # @example Import with strict mode (default)
46
+ # fb = impex.import # Raises error if file missing
47
+ # @example Import with non-strict mode
48
+ # fb = impex.import(strict: false) # Returns empty factbase if file missing
28
49
  def import(strict: true)
29
50
  fb = Factbase.new
30
51
  if File.exist?(@file)
@@ -40,8 +61,18 @@ class Judges::Impex
40
61
  end
41
62
 
42
63
  # Import factbase from file into existing factbase.
43
- # @param [Factbase] fb The factbase to import into
64
+ #
65
+ # Imports data from the file into an existing Factbase instance rather
66
+ # than creating a new one. This is useful when you need to merge data
67
+ # into an already populated factbase. The operation is timed and logged.
68
+ #
69
+ # @param [Factbase] fb The factbase to import into. The imported data
70
+ # will be added to this existing factbase.
44
71
  # @raise [RuntimeError] If file doesn't exist
72
+ # @example Import into existing factbase
73
+ # fb = Factbase.new
74
+ # # ... populate fb with some data ...
75
+ # impex.import_to(fb) # Adds data from file to existing facts
45
76
  def import_to(fb)
46
77
  raise "The factbase is absent at #{@file.to_rel}" unless File.exist?(@file)
47
78
  elapsed(@loog, level: Logger::INFO) do
@@ -51,7 +82,17 @@ class Judges::Impex
51
82
  end
52
83
 
53
84
  # Export factbase to file.
54
- # @param [Factbase] fb The factbase to export
85
+ #
86
+ # Exports the given Factbase instance to the file specified during
87
+ # initialization. Creates any necessary parent directories automatically.
88
+ # The operation is timed and logged with file size and fact count information.
89
+ #
90
+ # @param [Factbase] fb The factbase to export. All facts in this factbase
91
+ # will be serialized to the binary file format.
92
+ # @example Export a factbase
93
+ # fb = Factbase.new
94
+ # # ... add facts to fb ...
95
+ # impex.export(fb) # Saves to file specified in constructor
55
96
  def export(fb)
56
97
  elapsed(@loog, level: Logger::INFO) do
57
98
  FileUtils.mkdir_p(File.dirname(@file))
data/lib/judges/judge.rb CHANGED
@@ -28,25 +28,32 @@ class Judges::Judge
28
28
  @start = start
29
29
  end
30
30
 
31
- # Print it as a string.
32
- # @return [String] Name of it
31
+ # Returns the string representation of the judge.
32
+ #
33
+ # @return [String] The name of the judge (same as the directory name)
33
34
  def to_s
34
35
  name
35
36
  end
36
37
 
37
- # Run it with the given Factbase and environment variables.
38
+ # Executes the judge script with the provided factbase and configuration.
39
+ #
40
+ # This method sets up the execution environment by creating global variables,
41
+ # loading library files, and running the judge script. It tracks execution time
42
+ # and captures any errors that occur during execution.
38
43
  #
39
- # @param [Factbase] fb The factbase
40
- # @param [Hash] global Global options
41
- # @param [Hash] local Local options
42
- # @param [Judges::Options] options The options from command line
43
- # @return [Factbase::Churn] The changes just made
44
+ # @param [Factbase] fb The factbase instance to operate on
45
+ # @param [Hash] global Global configuration options shared across all judges
46
+ # @param [Hash] local Local configuration options specific to this judge
47
+ # @param [Judges::Options] options Command-line options object
48
+ # @return [Factbase::Churn] Object containing statistics about the changes made to the factbase
49
+ # @raise [RuntimeError] If the lib directory doesn't exist, the script can't be loaded, or execution fails
44
50
  def run(fb, global, local, options)
45
51
  $fb = Factbase::Tallied.new(fb)
46
52
  $judge = File.basename(@dir)
47
53
  $options = options
48
54
  $loog = @loog
49
55
  $global = global
56
+ $global.delete(:fb) # to make sure Tallied is always actual
50
57
  $local = local
51
58
  $start = @start
52
59
  options.to_h.each { |k, v| ENV.store(k.to_s, v.to_s) }
@@ -74,12 +81,22 @@ class Judges::Judge
74
81
  end
75
82
  end
76
83
 
77
- # Get the name of the judge.
84
+ # Returns the name of the judge.
85
+ #
86
+ # The name is derived from the directory name containing the judge.
87
+ #
88
+ # @return [String] The base name of the judge directory
78
89
  def name
79
90
  File.basename(@dir)
80
91
  end
81
92
 
82
- # Get the name of the .rb script in the judge.
93
+ # Returns the name of the main Ruby script file for this judge.
94
+ #
95
+ # The script file must have the same name as the judge directory with a .rb extension.
96
+ # For example, if the judge directory is "quality", the script must be "quality.rb".
97
+ #
98
+ # @return [String] The filename of the judge script (e.g., "judge_name.rb")
99
+ # @raise [RuntimeError] If the expected script file is not found in the judge directory
83
100
  def script
84
101
  b = "#{File.basename(@dir)}.rb"
85
102
  files = Dir.glob(File.join(@dir, '*.rb')).map { |f| File.basename(f) }
@@ -87,7 +104,12 @@ class Judges::Judge
87
104
  b
88
105
  end
89
106
 
90
- # Return all .yml tests files.
107
+ # Returns all YAML test files in the judge directory.
108
+ #
109
+ # Test files are expected to have a .yml extension and contain test data
110
+ # used to validate the judge's behavior.
111
+ #
112
+ # @return [Array<String>] Array of absolute paths to all .yml files in the judge directory
91
113
  def tests
92
114
  Dir.glob(File.join(@dir, '*.yml'))
93
115
  end
data/lib/judges/judges.rb CHANGED
@@ -42,19 +42,30 @@ class Judges::Judges
42
42
  @boost = boost
43
43
  end
44
44
 
45
- # Get one judge by name.
46
- # @param [String] name The name of the judge
47
- # @return [Judge] The judge object
48
- # @raise [RuntimeError] If judge doesn't exist
45
+ # Retrieves a specific judge by its name.
46
+ #
47
+ # The judge must exist as a directory within the judges directory with the given name.
48
+ #
49
+ # @param [String] name The name of the judge to retrieve (directory name)
50
+ # @return [Judges::Judge] The judge object initialized with the found directory
51
+ # @raise [RuntimeError] If no judge directory exists with the given name
49
52
  def get(name)
50
53
  d = File.absolute_path(File.join(@dir, name))
51
54
  raise "Judge #{name} doesn't exist in #{@dir}" unless File.exist?(d)
52
55
  Judges::Judge.new(d, @lib, @loog, start: @start)
53
56
  end
54
57
 
55
- # Iterate over all judges.
56
- # @yield [Judge] Yields each judge
57
- # @return [Enumerator] If no block given
58
+ # Iterates over all valid judges in the directory.
59
+ #
60
+ # This method discovers all judge directories, validates them (ensuring they contain
61
+ # a corresponding .rb file), and yields them in a specific order. The order is
62
+ # determined by:
63
+ # 1. Judges whose names match the boost list are placed first
64
+ # 2. Judges whose names start with the shuffle prefix are randomly reordered
65
+ # 3. All other judges maintain their alphabetical order
66
+ #
67
+ # @yield [Judges::Judge] Yields each valid judge object
68
+ # @return [Enumerator] Returns an enumerator if no block is given
58
69
  def each(&)
59
70
  return to_enum(__method__) unless block_given?
60
71
  list =
@@ -87,9 +98,14 @@ class Judges::Judges
87
98
  ret.each(&)
88
99
  end
89
100
 
90
- # Iterate over all judges with index.
91
- # @yield [Judge, Integer] Yields each judge with its index
92
- # @return [Integer] The total count of judges
101
+ # Iterates over all judges while tracking their index position.
102
+ #
103
+ # This method calls the #each method and additionally provides a zero-based
104
+ # index for each judge yielded. The judges are processed in the same order
105
+ # as determined by the #each method (with boost and shuffle rules applied).
106
+ #
107
+ # @yield [Judges::Judge, Integer] Yields each judge object along with its index (starting from 0)
108
+ # @return [Integer] The total count of judges processed
93
109
  def each_with_index
94
110
  idx = 0
95
111
  each do |p|
@@ -7,25 +7,62 @@ require 'others'
7
7
  require_relative '../judges'
8
8
 
9
9
  # Options for Ruby scripts in the judges.
10
+ #
11
+ # This class manages configuration options that can be passed to judge scripts.
12
+ # Options are key-value pairs that can be provided in various formats and are
13
+ # normalized into a hash with symbol keys. Values are automatically converted
14
+ # to appropriate types (integers for numeric strings, etc.).
15
+ #
16
+ # The class also provides dynamic method access to options using the 'others' gem,
17
+ # allowing options to be accessed as method calls.
18
+ #
10
19
  # Author:: Yegor Bugayenko (yegor256@gmail.com)
11
20
  # Copyright:: Copyright (c) 2024-2025 Yegor Bugayenko
12
21
  # License:: MIT
13
22
  class Judges::Options
14
- # Ctor.
15
- # @param [Array<String>] pairs List of pairs, like ["token=af73cd3", "max_speed=1"]
23
+ # Initialize a new Options instance.
24
+ #
25
+ # @param [Array<String>, String, Hash, nil] pairs List of key-value pairs.
26
+ # Can be provided as:
27
+ # - Array of strings: ["token=af73cd3", "max_speed=1"]
28
+ # - Comma-separated string: "token=af73cd3,max_speed=1"
29
+ # - Hash: { token: "af73cd3", max_speed: 1 }
30
+ # - nil: Creates empty options
31
+ # @example Initialize with array
32
+ # options = Judges::Options.new(["token=abc123", "debug=true"])
33
+ # @example Initialize with string
34
+ # options = Judges::Options.new("token=abc123,debug")
35
+ # @example Initialize with hash
36
+ # options = Judges::Options.new({ token: "abc123", debug: true })
16
37
  def initialize(pairs = nil)
17
38
  @pairs = pairs
18
39
  end
19
40
 
20
41
  # Check if options are empty.
21
- # @return [Boolean] true if no options are set
42
+ #
43
+ # @return [Boolean] true if no options are set, false otherwise
44
+ # @example Check if options are empty
45
+ # options = Judges::Options.new
46
+ # options.empty? # => true
47
+ # options = Judges::Options.new(["key=value"])
48
+ # options.empty? # => false
22
49
  def empty?
23
50
  to_h.empty?
24
51
  end
25
52
 
26
53
  # Merge with another Options object.
54
+ #
55
+ # Creates a new Options instance containing values from both this instance
56
+ # and the other. Values from the other Options object override values
57
+ # with the same key in this instance.
58
+ #
27
59
  # @param [Judges::Options] other The other options to merge
28
60
  # @return [Judges::Options] A new Options object with merged values
61
+ # @example Merge two Options objects
62
+ # opts1 = Judges::Options.new(["token=abc", "debug=true"])
63
+ # opts2 = Judges::Options.new(["token=xyz", "verbose=true"])
64
+ # merged = opts1 + opts2
65
+ # # merged now has token=xyz, debug=true, verbose=true
29
66
  def +(other)
30
67
  h = to_h
31
68
  other.to_h.each do |k, v|
@@ -34,7 +71,19 @@ class Judges::Options
34
71
  Judges::Options.new(h)
35
72
  end
36
73
 
37
- # Convert them all to a string (printable in a log).
74
+ # Convert options to a string representation.
75
+ #
76
+ # Creates a human-readable string representation of all options,
77
+ # suitable for logging. Sensitive values (longer than 8 characters)
78
+ # are partially masked with asterisks for security.
79
+ #
80
+ # @return [String] Formatted string with each option on a new line
81
+ # @example Convert to string
82
+ # options = Judges::Options.new(["token=supersecrettoken", "debug=true"])
83
+ # puts options.to_s
84
+ # # Output:
85
+ # # debug → "true"
86
+ # # token → "supe****oken"
38
87
  def to_s
39
88
  to_h.map do |k, v|
40
89
  v = v.to_s
@@ -44,7 +93,18 @@ class Judges::Options
44
93
  end
45
94
 
46
95
  # Convert options to hash.
96
+ #
97
+ # Converts the raw pairs into a normalized hash with the following transformations:
98
+ # - Keys are converted to uppercase symbols
99
+ # - Values without equals sign get 'true' as value
100
+ # - Numeric strings are converted to integers
101
+ # - Leading/trailing whitespace is stripped
102
+ # - Empty or nil keys are rejected
103
+ #
47
104
  # @return [Hash] The options as a hash with symbol keys
105
+ # @example Convert to hash
106
+ # options = Judges::Options.new("token=abc123,max_speed=100,debug")
107
+ # options.to_h # => { TOKEN: "abc123", MAX_SPEED: 100, DEBUG: "true" }
48
108
  def to_h
49
109
  @to_h ||=
50
110
  begin
@@ -72,6 +132,19 @@ class Judges::Options
72
132
  end
73
133
 
74
134
  # Get option by name.
135
+ #
136
+ # This method is implemented using the 'others' gem, which provides
137
+ # dynamic method handling. It allows accessing options as method calls.
138
+ # Method names are automatically converted to uppercase symbols to match
139
+ # the keys in the options hash.
140
+ #
141
+ # @param [Symbol, String] method_name The option name to retrieve
142
+ # @return [Object, nil] The value of the option, or nil if not found
143
+ # @example Access options as methods
144
+ # options = Judges::Options.new(["token=abc123", "max_speed=100"])
145
+ # options.token # => "abc123"
146
+ # options.max_speed # => 100
147
+ # options.missing_option # => nil
75
148
  others do |*args|
76
149
  to_h[args[0].upcase.to_sym]
77
150
  end
data/lib/judges.rb CHANGED
@@ -8,5 +8,5 @@
8
8
  # Copyright:: Copyright (c) 2024-2025 Yegor Bugayenko
9
9
  # License:: MIT
10
10
  module Judges
11
- VERSION = '0.44.0' unless const_defined?(:VERSION)
11
+ VERSION = '0.44.1' unless const_defined?(:VERSION)
12
12
  end
@@ -157,6 +157,21 @@ class TestUpdate < Minitest::Test
157
157
  end
158
158
  end
159
159
 
160
+ def test_isolates_churns
161
+ Dir.mktmpdir do |d|
162
+ save_it(File.join(d, 'first/first.rb'), '$global[:fb] ||= $fb; 2 + 2')
163
+ save_it(File.join(d, 'second/second.rb'), '$global[:fb] ||= $fb; $global[:fb].insert')
164
+ file = File.join(d, 'base.fb')
165
+ Judges::Update.new(Loog::VERBOSE).run(
166
+ { 'max-cycles' => 3, 'boost' => 'first' },
167
+ [d, file]
168
+ )
169
+ fb = Factbase.new
170
+ fb.import(File.binread(file))
171
+ assert_equal(3, fb.size)
172
+ end
173
+ end
174
+
160
175
  def test_fails_when_no_judges_used
161
176
  assert_raises(StandardError) do
162
177
  Dir.mktmpdir do |d|
data/test/test_judge.rb CHANGED
@@ -25,6 +25,30 @@ class TestJudge < Minitest::Test
25
25
  end
26
26
  end
27
27
 
28
+ def test_counts_churn
29
+ Dir.mktmpdir do |d|
30
+ save_it(File.join(d, "#{File.basename(d)}.rb"), '$fb.insert.foo = 42')
31
+ judge = Judges::Judge.new(d, nil, Loog::NULL)
32
+ fb = Factbase.new
33
+ c = judge.run(fb, {}, {}, {})
34
+ assert_equal(1, c.inserted)
35
+ assert_equal(0, c.deleted)
36
+ assert_equal(1, c.added)
37
+ end
38
+ end
39
+
40
+ def test_counts_churn_after_txn
41
+ Dir.mktmpdir do |d|
42
+ save_it(File.join(d, "#{File.basename(d)}.rb"), '$fb.txn { |fbt| fbt.insert.foo = 42 }')
43
+ judge = Judges::Judge.new(d, nil, Loog::NULL)
44
+ fb = Factbase.new
45
+ c = judge.run(fb, {}, {}, {})
46
+ assert_equal(1, c.inserted)
47
+ assert_equal(0, c.deleted)
48
+ assert_equal(1, c.added)
49
+ end
50
+ end
51
+
28
52
  def test_run_isolated
29
53
  Dir.mktmpdir do |d|
30
54
  save_it(File.join(d, "#{File.basename(d)}.rb"), '$fb.insert')
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: judges
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.44.0
4
+ version: 0.44.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yegor Bugayenko
@@ -286,6 +286,7 @@ files:
286
286
  - features/test.feature
287
287
  - features/trim.feature
288
288
  - features/update.feature
289
+ - features/version.feature
289
290
  - fixtures/guess/guess.rb
290
291
  - fixtures/guess/guess_made.yml
291
292
  - fixtures/guess/skipped.yml