pius-rdfs 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/AUTHORS +2 -0
- data/README +84 -0
- data/UNLICENSE +24 -0
- data/VERSION +1 -0
- data/lib/rdfs.rb +38 -0
- data/lib/rdfs/reasoner.rb +7 -0
- data/lib/rdfs/repository.rb +7 -0
- data/lib/rdfs/rule.rb +197 -0
- data/lib/rdfs/semantics.rb +140 -0
- data/lib/rdfs/version.rb +19 -0
- data/spec/spec_helper.rb +33 -0
- data/spec/unit/rule_spec.rb +104 -0
- metadata +145 -0
data/AUTHORS
ADDED
data/README
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
RDFS.rb: RDF Schema Reasoner for Ruby
|
2
|
+
=====================================
|
3
|
+
|
4
|
+
This is a pure-Ruby forward-chaining inference engine supporting RDFS
|
5
|
+
and RDFS++ entailment rules. It is intended to be used together with the
|
6
|
+
[RDF.rb](http://rdf.rubyforge.org/) library.
|
7
|
+
|
8
|
+
### About RDF Schema (RDFS)
|
9
|
+
|
10
|
+
* <http://www.w3.org/TR/rdf-schema/>
|
11
|
+
* <http://www.w3.org/TR/rdf-mt/>
|
12
|
+
* <http://en.wikipedia.org/wiki/RDF_Schema>
|
13
|
+
|
14
|
+
Examples
|
15
|
+
--------
|
16
|
+
|
17
|
+
require 'rdfs'
|
18
|
+
|
19
|
+
### Defining an RDFS entailment rule class
|
20
|
+
|
21
|
+
# @see http://www.w3.org/TR/rdf-mt/#RDFRules
|
22
|
+
class RDF1 < RDFS::Rule
|
23
|
+
antecedent :uuu, :aaa, :yyy
|
24
|
+
consequent :aaa, RDF.type, RDF.Property
|
25
|
+
end
|
26
|
+
|
27
|
+
### Defining an RDFS entailment rule instance
|
28
|
+
|
29
|
+
# @see http://www.w3.org/TR/rdf-mt/#RDFRules
|
30
|
+
rdf1 = RDFS::Rule.new do
|
31
|
+
antecedent :uuu, :aaa, :yyy
|
32
|
+
consequent :aaa, RDF.type, RDF.Property
|
33
|
+
end
|
34
|
+
|
35
|
+
Documentation
|
36
|
+
-------------
|
37
|
+
|
38
|
+
* <http://rdfs.rubyforge.org/>
|
39
|
+
|
40
|
+
Download
|
41
|
+
--------
|
42
|
+
|
43
|
+
To get a local working copy of the development repository, do:
|
44
|
+
|
45
|
+
% git clone git://github.com/bendiken/rdfs.git
|
46
|
+
|
47
|
+
Alternatively, you can download the latest development version as a tarball
|
48
|
+
as follows:
|
49
|
+
|
50
|
+
% wget http://github.com/bendiken/rdfs/tarball/master
|
51
|
+
|
52
|
+
Dependencies
|
53
|
+
------------
|
54
|
+
|
55
|
+
* [RDF.rb](http://rdf.rubyforge.org/) (>= 0.0.5)
|
56
|
+
|
57
|
+
Installation
|
58
|
+
------------
|
59
|
+
|
60
|
+
The recommended installation method is via RubyGems. To install the latest
|
61
|
+
official release from Gemcutter, do:
|
62
|
+
|
63
|
+
% [sudo] gem install rdfs
|
64
|
+
|
65
|
+
Resources
|
66
|
+
---------
|
67
|
+
|
68
|
+
* <http://rdfs.rubyforge.org/>
|
69
|
+
* <http://github.com/bendiken/rdfs>
|
70
|
+
* <http://gemcutter.org/gems/rdfs>
|
71
|
+
* <http://rubyforge.org/projects/rdfs/>
|
72
|
+
* <http://raa.ruby-lang.org/project/rdfs/>
|
73
|
+
|
74
|
+
Authors
|
75
|
+
------
|
76
|
+
|
77
|
+
* [Arto Bendiken](mailto:arto.bendiken@gmail.com) - <http://ar.to/>
|
78
|
+
* [Pius Uzamere](mailto:pius@alum.mit.edu) - <http://pius.me/>
|
79
|
+
|
80
|
+
License
|
81
|
+
-------
|
82
|
+
|
83
|
+
RDFS.rb is free and unencumbered public domain software. For more
|
84
|
+
information, see <http://unlicense.org/> or the accompanying UNLICENSE file.
|
data/UNLICENSE
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
This is free and unencumbered software released into the public domain.
|
2
|
+
|
3
|
+
Anyone is free to copy, modify, publish, use, compile, sell, or
|
4
|
+
distribute this software, either in source code form or as a compiled
|
5
|
+
binary, for any purpose, commercial or non-commercial, and by any
|
6
|
+
means.
|
7
|
+
|
8
|
+
In jurisdictions that recognize copyright laws, the author or authors
|
9
|
+
of this software dedicate any and all copyright interest in the
|
10
|
+
software to the public domain. We make this dedication for the benefit
|
11
|
+
of the public at large and to the detriment of our heirs and
|
12
|
+
successors. We intend this dedication to be an overt act of
|
13
|
+
relinquishment in perpetuity of all present and future rights to this
|
14
|
+
software under copyright law.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
19
|
+
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
20
|
+
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
21
|
+
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
22
|
+
OTHER DEALINGS IN THE SOFTWARE.
|
23
|
+
|
24
|
+
For more information, please refer to <http://unlicense.org/>
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.3.0
|
data/lib/rdfs.rb
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rdf'
|
3
|
+
require 'rdfs/version'
|
4
|
+
# require 'lib/rdfs/semantics'
|
5
|
+
# require 'lib/rdfs/rule'
|
6
|
+
# require 'lib/rdfs/repository'
|
7
|
+
|
8
|
+
##
|
9
|
+
# RDF Schema (RDFS) support.
|
10
|
+
#
|
11
|
+
# @see http://www.w3.org/TR/rdf-schema/
|
12
|
+
module RDFS
|
13
|
+
include RDF
|
14
|
+
|
15
|
+
autoload :Reasoner, 'rdfs/reasoner'
|
16
|
+
autoload :Repository, 'rdfs/repository'
|
17
|
+
autoload :Rule, 'rdfs/rule'
|
18
|
+
autoload :Semantics, 'rdfs/semantics'
|
19
|
+
|
20
|
+
##
|
21
|
+
# @return [#to_s] property
|
22
|
+
# @return [URI]
|
23
|
+
def self.[](property)
|
24
|
+
::RDF::RDFS[property]
|
25
|
+
end
|
26
|
+
|
27
|
+
##
|
28
|
+
# @param [Symbol] property
|
29
|
+
# @return [URI]
|
30
|
+
# @raise [NoMethodError]
|
31
|
+
def self.method_missing(property, *args, &block)
|
32
|
+
if args.empty?
|
33
|
+
::RDF::RDFS[property]
|
34
|
+
else
|
35
|
+
super
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
data/lib/rdfs/rule.rb
ADDED
@@ -0,0 +1,197 @@
|
|
1
|
+
module RDF
|
2
|
+
class Statement
|
3
|
+
PLACEHOLDERS = (p = [:aaa, :bbb, :ccc, :ddd, :uuu, :vvv, :xxx, :yyy, :zzz]) + p.collect {|pl| RDF::Literal.new(pl)} + p.collect {|pl| RDF::Node.new(pl)}
|
4
|
+
|
5
|
+
#TODO: consider moving these methods into the RDF gem instead of reopening RDF::Statement here
|
6
|
+
def with_substitutions(assignment_hash)
|
7
|
+
return self unless assignment_hash
|
8
|
+
statement_hash = to_hash
|
9
|
+
[:subject, :object, :predicate].each { |place_in_statement|
|
10
|
+
bound_variables, variable = assignment_hash.keys, statement_hash[place_in_statement]
|
11
|
+
statement_hash[place_in_statement] = assignment_hash[variable] if bound_variables.collect(&:to_s).include?(variable.to_s)
|
12
|
+
#TODO: fix node equality so I don't need to use to_s above
|
13
|
+
}
|
14
|
+
Statement.new(statement_hash)
|
15
|
+
end
|
16
|
+
|
17
|
+
def generality
|
18
|
+
to_hash.values.select {|k| PLACEHOLDERS.include? k}.size
|
19
|
+
end
|
20
|
+
|
21
|
+
def has_placeholder?
|
22
|
+
to_hash.values.detect {|k| PLACEHOLDERS.include? k}
|
23
|
+
end
|
24
|
+
|
25
|
+
def specificity
|
26
|
+
3-generality
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
module RDFS
|
32
|
+
##
|
33
|
+
# An RDFS entailment rule.
|
34
|
+
class Rule
|
35
|
+
include RDF
|
36
|
+
|
37
|
+
PLACEHOLDERS = (p = [:aaa, :bbb, :ccc, :ddd, :uuu, :vvv, :xxx, :yyy, :zzz]) + p.collect {|pl| RDF::Literal.new(pl)} + p.collect {|pl| RDF::Node.new(pl)}
|
38
|
+
|
39
|
+
# @return [Array<Statement>]
|
40
|
+
attr_reader :antecedents
|
41
|
+
|
42
|
+
# @return [Hash{Symbol => Class}]
|
43
|
+
attr_reader :constraints
|
44
|
+
|
45
|
+
# @return [Array<Statement>]
|
46
|
+
attr_reader :consequents
|
47
|
+
|
48
|
+
##
|
49
|
+
# @option options [Array<Statement>] :antecedents ([])
|
50
|
+
# @option options [Hash{Symbol => Class}] :constraints ({})
|
51
|
+
# @option options [Array<Statement>] :consequents ([])
|
52
|
+
# @yield [rule]
|
53
|
+
# @yieldparam [Rule]
|
54
|
+
def initialize(options = {}, &block)
|
55
|
+
@antecedents = (@@antecedents[self.class] || []).concat(options[:antecedents] || [])
|
56
|
+
@constraints = (@@constraints[self.class] || {}).merge( options[:constraints] || {})
|
57
|
+
@consequents = (@@consequents[self.class] || []).concat(options[:consequents] || [])
|
58
|
+
|
59
|
+
if block_given?
|
60
|
+
case block.arity
|
61
|
+
when 1 then block.call(self)
|
62
|
+
else instance_eval(&block)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
|
68
|
+
def match(statement1, statement2=nil, noisy = false)
|
69
|
+
statements = [statement1, statement2].compact
|
70
|
+
|
71
|
+
return false unless antecedents.size == statements.size
|
72
|
+
if antecedents.size == 1
|
73
|
+
return false unless (@subs = self.class.unitary_match(antecedents.first, statements.first))
|
74
|
+
return Rule.substitute(consequents, @subs)
|
75
|
+
|
76
|
+
elsif (implied_assignments = Rule.unitary_match(antecedents_ordered_by_decreasing_specificity.first, statements.first))
|
77
|
+
q = Rule.unitary_match(antecedents_ordered_by_decreasing_specificity.last.with_substitutions(implied_assignments),
|
78
|
+
statements.last.with_substitutions(implied_assignments))
|
79
|
+
assignments = q ? q.merge(implied_assignments) : q
|
80
|
+
return Rule.substitute(consequents, assignments)
|
81
|
+
elsif implied_assignments = Rule.unitary_match(antecedents_ordered_by_decreasing_specificity.first, statements.last)
|
82
|
+
q = Rule.unitary_match(antecedents_ordered_by_decreasing_specificity.last.with_substitutions(implied_assignments),
|
83
|
+
statements.first.with_substitutions(implied_assignments))
|
84
|
+
assignments = q ? q.merge(implied_assignments) : q
|
85
|
+
return Rule.substitute(consequents, assignments)
|
86
|
+
else
|
87
|
+
return false
|
88
|
+
end
|
89
|
+
end
|
90
|
+
alias_method :[], :match
|
91
|
+
|
92
|
+
|
93
|
+
#returns either false or the assignment hash of the match
|
94
|
+
def self.unitary_match(antecedent, statement)
|
95
|
+
a, s = antecedent.to_hash, statement.to_hash
|
96
|
+
#may need to exclude context
|
97
|
+
bound = {}
|
98
|
+
a.values.zip(s.values) {|antecedent_value, statement_value|
|
99
|
+
if PLACEHOLDERS.include?(antecedent_value) and !bound[antecedent_value]
|
100
|
+
bound[antecedent_value] = statement_value
|
101
|
+
elsif PLACEHOLDERS.include?(antecedent_value) and bound[antecedent_value]
|
102
|
+
return false unless bound[antecedent_value] == statement_value
|
103
|
+
else
|
104
|
+
return false unless antecedent_value == statement_value
|
105
|
+
end
|
106
|
+
}
|
107
|
+
return bound
|
108
|
+
end
|
109
|
+
|
110
|
+
def antecedents_ordered_by_decreasing_specificity
|
111
|
+
a ||= antecedents.sort_by(&:generality)
|
112
|
+
end
|
113
|
+
|
114
|
+
def self.substitute(consequents, assignment_hash)
|
115
|
+
return nil if assignment_hash.nil?
|
116
|
+
c = consequents.collect{|c| c.with_substitutions(assignment_hash)}
|
117
|
+
return c.detect(&:has_placeholder?) ? false : c
|
118
|
+
|
119
|
+
#perhaps add an integrity check to Rule to make sure that the consequents are fully substituted by the antecedents
|
120
|
+
end
|
121
|
+
|
122
|
+
##
|
123
|
+
# Defines an antecedent for this rule.
|
124
|
+
#
|
125
|
+
# @param [Symbol, URI] s
|
126
|
+
# @param [Symbol, URI] p
|
127
|
+
# @param [Symbol, URI] o
|
128
|
+
# @return [void]
|
129
|
+
def antecedent(s, p, o)
|
130
|
+
@antecedents << RDF::Statement.new(s, p, o)
|
131
|
+
end
|
132
|
+
|
133
|
+
##
|
134
|
+
# Defines a type constraint for this rule.
|
135
|
+
#
|
136
|
+
# @param [Hash{Symbol => Class}] types
|
137
|
+
# @return [void]
|
138
|
+
def constraint(types = {})
|
139
|
+
@constraints.merge!(types)
|
140
|
+
end
|
141
|
+
|
142
|
+
##
|
143
|
+
# Defines the consequent of this rule.
|
144
|
+
#
|
145
|
+
# @param [Symbol, URI] s
|
146
|
+
# @param [Symbol, URI] p
|
147
|
+
# @param [Symbol, URI] o
|
148
|
+
# @return [void]
|
149
|
+
def consequent(s, p, o)
|
150
|
+
@consequents << RDF::Statement.new(s, p, o)
|
151
|
+
end
|
152
|
+
|
153
|
+
protected
|
154
|
+
@@antecedents = {} # @private
|
155
|
+
@@constraints = {} # @private
|
156
|
+
@@consequents = {} # @private
|
157
|
+
|
158
|
+
##
|
159
|
+
# @private
|
160
|
+
def self.inherited(subclass)
|
161
|
+
@@antecedents[subclass] = []
|
162
|
+
@@constraints[subclass] = {}
|
163
|
+
@@consequents[subclass] = []
|
164
|
+
end
|
165
|
+
|
166
|
+
##
|
167
|
+
# Defines an antecedent for this rule class.
|
168
|
+
#
|
169
|
+
# @param [Symbol, URI] s
|
170
|
+
# @param [Symbol, URI] p
|
171
|
+
# @param [Symbol, URI] o
|
172
|
+
# @return [void]
|
173
|
+
def self.antecedent(s, p, o)
|
174
|
+
@@antecedents[self] << RDF::Statement.new(s, p, o)
|
175
|
+
end
|
176
|
+
|
177
|
+
##
|
178
|
+
# Defines a type constraint for this rule class.
|
179
|
+
#
|
180
|
+
# @param [Hash{Symbol => Class}] types
|
181
|
+
# @return [void]
|
182
|
+
def self.constraint(types = {})
|
183
|
+
@@constraints[self].merge!(types)
|
184
|
+
end
|
185
|
+
|
186
|
+
##
|
187
|
+
# Defines the consequent of this rule class.
|
188
|
+
#
|
189
|
+
# @param [Symbol, URI] s
|
190
|
+
# @param [Symbol, URI] p
|
191
|
+
# @param [Symbol, URI] o
|
192
|
+
# @return [void]
|
193
|
+
def self.consequent(s, p, o)
|
194
|
+
@@consequents[self] << RDF::Statement.new(s, p, o)
|
195
|
+
end
|
196
|
+
end
|
197
|
+
end
|
@@ -0,0 +1,140 @@
|
|
1
|
+
module RDFS
|
2
|
+
##
|
3
|
+
# The RDFS entailment rules.
|
4
|
+
#
|
5
|
+
# @see http://www.w3.org/TR/rdf-mt/
|
6
|
+
module Semantics
|
7
|
+
##
|
8
|
+
# RDF entailment rule `rdf1`.
|
9
|
+
#
|
10
|
+
# @see http://www.w3.org/TR/rdf-mt/#RDFRules
|
11
|
+
class RDF1 < Rule
|
12
|
+
antecedent :uuu, :aaa, :yyy
|
13
|
+
consequent :aaa, RDF.type, RDF.Property
|
14
|
+
end
|
15
|
+
|
16
|
+
##
|
17
|
+
# RDFS entailment rule `rdfs2` for `rdfs:domain`.
|
18
|
+
#
|
19
|
+
# @see http://www.w3.org/TR/rdf-mt/#RDFSRules
|
20
|
+
class RDFS2 < Rule
|
21
|
+
antecedent :aaa, RDFS.domain, :xxx
|
22
|
+
antecedent :uuu, :aaa, :yyy
|
23
|
+
consequent :uuu, RDF.type, :xxx
|
24
|
+
end
|
25
|
+
|
26
|
+
##
|
27
|
+
# RDFS entailment rule `rdfs3` for `rdfs:range`.
|
28
|
+
#
|
29
|
+
# @see http://www.w3.org/TR/rdf-mt/#RDFSRules
|
30
|
+
class RDFS3 < Rule
|
31
|
+
antecedent :aaa, RDFS.range, :xxx
|
32
|
+
antecedent :uuu, :aaa, :vvv
|
33
|
+
consequent :vvv, RDF.type, :xxx
|
34
|
+
end
|
35
|
+
|
36
|
+
##
|
37
|
+
# RDFS entailment rule `rdfs4a`.
|
38
|
+
#
|
39
|
+
# @see http://www.w3.org/TR/rdf-mt/#RDFSRules
|
40
|
+
class RDFS4a < Rule
|
41
|
+
antecedent :uuu, :aaa, :xxx
|
42
|
+
consequent :uuu, RDF.type, RDFS.Resource
|
43
|
+
end
|
44
|
+
|
45
|
+
##
|
46
|
+
# RDFS entailment rule `rdfs4b`.
|
47
|
+
#
|
48
|
+
# @see http://www.w3.org/TR/rdf-mt/#RDFSRules
|
49
|
+
class RDFS4b < Rule
|
50
|
+
antecedent :uuu, :aaa, :vvv
|
51
|
+
constraint :vvv => RDF::Node
|
52
|
+
consequent :vvv, RDF.type, RDFS.Resource
|
53
|
+
end
|
54
|
+
|
55
|
+
##
|
56
|
+
# RDFS entailment rule `rdfs5` for `rdfs:subPropertyOf`.
|
57
|
+
#
|
58
|
+
# @see http://www.w3.org/TR/rdf-mt/#RDFSRules
|
59
|
+
class RDFS5 < Rule
|
60
|
+
antecedent :uuu, RDFS.subPropertyOf, :vvv
|
61
|
+
antecedent :vvv, RDFS.subPropertyOf, :xxx
|
62
|
+
consequent :uuu, RDFS.subPropertyOf, :xxx
|
63
|
+
end
|
64
|
+
|
65
|
+
##
|
66
|
+
# RDFS entailment rule `rdfs6` for `rdfs:subPropertyOf`.
|
67
|
+
#
|
68
|
+
# @see http://www.w3.org/TR/rdf-mt/#RDFSRules
|
69
|
+
class RDFS6 < Rule
|
70
|
+
antecedent :uuu, RDF.type, RDF.Property
|
71
|
+
consequent :uuu, RDFS.subPropertyOf, :uuu
|
72
|
+
end
|
73
|
+
|
74
|
+
##
|
75
|
+
# RDFS entailment rule `rdfs7` for `rdfs:subPropertyOf`.
|
76
|
+
#
|
77
|
+
# @see http://www.w3.org/TR/rdf-mt/#RDFSRules
|
78
|
+
class RDFS7 < Rule
|
79
|
+
antecedent :aaa, RDFS.subPropertyOf, :bbb
|
80
|
+
antecedent :uuu, :aaa, :yyy
|
81
|
+
consequent :uuu, :bbb, :yyy
|
82
|
+
end
|
83
|
+
|
84
|
+
##
|
85
|
+
# RDFS entailment rule `rdfs8` for `rdfs:subClassOf`.
|
86
|
+
#
|
87
|
+
# @see http://www.w3.org/TR/rdf-mt/#RDFSRules
|
88
|
+
class RDFS8 < Rule
|
89
|
+
antecedent :uuu, RDF.type, RDFS.Class
|
90
|
+
consequent :uuu, RDFS.subClassOf, RDFS.Resource
|
91
|
+
end
|
92
|
+
|
93
|
+
##
|
94
|
+
# RDFS entailment rule `rdfs9` for `rdfs:subClassOf`.
|
95
|
+
#
|
96
|
+
# @see http://www.w3.org/TR/rdf-mt/#RDFSRules
|
97
|
+
class RDFS9 < Rule
|
98
|
+
antecedent :uuu, RDFS.subClassOf, :xxx
|
99
|
+
antecedent :vvv, RDF.type, :uuu
|
100
|
+
consequent :vvv, RDF.type, :xxx
|
101
|
+
end
|
102
|
+
|
103
|
+
##
|
104
|
+
# RDFS entailment rule `rdfs10` for `rdfs:subClassOf`.
|
105
|
+
#
|
106
|
+
# @see http://www.w3.org/TR/rdf-mt/#RDFSRules
|
107
|
+
class RDFS10 < Rule
|
108
|
+
antecedent :uuu, RDF.type, RDFS.Class
|
109
|
+
consequent :uuu, RDFS.subClassOf, :uuu
|
110
|
+
end
|
111
|
+
|
112
|
+
##
|
113
|
+
# RDFS entailment rule `rdfs11` for `rdfs:subClassOf`.
|
114
|
+
#
|
115
|
+
# @see http://www.w3.org/TR/rdf-mt/#RDFSRules
|
116
|
+
class RDFS11 < Rule
|
117
|
+
antecedent :uuu, RDFS.subClassOf, :vvv
|
118
|
+
antecedent :vvv, RDFS.subClassOf, :xxx
|
119
|
+
consequent :uuu, RDFS.subClassOf, :xxx
|
120
|
+
end
|
121
|
+
|
122
|
+
##
|
123
|
+
# RDFS entailment rule `rdfs12`.
|
124
|
+
#
|
125
|
+
# @see http://www.w3.org/TR/rdf-mt/#RDFSRules
|
126
|
+
class RDFS12 < Rule
|
127
|
+
antecedent :uuu, RDF.type, RDFS.ContainerMembershipProperty
|
128
|
+
consequent :uuu, RDFS.subPropertyOf, RDFS.member
|
129
|
+
end
|
130
|
+
|
131
|
+
##
|
132
|
+
# RDFS entailment rule `rdfs13`.
|
133
|
+
#
|
134
|
+
# @see http://www.w3.org/TR/rdf-mt/#RDFSRules
|
135
|
+
class RDFS13 < Rule
|
136
|
+
antecedent :uuu, RDF.type, RDFS.Datatype
|
137
|
+
consequent :uuu, RDFS.subClassOf, RDFS.Literal
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
data/lib/rdfs/version.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
module RDFS
|
2
|
+
module VERSION
|
3
|
+
MAJOR = 0
|
4
|
+
MINOR = 1
|
5
|
+
TINY = 0
|
6
|
+
EXTRA = nil
|
7
|
+
|
8
|
+
STRING = [MAJOR, MINOR, TINY].join('.')
|
9
|
+
STRING << "-#{EXTRA}" if EXTRA
|
10
|
+
|
11
|
+
##
|
12
|
+
# @return [String]
|
13
|
+
def self.to_s() STRING end
|
14
|
+
|
15
|
+
##
|
16
|
+
# @return [String]
|
17
|
+
def self.to_str() STRING end
|
18
|
+
end
|
19
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'pathname'
|
3
|
+
require 'rdf'
|
4
|
+
require 'rdfs'
|
5
|
+
require 'rdfs/rule'
|
6
|
+
|
7
|
+
class Pathname
|
8
|
+
def /(path)
|
9
|
+
(self + path).expand_path
|
10
|
+
end
|
11
|
+
end # class Pathname
|
12
|
+
|
13
|
+
spec_dir_path = Pathname(__FILE__).dirname.expand_path
|
14
|
+
require spec_dir_path.parent + 'lib/rdfs'
|
15
|
+
|
16
|
+
# # require fixture resources
|
17
|
+
Dir[spec_dir_path + "lib/rdfs/*.rb"].each do |fixture_file|
|
18
|
+
require fixture_file
|
19
|
+
end
|
20
|
+
|
21
|
+
# # require fixture resources
|
22
|
+
# Dir[spec_dir_path + "fixtures/*.rb"].each do |fixture_file|
|
23
|
+
# require fixture_file
|
24
|
+
# end
|
25
|
+
|
26
|
+
|
27
|
+
require 'rspec'
|
28
|
+
# optionally add autorun support
|
29
|
+
#require 'rspec/autorun'
|
30
|
+
|
31
|
+
Rspec.configure do |c|
|
32
|
+
c.mock_with :rspec
|
33
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
#require 'spec_helper'
|
2
|
+
require 'rdf'
|
3
|
+
|
4
|
+
require 'rdfs'
|
5
|
+
require 'rdfs/rule'
|
6
|
+
include RDF
|
7
|
+
include ::RDFS::Semantics
|
8
|
+
|
9
|
+
describe ::RDF::Statement do
|
10
|
+
it "should be able to substitute a mapping into itself" do
|
11
|
+
statement = Statement.new(:aaa, :xxx, FOAF.person)
|
12
|
+
mapping = {RDF::Node.new(:aaa) => 'rdf:friend', RDF::Node.new(:xxx) => 'rdf:knows'}
|
13
|
+
a = statement.with_substitutions(mapping)
|
14
|
+
a.should eql Statement.new('rdf:friend', 'rdf:knows', FOAF.person)
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should know its specificity" do
|
18
|
+
a1 = Statement.new(:aaa, RDFS.domain, :xxx)
|
19
|
+
a2 = Statement.new(:uuu, :aaa, :yyy)
|
20
|
+
|
21
|
+
[a1, a2].collect(&:specificity).should == [1,0]
|
22
|
+
[a1, a2].sort_by(&:specificity).should == [a2,a1]
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
describe ::RDFS::Rule do
|
29
|
+
|
30
|
+
before(:each) do
|
31
|
+
@rule1 = RDF1.new
|
32
|
+
@statement1 = Statement.new('joe:shmoe', 'rdf:jerk', 'schmuck')
|
33
|
+
@matching_statements_1 = [Statement.new('rdf:jerk', RDF.type, RDF.Property)]
|
34
|
+
|
35
|
+
@rule2 = RDFS2.new
|
36
|
+
@statement2 = Statement.new('rdf:annoys', RDFS.domain, FOAF.person)
|
37
|
+
@statement3 = Statement.new('tom', 'rdf:annoys', 'jerry')
|
38
|
+
@statement4 = Statement.new('tom', RDF.type, FOAF.person)
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should know its antecedents" do
|
42
|
+
@rule1.antecedents.should eql([Statement.new(:uuu, :aaa, :yyy)])
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should know its consequents" do
|
46
|
+
@rule1.consequents.should eql([Statement.new(:aaa, RDF.type, RDF.Property)])
|
47
|
+
end
|
48
|
+
|
49
|
+
it "should be able to substitute a mapping into consequents" do
|
50
|
+
consequents = [Statement.new(:aaa, :xxx, FOAF.person)]
|
51
|
+
mapping = {RDF::Node.new(:aaa) => 'rdf:friend', RDF::Node.new(:xxx) => 'rdf:knows'}
|
52
|
+
a = ::RDFS::Rule.substitute(consequents, mapping)
|
53
|
+
a.should eql [Statement.new('rdf:friend', 'rdf:knows', FOAF.person)]
|
54
|
+
end
|
55
|
+
|
56
|
+
it "should be able to do unitary matches" do
|
57
|
+
antecedent = Statement.new :uuu, :aaa, :yyy
|
58
|
+
@statement1 = Statement.new('joe:shmoe', 'rdf:jerk', 'schmuck')
|
59
|
+
::RDFS::Rule.unitary_match(antecedent, @statement1).should be_true
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should not unitary match if non-placeholders are different" do
|
63
|
+
a1 = Statement.new(:aaa, RDFS.domain, :xxx)
|
64
|
+
s1 = Statement.new('rdf:annoys', RDFS.subPropertyOf, FOAF.person)
|
65
|
+
::RDFS::Rule.unitary_match(a1, s1).should be_false
|
66
|
+
end
|
67
|
+
|
68
|
+
|
69
|
+
context "should generate consequents from pairs of statements that match the antecedents" do
|
70
|
+
|
71
|
+
it "with just one antecedent and one consequent" do
|
72
|
+
@rule1[@statement1].should eql(@matching_statements_1)
|
73
|
+
|
74
|
+
@rule_rdfs4a = RDFS4a.new
|
75
|
+
@statements_matching_rule_rdfs4a = [Statement.new('rdf:annoys', RDF.type, RDFS.Resource)]
|
76
|
+
@rule_rdfs4a[@statement2].should eql @statements_matching_rule_rdfs4a
|
77
|
+
end
|
78
|
+
|
79
|
+
it "matching should be commutative" do
|
80
|
+
@rule2[@statement2,@statement3].should eql @rule2[@statement3,@statement2]
|
81
|
+
end
|
82
|
+
|
83
|
+
it "with multiple antecedents and one consequent" do
|
84
|
+
@rule2 = RDFS2.new
|
85
|
+
@rule2[@statement2,@statement3].should eql([@statement4])
|
86
|
+
end
|
87
|
+
|
88
|
+
it "with multiple antecedents" do
|
89
|
+
@rule2[@statement2,@statement3].should eql [Statement.new('tom', RDF.type, FOAF.person)]
|
90
|
+
@rule2[@statement3,@statement2].should eql [Statement.new('tom', RDF.type, FOAF.person)]
|
91
|
+
end
|
92
|
+
|
93
|
+
end
|
94
|
+
|
95
|
+
context "should not generate consequents from pairs of statements that don't match the antecedents" do
|
96
|
+
it "with multiple antecedents" do
|
97
|
+
@rule2 = RDFS2.new
|
98
|
+
|
99
|
+
@statement2 = Statement.new('rdf:annoys', RDFS.domain, FOAF.person)
|
100
|
+
d = Statement.new('foo', 'bar', 'baz')
|
101
|
+
@rule2[@statement2,d].should be_false
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
metadata
ADDED
@@ -0,0 +1,145 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: pius-rdfs
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: -1713379756426313520
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 3
|
9
|
+
- 0
|
10
|
+
version: 0.3.0
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Arto Bendiken
|
14
|
+
- Pius Uzamere
|
15
|
+
autorequire:
|
16
|
+
bindir: bin
|
17
|
+
cert_chain: []
|
18
|
+
|
19
|
+
date: 2010-10-09 00:00:00 -04:00
|
20
|
+
default_executable:
|
21
|
+
dependencies:
|
22
|
+
- !ruby/object:Gem::Dependency
|
23
|
+
name: rdf-spec
|
24
|
+
prerelease: false
|
25
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
26
|
+
none: false
|
27
|
+
requirements:
|
28
|
+
- - ~>
|
29
|
+
- !ruby/object:Gem::Version
|
30
|
+
hash: 363868379743904425
|
31
|
+
segments:
|
32
|
+
- 0
|
33
|
+
- 2
|
34
|
+
- 0
|
35
|
+
version: 0.2.0
|
36
|
+
type: :development
|
37
|
+
version_requirements: *id001
|
38
|
+
- !ruby/object:Gem::Dependency
|
39
|
+
name: rspec
|
40
|
+
prerelease: false
|
41
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
42
|
+
none: false
|
43
|
+
requirements:
|
44
|
+
- - ">="
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
hash: -2689461885439978514
|
47
|
+
segments:
|
48
|
+
- 1
|
49
|
+
- 3
|
50
|
+
- 0
|
51
|
+
version: 1.3.0
|
52
|
+
type: :development
|
53
|
+
version_requirements: *id002
|
54
|
+
- !ruby/object:Gem::Dependency
|
55
|
+
name: yard
|
56
|
+
prerelease: false
|
57
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
58
|
+
none: false
|
59
|
+
requirements:
|
60
|
+
- - ">="
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
hash: -1257173255691836839
|
63
|
+
segments:
|
64
|
+
- 0
|
65
|
+
- 5
|
66
|
+
- 6
|
67
|
+
version: 0.5.6
|
68
|
+
type: :development
|
69
|
+
version_requirements: *id003
|
70
|
+
- !ruby/object:Gem::Dependency
|
71
|
+
name: rdf
|
72
|
+
prerelease: false
|
73
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
74
|
+
none: false
|
75
|
+
requirements:
|
76
|
+
- - ~>
|
77
|
+
- !ruby/object:Gem::Version
|
78
|
+
hash: 363868379743904425
|
79
|
+
segments:
|
80
|
+
- 0
|
81
|
+
- 2
|
82
|
+
- 0
|
83
|
+
version: 0.2.0
|
84
|
+
type: :runtime
|
85
|
+
version_requirements: *id004
|
86
|
+
description: RDFS.rb is a forward-chaining inference engine that implements the RDF Schema (RDFS) entailment rules.
|
87
|
+
email: pius@alum.mit.edu
|
88
|
+
executables: []
|
89
|
+
|
90
|
+
extensions: []
|
91
|
+
|
92
|
+
extra_rdoc_files: []
|
93
|
+
|
94
|
+
files:
|
95
|
+
- AUTHORS
|
96
|
+
- README
|
97
|
+
- UNLICENSE
|
98
|
+
- VERSION
|
99
|
+
- lib/rdfs/reasoner.rb
|
100
|
+
- lib/rdfs/repository.rb
|
101
|
+
- lib/rdfs/rule.rb
|
102
|
+
- lib/rdfs/semantics.rb
|
103
|
+
- lib/rdfs/version.rb
|
104
|
+
- lib/rdfs.rb
|
105
|
+
- spec/spec_helper.rb
|
106
|
+
- spec/unit/rule_spec.rb
|
107
|
+
has_rdoc: true
|
108
|
+
homepage: http://rdfs.rubyforge.org/
|
109
|
+
licenses:
|
110
|
+
- Public Domain
|
111
|
+
post_install_message:
|
112
|
+
rdoc_options: []
|
113
|
+
|
114
|
+
require_paths:
|
115
|
+
- lib
|
116
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
117
|
+
none: false
|
118
|
+
requirements:
|
119
|
+
- - ">="
|
120
|
+
- !ruby/object:Gem::Version
|
121
|
+
hash: -2660243542901265017
|
122
|
+
segments:
|
123
|
+
- 1
|
124
|
+
- 8
|
125
|
+
- 2
|
126
|
+
version: 1.8.2
|
127
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
128
|
+
none: false
|
129
|
+
requirements:
|
130
|
+
- - ">="
|
131
|
+
- !ruby/object:Gem::Version
|
132
|
+
hash: -2953524206653324603
|
133
|
+
segments:
|
134
|
+
- 0
|
135
|
+
version: "0"
|
136
|
+
requirements: []
|
137
|
+
|
138
|
+
rubyforge_project: rdfs
|
139
|
+
rubygems_version: 1.3.7
|
140
|
+
signing_key:
|
141
|
+
specification_version: 3
|
142
|
+
summary: A forward-chaining inference engine that implements the RDFS entailment rules.
|
143
|
+
test_files:
|
144
|
+
- spec/spec_helper.rb
|
145
|
+
- spec/unit/rule_spec.rb
|