judges 0.2.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
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