rbprolog 0.0.2 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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:
|