pius-rdfs 0.3.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/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
|