cycr 0.0.8 → 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.
- data/{README.txt → README.rdoc} +33 -7
- data/Rakefile +9 -1
- data/changelog.txt +10 -0
- data/cycr.gemspec +4 -5
- data/integration/assertion.rb +35 -0
- data/{spec → integration}/client.rb +23 -1
- data/lib/cyc/assertion.rb +36 -0
- data/lib/{cycr → cyc}/builder.rb +0 -3
- data/lib/{cycr → cyc}/client.rb +79 -19
- data/lib/{cycr → cyc}/collection.rb +4 -0
- data/lib/cyc/exception.rb +43 -0
- data/lib/{cycr → cyc}/extensions.rb +0 -0
- data/lib/{cycr → cyc}/parser.rb +17 -18
- data/lib/{cycr → cyc}/sexpr.rex +10 -8
- data/lib/{cycr → cyc}/sexpr.rex.rb +6 -3
- data/lib/cyc/symbol.rb +31 -0
- data/lib/cyc/variable.rb +31 -0
- data/lib/cycr.rb +10 -1
- data/spec/parser.rb +44 -0
- metadata +23 -20
- data/lib/cycr/assertion.rb +0 -14
- data/spec/assertion.rb +0 -36
data/{README.txt → README.rdoc}
RENAMED
|
@@ -62,7 +62,7 @@ The you can start 'irb' to see it in action:
|
|
|
62
62
|
cyc = Cyc::Client.new
|
|
63
63
|
|
|
64
64
|
# check if Dog generalizes to Animal
|
|
65
|
-
cyc.genls? :Dog, :Animal # =>
|
|
65
|
+
cyc.genls? :Dog, :Animal # => true
|
|
66
66
|
|
|
67
67
|
# check if Animal generalizes to Dog
|
|
68
68
|
cyc.genls? :Animal, :Dog # => nil
|
|
@@ -90,15 +90,41 @@ The you can start 'irb' to see it in action:
|
|
|
90
90
|
|
|
91
91
|
# What is more, you might even build complex subcalls, such as:
|
|
92
92
|
cyc.genls? :Person, :HomoSapiens # => nil
|
|
93
|
-
cyc.with_any_mt{|cyc| cyc.genls? :Person, :HomoSapiens} # =>
|
|
94
|
-
|
|
95
|
-
#
|
|
93
|
+
cyc.with_any_mt{|cyc| cyc.genls? :Person, :HomoSapiens} # => true
|
|
94
|
+
|
|
95
|
+
# The assertions are parsed, as well as Cyc symbols and variables
|
|
96
|
+
keys = cyc.key_predicate_rule_index :isa
|
|
97
|
+
# => [:POS, :NEG]
|
|
98
|
+
keys[0].class
|
|
99
|
+
# => Cyc::Symbol
|
|
100
|
+
cyc.symbolp keys[0]
|
|
101
|
+
# => true
|
|
102
|
+
|
|
103
|
+
keys1 = cyc.key_predicate_rule_index :isa, keys[0]
|
|
104
|
+
# => [:ComputerRunningMt, :HumanManipulationMt, :BuyingMt, ...
|
|
105
|
+
keys2 = cyc.key_predicate_rule_index :isa, keys[0], keys1[2]
|
|
106
|
+
# => [:BACKWARD]
|
|
107
|
+
rules = cyc.gather_predicate_rule_index :isa, keys[0], keys1[2], keys2[0]
|
|
108
|
+
# => [[:implies, [:and, [:objectOfPossessionTransfer, :TheBuying, ?OBJ],
|
|
109
|
+
[:activityObjectType, :TheSelectingAProduct, ?PREFERED]],
|
|
110
|
+
[:isa, ?OBJ, ?PREFERED]] : BuyingMt]
|
|
111
|
+
cyc.assertion_p rules[0]
|
|
112
|
+
# => true
|
|
113
|
+
|
|
114
|
+
rules[0].formula[1][1][2]
|
|
115
|
+
# => ?OBJ
|
|
116
|
+
rules[0].formula[1][1][2].class
|
|
117
|
+
# => Cyc::Variable
|
|
118
|
+
# the variable cannot be checked for type, since it won't be bound
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
# If you want to see the query which is send to Cyc, just turn on
|
|
96
122
|
# debugging:
|
|
97
123
|
cyc.debug = true
|
|
98
124
|
cyc.genls? :Dog, :Anial
|
|
99
125
|
# Send: (genls? #$Dog #$Animal)
|
|
100
126
|
# Recv: 200 T
|
|
101
|
-
# =>
|
|
127
|
+
# => true
|
|
102
128
|
|
|
103
129
|
# The same way, you can turn it off:
|
|
104
130
|
cyc.debug = false
|
|
@@ -108,9 +134,9 @@ The you can start 'irb' to see it in action:
|
|
|
108
134
|
|
|
109
135
|
== LICENSE:
|
|
110
136
|
|
|
111
|
-
(The MIT License)
|
|
137
|
+
(The MIT/X11 License)
|
|
112
138
|
|
|
113
|
-
Copyright (c) 2008-
|
|
139
|
+
Copyright (c) 2008-2012 Aleksander Pohl
|
|
114
140
|
|
|
115
141
|
Permission is hereby granted, free of charge, to any person obtaining
|
|
116
142
|
a copy of this software and associated documentation files (the
|
data/Rakefile
CHANGED
|
@@ -1,7 +1,15 @@
|
|
|
1
|
-
task :default => [:
|
|
1
|
+
task :default => [:test]
|
|
2
2
|
|
|
3
3
|
$gem_name = "cycr"
|
|
4
4
|
|
|
5
|
+
desc "Run tests"
|
|
6
|
+
task :test do
|
|
7
|
+
puts "WARNING: The test have to be run with an available Cyc server"
|
|
8
|
+
sh "rspec spec/parser.rb"
|
|
9
|
+
sh "rspec integration/assertion.rb"
|
|
10
|
+
sh "rspec integration/client.rb"
|
|
11
|
+
end
|
|
12
|
+
|
|
5
13
|
desc "Build the gem"
|
|
6
14
|
task :build do
|
|
7
15
|
sh "gem build #$gem_name.gemspec"
|
data/changelog.txt
CHANGED
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
0.1.0
|
|
2
|
+
- Add license info to some files
|
|
3
|
+
- Add tests to Rakefile
|
|
4
|
+
- More specs for the client
|
|
5
|
+
- Parse variables and cyc symbols
|
|
6
|
+
- Move files to cyc dir, improve parenthesis check
|
|
7
|
+
- Better organization of tests (specs/integration separation)
|
|
8
|
+
- T atom interpreted as true value
|
|
9
|
+
0.0.9
|
|
10
|
+
- raises error for raw answer if Cyc reports error
|
|
1
11
|
0.0.8
|
|
2
12
|
- fix documentation for Cyc::Builder
|
|
3
13
|
- removal of legacy code
|
data/cycr.gemspec
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Gem::Specification.new do |s|
|
|
2
2
|
s.name = "cycr"
|
|
3
|
-
s.version = "0.0
|
|
3
|
+
s.version = "0.1.0"
|
|
4
4
|
s.date = "#{Time.now.strftime("%Y-%m-%d")}"
|
|
5
5
|
s.summary = "Ruby client for the (Open)Cyc server"
|
|
6
6
|
s.email = "apohllo@o2.pl"
|
|
@@ -10,10 +10,9 @@ Gem::Specification.new do |s|
|
|
|
10
10
|
s.has_rdoc = false
|
|
11
11
|
s.authors = ['Aleksander Pohl']
|
|
12
12
|
s.files = `git ls-files`.split("\n")
|
|
13
|
-
s.test_files = Dir.glob("spec/**/*")
|
|
14
|
-
s.rdoc_options = ["--main", "README.
|
|
13
|
+
s.test_files = Dir.glob("spec/**/*") + Dir.glob("integration/**/*")
|
|
14
|
+
s.rdoc_options = ["--main", "README.rdoc"]
|
|
15
15
|
s.has_rdoc = true
|
|
16
|
-
s.extra_rdoc_files = ["README.
|
|
16
|
+
s.extra_rdoc_files = ["README.rdoc"]
|
|
17
17
|
s.add_development_dependency("rspec", [">= 1.2.9"])
|
|
18
18
|
end
|
|
19
|
-
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
$:.unshift "lib"
|
|
2
|
+
require 'cycr'
|
|
3
|
+
|
|
4
|
+
describe Cyc::Assertion do
|
|
5
|
+
before(:all) do
|
|
6
|
+
@client = Cyc::Client.new()
|
|
7
|
+
#@client.debug = true
|
|
8
|
+
@assertion = @client.talk('(gather-predicate-extent-index #$minimizeExtent #$BaseKB)').
|
|
9
|
+
first
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
after(:all) do
|
|
13
|
+
@client.close
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
it "should have microtheory assigned" do
|
|
17
|
+
@assertion.microtheory.should_not == nil
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
it "should have formula assigned" do
|
|
21
|
+
@assertion.formula.should_not == nil
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
it "should allow to check its direction" do
|
|
25
|
+
@client.assertion_direction(@assertion).should_not == nil
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
it "should allow to check its truth" do
|
|
29
|
+
@client.assertion_truth(@assertion).should_not == nil
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
it "should allow to check its strength" do
|
|
33
|
+
@client.assertion_strength(@assertion).should_not == nil
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -25,12 +25,34 @@ describe Cyc::Client do
|
|
|
25
25
|
result.should be_a_kind_of String
|
|
26
26
|
end
|
|
27
27
|
|
|
28
|
+
it "should raise an error for raw talk if Cyc reported error" do
|
|
29
|
+
lambda {@client.raw_talk("(aaa)")}.should raise_error(Cyc::CycError)
|
|
30
|
+
end
|
|
31
|
+
|
|
28
32
|
it "should allow to talk to server and return parsed answer" do
|
|
29
|
-
result = @client.talk(
|
|
33
|
+
result = @client.talk('(genls #$Dog)')
|
|
30
34
|
result.should_not == nil
|
|
31
35
|
result.should respond_to :size
|
|
32
36
|
end
|
|
33
37
|
|
|
38
|
+
it "should not allow to send a message with unbalanced parenthesis" do
|
|
39
|
+
lambda {@client.talk("(")}.should raise_error(Cyc::UnbalancedOpeningParenthesis)
|
|
40
|
+
lambda {@client.talk("())")}.should raise_error(Cyc::UnbalancedClosingParenthesis)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
it "should parse results with assertions" do
|
|
44
|
+
@client.talk('(gather-predicate-extent-index #$minimizeExtent #$BaseKB)').should_not == nil
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
it "should return assertions as results if present in the result" do
|
|
48
|
+
@client.talk('(gather-predicate-extent-index #$minimizeExtent #$BaseKB)').
|
|
49
|
+
first.class.should == Cyc::Assertion
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
it "should return results with continuation" do
|
|
53
|
+
@client.talk('(gather-predicate-extent-index #$minimizeExtent)').size.should > 100
|
|
54
|
+
end
|
|
55
|
+
|
|
34
56
|
it "should allow multiple processes to use the client" do
|
|
35
57
|
parent_pid = Process.pid
|
|
36
58
|
if fork
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
module Cyc
|
|
2
|
+
# Author:: Aleksander Pohl (mailto:apohllo@o2.pl)
|
|
3
|
+
# License:: MIT/X11 License
|
|
4
|
+
#
|
|
5
|
+
# This class represent the Cyc assertions.
|
|
6
|
+
class Assertion
|
|
7
|
+
# The logical formula of the assertion.
|
|
8
|
+
attr_reader :formula
|
|
9
|
+
|
|
10
|
+
# The microtheory the assertion was asserted in.
|
|
11
|
+
attr_reader :microtheory
|
|
12
|
+
|
|
13
|
+
# Initialize the assertion with a +formula+ and a +microtheory+.
|
|
14
|
+
def initialize(formula,microtheory)
|
|
15
|
+
@formula = formula
|
|
16
|
+
@microtheory = microtheory
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Returns the string representation of the assertion.
|
|
20
|
+
def to_s
|
|
21
|
+
"#{@formula} : #{@microtheory}"
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# Returns the representation of the assertion understandable by Cyc.
|
|
25
|
+
def to_cyc(raw=false)
|
|
26
|
+
"(find-assertion (caar (el-to-hl '#{@formula.to_cyc(true)})) #{@microtheory.to_cyc})"
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def ==(other)
|
|
30
|
+
return true if self.object_id == other.object_id
|
|
31
|
+
return false unless other.respond_to?(:formula)
|
|
32
|
+
return false unless other.respond_to?(:microtheory)
|
|
33
|
+
self.formula == other.formula && self.microtheory == other.microtheory
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
data/lib/{cycr → cyc}/builder.rb
RENAMED
data/lib/{cycr → cyc}/client.rb
RENAMED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
require 'net/telnet'
|
|
2
|
+
require 'cyc/exception'
|
|
2
3
|
|
|
3
4
|
module Cyc
|
|
4
5
|
# Author:: Aleksander Pohl (mailto:apohllo@o2.pl)
|
|
5
|
-
# License:: MIT License
|
|
6
|
+
# License:: MIT/X11 License
|
|
6
7
|
#
|
|
7
8
|
# This class is the implementation of the Cyc server client.
|
|
8
9
|
class Client
|
|
@@ -10,6 +11,7 @@ module Cyc
|
|
|
10
11
|
# to standard output
|
|
11
12
|
attr_accessor :debug
|
|
12
13
|
attr_reader :host, :port
|
|
14
|
+
|
|
13
15
|
# Creates new Client.
|
|
14
16
|
def initialize(host="localhost",port="3601",debug=false)
|
|
15
17
|
@debug = debug
|
|
@@ -34,7 +36,6 @@ module Cyc
|
|
|
34
36
|
# If the block is given, the command is guarded by assertion, that
|
|
35
37
|
# it will be performed, even if the connection was reset.
|
|
36
38
|
def connection
|
|
37
|
-
#puts "#{@pid} #{Process.pid}"
|
|
38
39
|
if @conn.nil? or @pid != Process.pid
|
|
39
40
|
reconnect
|
|
40
41
|
end
|
|
@@ -52,6 +53,7 @@ module Cyc
|
|
|
52
53
|
|
|
53
54
|
protected :connection, :reconnect
|
|
54
55
|
|
|
56
|
+
# Clears the microtheory cache.
|
|
55
57
|
def clear_cache
|
|
56
58
|
@mts_cache = {}
|
|
57
59
|
end
|
|
@@ -62,32 +64,58 @@ module Cyc
|
|
|
62
64
|
@conn = nil
|
|
63
65
|
end
|
|
64
66
|
|
|
65
|
-
# Sends message +msg+
|
|
66
|
-
# returns the parsed answer.
|
|
67
|
+
# Sends message +msg+ to the Cyc server and returns a parsed answer.
|
|
67
68
|
def talk(msg, options={})
|
|
68
69
|
send_message(msg)
|
|
69
70
|
receive_answer(options)
|
|
70
71
|
end
|
|
71
72
|
|
|
72
|
-
# Sends message +msg+
|
|
73
|
+
# Sends message +msg+ to the Cyc server and
|
|
73
74
|
# returns the raw answer (i.e. not parsed).
|
|
74
75
|
def raw_talk(msg, options={})
|
|
75
76
|
send_message(msg)
|
|
76
77
|
receive_raw_answer(options)
|
|
77
78
|
end
|
|
78
79
|
|
|
79
|
-
#
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
80
|
+
# Scans the :message: to find out if the parenthesis are matched.
|
|
81
|
+
# Raises UnbalancedClosingParenthesis exception if there is not matched closing
|
|
82
|
+
# parenthesis. The message of the exception contains the string with the
|
|
83
|
+
# unmatched parenthesis highlighted.
|
|
84
|
+
# Raises UnbalancedOpeningParenthesis exception if there is not matched opening
|
|
85
|
+
# parenthesis.
|
|
86
|
+
def check_parenthesis(message)
|
|
87
|
+
count = 0
|
|
88
|
+
position = 0
|
|
89
|
+
message.scan(/./) do |char|
|
|
90
|
+
position += 1
|
|
91
|
+
next if char !~ /\(|\)/
|
|
92
|
+
count += (char == "(" ? 1 : -1)
|
|
93
|
+
if count < 0
|
|
94
|
+
raise UnbalancedClosingParenthesis.
|
|
95
|
+
new((position > 1 ? message[0..position-2] : "") +
|
|
96
|
+
"<error>)</error>" + message[position..-1])
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
raise UnbalancedOpeningParenthesis.new(count) if count > 0
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
# Sends a raw message to the Cyc server. The user is
|
|
103
|
+
# responsible for receiving the answer by calling
|
|
104
|
+
# +receive_answer+ or +receive_raw_answer+.
|
|
105
|
+
def send_message(message)
|
|
106
|
+
position = 0
|
|
107
|
+
check_parenthesis(message)
|
|
108
|
+
@last_message = message
|
|
109
|
+
puts "Send: #{message}" if @debug
|
|
110
|
+
connection{|c| c.puts(message)}
|
|
84
111
|
end
|
|
85
112
|
|
|
113
|
+
# Receives and parses an answer for a message from the Cyc server.
|
|
86
114
|
def receive_answer(options={})
|
|
87
115
|
receive_raw_answer do |answer|
|
|
88
116
|
begin
|
|
89
117
|
result = @parser.parse(answer,options[:stack])
|
|
90
|
-
rescue
|
|
118
|
+
rescue ContinueParsing => ex
|
|
91
119
|
result = ex.stack
|
|
92
120
|
current_result = result
|
|
93
121
|
last_message = @last_message
|
|
@@ -97,20 +125,23 @@ module Cyc
|
|
|
97
125
|
current_result = receive_answer(options) || []
|
|
98
126
|
result.concat(current_result)
|
|
99
127
|
end
|
|
128
|
+
rescue CycError => ex
|
|
129
|
+
puts ex.to_s
|
|
130
|
+
return nil
|
|
100
131
|
end
|
|
101
132
|
return result
|
|
102
133
|
end
|
|
103
134
|
end
|
|
104
135
|
|
|
105
|
-
#
|
|
106
|
-
# the answer is yield to the block, otherwise the
|
|
136
|
+
# Receives raw answer from server. If a +block+ is given
|
|
137
|
+
# the answer is yield to the block, otherwise the answer is returned.
|
|
107
138
|
def receive_raw_answer(options={})
|
|
108
139
|
answer = connection{|c| c.waitfor(/./)}
|
|
109
140
|
puts "Recv: #{answer}" if @debug
|
|
110
141
|
if answer.nil?
|
|
111
|
-
raise "Unknwon error occured. " +
|
|
142
|
+
raise CycError.new("Unknwon error occured. " +
|
|
112
143
|
"Check the submitted query in detail:\n" +
|
|
113
|
-
@last_message
|
|
144
|
+
@last_message)
|
|
114
145
|
end
|
|
115
146
|
while not answer =~ /\n/ do
|
|
116
147
|
next_answer = connection{|c| c.waitfor(/./)}
|
|
@@ -133,16 +164,45 @@ module Cyc
|
|
|
133
164
|
end
|
|
134
165
|
else
|
|
135
166
|
unless $2.nil?
|
|
136
|
-
|
|
137
|
-
@last_message
|
|
167
|
+
raise CycError.new($2.sub(/^"/,"").sub(/"$/,"") + "\n" + @last_message)
|
|
138
168
|
else
|
|
139
|
-
|
|
169
|
+
raise CycError.new("Unknown error! #{answer}")
|
|
140
170
|
end
|
|
141
171
|
nil
|
|
142
172
|
end
|
|
143
173
|
end
|
|
144
174
|
|
|
145
|
-
|
|
175
|
+
# This hook allows for direct call on the Client class, that
|
|
176
|
+
# are translated into corresponding calls for Cyc server.
|
|
177
|
+
#
|
|
178
|
+
# E.g. if users initializes the client and calls some Ruby method
|
|
179
|
+
# cyc = Cyc::Client.new
|
|
180
|
+
# cyc.genls? :Dog, :Animal
|
|
181
|
+
#
|
|
182
|
+
# He/She returns a parsed answer from the server:
|
|
183
|
+
# => "T"
|
|
184
|
+
#
|
|
185
|
+
# Since dashes are not allowed in Ruby method names they are replaced
|
|
186
|
+
# with underscores:
|
|
187
|
+
#
|
|
188
|
+
# cyc.min_genls :Dog
|
|
189
|
+
#
|
|
190
|
+
# is translated into:
|
|
191
|
+
#
|
|
192
|
+
# (min-genls #$Dog)
|
|
193
|
+
#
|
|
194
|
+
# As you see the Ruby symbols are translated into Cyc terms (not Cyc symbols!).
|
|
195
|
+
#
|
|
196
|
+
# It is also possible to nest the calls to build more complex functions:
|
|
197
|
+
#
|
|
198
|
+
# cyc.with_any_mt do |cyc|
|
|
199
|
+
# cyc.min_genls :Dog
|
|
200
|
+
# end
|
|
201
|
+
#
|
|
202
|
+
# is translated into:
|
|
203
|
+
#
|
|
204
|
+
# (with-any-mt (min-genls #$Dog))
|
|
205
|
+
#
|
|
146
206
|
def method_missing(name,*args,&block)
|
|
147
207
|
@builder.reset
|
|
148
208
|
@builder.send(name,*args,&block)
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
module Cyc
|
|
2
|
+
# Author:: Aleksander Pohl (mailto:apohllo@o2.pl)
|
|
3
|
+
# License:: MIT/X11 License
|
|
4
|
+
#
|
|
5
|
+
# Base class for exceptions raised by the library.
|
|
6
|
+
class CycError < RuntimeError
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
# Error raised if the message sent to the server has
|
|
10
|
+
# more opening parentheses than closing parentheses.
|
|
11
|
+
class UnbalancedOpeningParenthesis < CycError
|
|
12
|
+
# The number of unbalanced opening parentheses.
|
|
13
|
+
attr_reader :count
|
|
14
|
+
|
|
15
|
+
# Initialize the exception with the +count+ of unbalanced
|
|
16
|
+
# opening parentheses.
|
|
17
|
+
def initialize(count)
|
|
18
|
+
super("There are #{count} unbalanced opening parentheses")
|
|
19
|
+
@count = count
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Error raised if the message sent to the server has
|
|
24
|
+
# more closing parentheses than opening parentheses.
|
|
25
|
+
class UnbalancedClosingParenthesis < CycError
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Exception raised by the parser if there is contents
|
|
29
|
+
# that cannot be parsed.
|
|
30
|
+
class ParserError < CycError
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Exception raised when there is a continuation sign,
|
|
34
|
+
# at the end of the parsed message.
|
|
35
|
+
class ContinueParsing < ParserError
|
|
36
|
+
attr_reader :stack
|
|
37
|
+
|
|
38
|
+
def initialize(stack)
|
|
39
|
+
@stack = stack
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
end
|
|
File without changes
|
data/lib/{cycr → cyc}/parser.rb
RENAMED
|
@@ -1,20 +1,15 @@
|
|
|
1
1
|
module Cyc
|
|
2
|
+
# Author:: Aleksander Pohl (mailto:apohllo@o2.pl)
|
|
3
|
+
# License:: MIT/X11 License
|
|
4
|
+
#
|
|
5
|
+
# The class used to parse the answer of the Cyc server.
|
|
2
6
|
class Parser
|
|
3
|
-
# Exception raised when there is a continuation sign,
|
|
4
|
-
# at the end of the parsed message.
|
|
5
|
-
class ContinueParsing < RuntimeError
|
|
6
|
-
attr_reader :stack
|
|
7
|
-
|
|
8
|
-
def initialize(stack)
|
|
9
|
-
@stack = stack
|
|
10
|
-
end
|
|
11
|
-
end
|
|
12
|
-
|
|
13
7
|
def initialize
|
|
14
8
|
@lexer = SExpressionLexer.new
|
|
15
9
|
end
|
|
16
10
|
|
|
17
|
-
# Parses message received from server.
|
|
11
|
+
# Parses message received from server. Accepts
|
|
12
|
+
# +message+ to parse and a +stack+ with a partial parse result.
|
|
18
13
|
def parse(message,stack=nil)
|
|
19
14
|
@lexer.scan_str(message)
|
|
20
15
|
stack ||= [[]]
|
|
@@ -27,12 +22,18 @@ module Cyc
|
|
|
27
22
|
top = stack.pop
|
|
28
23
|
stack[-1].push top
|
|
29
24
|
when :atom
|
|
30
|
-
|
|
31
|
-
|
|
25
|
+
if token[1] == "T"
|
|
26
|
+
stack[-1] << true
|
|
27
|
+
else
|
|
28
|
+
# FIXME find way to differentiate strings and atoms
|
|
29
|
+
stack[-1] << token[1]
|
|
30
|
+
end
|
|
32
31
|
when :cyc_symbol
|
|
32
|
+
stack[-1] << ::Cyc::Symbol.new(token[1][1..-1])
|
|
33
|
+
when :variable
|
|
34
|
+
stack[-1] << ::Cyc::Variable.new(token[1][1..-1])
|
|
35
|
+
when :term
|
|
33
36
|
stack[-1] << token[1][2..-1].to_sym
|
|
34
|
-
when :symbol
|
|
35
|
-
stack[-1] << token[1][3..-1].to_sym
|
|
36
37
|
when :string
|
|
37
38
|
stack[-1] << token[1]
|
|
38
39
|
when :open_as
|
|
@@ -57,9 +58,7 @@ module Cyc
|
|
|
57
58
|
rescue ContinueParsing => ex
|
|
58
59
|
raise
|
|
59
60
|
rescue Exception => ex
|
|
60
|
-
|
|
61
|
-
puts ex
|
|
62
|
-
nil
|
|
61
|
+
raise ParserError.new("Exception #{ex} occurred when parsing message '#{message}'.")
|
|
63
62
|
end
|
|
64
63
|
end
|
|
65
64
|
end
|
data/lib/{cycr → cyc}/sexpr.rex
RENAMED
|
@@ -7,8 +7,9 @@ macro
|
|
|
7
7
|
LINE_TERMINATOR \r|\n|\r\n
|
|
8
8
|
INPUT_CHARACTER [^\r\n\"\(\):& ]
|
|
9
9
|
WHITE_SPACE [\ \t\f\r\n] | \r\n
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
CYC_SYMBOL :[^<>\r\n\"\(\):&\?\#\ ]+
|
|
11
|
+
VARIABLE \?[^<>\r\n\"\(\):&\?\#\ ]+
|
|
12
|
+
TERM \#\$[a-zA-Z0-9:_-]+
|
|
12
13
|
ATOM [^\r\n\"\(\):&\ ]+
|
|
13
14
|
OPEN_PAR \(
|
|
14
15
|
CLOSE_PAR \)
|
|
@@ -27,13 +28,14 @@ rule
|
|
|
27
28
|
{CLOSE_LIST_QUOTE} { [:close_quote,text] }
|
|
28
29
|
{DOT}{DOT}{DOT} { [:continuation] }
|
|
29
30
|
# keywords
|
|
30
|
-
{OPEN_PAR}
|
|
31
|
-
{CLOSE_PAR}
|
|
32
|
-
NIL
|
|
31
|
+
{OPEN_PAR} { [:open_par,text] }
|
|
32
|
+
{CLOSE_PAR} { [:close_par,text] }
|
|
33
|
+
NIL { [:nil,text] }
|
|
33
34
|
# identifiers
|
|
34
|
-
{
|
|
35
|
-
{
|
|
36
|
-
{
|
|
35
|
+
{CYC_SYMBOL} { [:cyc_symbol,text] }
|
|
36
|
+
{VARIABLE} { [:variable,text] }
|
|
37
|
+
{TERM} { [:term,text] }
|
|
38
|
+
{ATOM} { [:atom,text] }
|
|
37
39
|
# literals
|
|
38
40
|
{QUOTE} { state = :STRING; @str = ""; [:in_string] }
|
|
39
41
|
{ASSERTION_SEP} { [:assertion_sep]}
|
|
@@ -73,11 +73,14 @@ class SExpressionLexer
|
|
|
73
73
|
when (text = ss.scan(/NIL/))
|
|
74
74
|
@rex_tokens.push action { [:nil,text] }
|
|
75
75
|
|
|
76
|
-
when (text = ss.scan(/:[^<>\r\n\"\(\)
|
|
77
|
-
@rex_tokens.push action { [:
|
|
76
|
+
when (text = ss.scan(/:[^<>\r\n\"\(\):&\?\#\ ]+/))
|
|
77
|
+
@rex_tokens.push action { [:cyc_symbol,text] }
|
|
78
|
+
|
|
79
|
+
when (text = ss.scan(/\?[^<>\r\n\"\(\):&\?\#\ ]+/))
|
|
80
|
+
@rex_tokens.push action { [:variable,text] }
|
|
78
81
|
|
|
79
82
|
when (text = ss.scan(/\#\$[a-zA-Z0-9:_-]+/))
|
|
80
|
-
@rex_tokens.push action { [:
|
|
83
|
+
@rex_tokens.push action { [:term,text] }
|
|
81
84
|
|
|
82
85
|
when (text = ss.scan(/[^\r\n\"\(\):&\ ]+/))
|
|
83
86
|
@rex_tokens.push action { [:atom,text] }
|
data/lib/cyc/symbol.rb
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
module Cyc
|
|
2
|
+
# Author:: Aleksander Pohl (mailto:apohllo@o2.pl)
|
|
3
|
+
# License:: MIT/X11 License
|
|
4
|
+
#
|
|
5
|
+
# This class represent the Cyc symbol.
|
|
6
|
+
class Symbol
|
|
7
|
+
# The name of the symbol.
|
|
8
|
+
attr_reader :name
|
|
9
|
+
|
|
10
|
+
# Initialize the symbol with its +name+.
|
|
11
|
+
def initialize(name)
|
|
12
|
+
@name = name
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# String representation of the symbol.
|
|
16
|
+
def to_s
|
|
17
|
+
self.to_cyc
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# Representation of the symbol understandable by Cyc.
|
|
21
|
+
def to_cyc(raw=false)
|
|
22
|
+
":#{@name}"
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Two symbols are equal if they have the same name.
|
|
26
|
+
def ==(other)
|
|
27
|
+
return false if other.class != self.class
|
|
28
|
+
self.name == other.name
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
data/lib/cyc/variable.rb
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
module Cyc
|
|
2
|
+
# Author:: Aleksander Pohl (mailto:apohllo@o2.pl)
|
|
3
|
+
# License:: MIT/X11 License
|
|
4
|
+
#
|
|
5
|
+
# This class represent the Cyc variable.
|
|
6
|
+
class Variable
|
|
7
|
+
# The name of the variable.
|
|
8
|
+
attr_reader :name
|
|
9
|
+
|
|
10
|
+
# Initialize the variable with its +name+.
|
|
11
|
+
def initialize(name)
|
|
12
|
+
@name = name
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# String representation of the variable.
|
|
16
|
+
def to_s
|
|
17
|
+
self.to_cyc
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# Representation of the variable understandable by Cyc.
|
|
21
|
+
def to_cyc(raw=false)
|
|
22
|
+
"?#{@name}"
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Two variables are equal if they have the same name.
|
|
26
|
+
def ==(other)
|
|
27
|
+
return false if other.class != self.class
|
|
28
|
+
self.name == other.name
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
data/lib/cycr.rb
CHANGED
|
@@ -1 +1,10 @@
|
|
|
1
|
-
|
|
1
|
+
require 'cyc/exception'
|
|
2
|
+
require 'cyc/assertion'
|
|
3
|
+
require 'cyc/builder'
|
|
4
|
+
require 'cyc/client'
|
|
5
|
+
require 'cyc/collection'
|
|
6
|
+
require 'cyc/extensions'
|
|
7
|
+
require 'cyc/parser'
|
|
8
|
+
require 'cyc/sexpr.rex'
|
|
9
|
+
require 'cyc/symbol'
|
|
10
|
+
require 'cyc/variable'
|
data/spec/parser.rb
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
$:.unshift "lib"
|
|
2
|
+
require 'cycr'
|
|
3
|
+
|
|
4
|
+
describe Cyc::Parser do
|
|
5
|
+
before(:all) do
|
|
6
|
+
@parser = Cyc::Parser.new
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
it "should parse an empty list" do
|
|
10
|
+
@parser.parse('()').should == []
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
it "should parse a Cyc term" do
|
|
14
|
+
@parser.parse('#$Dog').should == :Dog
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
it "should parse nested lists" do
|
|
18
|
+
@parser.parse('(())').should == [[]]
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
it "should raise continuation exception if the message contains continuation" do
|
|
22
|
+
lambda {@parser.parse('(#$Dog ...)')}.should raise_exception(Cyc::ContinueParsing)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
it "should raise parse error if the message is invalid" do
|
|
26
|
+
lambda {@parser.parse('(#$Dog ))')}.should raise_exception(Cyc::ParserError)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
it "should parse an assertion" do
|
|
30
|
+
@parser.parse('#<AS:(#$equals):#$BaseKB>').should == Cyc::Assertion.new([:equals],:BaseKB)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
it "should parse a Cyc symbol" do
|
|
34
|
+
@parser.parse(':BACKWARD').should == Cyc::Symbol.new("BACKWARD")
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
it "should parse a variable" do
|
|
38
|
+
@parser.parse('?OBJ').should == Cyc::Variable.new("OBJ")
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
it "should parse true value" do
|
|
42
|
+
@parser.parse('T').should == true
|
|
43
|
+
end
|
|
44
|
+
end
|
metadata
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name: cycr
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
4
|
prerelease:
|
|
5
|
-
version: 0.0
|
|
5
|
+
version: 0.1.0
|
|
6
6
|
platform: ruby
|
|
7
7
|
authors:
|
|
8
8
|
- Aleksander Pohl
|
|
@@ -10,8 +10,7 @@ autorequire:
|
|
|
10
10
|
bindir: bin
|
|
11
11
|
cert_chain: []
|
|
12
12
|
|
|
13
|
-
date:
|
|
14
|
-
default_executable:
|
|
13
|
+
date: 2012-02-13 00:00:00 Z
|
|
15
14
|
dependencies:
|
|
16
15
|
- !ruby/object:Gem::Dependency
|
|
17
16
|
name: rspec
|
|
@@ -31,32 +30,35 @@ executables: []
|
|
|
31
30
|
extensions: []
|
|
32
31
|
|
|
33
32
|
extra_rdoc_files:
|
|
34
|
-
- README.
|
|
33
|
+
- README.rdoc
|
|
35
34
|
files:
|
|
36
35
|
- .gitignore
|
|
37
|
-
- README.
|
|
36
|
+
- README.rdoc
|
|
38
37
|
- Rakefile
|
|
39
38
|
- changelog.txt
|
|
40
39
|
- cycr.gemspec
|
|
40
|
+
- integration/assertion.rb
|
|
41
|
+
- integration/client.rb
|
|
42
|
+
- lib/cyc/assertion.rb
|
|
43
|
+
- lib/cyc/builder.rb
|
|
44
|
+
- lib/cyc/client.rb
|
|
45
|
+
- lib/cyc/collection.rb
|
|
46
|
+
- lib/cyc/exception.rb
|
|
47
|
+
- lib/cyc/extensions.rb
|
|
48
|
+
- lib/cyc/parser.rb
|
|
49
|
+
- lib/cyc/sexpr.rex
|
|
50
|
+
- lib/cyc/sexpr.rex.rb
|
|
51
|
+
- lib/cyc/symbol.rb
|
|
52
|
+
- lib/cyc/variable.rb
|
|
41
53
|
- lib/cycr.rb
|
|
42
|
-
-
|
|
43
|
-
- lib/cycr/builder.rb
|
|
44
|
-
- lib/cycr/client.rb
|
|
45
|
-
- lib/cycr/collection.rb
|
|
46
|
-
- lib/cycr/extensions.rb
|
|
47
|
-
- lib/cycr/parser.rb
|
|
48
|
-
- lib/cycr/sexpr.rex
|
|
49
|
-
- lib/cycr/sexpr.rex.rb
|
|
50
|
-
- spec/assertion.rb
|
|
51
|
-
- spec/client.rb
|
|
52
|
-
has_rdoc: true
|
|
54
|
+
- spec/parser.rb
|
|
53
55
|
homepage: http://github.com/apohllo/cycr
|
|
54
56
|
licenses: []
|
|
55
57
|
|
|
56
58
|
post_install_message:
|
|
57
59
|
rdoc_options:
|
|
58
60
|
- --main
|
|
59
|
-
- README.
|
|
61
|
+
- README.rdoc
|
|
60
62
|
require_paths:
|
|
61
63
|
- lib
|
|
62
64
|
required_ruby_version: !ruby/object:Gem::Requirement
|
|
@@ -74,10 +76,11 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
74
76
|
requirements: []
|
|
75
77
|
|
|
76
78
|
rubyforge_project:
|
|
77
|
-
rubygems_version: 1.5
|
|
79
|
+
rubygems_version: 1.8.5
|
|
78
80
|
signing_key:
|
|
79
81
|
specification_version: 3
|
|
80
82
|
summary: Ruby client for the (Open)Cyc server
|
|
81
83
|
test_files:
|
|
82
|
-
- spec/
|
|
83
|
-
-
|
|
84
|
+
- spec/parser.rb
|
|
85
|
+
- integration/client.rb
|
|
86
|
+
- integration/assertion.rb
|
data/lib/cycr/assertion.rb
DELETED
data/spec/assertion.rb
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
$:.unshift "lib"
|
|
2
|
-
require 'cycr'
|
|
3
|
-
|
|
4
|
-
describe Cyc::Assertion do
|
|
5
|
-
before(:all) do
|
|
6
|
-
@client = Cyc::Client.new()
|
|
7
|
-
#@client.debug = true
|
|
8
|
-
end
|
|
9
|
-
|
|
10
|
-
after(:all) do
|
|
11
|
-
@client.close
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
it "should parse results with assertions" do
|
|
15
|
-
@client.talk("(gather-predicate-extent-index \#$minimizeExtent \#$BaseKB)").should_not == nil
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
it "should return assertions as results if present in the result" do
|
|
19
|
-
@client.talk("(gather-predicate-extent-index \#$minimizeExtent \#$BaseKB)").
|
|
20
|
-
first.class.should == Cyc::Assertion
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
it "should have microtheory assigned" do
|
|
24
|
-
@client.talk("(gather-predicate-extent-index \#$minimizeExtent \#$BaseKB)").
|
|
25
|
-
first.microtheory.should_not == nil
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
it "should have formula assigned" do
|
|
29
|
-
@client.talk("(gather-predicate-extent-index \#$minimizeExtent \#$BaseKB)").
|
|
30
|
-
first.formula.should_not == nil
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
it "should return many results" do
|
|
34
|
-
@client.talk("(gather-predicate-extent-index \#$minimizeExtent)").size.should > 100
|
|
35
|
-
end
|
|
36
|
-
end
|