factbase 0.0.7 → 0.0.9

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: 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: []