rbprolog 0.1.0 → 0.2.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 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