factbase 0.11.1 → 0.12.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: e27fe11aa944dcd02303229649c86810bd2585e18c86ec227b113d2a50633ec4
4
- data.tar.gz: a3fad9da51b5201a84f71177475a8b768bb037f6f7dc9fbc01f61b076e9a6559
3
+ metadata.gz: f31200ddcd8de0d737dbabea9aefc051794f86bbae0891f8d624545912972add
4
+ data.tar.gz: 7c1688856cde3e72f8e9f53e846b39c7cef508a0df95cc88d0631bfae36ce07f
5
5
  SHA512:
6
- metadata.gz: cef5dbc22c5692f7e3219cfc11802ba7b114cdd5d30ae65e20960186b919ff69b6a5015e7fc5985644713dd852b624e9575784496b62e8155c254871dac9b3d4
7
- data.tar.gz: ed05d5bf86469a9c30c7f66c03222b65ec4b3a02ac9a403bda966914538c83e27be9d4ffc6a0e7e8890dc00a57d2e21810cc3b6ac8b98bd66a28d9dcefcbe469
6
+ metadata.gz: 26c83d3a288f8106bfe17856bccb9c1bde6b130384e9a4546456a76c1b6a69fff9c49954789aaeee6413f7cfae638d6f1320f1de4f7ac000b3c552b31449ebbd
7
+ data.tar.gz: 761d577bc112c4d542667508924406570ff449fbab87af3a18fc0ce7c8a94cccf6d40f400b1b1c3f6bd76d95a51678a680fd17feeee0b89caacbac2b56e8e6f6
data/.rultor.yml CHANGED
@@ -16,8 +16,8 @@ release:
16
16
  [[ "${tag}" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] || exit -1
17
17
  bundle exec rake
18
18
  rm -rf *.gem
19
- sed -i "s/0\.0\.0/${tag}/g" lib/factbase.rb
20
- git add lib/factbase.rb
19
+ sed -i "s/0\.0\.0/${tag}/g" lib/factbase/version.rb
20
+ git add lib/factbase/version.rb
21
21
  git commit -m "version set to ${tag}"
22
22
  gem build factbase.gemspec
23
23
  chmod 0600 ../rubygems.yml
data/Gemfile.lock CHANGED
@@ -22,7 +22,7 @@ GEM
22
22
  builder (3.3.0)
23
23
  concurrent-ruby (1.3.5)
24
24
  date (3.4.1)
25
- decoor (0.0.1)
25
+ decoor (0.1.0)
26
26
  docile (1.4.1)
27
27
  elapsed (0.0.1)
28
28
  loog (> 0)
data/README.md CHANGED
@@ -210,33 +210,33 @@ This is the result of the benchmark:
210
210
  <!-- benchmark_begin -->
211
211
  ```text
212
212
  user
213
- insert 20000 facts 0.606861
214
- export 20000 facts 0.029288
215
- import 410768 bytes (20000 facts) 0.029856
216
- insert 10 facts 0.042954
217
- query 10 times w/txn 1.951537
218
- query 10 times w/o txn 0.038436
219
- modify 10 attrs w/txn 1.815854
220
- delete 10 facts w/txn 1.023006
221
- (and (eq what 'issue-was-closed') (exists... -> 200 2.130857
222
- (and (eq what 'issue-was-closed') (exists... -> 200/txn 1.146039
223
- (and (eq what 'issue-was-closed') (exists... -> zero 2.424541
224
- (and (eq what 'issue-was-closed') (exists... -> zero/txn 1.297135
225
- (gt time '2024-03-23T03:21:43Z') 0.109071
226
- (gt cost 50) 0.092356
227
- (eq title 'Object Thinking 5000') 0.002707
228
- (and (eq foo 42.998) (or (gt bar 200) (absent zzz))) 0.024449
229
- (eq id (agg (always) (max id))) 0.257526
230
- (join "c<=cost,b<=bar" (eq id (agg (always) (max id)))) 0.650843
231
- delete! 0.075867
232
- Taped.append() x50000 0.038991
233
- Taped.each() x125 1.321896
234
- Taped.delete_if() x375 0.830375
213
+ insert 20000 facts 0.618307
214
+ export 20000 facts 0.021391
215
+ import 410726 bytes (20000 facts) 0.030150
216
+ insert 10 facts 0.045651
217
+ query 10 times w/txn 1.970434
218
+ query 10 times w/o txn 0.039459
219
+ modify 10 attrs w/txn 1.819769
220
+ delete 10 facts w/txn 1.056563
221
+ (and (eq what 'issue-was-closed') (exists... -> 200 2.125753
222
+ (and (eq what 'issue-was-closed') (exists... -> 200/txn 1.135618
223
+ (and (eq what 'issue-was-closed') (exists... -> zero 2.422668
224
+ (and (eq what 'issue-was-closed') (exists... -> zero/txn 1.288236
225
+ (gt time '2024-03-23T03:21:43Z') 0.108849
226
+ (gt cost 50) 0.090092
227
+ (eq title 'Object Thinking 5000') 0.002640
228
+ (and (eq foo 42.998) (or (gt bar 200) (absent zzz))) 0.023785
229
+ (eq id (agg (always) (max id))) 0.252980
230
+ (join "c<=cost,b<=bar" (eq id (agg (always) (max id)))) 0.655997
231
+ delete! 0.075510
232
+ Taped.append() x50000 0.042923
233
+ Taped.each() x125 1.343819
234
+ Taped.delete_if() x375 0.830124
235
235
  ```
236
236
 
237
237
  The results were calculated in [this GHA job][benchmark-gha]
238
- on 2025-06-03 at 09:54,
238
+ on 2025-06-21 at 08:24,
239
239
  on Linux with 4 CPUs.
240
240
  <!-- benchmark_end -->
241
241
 
242
- [benchmark-gha]: https://github.com/yegor256/factbase/actions/runs/15414210508
242
+ [benchmark-gha]: https://github.com/yegor256/factbase/actions/runs/15793882855
data/factbase.gemspec CHANGED
@@ -4,7 +4,7 @@
4
4
  # SPDX-License-Identifier: MIT
5
5
 
6
6
  require 'English'
7
- require_relative 'lib/factbase'
7
+ require_relative 'lib/factbase/version'
8
8
 
9
9
  Gem::Specification.new do |s|
10
10
  s.required_rubygems_version = Gem::Requirement.new('>= 0') if s.respond_to? :required_rubygems_version=
data/lib/factbase/term.rb CHANGED
@@ -118,9 +118,9 @@ class Factbase::Term
118
118
  def evaluate(fact, maps, fb)
119
119
  send(@op, fact, maps, fb)
120
120
  rescue NoMethodError => e
121
- raise "Probably the term '#{@op}' is not defined at #{self}:\n#{Backtrace.new(e)}"
121
+ raise "Probably the term '#{@op}' is not defined at #{self}: #{e.message}"
122
122
  rescue StandardError => e
123
- raise "#{e.message} at #{self}:\n#{Backtrace.new(e)}"
123
+ raise "#{e.message} at #{self}"
124
124
  end
125
125
 
126
126
  # Simplify it if possible.
@@ -19,4 +19,29 @@ module Factbase::Debug
19
19
  puts "#{self} -> #{r}"
20
20
  r
21
21
  end
22
+
23
+ def assert(fact, maps, fb)
24
+ assert_args(2)
25
+ message = @operands[0]
26
+ unless message.is_a?(String)
27
+ raise ArgumentError,
28
+ "A string expected as first argument of 'assert', but '#{message}' provided"
29
+ end
30
+ t = @operands[1]
31
+ unless t.is_a?(Factbase::Term)
32
+ raise ArgumentError,
33
+ "A term expected as second argument of 'assert', but '#{t}' provided"
34
+ end
35
+ result = t.evaluate(fact, maps, fb)
36
+ # Convert result to boolean-like evaluation
37
+ # Arrays are truthy if they contain at least one truthy element
38
+ truthy =
39
+ if result.is_a?(Array)
40
+ result.any? { |v| v && v != 0 }
41
+ else
42
+ result && result != 0
43
+ end
44
+ raise message unless truthy
45
+ true
46
+ end
22
47
  end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ # SPDX-FileCopyrightText: Copyright (c) 2024-2025 Yegor Bugayenko
4
+ # SPDX-License-Identifier: MIT
5
+
6
+ # Just version.
7
+ # Author:: Yegor Bugayenko (yegor256@gmail.com)
8
+ # Copyright:: Copyright (c) 2024-2025 Yegor Bugayenko
9
+ # License:: MIT
10
+ class Factbase
11
+ # Current version of the gem (changed by .rultor.yml on every release)
12
+ VERSION = '0.12.0' unless const_defined?(:VERSION)
13
+ end
data/lib/factbase.rb CHANGED
@@ -81,8 +81,7 @@ require 'yaml'
81
81
  # Copyright:: Copyright (c) 2024-2025 Yegor Bugayenko
82
82
  # License:: MIT
83
83
  class Factbase
84
- # Current version of the gem (changed by .rultor.yml on every release)
85
- VERSION = '0.11.1' unless const_defined?(:VERSION)
84
+ require_relative 'factbase/version'
86
85
 
87
86
  # An exception that may be thrown in a transaction, to roll it back.
88
87
  class Rollback < StandardError; end
@@ -33,4 +33,79 @@ class TestDebug < Factbase::Test
33
33
  end
34
34
  assert_match(/Too many \(\d+\) operands for 'traced' \(\d+ expected\)/, e.message)
35
35
  end
36
+
37
+ def test_assert_with_true_condition
38
+ t = Factbase::Term.new(:assert, ['all must be positive', Factbase::Term.new(:gt, [:foo, 0])])
39
+ assert(t.evaluate(fact('foo' => 5), [], Factbase.new))
40
+ end
41
+
42
+ def test_assert_with_false_condition
43
+ t = Factbase::Term.new(:assert, ['all must be positive', Factbase::Term.new(:gt, [:foo, 0])])
44
+ e =
45
+ assert_raises(RuntimeError) do
46
+ t.evaluate(fact('foo' => -1), [], Factbase.new)
47
+ end
48
+ assert_equal("all must be positive at (assert 'all must be positive' (gt foo 0))", e.message)
49
+ end
50
+
51
+ def test_assert_with_zero_value
52
+ t = Factbase::Term.new(:assert, ['value must not be zero', Factbase::Term.new(:gt, [:foo, 0])])
53
+ e =
54
+ assert_raises(RuntimeError) do
55
+ t.evaluate(fact('foo' => 0), [], Factbase.new)
56
+ end
57
+ assert_equal("value must not be zero at (assert 'value must not be zero' (gt foo 0))", e.message)
58
+ end
59
+
60
+ def test_assert_with_array_true_condition
61
+ t = Factbase::Term.new(:assert, ['at least one positive', Factbase::Term.new(:gt, [:foo, 0])])
62
+ assert(t.evaluate(fact('foo' => [1, 2, 3]), [], Factbase.new))
63
+ end
64
+
65
+ def test_assert_with_array_false_condition
66
+ t = Factbase::Term.new(:assert, ['at least one positive', Factbase::Term.new(:gt, [:foo, 0])])
67
+ e =
68
+ assert_raises(RuntimeError) do
69
+ t.evaluate(fact('foo' => [-1, -2, -3]), [], Factbase.new)
70
+ end
71
+ assert_equal("at least one positive at (assert 'at least one positive' (gt foo 0))", e.message)
72
+ end
73
+
74
+ def test_assert_with_mixed_array
75
+ t = Factbase::Term.new(:assert, ['at least one positive', Factbase::Term.new(:gt, [:foo, 0])])
76
+ assert(t.evaluate(fact('foo' => [-1, 0, 3]), [], Factbase.new))
77
+ end
78
+
79
+ def test_assert_raises_when_message_not_string
80
+ e =
81
+ assert_raises(StandardError) do
82
+ Factbase::Term.new(:assert, [123, Factbase::Term.new(:gt, [:foo, 0])]).evaluate(fact, [], Factbase.new)
83
+ end
84
+ assert_match(/A string expected as first argument of 'assert', but '123' provided/, e.message)
85
+ end
86
+
87
+ def test_assert_raises_when_second_arg_not_term
88
+ e =
89
+ assert_raises(StandardError) do
90
+ Factbase::Term.new(:assert, %w[message not_a_term]).evaluate(fact, [], Factbase.new)
91
+ end
92
+ assert_match(/A term expected as second argument of 'assert', but 'not_a_term' provided/, e.message)
93
+ end
94
+
95
+ def test_assert_raises_when_too_few_args
96
+ e =
97
+ assert_raises(StandardError) do
98
+ Factbase::Term.new(:assert, ['message']).evaluate(fact, [], Factbase.new)
99
+ end
100
+ assert_match(/Too few \(\d+\) operands for 'assert' \(\d+ expected\)/, e.message)
101
+ end
102
+
103
+ def test_assert_raises_when_too_many_args
104
+ e =
105
+ assert_raises(StandardError) do
106
+ Factbase::Term.new(:assert, ['message', Factbase::Term.new(:gt, [:foo, 0]), 'extra']).evaluate(fact, [],
107
+ Factbase.new)
108
+ end
109
+ assert_match(/Too many \(\d+\) operands for 'assert' \(\d+ expected\)/, e.message)
110
+ end
36
111
  end
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.11.1
4
+ version: 0.12.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yegor Bugayenko
@@ -249,6 +249,7 @@ files:
249
249
  - lib/factbase/to_json.rb
250
250
  - lib/factbase/to_xml.rb
251
251
  - lib/factbase/to_yaml.rb
252
+ - lib/factbase/version.rb
252
253
  - renovate.json
253
254
  - test/factbase/cached/test_cached_factbase.rb
254
255
  - test/factbase/cached/test_cached_query.rb