rbprolog 0.1.0 → 0.2.0

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
  SHA1:
3
- metadata.gz: dda78e71e7f2217c87e9a9c52e81be412f3adc15
4
- data.tar.gz: 281cf156ef8af5401c8f6365bd7e10f7345d093e
3
+ metadata.gz: d723ef7238bd43d66ba6107479b1b3ceb3f2c343
4
+ data.tar.gz: bfa0dc55e11633ec5d83ad1dcbbb02a5008dfa4c
5
5
  SHA512:
6
- metadata.gz: 70aab09d55abbe7a3ce29d0ceabd55dd149ed3cae2395dd16a038c17de64ec15ebcd7a3f3ddfed2fd4d73dab2a92d9304206ade6bf0aa900d9d010e9718337eb
7
- data.tar.gz: 441e56975d5aecb431d0aa39801734052949e88a0ea4806d1d7b8a7f0d19ec32c99700d85ab19a0767dd5c2034d7e9342616f504013cd2fb9ce825608aa14093
6
+ metadata.gz: da369f5d469d14ee459e145ac505a4b513aa3db32f1617bf5262268c08b2b19c46960bf54eff4b577afaf063c91b561a1432bfe44bed9b8a168eeb0837b3c977
7
+ data.tar.gz: 1c8216be63234451c9ac110cf1b02173198ec3491ffba96bcc6a6d5159550b82f7f819ee2c2de2753fbc4bb3ebd525ad94561d8077310eedb523b71fcfaab3f4
data/Rakefile CHANGED
@@ -1,4 +1,8 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
1
3
  require "bundler/gem_tasks"
2
4
  require 'rake/testtask'
3
5
 
4
- Rake::TestTask.new
6
+ Rake::TestTask.new do |t|
7
+ t.libs << 'lib' << 'test'
8
+ end
@@ -14,7 +14,8 @@ module Rbprolog
14
14
  context.scope(self) do |scoped_args|
15
15
  puts " => #{@sym}?(#{scoped_args.join(', ')})" if rule_index == 0
16
16
 
17
- rule.each_match(rules, *scoped_args, id + [rule_index]) do |hash|
17
+ # rules.reject is to avoid endless loop caused by self reference
18
+ rule.each_match(rules.reject {|item| item == rule}, *scoped_args, id + [rule_index]) do |hash|
18
19
  context.scope(self) do
19
20
  rule.args.each_with_index do |rule_arg, rule_arg_index|
20
21
  if Var === scoped_args[rule_arg_index]
@@ -0,0 +1,26 @@
1
+ module Rbprolog
2
+ class Evaluation
3
+ #FIXME the design is not good to have an empty array as args
4
+ attr_accessor :args
5
+
6
+ def initialize(expression)
7
+ @args = []
8
+ @expression = expression
9
+ end
10
+
11
+ def each_deduce(context, rules, id)
12
+ print "#{"\t" * id.size}#{id.join('.')} ?(#{@args.join(', ')})"
13
+
14
+ context.scope(self) do |scoped_args|
15
+ puts " => ?(#{scoped_args.join(', ')})"
16
+
17
+ kclass = Class.new
18
+ kclass.send(:define_singleton_method, :const_missing) do |sym|
19
+ context.deduce(sym)
20
+ end
21
+
22
+ yield context.binds if kclass.class_eval(@expression)
23
+ end
24
+ end
25
+ end
26
+ end
data/lib/rbprolog/rule.rb CHANGED
@@ -1,5 +1,4 @@
1
1
  module Rbprolog
2
-
3
2
  #when fail at one predicate, the output values need be reset, and remove from the parent rule/s context
4
3
  class Rule
5
4
  attr_accessor :args, :sym
@@ -7,7 +6,7 @@ module Rbprolog
7
6
  def initialize(sym, *args, deductions)
8
7
  @sym = sym
9
8
  @args = args
10
- @deductions = [deductions].flatten
9
+ @deductions = [deductions].flatten.map {|deduction| Deduction === deduction ? deduction : Evaluation.new(deduction.call)}
11
10
  end
12
11
 
13
12
  def each_match(rules, *args, id)
@@ -42,18 +41,9 @@ module Rbprolog
42
41
  yield
43
42
  else
44
43
  deduction = deductions.shift
45
- if Deduction === deduction
46
- deduction.each_deduce(context, rules, id + [@deductions.size - deductions.size - 1]) do |hash|
47
- deduce_deductions(context, rules, *deductions, id, &block)
48
- end
49
- else
50
- @logic.send(:define_singleton_method, :const_missing) do |sym|
51
- context[sym]
52
- end
53
-
54
- deduction.call && deduce_deductions(context, rules, *deductions, id, &block)
44
+ deduction.each_deduce(context, rules, id + [@deductions.size - deductions.size - 1]) do |hash|
45
+ deduce_deductions(context, rules, *deductions, id, &block)
55
46
  end
56
-
57
47
  end
58
48
  end
59
49
  end
@@ -1,3 +1,3 @@
1
1
  module Rbprolog
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0"
3
3
  end
data/lib/rbprolog.rb CHANGED
@@ -1,8 +1,54 @@
1
- require_relative "rbprolog/version"
2
- require_relative 'rbprolog/context'
3
- require_relative 'rbprolog/rule'
4
- require_relative 'rbprolog/deduction'
5
- require_relative 'rbprolog/var'
1
+ require "rbprolog/version"
2
+ require 'rbprolog/context'
3
+ require 'rbprolog/rule'
4
+ require 'rbprolog/deduction'
5
+ require 'rbprolog/evaluation'
6
+ require 'rbprolog/var'
7
+
8
+ =begin rdoc
9
+ Simulate the prolog logic processing partially by using ruby based DSL
10
+
11
+ = Representations (Conventions)
12
+ [rule - class level]
13
+ * name arg0, arg1, ..., {:if => [deduction0, deduction1, ...]}
14
+ * name: defined in the keywords
15
+ * arg: use const to present the variable, and non-const for value
16
+ * deduction: see below
17
+
18
+ [fact - class level]
19
+ * name: arg0, arg1, ...
20
+
21
+ [deduction - class level]
22
+ * name? arg0, arg1, ...
23
+ * return: true or false
24
+
25
+ [question - instance level]
26
+ * name? arg0, arg1, ...
27
+
28
+ [enumerator - instance level]
29
+ * name! arg0, arg1, ...
30
+ * Deduce all possible answers
31
+
32
+ = Example
33
+ class FriendLogic
34
+ include Rbprolog
35
+
36
+ keywords :likes, :friends
37
+
38
+ likes 'p1', 's1'
39
+ likes 'p1', 's2'
40
+ likes 'p2', 's2'
41
+ likes 'p3', 's1'
42
+ likes 'p4', X
43
+
44
+ friends 'p1', W, :if => likes?(W, 's2')
45
+ friends X, Y, :if => [likes?(X, Z), likes?(Y, Z)]
46
+ end
47
+
48
+ l = FriendLogic.new
49
+ l.likes?('p1', 's1') #=> true
50
+ l.friends?('p1', 'p4') #=> true
51
+ =end
6
52
 
7
53
  module Rbprolog
8
54
  def self.included(mod)
@@ -12,6 +58,18 @@ module Rbprolog
12
58
  end
13
59
  end
14
60
 
61
+ #
62
+ #Initialize the rbprolog instance, each instance can have its
63
+ #own fact and rules. The definition can be passed in as string or block.
64
+ #string is required when variable such as X is used.
65
+ # l = FriendLogic.new do
66
+ # likes 'p5', 's1'
67
+ # end
68
+ #or
69
+ # l = FriendLogic.new %q{
70
+ # friends 'p2', X, :if => likes?(X, 's1')
71
+ # }
72
+ #
15
73
  def initialize(string = nil, &block)
16
74
  if string || block
17
75
  self.extend(Rbprolog)
@@ -27,6 +85,7 @@ module Rbprolog
27
85
  end
28
86
 
29
87
  module ClassMethods
88
+ #Define the vocabulary of rules and facts
30
89
  def keywords(*syms)
31
90
  raise if syms.any? {|sym| sym.to_s.end_with? '?'}
32
91
 
@@ -38,6 +97,7 @@ module Rbprolog
38
97
  Var.new(sym)
39
98
  end
40
99
 
100
+ #Generate rule, fact and deduction based on conventions
41
101
  def method_missing(sym, *args)
42
102
  if self.syms.include? sym
43
103
  Hash === args.last ? rule(sym, *args) : rule(sym, *args, :if => [])
@@ -48,6 +108,7 @@ module Rbprolog
48
108
  end
49
109
  end
50
110
 
111
+ #Internal class method to install instance methods for question and enumerator
51
112
  def rule(sym, *args, options)
52
113
  self.rules ||= []
53
114
  self.rules << Rule.new(sym, *args, options[:if])
data/rbprolog.gemspec CHANGED
@@ -20,4 +20,5 @@ Gem::Specification.new do |spec|
20
20
 
21
21
  spec.add_development_dependency "bundler", "~> 1.3"
22
22
  spec.add_development_dependency "rake"
23
+ spec.add_development_dependency "simplecov"
23
24
  end
@@ -0,0 +1,29 @@
1
+ require 'test_helper'
2
+ require 'test/unit'
3
+ require 'rbprolog'
4
+
5
+ class EvaluationLogic
6
+ include Rbprolog
7
+
8
+ keywords :must, :can, :can_not, :must_not
9
+
10
+ %w(a b c).each {|t| must 'win', t}
11
+ must_not 'linux', 'd'
12
+ can_not X, Y, :if => [must?(U, Y), ->{'U != X'}]
13
+ can_not X, Y, :if => must_not?(X, Y)
14
+ #can X, Y, :if => !can_not?(X, Y)
15
+ end
16
+
17
+ class TestEvaluation < Test::Unit::TestCase
18
+ def test_evaluation
19
+ l = EvaluationLogic.new
20
+
21
+ assert_equal true, l.must?('win', 'a')
22
+ assert_equal true, l.can_not?('linux', 'd')
23
+ assert_equal true, l.can_not?('linux', 'a')
24
+ assert_equal true, l.can_not?('linux', 'b')
25
+ assert_equal true, l.can_not?('linux', 'c')
26
+
27
+ assert_equal(['a', 'b', 'c', 'd'], l.can_not!('linux', Rbprolog::Var.new(:G)).map {|hash| hash[:G]}.uniq.sort)
28
+ end
29
+ end
@@ -0,0 +1,2 @@
1
+ require 'simplecov'
2
+ SimpleCov.start
@@ -1,3 +1,4 @@
1
+ require 'test_helper'
1
2
  require 'test/unit'
2
3
  require 'rbprolog'
3
4
 
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.1.0
4
+ version: 0.2.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-31 00:00:00.000000000 Z
11
+ date: 2013-08-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -38,6 +38,20 @@ dependencies:
38
38
  - - '>='
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: simplecov
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
41
55
  description: A ruby implementation to simulate prolog partially
42
56
  email:
43
57
  - ruijia.li@gmail.com
@@ -53,10 +67,13 @@ files:
53
67
  - lib/rbprolog.rb
54
68
  - lib/rbprolog/context.rb
55
69
  - lib/rbprolog/deduction.rb
70
+ - lib/rbprolog/evaluation.rb
56
71
  - lib/rbprolog/rule.rb
57
72
  - lib/rbprolog/var.rb
58
73
  - lib/rbprolog/version.rb
59
74
  - rbprolog.gemspec
75
+ - test/test_evaluation.rb
76
+ - test/test_helper.rb
60
77
  - test/test_rbprolog.rb
61
78
  homepage: https://github.com/rli9/rbprolog
62
79
  licenses:
@@ -83,4 +100,6 @@ signing_key:
83
100
  specification_version: 4
84
101
  summary: A prolog DSL in ruby to do AI logic analysis
85
102
  test_files:
103
+ - test/test_evaluation.rb
104
+ - test/test_helper.rb
86
105
  - test/test_rbprolog.rb