factbase 0.19.13 → 0.19.14

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: 637517dba0f659ed627e82e2b7959e113ea5b5a7b1193f800018492cde27d761
4
- data.tar.gz: c59487d4138740f493f220d9b338139cc26d0de206b0913d078fe4ecec26e2b2
3
+ metadata.gz: 5853fdb37b5bcd303e1a04fe0c679688949d1a405760683d73d3220bbc1b759c
4
+ data.tar.gz: a08d1a6d7c733774cd49037c98d78e7c560a8b848839a4b5b006170f0961b7d4
5
5
  SHA512:
6
- metadata.gz: d78b66be0333c5c19d9db04931360a7d30b0a01115dc259daeaf5146a861211f884396c91ccf3e17ee0ff607aba7e4f95a4e2dba8a18e3a79d57b262fe5c3624
7
- data.tar.gz: 714a0e0a2a023348f3e65250c2721e05b17d2c5649b45dcaed3d50a59e66a79cb1077895c8fba16cc26ba0417e9c8d817ead2874d9df4320eb27dba4bacaf15d
6
+ metadata.gz: 234861469a26be76f2bcfc7f06f2b43e57144ea1c86bef5452a51f6661e77ccd11f9a5484baed014f1cc66dd27768cb80d1b217a9724685b70ab0ed3846bb756
7
+ data.tar.gz: 0e9124c4d97b6f37ec49bfc855b1d1626661e2ccc20a4ad45955c9c0899d6852b1555b5ee0bbe831306306b01c8da22b0b25575647da6df1d23a25bc7d1b2030
data/Gemfile.lock CHANGED
@@ -21,7 +21,7 @@ GEM
21
21
  backtrace (0.4.1)
22
22
  benchmark (0.5.0)
23
23
  builder (3.3.0)
24
- concurrent-ruby (1.3.6)
24
+ concurrent-ruby (1.3.7)
25
25
  date (3.5.1)
26
26
  decoor (0.1.0)
27
27
  docile (1.4.1)
@@ -31,8 +31,8 @@ GEM
31
31
  tago (~> 0.1)
32
32
  ellipsized (0.3.0)
33
33
  erb (6.0.4)
34
- json (2.19.5)
35
- language_server-protocol (3.17.0.5)
34
+ json (2.20.0)
35
+ language_server-protocol (3.17.0.6)
36
36
  lint_roller (1.1.0)
37
37
  logger (1.7.0)
38
38
  loog (0.8.0)
@@ -46,13 +46,13 @@ GEM
46
46
  builder
47
47
  minitest (>= 5.0, < 7)
48
48
  ruby-progressbar
49
- nokogiri (1.19.3-arm64-darwin)
49
+ nokogiri (1.19.4-arm64-darwin)
50
50
  racc (~> 1.4)
51
- nokogiri (1.19.3-x64-mingw-ucrt)
51
+ nokogiri (1.19.4-x64-mingw-ucrt)
52
52
  racc (~> 1.4)
53
- nokogiri (1.19.3-x86_64-darwin)
53
+ nokogiri (1.19.4-x86_64-darwin)
54
54
  racc (~> 1.4)
55
- nokogiri (1.19.3-x86_64-linux-gnu)
55
+ nokogiri (1.19.4-x86_64-linux-gnu)
56
56
  racc (~> 1.4)
57
57
  os (1.1.4)
58
58
  others (0.1.1)
@@ -78,7 +78,7 @@ GEM
78
78
  tsort
79
79
  regexp_parser (2.12.0)
80
80
  rexml (3.4.4)
81
- rubocop (1.86.2)
81
+ rubocop (1.88.1)
82
82
  json (~> 2.3)
83
83
  language_server-protocol (~> 3.17.0.2)
84
84
  lint_roller (~> 1.1.0)
@@ -89,10 +89,10 @@ GEM
89
89
  rubocop-ast (>= 1.49.0, < 2.0)
90
90
  ruby-progressbar (~> 1.7)
91
91
  unicode-display_width (>= 2.4.0, < 4.0)
92
- rubocop-ast (1.49.1)
92
+ rubocop-ast (1.50.0)
93
93
  parser (>= 3.3.7.2)
94
94
  prism (~> 1.7)
95
- rubocop-elegant (0.5.1)
95
+ rubocop-elegant (0.7.0)
96
96
  lint_roller (~> 1.1)
97
97
  rubocop (~> 1.75)
98
98
  rubocop-minitest (0.39.1)
@@ -111,7 +111,7 @@ GEM
111
111
  docile (~> 1.1)
112
112
  simplecov-html (~> 0.11)
113
113
  simplecov_json_formatter (~> 0.1)
114
- simplecov-cobertura (3.1.0)
114
+ simplecov-cobertura (3.2.0)
115
115
  rexml
116
116
  simplecov (~> 0.19)
117
117
  simplecov-html (0.13.2)
data/README.md CHANGED
@@ -357,24 +357,24 @@ This is the result of the benchmark:
357
357
  <!-- benchmark_begin -->
358
358
  ```text
359
359
  user
360
- void scan 0.001115
361
- 20k facts: export: 2979KB 0.979531
362
- 20k facts: import: 2979KB 1.055363
363
- 50k facts: read 0.000212
364
- 50k facts: read in txn 0.001724
365
- 50k facts: insert 0.000081
366
- 50k facts: insert in txn 0.000226
367
- 50k facts: modify 1.604103
368
- 50k facts: modify in txn 3.126437
369
- 12k facts: large query: match 3k 13.220472
370
- 12k facts: large query: match 3k in txn 18.484006
371
- 12k facts: large query: match zero 13.730576
372
- 12k facts: large query: match zero in txn 19.485743
360
+ void scan 0.001099
361
+ 20k facts: export: 2970KB 0.836539
362
+ 20k facts: import: 2970KB 1.034012
363
+ 50k facts: read 0.000256
364
+ 50k facts: read in txn 0.002758
365
+ 50k facts: insert 0.000100
366
+ 50k facts: insert in txn 0.000257
367
+ 50k facts: modify 1.484502
368
+ 50k facts: modify in txn 2.812194
369
+ 12k facts: large query: match 3k 14.318373
370
+ 12k facts: large query: match 3k in txn 19.628950
371
+ 12k facts: large query: match zero 15.134839
372
+ 12k facts: large query: match zero in txn 20.974642
373
373
  ```
374
374
 
375
375
  The results were calculated in [this GHA job][benchmark-gha]
376
- on 2026-06-14 at 16:40,
376
+ on 2026-06-19 at 04:35,
377
377
  on Linux with 4 CPUs.
378
378
  <!-- benchmark_end -->
379
379
 
380
- [benchmark-gha]: https://github.com/yegor256/factbase/actions/runs/27505290212
380
+ [benchmark-gha]: https://github.com/yegor256/factbase/actions/runs/27805571606
data/lib/factbase/inv.rb CHANGED
@@ -7,17 +7,25 @@ require 'decoor'
7
7
  require 'others'
8
8
  require_relative '../factbase'
9
9
 
10
+ # @todo #644:30min Add a test that validates YARD docstring examples
11
+ # match the actual API signatures. The docstring in this class was
12
+ # recently fixed because the block signature was documented as
13
+ # |f, fbt| but the actual implementation passes |property, value|.
14
+ # A general test that parses docstrings and checks their examples
15
+ # against the real method signatures would prevent this class of
16
+ # bugs from recurring across the codebase.
17
+ #
10
18
  # A decorator of a Factbase, that checks invariants on every set.
11
19
  #
12
- # For example, you can use this decorator if you want to check that every
13
- # fact has +when+:
20
+ # For example, you can use this decorator if you want to make sure that
21
+ # no property +b+ is set to a +String+ value:
14
22
  #
15
- # fb = Factbase::Inv.new(Factbase.new) do |f, fbt|
16
- # assert !f['when'].nil?
23
+ # fb = Factbase::Inv.new(Factbase.new) do |p, v|
24
+ # raise "b cannot be a string" if p == 'b' && v.is_a?(String)
17
25
  # end
18
26
  #
19
- # The second argument passed to the block is the factbase, while the first
20
- # one is the fact just touched.
27
+ # The first block argument is the property name (a +String+), the second
28
+ # is the value being assigned.
21
29
  #
22
30
  # Author:: Yegor Bugayenko (yegor256@gmail.com)
23
31
  # Copyright:: Copyright (c) 2024-2026 Yegor Bugayenko
@@ -131,10 +131,11 @@ class Factbase::Logged
131
131
  @maps = maps
132
132
  @tube = tube
133
133
  @fb = fb
134
+ @termtext = term.is_a?(Factbase::Term) ? term.to_s : term
134
135
  end
135
136
 
136
137
  def to_s
137
- @term.to_s
138
+ @termtext
138
139
  end
139
140
 
140
141
  def each(fb = @fb, params = {}, &)
@@ -147,10 +148,14 @@ class Factbase::Logged
147
148
  r = qry.each(fb, params, &)
148
149
  end
149
150
  unless r.is_a?(Integer)
150
- raise(StandardError, ".query(#{@term.to_s.inspect}).each() of #{qry.class} returned #{r.class}")
151
+ raise(StandardError, ".query(#{@termtext.inspect}).each() of #{qry.class} returned #{r.class}")
151
152
  end
152
- q = Factbase::Syntax.new(@term).to_term.to_s
153
- q = "#{q} with {#{params.map { |k, v| "#{k}=#{v}" }.join(', ')}}" if params.is_a?(Hash) && !params.empty?
153
+ if params.is_a?(Hash) && !params.empty?
154
+ q = "#{@termtext} with {#{params.map do |k, v|
155
+ "#{k}=#{v}"
156
+ end.join(', ')}}"
157
+ end
158
+ q ||= @termtext
154
159
  if r.zero?
155
160
  @tube.say(mono, "Zero/#{@fb.size} facts found by #{q} #{tail}")
156
161
  else
@@ -161,16 +166,15 @@ class Factbase::Logged
161
166
 
162
167
  def one(fb = @fb, params = {})
163
168
  mono = Process.clock_gettime(Factbase::Logged::MONO)
164
- q = Factbase::Syntax.new(@term).to_term.to_s
165
169
  r = nil
166
170
  tail =
167
171
  Factbase::Logged.elapsed do
168
172
  r = @fb.query(@term, @maps).one(fb, params)
169
173
  end
170
174
  if r.nil?
171
- @tube.say(mono, "Nothing found by '#{q}' #{tail}")
175
+ @tube.say(mono, "Nothing found by '#{@termtext}' #{tail}")
172
176
  else
173
- @tube.say(mono, "Found #{r} (#{r.class}) by '#{q}' #{tail}")
177
+ @tube.say(mono, "Found #{r} (#{r.class}) by '#{@termtext}' #{tail}")
174
178
  end
175
179
  r
176
180
  end
@@ -122,8 +122,10 @@ class Factbase::Rules
122
122
 
123
123
  def it(fact, fb)
124
124
  return if Factbase::Syntax.new(@expr).to_term.evaluate(fact, [], fb)
125
- e = "#{@expr[0..32]}..." if @expr.length > 32
126
- raise(ArgumentError, "The fact doesn't match the #{e.inspect} rule: #{fact}")
125
+ raise(
126
+ ArgumentError,
127
+ "The fact doesn't match the #{(@expr.length > 32 ? "#{@expr[0..31]}..." : @expr).inspect} rule: #{fact}"
128
+ )
127
129
  end
128
130
  end
129
131
 
@@ -47,7 +47,7 @@ class Factbase::Arithmetic < Factbase::TermBase
47
47
  when 'weeks', 'week'
48
48
  num * 60 * 60 * 24 * 7
49
49
  else
50
- raise(ArgumentError, "Unknown time unit '#{units}' in '#{r}")
50
+ raise(ArgumentError, "Unknown time unit '#{units}' in '#{r}'")
51
51
  end
52
52
  end
53
53
  v.__send__(@op, r)
@@ -22,7 +22,12 @@ class Factbase::Env < Factbase::TermBase
22
22
  # @return [String] The value of the environment variable or the default
23
23
  def evaluate(fact, maps, fb)
24
24
  assert_args(2)
25
- n = _values(0, fact, maps, fb)[0]
26
- ENV.fetch(n.upcase) { _values(1, fact, maps, fb)[0] }
25
+ n = _values(0, fact, maps, fb)
26
+ return if n.nil?
27
+ ENV.fetch(n[0].upcase) do
28
+ d = _values(1, fact, maps, fb)
29
+ return if d.nil?
30
+ d[0]
31
+ end
27
32
  end
28
33
  end
@@ -23,6 +23,14 @@ class Factbase::ToFloat < Factbase::TermBase
23
23
  assert_args(1)
24
24
  vv = _values(0, fact, maps, fb)
25
25
  return if vv.nil?
26
- Float(vv[0])
26
+ to_float(vv[0])
27
+ end
28
+
29
+ private
30
+
31
+ def to_float(value)
32
+ Float(value.to_s)
33
+ rescue ArgumentError, TypeError => e
34
+ raise(RuntimeError, "Cannot convert '#{value}' to Float in (to_float ...): #{e.message}")
27
35
  end
28
36
  end
@@ -23,6 +23,14 @@ class Factbase::ToInteger < Factbase::TermBase
23
23
  assert_args(1)
24
24
  vv = _values(0, fact, maps, fb)
25
25
  return if vv.nil?
26
- Integer(vv[0])
26
+ to_integer(vv[0])
27
+ end
28
+
29
+ private
30
+
31
+ def to_integer(value)
32
+ Integer(value.to_s)
33
+ rescue ArgumentError, TypeError => e
34
+ raise(RuntimeError, "Cannot convert '#{value}' to Integer in (to_integer ...): #{e.message}")
27
35
  end
28
36
  end
@@ -8,5 +8,5 @@
8
8
  # Copyright:: Copyright (c) 2024-2026 Yegor Bugayenko
9
9
  # License:: MIT
10
10
  class Factbase
11
- VERSION = '0.19.13' unless const_defined?(:VERSION)
11
+ VERSION = '0.19.14' unless const_defined?(:VERSION)
12
12
  end
data/lib/factbase.rb CHANGED
@@ -17,7 +17,7 @@ require 'yaml'
17
17
  # f = fb.insert # new fact created
18
18
  # f.name = 'Jeff Lebowski'
19
19
  # f.age = 42
20
- # found = f.query('(gt 20 age)').each.to_a[0]
20
+ # found = fb.query('(gt 20 age)').each.to_a[0]
21
21
  # assert(found.age == 42)
22
22
  #
23
23
  # Every fact is a key-value hash map. Every value is a non-empty set of values.
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: factbase
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.19.13
4
+ version: 0.19.14
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yegor Bugayenko