judges 0.2.0 → 0.4.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f36d80279b095db31b037136ab951bbc395bd5b5d74922149706ab8fe404381b
4
- data.tar.gz: c0e1c403f0857e5c1764c8a0cf620761c36bf9e92dbcf9f4c4f2dbc420755651
3
+ metadata.gz: 2cc71c6f27206802eb89caac6ea4cf95558c5f36f484efea771e5ad5c442084d
4
+ data.tar.gz: 717c6de821765a54a916dc2eabafaf63827fd5a522584c7af866f5beea5475c7
5
5
  SHA512:
6
- metadata.gz: d729a939b8a4b5894122d3e899487b8838dc92db04176f7ab3cb843d401b05edfd081744c5979c9169d98f78070ab0637f54b1f6d3623c60086e70b8666398f7
7
- data.tar.gz: 15246686f5279034d4a57d0050931d93ebe6546c807e30e2d1bc0dd8611b7b8edfe6cd552272db3103f1001947078aa2b49b8a58935b1831fde503e509eef3ec
6
+ metadata.gz: 895ea9f8d9b1527113c1a33d1c5e5a5d18b16994d00593d7f3eaf5c135c9a9eb9787c7ca969bcbced5b025eef8ff03e3927ecc90d3ee0738b9cee3cf1b948799
7
+ data.tar.gz: 2c86328e14c85f7685fb46b8cf78bcac87058725db51b57ca447186c61cbf5650dee93570c7000c11105792a14d8b8879d54e861325c1f12a97f200b09e33bb3
data/Gemfile.lock CHANGED
@@ -9,14 +9,15 @@ PATH
9
9
  iri (~> 0.8)
10
10
  loog (~> 0.2)
11
11
  nokogiri (~> 1.10)
12
+ retries (~> 0.0)
12
13
  typhoeus (~> 1.3)
13
14
 
14
15
  GEM
15
16
  remote: https://rubygems.org/
16
17
  specs:
17
- actionpack (7.1.3.3)
18
- actionview (= 7.1.3.3)
19
- activesupport (= 7.1.3.3)
18
+ actionpack (7.1.3.4)
19
+ actionview (= 7.1.3.4)
20
+ activesupport (= 7.1.3.4)
20
21
  nokogiri (>= 1.8.5)
21
22
  racc
22
23
  rack (>= 2.2.4)
@@ -24,13 +25,13 @@ GEM
24
25
  rack-test (>= 0.6.3)
25
26
  rails-dom-testing (~> 2.2)
26
27
  rails-html-sanitizer (~> 1.6)
27
- actionview (7.1.3.3)
28
- activesupport (= 7.1.3.3)
28
+ actionview (7.1.3.4)
29
+ activesupport (= 7.1.3.4)
29
30
  builder (~> 3.1)
30
31
  erubi (~> 1.11)
31
32
  rails-dom-testing (~> 2.2)
32
33
  rails-html-sanitizer (~> 1.6)
33
- activesupport (7.1.3.3)
34
+ activesupport (7.1.3.4)
34
35
  base64
35
36
  bigdecimal
36
37
  concurrent-ruby (~> 1.0, >= 1.0.2)
@@ -84,7 +85,7 @@ GEM
84
85
  erubi (1.12.0)
85
86
  ethon (0.16.0)
86
87
  ffi (>= 1.15.0)
87
- factbase (0.0.41)
88
+ factbase (0.0.42)
88
89
  json (~> 2.7)
89
90
  loog (~> 0.2)
90
91
  nokogiri (~> 1.10)
@@ -92,6 +93,7 @@ GEM
92
93
  ffi (1.17.0-aarch64-linux-gnu)
93
94
  ffi (1.17.0-arm-linux-gnu)
94
95
  ffi (1.17.0-arm64-darwin)
96
+ ffi (1.17.0-x64-mingw-ucrt)
95
97
  ffi (1.17.0-x86-linux-gnu)
96
98
  ffi (1.17.0-x86_64-darwin)
97
99
  ffi (1.17.0-x86_64-linux-gnu)
@@ -121,6 +123,8 @@ GEM
121
123
  racc (~> 1.4)
122
124
  nokogiri (1.16.5-arm64-darwin)
123
125
  racc (~> 1.4)
126
+ nokogiri (1.16.5-x64-mingw-ucrt)
127
+ racc (~> 1.4)
124
128
  nokogiri (1.16.5-x86-linux)
125
129
  racc (~> 1.4)
126
130
  nokogiri (1.16.5-x86_64-darwin)
@@ -150,9 +154,9 @@ GEM
150
154
  rails-html-sanitizer (1.6.0)
151
155
  loofah (~> 2.21)
152
156
  nokogiri (~> 1.14)
153
- railties (7.1.3.3)
154
- actionpack (= 7.1.3.3)
155
- activesupport (= 7.1.3.3)
157
+ railties (7.1.3.4)
158
+ actionpack (= 7.1.3.4)
159
+ activesupport (= 7.1.3.4)
156
160
  irb
157
161
  rackup (>= 1.0.0)
158
162
  rake (>= 12.2)
@@ -165,6 +169,7 @@ GEM
165
169
  regexp_parser (2.9.2)
166
170
  reline (0.5.8)
167
171
  io-console (~> 0.5)
172
+ retries (0.0.5)
168
173
  rexml (3.2.8)
169
174
  strscan (>= 3.0.9)
170
175
  rspec-core (3.13.0)
@@ -244,6 +249,7 @@ PLATFORMS
244
249
  aarch64-linux
245
250
  arm-linux
246
251
  arm64-darwin
252
+ x64-mingw-ucrt
247
253
  x86-linux
248
254
  x86_64-darwin
249
255
  x86_64-linux
data/fixtures/try/try.rb CHANGED
@@ -20,7 +20,7 @@
20
20
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
21
  # SOFTWARE.
22
22
 
23
- each_once($fb, "(and (exists number) (lt time #{Time.now.utc.iso8601}))") do |f|
23
+ $fb.query("(and (exists number) (lt time #{Time.now.utc.iso8601}))").each do |f|
24
24
  n = $fb.insert
25
25
  n.guess = f.number
26
26
  end
data/judges.gemspec CHANGED
@@ -26,7 +26,7 @@ Gem::Specification.new do |s|
26
26
  s.required_rubygems_version = Gem::Requirement.new('>= 0') if s.respond_to? :required_rubygems_version=
27
27
  s.required_ruby_version = '>=3.2'
28
28
  s.name = 'judges'
29
- s.version = '0.2.0'
29
+ s.version = '0.4.0'
30
30
  s.license = 'MIT'
31
31
  s.summary = 'Command-Line Tool for a Factbase'
32
32
  s.description =
@@ -42,13 +42,14 @@ Gem::Specification.new do |s|
42
42
  s.executables = s.files.grep(%r{^bin/}) { |f| File.basename(f) }
43
43
  s.rdoc_options = ['--charset=UTF-8']
44
44
  s.extra_rdoc_files = ['README.md', 'LICENSE.txt']
45
- s.add_runtime_dependency 'backtrace', '~> 0.3'
45
+ s.add_runtime_dependency 'backtrace', '~>0.3'
46
46
  s.add_runtime_dependency 'concurrent-ruby', '1.2.3'
47
47
  s.add_runtime_dependency 'factbase', '~>0.0'
48
48
  s.add_runtime_dependency 'gli', '~>2.21'
49
49
  s.add_runtime_dependency 'iri', '~>0.8'
50
50
  s.add_runtime_dependency 'loog', '~>0.2'
51
- s.add_runtime_dependency 'nokogiri', '~> 1.10'
51
+ s.add_runtime_dependency 'nokogiri', '~>1.10'
52
+ s.add_runtime_dependency 'retries', '~>0.0'
52
53
  s.add_runtime_dependency 'typhoeus', '~>1.3'
53
54
  s.metadata['rubygems_mfa_required'] = 'true'
54
55
  end
data/lib/judges/baza.rb CHANGED
@@ -21,6 +21,7 @@
21
21
  # SOFTWARE.
22
22
 
23
23
  require 'typhoeus'
24
+ require 'retries'
24
25
  require 'iri'
25
26
  require 'loog'
26
27
  require_relative '../judges'
@@ -45,17 +46,20 @@ class Judges::Baza
45
46
  def push(name, data)
46
47
  id = 0
47
48
  elapsed(@loog) do
48
- ret = Typhoeus::Request.put(
49
- home.append('push').append(name).to_s,
50
- body: data,
51
- headers: headers.merge(
52
- 'Content-Type' => 'application/octet-stream',
53
- 'Content-Length' => data.size
54
- ),
55
- connecttimeout: @timeout,
56
- timeout: @timeout
57
- )
58
- check_code(ret)
49
+ ret = with_retries do
50
+ checked(
51
+ Typhoeus::Request.put(
52
+ home.append('push').append(name).to_s,
53
+ body: data,
54
+ headers: headers.merge(
55
+ 'Content-Type' => 'application/octet-stream',
56
+ 'Content-Length' => data.size
57
+ ),
58
+ connecttimeout: @timeout,
59
+ timeout: @timeout
60
+ )
61
+ )
62
+ end
59
63
  id = ret.body.to_i
60
64
  throw :"Pushed #{data.size} bytes to #{@host}, job ID is ##{id}"
61
65
  end
@@ -79,7 +83,7 @@ class Judges::Baza
79
83
  f.write(chunk)
80
84
  end
81
85
  request.run
82
- check_code(request.response)
86
+ checked(request.response)
83
87
  end
84
88
  data = File.binread(file)
85
89
  throw :"Pulled #{data.size} bytes of job ##{id} factbase at #{@host}"
@@ -92,11 +96,14 @@ class Judges::Baza
92
96
  def finished?(id)
93
97
  finished = false
94
98
  elapsed(@loog) do
95
- ret = Typhoeus::Request.get(
96
- home.append('finished').append(id).to_s,
97
- headers:
98
- )
99
- check_code(ret)
99
+ ret = with_retries do
100
+ checked(
101
+ Typhoeus::Request.get(
102
+ home.append('finished').append(id).to_s,
103
+ headers:
104
+ )
105
+ )
106
+ end
100
107
  finished = ret.body == 'yes'
101
108
  throw :"The job ##{id} is #{finished ? '' : 'not yet '}finished at #{@host}"
102
109
  end
@@ -106,11 +113,14 @@ class Judges::Baza
106
113
  def recent(name)
107
114
  job = 0
108
115
  elapsed(@loog) do
109
- ret = Typhoeus::Request.get(
110
- home.append('recent').append("#{name}.txt").to_s,
111
- headers:
112
- )
113
- check_code(ret)
116
+ ret = with_retries do
117
+ checked(
118
+ Typhoeus::Request.get(
119
+ home.append('recent').append("#{name}.txt").to_s,
120
+ headers:
121
+ )
122
+ )
123
+ end
114
124
  job = ret.body.to_i
115
125
  throw :"The recent \"#{name}\" job's ID is ##{job} at #{@host}"
116
126
  end
@@ -120,11 +130,12 @@ class Judges::Baza
120
130
  def name_exists?(name)
121
131
  exists = 0
122
132
  elapsed(@loog) do
123
- ret = Typhoeus::Request.get(
124
- home.append('exists').append(name).to_s,
125
- headers:
133
+ ret = checked(
134
+ Typhoeus::Request.get(
135
+ home.append('exists').append(name).to_s,
136
+ headers:
137
+ )
126
138
  )
127
- check_code(ret)
128
139
  exists = ret.body == 'yes'
129
140
  throw :"The name \"#{name}\" #{exists ? 'exists' : "doesn't exist"} at #{@host}"
130
141
  end
@@ -148,14 +159,14 @@ class Judges::Baza
148
159
  .scheme(@ssl ? 'https' : 'http')
149
160
  end
150
161
 
151
- def check_code(ret, allowed = [200])
162
+ def checked(ret, allowed = [200])
152
163
  allowed = [allowed] unless allowed.is_a?(Array)
153
164
  mtd = (ret.request.original_options[:method] || '???').upcase
154
165
  url = ret.effective_url
155
166
  log = "#{mtd} #{url} -> #{ret.code}"
156
167
  if allowed.include?(ret.code)
157
168
  @loog.debug(log)
158
- return
169
+ return ret
159
170
  end
160
171
  @loog.debug("#{log}\n #{(ret.headers || {}).map { |k, v| "#{k}: #{v}" }.join("\n ")}")
161
172
  msg =
@@ -56,9 +56,9 @@ class Judges::Update
56
56
  if c > 1
57
57
  @loog.info("\n\nStarting cycle ##{c}#{opts['max-cycles'] ? " (out of #{opts['max-cycles']})" : ''}...")
58
58
  end
59
- diff = cycle(opts, judges, fb, options)
59
+ churn = cycle(opts, judges, fb, options)
60
60
  impex.export(fb)
61
- if diff.zero?
61
+ if churn.zero?
62
62
  @loog.info("The update cycle ##{c} has made no changes to the factbase, let's stop")
63
63
  break
64
64
  end
@@ -66,36 +66,50 @@ class Judges::Update
66
66
  @loog.info("Too many cycles already, as set by --max-cycles=#{opts['max-cycles']}, breaking")
67
67
  break
68
68
  end
69
- @loog.info(
70
- "By #{diff.abs} fact(s) the factbase " \
71
- "#{diff.positive? ? 'increased' : 'decreased'} " \
72
- "its size at the cycle ##{c}"
73
- )
69
+ @loog.info("At the cycle #{c}, the factbase was modified by #{churn} fact(s)")
74
70
  end
75
71
  throw :"Update finished in #{c} cycle(s), #{format('+%d', fb.size - before)} fact(s)"
76
72
  end
77
73
  end
78
74
 
75
+ # How many facts were modified.
76
+ class Churn
77
+ attr_reader :added, :removed
78
+
79
+ def initialize(added, removed)
80
+ @added = added
81
+ @removed = removed
82
+ end
83
+
84
+ def to_s
85
+ "#{format('+%d', @added)}/#{format('+%d', -@removed)}"
86
+ end
87
+
88
+ def zero?
89
+ @added.zero? && @removed.zero?
90
+ end
91
+
92
+ def +(other)
93
+ Churn.new(@added + other.added, @removed + other.removed)
94
+ end
95
+ end
96
+
79
97
  private
80
98
 
99
+ # Run all judges in a full cycle, one by one.
100
+ # @return [Churn] How many modifications have been made
81
101
  def cycle(opts, judges, fb, options)
82
102
  errors = []
83
- diff = 0
103
+ churn = Churn.new(0, 0)
84
104
  global = {}
85
105
  elapsed(@loog) do
86
106
  done = judges.each_with_index do |p, i|
87
- local = {}
88
- @loog.info("👉 Running #{p.name} (##{i}) at #{p.dir.to_rel}...")
89
- before = fb.size
90
- begin
91
- p.run(fb, global, local, options)
92
- rescue StandardError, SyntaxError => e
93
- @loog.warn(Backtrace.new(e))
94
- errors << p.script
95
- end
96
- after = fb.size
97
- @loog.info("👍 The judge #{p.dir.to_rel} added #{after - before} facts") if after > before
98
- diff += after - before
107
+ @loog.info("\n👉 Running #{p.name} (##{i}) at #{p.dir.to_rel}...")
108
+ churn += one_judge(fb, p, global, options)
109
+ @loog.info("👍 The judge #{p.name} modified #{churn} facts")
110
+ rescue StandardError, SyntaxError => e
111
+ @loog.warn(Backtrace.new(e))
112
+ errors << p.script
99
113
  end
100
114
  throw :"👍 #{done} judge(s) processed" if errors.empty?
101
115
  throw :"❌ #{done} judge(s) processed with #{errors.size} errors"
@@ -104,6 +118,21 @@ class Judges::Update
104
118
  raise "Failed to update correctly (#{errors.size} errors)" unless opts['quiet']
105
119
  @loog.info('Not failing because of the --quiet flag provided')
106
120
  end
107
- diff
121
+ churn
122
+ end
123
+
124
+ # Run a single judge.
125
+ # @return [Churn] How many modifications have been made
126
+ def one_judge(fb, judge, global, options)
127
+ local = {}
128
+ before = fb.size
129
+ judge.run(fb, global, local, options)
130
+ after = fb.size
131
+ diff = after - before
132
+ if diff.positive?
133
+ Churn.new(diff, 0)
134
+ else
135
+ Churn.new(0, diff)
136
+ end
108
137
  end
109
138
  end
data/lib/judges/judge.rb CHANGED
@@ -23,8 +23,6 @@
23
23
  require_relative '../judges'
24
24
  require_relative '../judges/to_rel'
25
25
  require_relative '../judges/elapsed'
26
- require_relative '../judges/fb/once'
27
- require_relative '../judges/fb/if_absent'
28
26
 
29
27
  # A single judge.
30
28
  # Author:: Yegor Bugayenko (yegor256@gmail.com)
data/lib/judges.rb CHANGED
@@ -25,5 +25,5 @@
25
25
  # Copyright:: Copyright (c) 2024 Yegor Bugayenko
26
26
  # License:: MIT
27
27
  module Judges
28
- VERSION = '0.2.0'
28
+ VERSION = '0.4.0'
29
29
  end
data/test/test_judge.rb CHANGED
@@ -55,14 +55,6 @@ class TestPack < Minitest::Test
55
55
  end
56
56
  end
57
57
 
58
- def test_with_supplemenary_functions
59
- Dir.mktmpdir do |d|
60
- File.write(File.join(d, 'x.rb'), 'each_once($fb, "(always)").to_a')
61
- judge = Judges::Judge.new(d, nil, Loog::NULL)
62
- judge.run(Factbase.new, {}, {}, {})
63
- end
64
- end
65
-
66
58
  def test_passes_local_vars_between_tests
67
59
  Dir.mktmpdir do |d|
68
60
  File.write(
@@ -93,21 +85,6 @@ class TestPack < Minitest::Test
93
85
  end
94
86
  end
95
87
 
96
- def test_with_library
97
- Dir.mktmpdir do |d|
98
- dir = File.join(d, 'judges')
99
- FileUtils.mkdir_p(dir)
100
- File.write(File.join(dir, 'x.rb'), '$fb.insert.bar = $foo; each_once($fb, "(always)").to_a')
101
- lib = File.join(d, 'lib')
102
- FileUtils.mkdir_p(lib)
103
- File.write(File.join(lib, 'y.rb'), '$foo = 42')
104
- judge = Judges::Judge.new(dir, lib, Loog::NULL)
105
- fb = Factbase.new
106
- judge.run(fb, {}, {}, {})
107
- assert_equal(42, fb.query('(always)').each.to_a.first.bar)
108
- end
109
- end
110
-
111
88
  def test_with_broken_ruby_syntax
112
89
  assert_raises do
113
90
  Dir.mktmpdir do |d|
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: judges
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yegor Bugayenko
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-06-04 00:00:00.000000000 Z
11
+ date: 2024-06-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: backtrace
@@ -108,6 +108,20 @@ dependencies:
108
108
  - - "~>"
109
109
  - !ruby/object:Gem::Version
110
110
  version: '1.10'
111
+ - !ruby/object:Gem::Dependency
112
+ name: retries
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '0.0'
118
+ type: :runtime
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '0.0'
111
125
  - !ruby/object:Gem::Dependency
112
126
  name: typhoeus
113
127
  requirement: !ruby/object:Gem::Requirement
@@ -187,8 +201,6 @@ files:
187
201
  - lib/judges/commands/trim.rb
188
202
  - lib/judges/commands/update.rb
189
203
  - lib/judges/elapsed.rb
190
- - lib/judges/fb/if_absent.rb
191
- - lib/judges/fb/once.rb
192
204
  - lib/judges/impex.rb
193
205
  - lib/judges/judge.rb
194
206
  - lib/judges/judges.rb
@@ -205,8 +217,6 @@ files:
205
217
  - test/commands/test_test.rb
206
218
  - test/commands/test_trim.rb
207
219
  - test/commands/test_update.rb
208
- - test/fb/test_if_absent.rb
209
- - test/fb/test_once.rb
210
220
  - test/test__helper.rb
211
221
  - test/test_baza.rb
212
222
  - test/test_categories.rb
@@ -1,74 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # Copyright (c) 2024 Yegor Bugayenko
4
- #
5
- # Permission is hereby granted, free of charge, to any person obtaining a copy
6
- # of this software and associated documentation files (the 'Software'), to deal
7
- # in the Software without restriction, including without limitation the rights
8
- # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- # copies of the Software, and to permit persons to whom the Software is
10
- # furnished to do so, subject to the following conditions:
11
- #
12
- # The above copyright notice and this permission notice shall be included in all
13
- # copies or substantial portions of the Software.
14
- #
15
- # THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- # SOFTWARE.
22
-
23
- require 'judges'
24
- require 'time'
25
-
26
- # Injects a fact if it's absent in the factbase.
27
- def if_absent(fb)
28
- attrs = {}
29
- f = Judges::Accumulator.new(attrs)
30
- yield f
31
- q = attrs.map do |k, v|
32
- vv = v.to_s
33
- if v.is_a?(String)
34
- vv = "'#{vv.gsub('"', '\\\\"').gsub("'", "\\\\'")}'"
35
- elsif v.is_a?(Time)
36
- vv = v.utc.iso8601
37
- end
38
- "(eq #{k} #{vv})"
39
- end.join(' ')
40
- q = "(and #{q})"
41
- return unless fb.query(q).each.to_a.empty?
42
- n = fb.insert
43
- attrs.each { |k, v| n.send("#{k}=", v) }
44
- n
45
- end
46
-
47
- # Predents to be a fact, just accumulating all attribute sets.
48
- # Author:: Yegor Bugayenko (yegor256@gmail.com)
49
- # Copyright:: Copyright (c) 2024 Yegor Bugayenko
50
- # License:: MIT
51
- class Judges::Accumulator
52
- def initialize(map)
53
- @map = map
54
- end
55
-
56
- def method_missing(*args)
57
- k = args[0]
58
- if k.end_with?('=')
59
- @map[k[0..-2].to_sym] = args[1]
60
- else
61
- @map[k.to_sym]
62
- end
63
- end
64
-
65
- # rubocop:disable Style/OptionalBooleanParameter
66
- def respond_to?(_method, _include_private = false)
67
- # rubocop:enable Style/OptionalBooleanParameter
68
- true
69
- end
70
-
71
- def respond_to_missing?(_method, _include_private = false)
72
- true
73
- end
74
- end
@@ -1,54 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # Copyright (c) 2024 Yegor Bugayenko
4
- #
5
- # Permission is hereby granted, free of charge, to any person obtaining a copy
6
- # of this software and associated documentation files (the 'Software'), to deal
7
- # in the Software without restriction, including without limitation the rights
8
- # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- # copies of the Software, and to permit persons to whom the Software is
10
- # furnished to do so, subject to the following conditions:
11
- #
12
- # The above copyright notice and this permission notice shall be included in all
13
- # copies or substantial portions of the Software.
14
- #
15
- # THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- # SOFTWARE.
22
-
23
- require 'judges'
24
- require 'factbase/tuples'
25
-
26
- # Returns a decorated global factbase, which only touches facts once.
27
- def each_once(fb, query, judge: $judge)
28
- return to_enum(__method__, fb, query, judge:) unless block_given?
29
- q = "(and #{query} (not (eq seen '#{judge}')))"
30
- fb.query(q).each do |f|
31
- yield f
32
- f.seen = judge
33
- end
34
- end
35
-
36
- # Returns a decorated global factbase, which only touches a tuple once.
37
- def each_tuple_once(fb, *queries, judge: $judge)
38
- return to_enum(__method__, fb, *queries, judge:) unless block_given?
39
- qq = queries.map { |q| "(and #{q} (not (eq seen '#{judge}')))" }
40
- Factbase::Tuples.new(fb, qq).each do |fs|
41
- yield fs
42
- fs.each do |f|
43
- f.seen = judge
44
- end
45
- end
46
- end
47
-
48
- def each_tuple_once_txn(fb, *queries, judge: $judge)
49
- fb.txn do |fbt|
50
- each_tuple_once(fb, *queries, judge:) do |fs|
51
- yield [fbt] + fs
52
- end
53
- end
54
- end
@@ -1,103 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # Copyright (c) 2024 Yegor Bugayenko
4
- #
5
- # Permission is hereby granted, free of charge, to any person obtaining a copy
6
- # of this software and associated documentation files (the 'Software'), to deal
7
- # in the Software without restriction, including without limitation the rights
8
- # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- # copies of the Software, and to permit persons to whom the Software is
10
- # furnished to do so, subject to the following conditions:
11
- #
12
- # The above copyright notice and this permission notice shall be included in all
13
- # copies or substantial portions of the Software.
14
- #
15
- # THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- # SOFTWARE.
22
-
23
- require 'minitest/autorun'
24
- require 'tmpdir'
25
- require 'factbase'
26
- require 'factbase/looged'
27
- require 'loog'
28
- require_relative '../../lib/judges'
29
- require_relative '../../lib/judges/fb/if_absent'
30
-
31
- # Test.
32
- # Author:: Yegor Bugayenko (yegor256@gmail.com)
33
- # Copyright:: Copyright (c) 2024 Yegor Bugayenko
34
- # License:: MIT
35
- class TestIfAbsent < Minitest::Test
36
- def test_ignores
37
- fb = Factbase.new
38
- fb.insert.foo = 'hello dude'
39
- n = if_absent(fb) do |f|
40
- f.foo = 'hello dude'
41
- end
42
- assert(n.nil?)
43
- end
44
-
45
- def test_ignores_with_time
46
- fb = Factbase.new
47
- t = Time.now
48
- fb.insert.foo = t
49
- n = if_absent(fb) do |f|
50
- f.foo = t
51
- end
52
- assert(n.nil?)
53
- end
54
-
55
- def test_injects
56
- fb = Factbase.new
57
- n = if_absent(fb) do |f|
58
- f.foo = 42
59
- end
60
- assert_equal(42, n.foo)
61
- end
62
-
63
- def test_injects_and_reads
64
- if_absent(Factbase.new) do |f|
65
- f.foo = 42
66
- assert_equal(42, f.foo)
67
- end
68
- end
69
-
70
- def test_complex_ignores
71
- fb = Factbase.new
72
- f1 = fb.insert
73
- f1.foo = 'hello, "dude"!'
74
- f1.abc = 42
75
- t = Time.now
76
- f1.z = t
77
- f1.bar = 3.14
78
- n = if_absent(fb) do |f|
79
- f.foo = 'hello, "dude"!'
80
- f.abc = 42
81
- f.z = t
82
- f.bar = 3.14
83
- end
84
- assert(n.nil?)
85
- end
86
-
87
- def test_complex_injects
88
- fb = Factbase.new
89
- f1 = fb.insert
90
- f1.foo = 'hello, dude!'
91
- f1.abc = 42
92
- t = Time.now
93
- f1.z = t
94
- f1.bar = 3.14
95
- n = if_absent(fb) do |f|
96
- f.foo = "hello, \\\"dude\\\" \\' \\' ( \n\n ) (! '"
97
- f.abc = 42
98
- f.z = t + 1
99
- f.bar = 3.15
100
- end
101
- assert(!n.nil?)
102
- end
103
- end
data/test/fb/test_once.rb DELETED
@@ -1,88 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # Copyright (c) 2024 Yegor Bugayenko
4
- #
5
- # Permission is hereby granted, free of charge, to any person obtaining a copy
6
- # of this software and associated documentation files (the 'Software'), to deal
7
- # in the Software without restriction, including without limitation the rights
8
- # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- # copies of the Software, and to permit persons to whom the Software is
10
- # furnished to do so, subject to the following conditions:
11
- #
12
- # The above copyright notice and this permission notice shall be included in all
13
- # copies or substantial portions of the Software.
14
- #
15
- # THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- # SOFTWARE.
22
-
23
- require 'minitest/autorun'
24
- require 'factbase'
25
- require_relative '../../lib/judges'
26
- require_relative '../../lib/judges/fb/once'
27
-
28
- # Test.
29
- # Author:: Yegor Bugayenko (yegor256@gmail.com)
30
- # Copyright:: Copyright (c) 2024 Yegor Bugayenko
31
- # License:: MIT
32
- class TestOnce < Minitest::Test
33
- def test_touch_once
34
- fb = Factbase.new
35
- fb.insert
36
- assert(!each_once(fb, '(always)', judge: 'something').to_a.empty?)
37
- assert(each_once(fb, '(always)', judge: 'something').to_a.empty?)
38
- end
39
-
40
- def test_seen_property
41
- fb = Factbase.new
42
- f1 = fb.insert
43
- f1.foo = 42
44
- assert_equal(1, each_tuple_once(fb, '(eq foo 42)', judge: 'x').to_a.size)
45
- assert(each_tuple_once(fb, '(eq foo 42)', judge: 'x').to_a.empty?)
46
- end
47
-
48
- def test_seen_all_or_nothing
49
- fb = Factbase.new
50
- f1 = fb.insert
51
- f1.a = 1
52
- assert(each_tuple_once(fb, '(exists a)', '(exists b)', judge: 'x').to_a.empty?)
53
- f2 = fb.insert
54
- f2.b = 1
55
- assert(!each_tuple_once(fb, '(exists a)', '(exists b)', judge: 'x').to_a.empty?)
56
- assert(each_tuple_once(fb, '(exists a)', '(exists b)', judge: 'x').to_a.empty?)
57
- end
58
-
59
- def test_with_txn
60
- fb = Factbase.new
61
- f1 = fb.insert
62
- f1.foo = 42
63
- each_tuple_once(fb, '(exists foo)', judge: 'xx') do |fs|
64
- fb.txn do |fbt|
65
- f = fbt.insert
66
- f.bar = 1
67
- end
68
- fs[0].xyz = 'hey'
69
- end
70
- assert_equal(1, fb.query('(exists seen)').each.to_a.size)
71
- assert_equal(1, fb.query('(exists bar)').each.to_a.size)
72
- assert_equal(1, fb.query('(exists xyz)').each.to_a.size)
73
- end
74
-
75
- def test_with_chain_txn
76
- fb = Factbase.new
77
- f1 = fb.insert
78
- f1.foo = 42
79
- each_tuple_once_txn(fb, '(exists foo)', judge: 'xx') do |fbt, ff|
80
- f = fbt.insert
81
- f.bar = 1
82
- ff.xyz = 'hey'
83
- end
84
- assert_equal(1, fb.query('(exists seen)').each.to_a.size)
85
- assert_equal(1, fb.query('(exists bar)').each.to_a.size)
86
- assert_equal(1, fb.query('(exists xyz)').each.to_a.size)
87
- end
88
- end