cycr 0.0.3
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 +0 -0
- data/Rakefile +23 -0
- data/cycr.gemspec +20 -0
- data/lib/cycr/assertion.rb +14 -0
- data/lib/cycr/client.rb +208 -0
- data/lib/cycr/collection.rb +76 -0
- data/lib/cycr/constants.rb +8 -0
- data/lib/cycr/domains.lisp +584 -0
- data/lib/cycr/extensions.rb +26 -0
- data/lib/cycr/nart.rb +21 -0
- data/lib/cycr/parser.rb +63 -0
- data/lib/cycr/sexpr.flex +74 -0
- data/lib/cycr/sexpr.rex +55 -0
- data/lib/cycr/sexpr.rex.rb +136 -0
- data/lib/cycr/words_reader.lisp +204 -0
- data/lib/cycr.rb +1 -0
- data/spec/assertion.rb +36 -0
- data/spec/client.rb +39 -0
- metadata +101 -0
data/README.txt
ADDED
File without changes
|
data/Rakefile
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
task :default => [:install]
|
2
|
+
|
3
|
+
$gem_name = "cycr"
|
4
|
+
|
5
|
+
desc "Build the gem"
|
6
|
+
task :build do
|
7
|
+
sh "gem build #$gem_name.gemspec"
|
8
|
+
end
|
9
|
+
|
10
|
+
desc "Install the library at local machnie"
|
11
|
+
task :install => :build do
|
12
|
+
sh "sudo gem install #$gem_name -l"
|
13
|
+
end
|
14
|
+
|
15
|
+
desc "Uninstall the library from local machnie"
|
16
|
+
task :uninstall do
|
17
|
+
sh "sudo gem uninstall #$gem_name"
|
18
|
+
end
|
19
|
+
|
20
|
+
desc "Clean"
|
21
|
+
task :clean do
|
22
|
+
sh "rm #$gem_name*.gem"
|
23
|
+
end
|
data/cycr.gemspec
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = "cycr"
|
3
|
+
s.version = "0.0.3"
|
4
|
+
s.date = "2010-10-19"
|
5
|
+
s.summary = "Ruby client for the (Open)Cyc server"
|
6
|
+
s.email = "apohllo@o2.pl"
|
7
|
+
s.homepage = "http://www.opencyc.org"
|
8
|
+
s.require_path = "lib"
|
9
|
+
s.description = "Ruby wrapper for (Open)Cyc server and ontology"
|
10
|
+
s.has_rdoc = false
|
11
|
+
s.authors = ['Aleksander Pohl']
|
12
|
+
s.files = ["Rakefile", "cycr.gemspec", 'lib/cycr.rb'] +
|
13
|
+
Dir.glob("lib/**/*")
|
14
|
+
s.test_files = Dir.glob("spec/**/*")
|
15
|
+
s.rdoc_options = ["--main", "README.txt"]
|
16
|
+
s.has_rdoc = true
|
17
|
+
s.extra_rdoc_files = ["README.txt"]
|
18
|
+
s.add_dependency("rspec", [">= 1.2.9"])
|
19
|
+
end
|
20
|
+
|
data/lib/cycr/client.rb
ADDED
@@ -0,0 +1,208 @@
|
|
1
|
+
require 'net/telnet'
|
2
|
+
|
3
|
+
module Cyc
|
4
|
+
# Author:: Aleksander Pohl (mailto:apohllo@o2.pl)
|
5
|
+
# License:: MIT License
|
6
|
+
#
|
7
|
+
# This class is the implementation of the Cyc server client.
|
8
|
+
class Client
|
9
|
+
# If set to true, all communication with the server is logged
|
10
|
+
# to standard output
|
11
|
+
attr_accessor :debug
|
12
|
+
attr_reader :host, :port
|
13
|
+
# Creates new Client.
|
14
|
+
def initialize(host="localhost",port="3601",debug=false)
|
15
|
+
@debug = debug
|
16
|
+
@host = host
|
17
|
+
@port = port
|
18
|
+
@pid = Process.pid
|
19
|
+
@parser = Parser.new
|
20
|
+
@mts_cache = {}
|
21
|
+
|
22
|
+
# read domains mapings
|
23
|
+
# talk(File.read(File.join(
|
24
|
+
# File.dirname(__FILE__), 'domains.lisp')))
|
25
|
+
|
26
|
+
# read utility functions
|
27
|
+
talk(File.read(File.join(
|
28
|
+
File.dirname(__FILE__), 'words_reader.lisp')))
|
29
|
+
|
30
|
+
# wait untill files are processed
|
31
|
+
send_message("(define end-of-routines () ())")
|
32
|
+
while answer = receive_answer do
|
33
|
+
break if answer =~ /END-OF-ROUTINES/
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# (Re)connects to the cyc server.
|
38
|
+
def reconnect
|
39
|
+
@pid = Process.pid
|
40
|
+
@conn = Net::Telnet.new("Port" => @port, "Telnetmode" => false,
|
41
|
+
"Timeout" => 600, "Host" => @host)
|
42
|
+
end
|
43
|
+
|
44
|
+
# Returns the connection object. Ensures that the pid of current
|
45
|
+
# process is the same as the pid, the connection was initialized with.
|
46
|
+
#
|
47
|
+
# If the block is given, the command is guarded by assertion, that
|
48
|
+
# it will be performed, even if the connection was reset.
|
49
|
+
def connection
|
50
|
+
#puts "#{@pid} #{Process.pid}"
|
51
|
+
if @conn.nil? or @pid != Process.pid
|
52
|
+
reconnect
|
53
|
+
end
|
54
|
+
if block_given?
|
55
|
+
begin
|
56
|
+
yield @conn
|
57
|
+
rescue Errno::ECONNRESET
|
58
|
+
reconnect
|
59
|
+
yield @conn
|
60
|
+
end
|
61
|
+
else
|
62
|
+
@conn
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
protected :connection, :reconnect
|
67
|
+
|
68
|
+
def clear_cache
|
69
|
+
@mts_cache = {}
|
70
|
+
end
|
71
|
+
|
72
|
+
# Closes connection with the server
|
73
|
+
def close
|
74
|
+
connection{|c| c.puts("(api-quit)")}
|
75
|
+
@conn = nil
|
76
|
+
end
|
77
|
+
|
78
|
+
NART_QUERY =<<-END
|
79
|
+
(clet ((result ())
|
80
|
+
(call-value :call))
|
81
|
+
(pif (listp call-value)
|
82
|
+
(cdolist (el call-value)
|
83
|
+
(pif (nart-p el)
|
84
|
+
(cpush (nart-id el) result)
|
85
|
+
(cpush el result)))
|
86
|
+
(pif (nart-p call-value)
|
87
|
+
(cpush (nart-id call-value) result)
|
88
|
+
(cpush call-value result)))
|
89
|
+
result)
|
90
|
+
END
|
91
|
+
|
92
|
+
|
93
|
+
# Sends message +msg+ directly to the Cyc server and receives
|
94
|
+
# the answer.
|
95
|
+
def talk(msg, options={})
|
96
|
+
#conn.puts(msg.respond_to?(:to_cyc) ? msg.to_cyc : msg)
|
97
|
+
msg = NART_QUERY.sub(/:call/,msg) if options[:nart]
|
98
|
+
|
99
|
+
send_message(msg)
|
100
|
+
receive_answer(options)
|
101
|
+
end
|
102
|
+
|
103
|
+
# Send the raw message.
|
104
|
+
def send_message(msg)
|
105
|
+
@last_message = msg
|
106
|
+
puts "Send: #{msg}" if @debug
|
107
|
+
connection{|c| c.puts(msg)}
|
108
|
+
end
|
109
|
+
|
110
|
+
# Receive answer from server.
|
111
|
+
def receive_answer(options={})
|
112
|
+
answer = connection{|c| c.waitfor(/./)}
|
113
|
+
puts "Recv: #{answer}" if @debug
|
114
|
+
if answer.nil?
|
115
|
+
raise "Unknwon error occured. " +
|
116
|
+
"Check the submitted query in detail!"
|
117
|
+
end
|
118
|
+
while not answer =~ /\n/ do
|
119
|
+
next_answer = connection{|c| c.waitfor(/./)}
|
120
|
+
puts "Recv: #{next_answer}" if @debug
|
121
|
+
if answer.nil?
|
122
|
+
answer = next_answer
|
123
|
+
else
|
124
|
+
answer += next_answer
|
125
|
+
end
|
126
|
+
end
|
127
|
+
# XXX ignore some potential asynchronous answers
|
128
|
+
answer = answer.split("\n")[-1]
|
129
|
+
answer = answer.sub(/(\d\d\d) (.*)/,"\\2")
|
130
|
+
if($1.to_i == 200)
|
131
|
+
begin
|
132
|
+
result = @parser.parse(answer,options[:stack])
|
133
|
+
result = options[:nart] ? substitute_narts(result) : result
|
134
|
+
rescue Parser::ContinueParsing => ex
|
135
|
+
result = ex.stack
|
136
|
+
current_result = result
|
137
|
+
last_message = @last_message
|
138
|
+
while current_result.size == 100 do
|
139
|
+
send_message("(subseq #{last_message} #{result.size} " +
|
140
|
+
"#{result.size + 100})")
|
141
|
+
current_result = receive_answer(options)
|
142
|
+
result.concat(current_result)
|
143
|
+
end
|
144
|
+
result
|
145
|
+
end
|
146
|
+
else
|
147
|
+
unless $2.nil?
|
148
|
+
puts $2.sub(/^"/,"").sub(/"$/,"") + "\n" +
|
149
|
+
@last_message
|
150
|
+
else
|
151
|
+
puts "unknown error!"
|
152
|
+
end
|
153
|
+
nil
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
|
158
|
+
def method_missing(name,*args)
|
159
|
+
#"_missing_method_#{name}"
|
160
|
+
method_name = name.to_s.gsub("_","-").sub(/-nart$/,"")
|
161
|
+
options = {}
|
162
|
+
def method_name.to_cyc(quote=false)
|
163
|
+
self
|
164
|
+
end
|
165
|
+
options[:nart] = true if name.to_s =~ /_nart$/
|
166
|
+
talk(([method_name] + args).to_cyc,options)
|
167
|
+
end
|
168
|
+
|
169
|
+
DENOTATION_QUERY =<<-END
|
170
|
+
(nart-denotation-mapper ":word")
|
171
|
+
END
|
172
|
+
|
173
|
+
def denotation_mapper(name)
|
174
|
+
send_message(DENOTATION_QUERY.sub(/:word/,name))
|
175
|
+
receive_answer(:nart => true)
|
176
|
+
end
|
177
|
+
|
178
|
+
|
179
|
+
# Finds collection with given name. The name has to
|
180
|
+
# be the name of the exact name of the constant.
|
181
|
+
def find_collection(name)
|
182
|
+
term = self.find_constant(name)
|
183
|
+
Collection.new(term, self) unless term.nil?
|
184
|
+
end
|
185
|
+
|
186
|
+
protected
|
187
|
+
|
188
|
+
def substitute_narts(terms)
|
189
|
+
unless terms.nil?
|
190
|
+
terms.collect{|t| t.is_a?(String) ? Cyc::Nart.new(t,self) : t}
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
def relevant_mts(term)
|
195
|
+
@mts_cache[term] ||=
|
196
|
+
(mts = self.term_mts(term)
|
197
|
+
if mts
|
198
|
+
mts.select{|mt| mt.is_a? Symbol}.
|
199
|
+
reject{|mt| IRRELEVANT_MTS.include?(mt)}
|
200
|
+
else
|
201
|
+
[]
|
202
|
+
end)
|
203
|
+
end
|
204
|
+
|
205
|
+
def with_reconnect
|
206
|
+
end
|
207
|
+
end
|
208
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
module Cyc
|
2
|
+
class Collection
|
3
|
+
attr_reader :symbol
|
4
|
+
|
5
|
+
def initialize(symbol, cyc)
|
6
|
+
@symbol = symbol
|
7
|
+
@cyc = cyc
|
8
|
+
@printed = false
|
9
|
+
end
|
10
|
+
|
11
|
+
def printed?
|
12
|
+
@printed
|
13
|
+
end
|
14
|
+
|
15
|
+
def parents
|
16
|
+
unless @parents
|
17
|
+
parents = @cyc.min_genls(symbol)
|
18
|
+
@parents = if parents
|
19
|
+
parents.map{|p| Collection.new(p,@cyc)}
|
20
|
+
else
|
21
|
+
[]
|
22
|
+
end
|
23
|
+
end
|
24
|
+
@parents
|
25
|
+
end
|
26
|
+
|
27
|
+
def children
|
28
|
+
unless @children
|
29
|
+
children = @cyc.max_specs(symbol)
|
30
|
+
if children
|
31
|
+
@children = children.map{|p| Collection.new(p,@cyc)}
|
32
|
+
else
|
33
|
+
@children = []
|
34
|
+
end
|
35
|
+
end
|
36
|
+
@children
|
37
|
+
end
|
38
|
+
|
39
|
+
def comment
|
40
|
+
@cyc.comment(@symbol)
|
41
|
+
end
|
42
|
+
|
43
|
+
def lexemes()
|
44
|
+
default_str = [@cyc.symbol_str(symbol)]
|
45
|
+
aux_strs = @cyc.symbol_strs(symbol) || []
|
46
|
+
(default_str + aux_strs).uniq.compact.join(", ")
|
47
|
+
end
|
48
|
+
|
49
|
+
def to_s
|
50
|
+
@symbol.to_s
|
51
|
+
end
|
52
|
+
|
53
|
+
def ==(other)
|
54
|
+
return false unless other.is_a? Collection
|
55
|
+
self.symbol == other.symbol
|
56
|
+
end
|
57
|
+
|
58
|
+
def =~(other)
|
59
|
+
return false unless other.is_a? Collection
|
60
|
+
self.parents - other.parents == [] &&
|
61
|
+
other.parents - self.parents == []
|
62
|
+
end
|
63
|
+
|
64
|
+
def ancestor?(node)
|
65
|
+
return true if node == :Thing
|
66
|
+
ancestors = @parents.dup
|
67
|
+
while !ancestors.empty?
|
68
|
+
ancestor = ancestors.shift
|
69
|
+
return true if ancestor == node
|
70
|
+
ancestors += ancestor.parents
|
71
|
+
ancestors.uniq!
|
72
|
+
end
|
73
|
+
false
|
74
|
+
end
|
75
|
+
end # Node
|
76
|
+
end
|
@@ -0,0 +1,8 @@
|
|
1
|
+
module Cyc
|
2
|
+
# These Microteories contain non-ontological assertions.
|
3
|
+
IRRELEVANT_MTS = [:WordNetMappingMt, :EnglishMt, :UniversalVocabularyMt,
|
4
|
+
:BaseKB, :CycHistoricalPossibilityTheoryMt, :SENSUSMappingMt,
|
5
|
+
:GeneralLexiconMt, :BookkeepingMt, :CycNounLearnerMt, :HPKBVocabMt,
|
6
|
+
:SKSIMt, :TopicMt, :SNOMEDMappingMt, :MeSHMappingMt, :CycNounLearnerMt,
|
7
|
+
:TheMotleyFoolUKCorpusMt, :AnalystDatabaseMt, :CyclistsMt ]
|
8
|
+
end
|