factbase 0.0.7 → 0.0.9

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: 453a090310ef10ace85c3ee099b85bd8744d24428923f1e896626b996d3124ca
4
- data.tar.gz: 0236a9f6bb4b4dacca29bd1d61da395a8dadb084b81e915b7694a763ecf0985b
3
+ metadata.gz: 38ebbf43ee181a50bc4ca45d32ac3ba1394180e25ea719b41917606c2d00a6c9
4
+ data.tar.gz: f2e71d19bd3523a4db543b410989f88708e3120cbebde21682080b822e11c7d7
5
5
  SHA512:
6
- metadata.gz: 00312f424b58cfda7eee00a7fba6792da9a5b439eab34e29745cdd481913df87afc016944387e95356ece05feddbc444d90ddb52bdf2a20d3bc4ac38e7224a79
7
- data.tar.gz: 224a5b63c85cf5fc604da26f8f4205a35fe6b3ace5f8fb959b6a2a3fd71f08dc79a2804215dab823c1143e02a8ddd06de0df3154912e116de04da97233ff8795
6
+ metadata.gz: 802e11490eda7455f3d00ecce17c70e73f6520c5f06a25ea1ad7393ceb98a8ca67858343d4ee544183f10b695c872f140855037f091623ba057296c755fe6c13
7
+ data.tar.gz: d58f72e6aeabd5e99fe7424c769f56074c2f9dc95593dd76c3373ee770dcfd96c1f05dd51731c25660bfcb2aedfde2ffe8f7842679e6e46ef95532b090c3428c
data/factbase.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 = '>=2.3'
28
28
  s.name = 'factbase'
29
- s.version = '0.0.7'
29
+ s.version = '0.0.9'
30
30
  s.license = 'MIT'
31
31
  s.summary = 'Factbase'
32
32
  s.description = 'Fact base in memory and on disc'
@@ -39,5 +39,6 @@ Gem::Specification.new do |s|
39
39
  s.extra_rdoc_files = ['README.md', 'LICENSE.txt']
40
40
  s.add_runtime_dependency 'json', '~> 2.7'
41
41
  s.add_runtime_dependency 'nokogiri', '~> 1.10'
42
+ s.add_runtime_dependency 'yaml', '~> 0.3'
42
43
  s.metadata['rubygems_mfa_required'] = 'true'
43
44
  end
data/lib/factbase/fact.rb CHANGED
@@ -20,6 +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
+ require 'json'
23
24
  require_relative '../factbase'
24
25
 
25
26
  # Fact.
@@ -32,26 +33,37 @@ class Factbase::Fact
32
33
  @map = map
33
34
  end
34
35
 
36
+ def to_s
37
+ @map.to_json
38
+ end
39
+
35
40
  def method_missing(*args)
36
41
  k = args[0].to_s
37
42
  if k.end_with?('=')
38
43
  kk = k[0..-2]
39
44
  raise "Invalid prop name '#{kk}'" unless kk.match?(/^[a-z][a-zA-Z0-9]+$/)
45
+ v = args[1]
46
+ raise "Prop value can't be empty" if v == ''
40
47
  @mutex.synchronize do
41
- @map[kk] = [] if @map[kk].nil?
42
- @map[kk] << args[1]
48
+ before = @map[kk]
49
+ return if before == v
50
+ if before.nil?
51
+ @map[kk] = v
52
+ return
53
+ end
54
+ @map[kk] = [@map[kk]] unless @map[kk].is_a?(Array)
55
+ @map[kk] << v
43
56
  end
44
57
  nil
45
58
  elsif k == '[]'
46
- kk = args[1].to_s
47
- @mutex.synchronize do
48
- @map[kk] = [] if @map[kk].nil?
49
- end
50
- @map[kk]
59
+ @map[args[1].to_s]
51
60
  else
52
61
  v = @map[k]
53
- raise "Can't find '#{k}'" if v.nil?
54
- v[0]
62
+ if v.nil?
63
+ raise "Can't get '#{k}', the fact is empty" if @map.empty?
64
+ raise "Can't find '#{k}' attribute in [#{@map.keys.join(', ')}]"
65
+ end
66
+ v.is_a?(Array) ? v[0] : v
55
67
  end
56
68
  end
57
69
 
@@ -45,14 +45,4 @@ class Factbase::Query
45
45
  yield f
46
46
  end
47
47
  end
48
-
49
- # Turn it into an array.
50
- # @return [Array] All facts in an array
51
- # rubocop:disable Style/MapIntoArray
52
- def to_a
53
- array = []
54
- each { |f| array << f }
55
- array
56
- end
57
- # rubocop:enable Style/MapIntoArray
58
48
  end
@@ -20,6 +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
+ require_relative '../factbase'
23
24
  require_relative 'fact'
24
25
  require_relative 'term'
25
26
 
@@ -72,6 +73,7 @@ class Factbase::Syntax
72
73
  [Factbase::Term.new(op, operands), at + 1]
73
74
  end
74
75
 
76
+ # Turns a query into an array of tokens.
75
77
  def to_tokens
76
78
  list = []
77
79
  acc = ''
@@ -108,6 +110,7 @@ class Factbase::Syntax
108
110
  if t.is_a?(Symbol)
109
111
  t
110
112
  elsif t.start_with?('\'', '"')
113
+ raise 'String literal can\'t be empty' if t.length <= 2
111
114
  t[1..-2]
112
115
  elsif t.match?(/^[0-9]+$/)
113
116
  t.to_i
data/lib/factbase/term.rb CHANGED
@@ -84,7 +84,7 @@ class Factbase::Term
84
84
  def exists(fact)
85
85
  assert_args(1)
86
86
  k = @operands[0].to_s
87
- !fact[k].empty?
87
+ !fact[k].nil?
88
88
  end
89
89
 
90
90
  def absent(fact)
@@ -97,8 +97,9 @@ class Factbase::Term
97
97
  assert_args(2)
98
98
  k = @operands[0].to_s
99
99
  v = fact[k]
100
- return false if v.empty?
101
- v.include?(@operands[1])
100
+ return true if v == @operands[1]
101
+ return v.include?(@operands[1]) if v.is_a?(Array)
102
+ false
102
103
  end
103
104
 
104
105
  def lt(fact)
data/lib/factbase.rb CHANGED
@@ -22,6 +22,7 @@
22
22
 
23
23
  require 'json'
24
24
  require 'nokogiri'
25
+ require 'yaml'
25
26
 
26
27
  # Factbase.
27
28
  # Author:: Yegor Bugayenko (yegor256@gmail.com)
@@ -99,10 +100,14 @@ class Factbase
99
100
  @maps.each do |m|
100
101
  xml.f do
101
102
  m.each do |k, vv|
102
- xml.send(:"#{k}") do
103
- vv.each do |v|
104
- xml.send(:v, v)
103
+ if vv.is_a?(Array)
104
+ xml.send(:"#{k}") do
105
+ vv.each do |v|
106
+ xml.send(:v, v)
107
+ end
105
108
  end
109
+ else
110
+ xml.send(:"#{k}", vv)
106
111
  end
107
112
  end
108
113
  end
@@ -110,4 +115,10 @@ class Factbase
110
115
  end
111
116
  end.to_xml
112
117
  end
118
+
119
+ # Convert the entire factbase into YAML.
120
+ # @return [String] The factbase in YAML format
121
+ def to_yaml
122
+ YAML.dump({ 'facts' => @maps })
123
+ end
113
124
  end
@@ -33,9 +33,30 @@ class TestFact < Minitest::Test
33
33
  map = {}
34
34
  f = Factbase::Fact.new(Mutex.new, map)
35
35
  f.foo = 42
36
- assert_equal(42, f.foo)
36
+ assert_equal(42, f.foo, f.to_s)
37
37
  f.foo = 256
38
- assert_equal(42, f.foo)
39
- assert_equal([42, 256], f['foo'])
38
+ assert_equal(42, f.foo, f.to_s)
39
+ assert_equal([42, 256], f['foo'], f.to_s)
40
+ end
41
+
42
+ def test_fails_when_empty
43
+ f = Factbase::Fact.new(Mutex.new, {})
44
+ assert_raises do
45
+ f.something
46
+ end
47
+ end
48
+
49
+ def test_fails_when_not_found
50
+ f = Factbase::Fact.new(Mutex.new, {})
51
+ f.first = 42
52
+ assert_raises do
53
+ f.second
54
+ end
55
+ end
56
+
57
+ def test_set_by_name
58
+ f = Factbase::Fact.new(Mutex.new, {})
59
+ f.send('foo=', 42)
60
+ assert_equal(42, f.foo, f.to_s)
40
61
  end
41
62
  end
@@ -92,6 +92,7 @@ class TestSyntax < Minitest::Test
92
92
  '(foo x y z (',
93
93
  '(foo x y (z t (f 42 ',
94
94
  ')foo ) y z)',
95
+ '(x "")',
95
96
  ")y 42 'Hey you)",
96
97
  ')',
97
98
  '"'
@@ -31,14 +31,16 @@ class TestTerm < Minitest::Test
31
31
  def test_simple_matching
32
32
  t = Factbase::Term.new(:eq, ['foo', 42])
33
33
  assert(t.matches?(fact('foo' => [42])))
34
- assert(!t.matches?(fact('foo' => ['Hello!'])))
34
+ assert(!t.matches?(fact('foo' => 'Hello!')))
35
35
  assert(!t.matches?(fact('bar' => ['Hello!'])))
36
36
  end
37
37
 
38
38
  def test_eq_matching
39
39
  t = Factbase::Term.new(:eq, ['foo', 42])
40
+ assert(t.matches?(fact('foo' => 42)))
40
41
  assert(t.matches?(fact('foo' => [10, 5, 6, -8, 'hey', 42, 9, 'fdsf'])))
41
42
  assert(!t.matches?(fact('foo' => [100])))
43
+ assert(!t.matches?(fact('foo' => [])))
42
44
  end
43
45
 
44
46
  def test_lt_matching
@@ -61,7 +63,7 @@ class TestTerm < Minitest::Test
61
63
  def test_not_exists_matching
62
64
  t = Factbase::Term.new(:not, [Factbase::Term.new(:eq, ['foo', 100])])
63
65
  assert(t.matches?(fact('foo' => [42, 12, -90])))
64
- assert(!t.matches?(fact('foo' => [100])))
66
+ assert(!t.matches?(fact('foo' => 100)))
65
67
  end
66
68
 
67
69
  def test_or_matching
@@ -23,6 +23,7 @@
23
23
  require 'minitest/autorun'
24
24
  require 'json'
25
25
  require 'nokogiri'
26
+ require 'yaml'
26
27
  require_relative '../lib/factbase'
27
28
 
28
29
  # Factbase main module test.
@@ -53,7 +54,7 @@ class TestFactbase < Minitest::Test
53
54
  File.write(f.path, f1.export)
54
55
  f2.import(File.read(f.path))
55
56
  end
56
- assert_equal(1, f2.query('(eq foo 42)').to_a.count)
57
+ assert_equal(1, f2.query('(eq foo 42)').extend(Enumerable).to_a.count)
57
58
  end
58
59
 
59
60
  def test_to_json
@@ -75,4 +76,17 @@ class TestFactbase < Minitest::Test
75
76
  assert(!xml.xpath('/fb[count(f) = 2]').empty?)
76
77
  assert(!xml.xpath('/fb/f/foo[v="42"]').empty?)
77
78
  end
79
+
80
+ def test_to_yaml
81
+ fb = Factbase.new
82
+ f = fb.insert
83
+ f.foo = 42
84
+ f.foo = 256
85
+ fb.insert
86
+ yaml = YAML.load(fb.to_yaml)
87
+ assert_equal(2, yaml['facts'].size)
88
+ assert_equal(42, yaml['facts'][0]['foo'][0])
89
+ assert_equal(256, yaml['facts'][0]['foo'][1])
90
+ assert_equal(2, yaml['facts'][1]['id'])
91
+ end
78
92
  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.0.7
4
+ version: 0.0.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yegor Bugayenko
@@ -38,6 +38,20 @@ dependencies:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: '1.10'
41
+ - !ruby/object:Gem::Dependency
42
+ name: yaml
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '0.3'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '0.3'
41
55
  description: Fact base in memory and on disc
42
56
  email: yegor256@gmail.com
43
57
  executables: []