rbprolog 0.0.2 → 0.1.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 +4 -4
- data/lib/rbprolog/context.rb +17 -7
- data/lib/rbprolog/deduction.rb +8 -19
- data/lib/rbprolog/rule.rb +9 -9
- data/lib/rbprolog/version.rb +1 -1
- data/lib/rbprolog.rb +23 -13
- data/rbprolog.gemspec +0 -2
- data/test/test_rbprolog.rb +20 -0
- metadata +3 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: dda78e71e7f2217c87e9a9c52e81be412f3adc15
|
4
|
+
data.tar.gz: 281cf156ef8af5401c8f6365bd7e10f7345d093e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 70aab09d55abbe7a3ce29d0ceabd55dd149ed3cae2395dd16a038c17de64ec15ebcd7a3f3ddfed2fd4d73dab2a92d9304206ade6bf0aa900d9d010e9718337eb
|
7
|
+
data.tar.gz: 441e56975d5aecb431d0aa39801734052949e88a0ea4806d1d7b8a7f0d19ec32c99700d85ab19a0767dd5c2034d7e9342616f504013cd2fb9ce825608aa14093
|
data/lib/rbprolog/context.rb
CHANGED
@@ -2,6 +2,11 @@ module Rbprolog
|
|
2
2
|
class Context
|
3
3
|
attr_accessor :binds
|
4
4
|
|
5
|
+
def initialize
|
6
|
+
@scopes = []
|
7
|
+
@binds = {}
|
8
|
+
end
|
9
|
+
|
5
10
|
def match?(v1, v2)
|
6
11
|
v1 = deduce(v1)
|
7
12
|
Var === v1 || Var === v2 || v1 == v2
|
@@ -16,10 +21,18 @@ module Rbprolog
|
|
16
21
|
end
|
17
22
|
end
|
18
23
|
|
24
|
+
def [](sym)
|
25
|
+
@binds[sym]
|
26
|
+
end
|
27
|
+
|
28
|
+
def []=(sym, value)
|
29
|
+
@binds[sym] = value
|
30
|
+
end
|
31
|
+
|
19
32
|
def deduce(v)
|
20
33
|
if Var === v
|
21
34
|
unless @binds[v.sym]
|
22
|
-
@
|
35
|
+
@scopes.last << v.sym
|
23
36
|
@binds[v.sym] = Var.new(v.sym)
|
24
37
|
end
|
25
38
|
|
@@ -30,16 +43,13 @@ module Rbprolog
|
|
30
43
|
end
|
31
44
|
|
32
45
|
def scope(predicate, &block)
|
33
|
-
@
|
34
|
-
@stacks.push([])
|
35
|
-
|
36
|
-
@binds ||= {}
|
46
|
+
@scopes.push([])
|
37
47
|
|
38
48
|
mirror = @binds.clone
|
39
49
|
|
40
|
-
result = yield
|
50
|
+
result = yield predicate.args.map {|arg| self.deduce(arg)}
|
41
51
|
|
42
|
-
@
|
52
|
+
@scopes.pop.each {|bind| @binds.delete bind}
|
43
53
|
@binds.merge!(mirror)
|
44
54
|
|
45
55
|
result
|
data/lib/rbprolog/deduction.rb
CHANGED
@@ -1,35 +1,24 @@
|
|
1
1
|
module Rbprolog
|
2
2
|
class Deduction
|
3
|
-
include Enumerable
|
4
|
-
|
5
3
|
attr_accessor :args, :sym
|
6
4
|
|
7
|
-
def initialize(
|
8
|
-
@logic = logic
|
5
|
+
def initialize(sym, *args)
|
9
6
|
@sym = sym
|
10
|
-
|
11
7
|
@args = args
|
12
8
|
end
|
13
9
|
|
14
|
-
def each
|
15
|
-
each_deduce(Context.new, @logic.rules, []) do |hash|
|
16
|
-
yield hash
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
10
|
def each_deduce(context, rules, id)
|
21
|
-
print "#{"\t" * id.size}#{id.join('.')} #{@sym}?(#{@args.
|
11
|
+
print "#{"\t" * id.size}#{id.join('.')} #{@sym}?(#{@args.join(', ')})"
|
22
12
|
|
23
|
-
rules.select {|rule| rule.sym == @sym}.each_with_index do |rule,
|
24
|
-
context.scope(self) do
|
25
|
-
puts " => #{@sym}?(#{
|
13
|
+
rules.select {|rule| rule.sym == @sym}.each_with_index do |rule, rule_index|
|
14
|
+
context.scope(self) do |scoped_args|
|
15
|
+
puts " => #{@sym}?(#{scoped_args.join(', ')})" if rule_index == 0
|
26
16
|
|
27
|
-
rule.
|
17
|
+
rule.each_match(rules, *scoped_args, id + [rule_index]) do |hash|
|
28
18
|
context.scope(self) do
|
29
19
|
rule.args.each_with_index do |rule_arg, rule_arg_index|
|
30
|
-
|
31
|
-
|
32
|
-
context.binds[deduced_arg.sym] = Var === rule_arg ? hash[rule_arg.sym] : rule_arg
|
20
|
+
if Var === scoped_args[rule_arg_index]
|
21
|
+
context[scoped_args[rule_arg_index].sym] = Var === rule_arg ? hash[rule_arg.sym] : rule_arg
|
33
22
|
end
|
34
23
|
end
|
35
24
|
|
data/lib/rbprolog/rule.rb
CHANGED
@@ -10,13 +10,13 @@ module Rbprolog
|
|
10
10
|
@deductions = [deductions].flatten
|
11
11
|
end
|
12
12
|
|
13
|
-
def
|
14
|
-
print "#{"\t" * id.size}#{id.join('.')} #{@sym}(#{@args.
|
13
|
+
def each_match(rules, *args, id)
|
14
|
+
print "#{"\t" * id.size}#{id.join('.')} #{@sym}(#{@args.join(', ')}).deduce(#{args.join(', ')})"
|
15
15
|
|
16
16
|
context = Context.new
|
17
|
-
context.scope(self) do
|
17
|
+
context.scope(self) do |scoped_args|
|
18
18
|
if self.match!(context, args)
|
19
|
-
puts " => #{@sym}(#{@args.map {|arg| context.deduce(arg)
|
19
|
+
puts " => #{@sym}(#{@args.map {|arg| context.deduce(arg)}.join(', ')})"
|
20
20
|
deduce_deductions(context, rules, *@deductions, id) do
|
21
21
|
yield context.binds
|
22
22
|
end
|
@@ -41,17 +41,17 @@ module Rbprolog
|
|
41
41
|
if deductions.empty?
|
42
42
|
yield
|
43
43
|
else
|
44
|
-
|
45
|
-
if Deduction ===
|
46
|
-
|
44
|
+
deduction = deductions.shift
|
45
|
+
if Deduction === deduction
|
46
|
+
deduction.each_deduce(context, rules, id + [@deductions.size - deductions.size - 1]) do |hash|
|
47
47
|
deduce_deductions(context, rules, *deductions, id, &block)
|
48
48
|
end
|
49
49
|
else
|
50
50
|
@logic.send(:define_singleton_method, :const_missing) do |sym|
|
51
|
-
context
|
51
|
+
context[sym]
|
52
52
|
end
|
53
53
|
|
54
|
-
|
54
|
+
deduction.call && deduce_deductions(context, rules, *deductions, id, &block)
|
55
55
|
end
|
56
56
|
|
57
57
|
end
|
data/lib/rbprolog/version.rb
CHANGED
data/lib/rbprolog.rb
CHANGED
@@ -7,18 +7,23 @@ require_relative 'rbprolog/var'
|
|
7
7
|
module Rbprolog
|
8
8
|
def self.included(mod)
|
9
9
|
class << mod
|
10
|
-
attr_accessor :rules, :syms
|
11
|
-
|
12
10
|
include ClassMethods
|
11
|
+
attr_accessor :rules, :syms
|
13
12
|
end
|
14
13
|
end
|
15
14
|
|
16
|
-
def initialize(&block)
|
17
|
-
|
15
|
+
def initialize(string = nil, &block)
|
16
|
+
if string || block
|
17
|
+
self.extend(Rbprolog)
|
18
|
+
|
19
|
+
self.singleton_class.keywords(*self.class.syms)
|
20
|
+
self.singleton_class.class_eval(string) if string
|
21
|
+
self.singleton_class.class_eval(&block) if block
|
22
|
+
end
|
18
23
|
end
|
19
24
|
|
20
25
|
def rules
|
21
|
-
self.class.rules + (
|
26
|
+
self.class.rules + (self.singleton_class.rules || [])
|
22
27
|
end
|
23
28
|
|
24
29
|
module ClassMethods
|
@@ -37,7 +42,7 @@ module Rbprolog
|
|
37
42
|
if self.syms.include? sym
|
38
43
|
Hash === args.last ? rule(sym, *args) : rule(sym, *args, :if => [])
|
39
44
|
elsif self.syms.include? sym.to_s.chomp('?').to_sym
|
40
|
-
Deduction.new(
|
45
|
+
Deduction.new(sym.to_s.chomp('?').to_sym, *args)
|
41
46
|
else
|
42
47
|
super
|
43
48
|
end
|
@@ -48,14 +53,19 @@ module Rbprolog
|
|
48
53
|
self.rules << Rule.new(sym, *args, options[:if])
|
49
54
|
|
50
55
|
unless method_defined?(sym)
|
51
|
-
#FIXME only allow fact for now
|
52
|
-
define_method(sym) do |*args|
|
53
|
-
@rules ||= []
|
54
|
-
@rules << Rule.new(sym, *args, [])
|
55
|
-
end
|
56
|
-
|
57
56
|
define_method("#{sym}!") do |*args|
|
58
|
-
Deduction.new(
|
57
|
+
deduction = Deduction.new(sym, *args)
|
58
|
+
|
59
|
+
deduction.extend(Enumerable)
|
60
|
+
|
61
|
+
rules = self.rules
|
62
|
+
deduction.define_singleton_method(:each) do |&block|
|
63
|
+
each_deduce(Context.new, rules, []) do |hash|
|
64
|
+
block.call hash
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
deduction
|
59
69
|
end
|
60
70
|
|
61
71
|
define_method("#{sym}?") do |*args|
|
data/rbprolog.gemspec
CHANGED
@@ -18,8 +18,6 @@ Gem::Specification.new do |spec|
|
|
18
18
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
19
|
spec.require_paths = ["lib"]
|
20
20
|
|
21
|
-
spec.metadata = { "Source Code" => "https://github.com/rli9/rbprolog" }
|
22
|
-
|
23
21
|
spec.add_development_dependency "bundler", "~> 1.3"
|
24
22
|
spec.add_development_dependency "rake"
|
25
23
|
end
|
data/test/test_rbprolog.rb
CHANGED
@@ -37,6 +37,26 @@ class TestRbprolog < Test::Unit::TestCase
|
|
37
37
|
assert_equal ['p1', 'p2', 'p3', 'p4'], l.friends!('p1', Rbprolog::Var.new(:W)).map {|hash| hash[:W]}.uniq.sort
|
38
38
|
end
|
39
39
|
|
40
|
+
def test_logic_instance_should_allow_new_fact
|
41
|
+
l = FriendLogic.new do
|
42
|
+
likes 'p5', 's1'
|
43
|
+
end
|
44
|
+
|
45
|
+
assert_equal true, l.likes?('p5', 's1')
|
46
|
+
assert_equal false, l.likes?('p5', 's2')
|
47
|
+
assert_equal true, l.friends?('p5', 'p3')
|
48
|
+
assert_equal false, l.friends?('p5', 'p2')
|
49
|
+
end
|
50
|
+
|
51
|
+
def test_logic_instance_should_allow_new_rule
|
52
|
+
l = FriendLogic.new %q{
|
53
|
+
friends 'p2', X, :if => likes?(X, 's1')
|
54
|
+
}
|
55
|
+
|
56
|
+
assert_equal true, l.friends?('p2', 'p3')
|
57
|
+
assert_equal true, l.friends?('p2', 'p1')
|
58
|
+
end
|
59
|
+
|
40
60
|
def test_logic_instances_should_be_independent
|
41
61
|
l1 = FriendLogic.new do
|
42
62
|
likes 'p5', 's1'
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rbprolog
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ruijia Li
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-07-
|
11
|
+
date: 2013-07-31 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -61,8 +61,7 @@ files:
|
|
61
61
|
homepage: https://github.com/rli9/rbprolog
|
62
62
|
licenses:
|
63
63
|
- MIT
|
64
|
-
metadata:
|
65
|
-
Source Code: https://github.com/rli9/rbprolog
|
64
|
+
metadata: {}
|
66
65
|
post_install_message:
|
67
66
|
rdoc_options: []
|
68
67
|
require_paths:
|