rdf 1.1.3 → 1.1.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CREDITS +1 -0
- data/VERSION +1 -1
- data/lib/rdf.rb +10 -48
- data/lib/rdf/cli/vocab-loader.rb +78 -142
- data/lib/rdf/mixin/enumerable.rb +25 -0
- data/lib/rdf/mixin/mutable.rb +3 -0
- data/lib/rdf/model/graph.rb +1 -1
- data/lib/rdf/model/node.rb +25 -2
- data/lib/rdf/model/statement.rb +20 -12
- data/lib/rdf/model/uri.rb +11 -2
- data/lib/rdf/nquads.rb +8 -6
- data/lib/rdf/ntriples/writer.rb +14 -10
- data/lib/rdf/query/pattern.rb +10 -8
- data/lib/rdf/reader.rb +11 -2
- data/lib/rdf/repository.rb +1 -1
- data/lib/rdf/vocab.rb +396 -96
- data/lib/rdf/vocab/cc.rb +117 -25
- data/lib/rdf/vocab/cert.rb +230 -117
- data/lib/rdf/vocab/dc.rb +930 -233
- data/lib/rdf/vocab/dc11.rb +151 -37
- data/lib/rdf/vocab/doap.rb +326 -114
- data/lib/rdf/vocab/exif.rb +930 -533
- data/lib/rdf/vocab/foaf.rb +602 -346
- data/lib/rdf/vocab/geo.rb +139 -33
- data/lib/rdf/vocab/gr.rb +1551 -1084
- data/lib/rdf/vocab/ht.rb +319 -0
- data/lib/rdf/vocab/ical.rb +507 -349
- data/lib/rdf/vocab/ma.rb +504 -280
- data/lib/rdf/vocab/mo.rb +2425 -876
- data/lib/rdf/vocab/og.rb +178 -90
- data/lib/rdf/vocab/owl.rb +513 -219
- data/lib/rdf/vocab/prov.rb +1557 -479
- data/lib/rdf/vocab/rdfs.rb +107 -31
- data/lib/rdf/vocab/rdfv.rb +165 -0
- data/lib/rdf/vocab/rsa.rb +61 -18
- data/lib/rdf/vocab/rss.rb +55 -22
- data/lib/rdf/vocab/schema.rb +8590 -3995
- data/lib/rdf/vocab/sioc.rb +657 -218
- data/lib/rdf/vocab/skos.rb +227 -134
- data/lib/rdf/vocab/skosxl.rb +47 -33
- data/lib/rdf/vocab/vcard.rb +693 -327
- data/lib/rdf/vocab/void.rb +175 -132
- data/lib/rdf/vocab/vs.rb +27 -0
- data/lib/rdf/vocab/wdrs.rb +123 -119
- data/lib/rdf/vocab/wot.rb +155 -45
- data/lib/rdf/vocab/xhtml.rb +2 -1
- data/lib/rdf/vocab/xhv.rb +496 -231
- data/lib/rdf/vocab/xsd.rb +382 -53
- data/lib/rdf/writer.rb +8 -4
- metadata +5 -4
- data/lib/rdf/vocab/http.rb +0 -84
- data/lib/rdf/vocab/v.rb +0 -154
data/lib/rdf/model/statement.rb
CHANGED
@@ -6,19 +6,25 @@ module RDF
|
|
6
6
|
# s = RDF::URI.new("http://rubygems.org/gems/rdf")
|
7
7
|
# p = RDF::DC.creator
|
8
8
|
# o = RDF::URI.new("http://ar.to/#self")
|
9
|
-
# RDF::Statement
|
9
|
+
# RDF::Statement(s, p, o)
|
10
10
|
#
|
11
11
|
# @example Creating an RDF statement with a context
|
12
12
|
# uri = RDF::URI("http://example/")
|
13
|
-
# RDF::Statement
|
13
|
+
# RDF::Statement(s, p, o, :context => uri)
|
14
14
|
#
|
15
15
|
# @example Creating an RDF statement from a `Hash`
|
16
|
-
# RDF::Statement
|
16
|
+
# RDF::Statement({
|
17
17
|
# :subject => RDF::URI.new("http://rubygems.org/gems/rdf"),
|
18
18
|
# :predicate => RDF::DC.creator,
|
19
19
|
# :object => RDF::URI.new("http://ar.to/#self"),
|
20
20
|
# })
|
21
21
|
#
|
22
|
+
# @example Creating an RDF statement with interned nodes
|
23
|
+
# RDF::Statement(:s, p, :o)
|
24
|
+
#
|
25
|
+
# @example Creating an RDF statement with a string
|
26
|
+
# RDF::Statement(s, p, "o")
|
27
|
+
#
|
22
28
|
class Statement
|
23
29
|
include RDF::Value
|
24
30
|
|
@@ -54,21 +60,23 @@ module RDF
|
|
54
60
|
##
|
55
61
|
# @overload initialize(options = {})
|
56
62
|
# @param [Hash{Symbol => Object}] options
|
57
|
-
# @option options [RDF::
|
63
|
+
# @option options [RDF::Term] :subject (nil)
|
64
|
+
# A symbol is converted to an interned {Node}.
|
58
65
|
# @option options [RDF::URI] :predicate (nil)
|
59
|
-
# @option options [RDF::
|
60
|
-
# if not
|
61
|
-
# @option options [RDF::
|
62
|
-
# Note, in RDF 1.1, a context MUST be an
|
66
|
+
# @option options [RDF::Resource] :object (nil)
|
67
|
+
# if not a {Resource}, it is coerced to {Literal} or {Node} depending on if it is a symbol or something other than a {Term}.
|
68
|
+
# @option options [RDF::Term] :context (nil)
|
69
|
+
# Note, in RDF 1.1, a context MUST be an {Resource}.
|
63
70
|
# @return [RDF::Statement]
|
64
71
|
#
|
65
72
|
# @overload initialize(subject, predicate, object, options = {})
|
66
|
-
# @param [RDF::
|
73
|
+
# @param [RDF::Term] subject
|
74
|
+
# A symbol is converted to an interned {Node}.
|
67
75
|
# @param [RDF::URI] predicate
|
68
|
-
# @param [RDF::
|
69
|
-
# if not
|
76
|
+
# @param [RDF::Resource] object
|
77
|
+
# if not a {Resource}, it is coerced to {Literal} or {Node} depending on if it is a symbol or something other than a {Term}.
|
70
78
|
# @param [Hash{Symbol => Object}] options
|
71
|
-
# @option options [RDF::
|
79
|
+
# @option options [RDF::Term] :context (nil)
|
72
80
|
# @return [RDF::Statement]
|
73
81
|
def initialize(subject = nil, predicate = nil, object = nil, options = {})
|
74
82
|
case subject
|
data/lib/rdf/model/uri.rb
CHANGED
@@ -140,8 +140,9 @@ module RDF
|
|
140
140
|
#
|
141
141
|
# @param (see #initialize)
|
142
142
|
# @return [RDF::URI] an immutable, frozen URI object
|
143
|
-
def self.intern(
|
144
|
-
|
143
|
+
def self.intern(*args)
|
144
|
+
str = args.first
|
145
|
+
(cache[str = str.to_s] ||= self.new(*args)).freeze
|
145
146
|
end
|
146
147
|
|
147
148
|
##
|
@@ -632,6 +633,14 @@ module RDF
|
|
632
633
|
return nil # no QName found
|
633
634
|
end
|
634
635
|
|
636
|
+
##
|
637
|
+
# Returns a string version of the QName or the full IRI
|
638
|
+
#
|
639
|
+
# @return [String] or `nil`
|
640
|
+
def pname
|
641
|
+
(q = self.qname) ? q.join(":") : to_s
|
642
|
+
end
|
643
|
+
|
635
644
|
##
|
636
645
|
# Returns a duplicate copy of `self`.
|
637
646
|
#
|
data/lib/rdf/nquads.rb
CHANGED
@@ -114,17 +114,18 @@ module RDF
|
|
114
114
|
# @param [RDF::Term] object
|
115
115
|
# @return [void]
|
116
116
|
def write_quad(subject, predicate, object, context)
|
117
|
-
puts format_quad(subject, predicate, object, context)
|
117
|
+
puts format_quad(subject, predicate, object, context, @options)
|
118
118
|
end
|
119
119
|
|
120
120
|
##
|
121
121
|
# Returns the N-Quads representation of a statement.
|
122
122
|
#
|
123
123
|
# @param [RDF::Statement] statement
|
124
|
+
# @param [Hash{Symbol => Object}] options = ({})
|
124
125
|
# @return [String]
|
125
126
|
# @since 0.4.0
|
126
|
-
def format_statement(statement)
|
127
|
-
format_quad(*statement.to_quad)
|
127
|
+
def format_statement(statement, options = {})
|
128
|
+
format_quad(*statement.to_quad, options)
|
128
129
|
end
|
129
130
|
|
130
131
|
##
|
@@ -134,10 +135,11 @@ module RDF
|
|
134
135
|
# @param [RDF::URI] predicate
|
135
136
|
# @param [RDF::Term] object
|
136
137
|
# @param [RDF::Term] context
|
138
|
+
# @param [Hash{Symbol => Object}] options = ({})
|
137
139
|
# @return [String]
|
138
|
-
def format_quad(subject, predicate, object, context)
|
139
|
-
s = "%s %s %s " % [subject, predicate, object].map { |value| format_term(value) }
|
140
|
-
s += format_term(context) + " " if context
|
140
|
+
def format_quad(subject, predicate, object, context, options = {})
|
141
|
+
s = "%s %s %s " % [subject, predicate, object].map { |value| format_term(value, options) }
|
142
|
+
s += format_term(context, options) + " " if context
|
141
143
|
s + "."
|
142
144
|
end
|
143
145
|
end # Writer
|
data/lib/rdf/ntriples/writer.rb
CHANGED
@@ -179,7 +179,7 @@ module RDF::NTriples
|
|
179
179
|
#
|
180
180
|
# @param [IO, File] output
|
181
181
|
# the output stream
|
182
|
-
# @param [Hash{Symbol => Object}] options
|
182
|
+
# @param [Hash{Symbol => Object}] options = ({})
|
183
183
|
# any additional options. See {RDF::Writer#initialize}
|
184
184
|
# @option options [Boolean] :validate (true)
|
185
185
|
# whether to validate terms when serializing
|
@@ -208,16 +208,17 @@ module RDF::NTriples
|
|
208
208
|
# @param [RDF::Term] object
|
209
209
|
# @return [void]
|
210
210
|
def write_triple(subject, predicate, object)
|
211
|
-
puts format_triple(subject, predicate, object)
|
211
|
+
puts format_triple(subject, predicate, object, @options)
|
212
212
|
end
|
213
213
|
|
214
214
|
##
|
215
215
|
# Returns the N-Triples representation of a statement.
|
216
216
|
#
|
217
217
|
# @param [RDF::Statement] statement
|
218
|
+
# @param [Hash{Symbol => Object}] options = ({})
|
218
219
|
# @return [String]
|
219
|
-
def format_statement(statement)
|
220
|
-
format_triple(*statement.to_triple)
|
220
|
+
def format_statement(statement, options = {})
|
221
|
+
format_triple(*statement.to_triple, options)
|
221
222
|
end
|
222
223
|
|
223
224
|
##
|
@@ -226,26 +227,29 @@ module RDF::NTriples
|
|
226
227
|
# @param [RDF::Resource] subject
|
227
228
|
# @param [RDF::URI] predicate
|
228
229
|
# @param [RDF::Term] object
|
230
|
+
# @param [Hash{Symbol => Object}] options = ({})
|
229
231
|
# @return [String]
|
230
|
-
def format_triple(subject, predicate, object)
|
231
|
-
"%s %s %s ." % [subject, predicate, object].map { |value| format_term(value) }
|
232
|
+
def format_triple(subject, predicate, object, options = {})
|
233
|
+
"%s %s %s ." % [subject, predicate, object].map { |value| format_term(value, options) }
|
232
234
|
end
|
233
235
|
|
234
236
|
##
|
235
237
|
# Returns the N-Triples representation of a blank node.
|
236
238
|
#
|
237
239
|
# @param [RDF::Node] node
|
238
|
-
# @param [Hash{Symbol => Object}] options
|
240
|
+
# @param [Hash{Symbol => Object}] options = ({})
|
241
|
+
# @option options [Boolean] :unique_bnodes (false)
|
242
|
+
# Serialize node using unique identifier, rather than any used to create the node.
|
239
243
|
# @return [String]
|
240
244
|
def format_node(node, options = {})
|
241
|
-
node.to_base
|
245
|
+
options[:unique_bnodes] ? node.to_unique_base : node.to_base
|
242
246
|
end
|
243
247
|
|
244
248
|
##
|
245
249
|
# Returns the N-Triples representation of a URI reference.
|
246
250
|
#
|
247
251
|
# @param [RDF::URI] uri
|
248
|
-
# @param [Hash{Symbol => Object}] options
|
252
|
+
# @param [Hash{Symbol => Object}] options = ({})
|
249
253
|
# @return [String]
|
250
254
|
def format_uri(uri, options = {})
|
251
255
|
uri.to_base
|
@@ -255,7 +259,7 @@ module RDF::NTriples
|
|
255
259
|
# Returns the N-Triples representation of a literal.
|
256
260
|
#
|
257
261
|
# @param [RDF::Literal, String, #to_s] literal
|
258
|
-
# @param [Hash{Symbol => Object}] options
|
262
|
+
# @param [Hash{Symbol => Object}] options = ({})
|
259
263
|
# @return [String]
|
260
264
|
def format_literal(literal, options = {})
|
261
265
|
case literal
|
data/lib/rdf/query/pattern.rb
CHANGED
@@ -18,21 +18,23 @@ module RDF; class Query
|
|
18
18
|
##
|
19
19
|
# @overload initialize(options = {})
|
20
20
|
# @param [Hash{Symbol => Object}] options
|
21
|
-
# @option options [Variable, Resource, nil] :subject (nil)
|
22
|
-
# @option options [Variable, URI, nil] :predicate (nil)
|
23
|
-
# @option options [Variable, Term, nil] :object (nil)
|
24
|
-
# @option options [Variable, Resource, nil, false] :context (nil)
|
21
|
+
# @option options [Variable, Resource, Symbol, nil] :subject (nil)
|
22
|
+
# @option options [Variable, URI, Symbol, nil] :predicate (nil)
|
23
|
+
# @option options [Variable, Term, Symbol, nil] :object (nil)
|
24
|
+
# @option options [Variable, Resource, Symbol, nil, false] :context (nil)
|
25
25
|
# A context of nil matches any context, a context of false, matches only the default context.
|
26
26
|
# @option options [Boolean] :optional (false)
|
27
27
|
#
|
28
28
|
# @overload initialize(subject, predicate, object, options = {})
|
29
|
-
# @param [Variable, Resource, nil] subject
|
30
|
-
# @param [Variable, URI, nil] predicate
|
31
|
-
# @param [Variable, Termm, nil] object
|
29
|
+
# @param [Variable, Resource, Symbol, nil] subject
|
30
|
+
# @param [Variable, URI, Symbol, nil] predicate
|
31
|
+
# @param [Variable, Termm, Symbol, nil] object
|
32
32
|
# @param [Hash{Symbol => Object}] options
|
33
|
-
# @option options [Variable, Resource, nil, false] :context (nil)
|
33
|
+
# @option options [Variable, Resource, Symbol, nil, false] :context (nil)
|
34
34
|
# A context of nil matches any context, a context of false, matches only the default context.
|
35
35
|
# @option options [Boolean] :optional (false)
|
36
|
+
#
|
37
|
+
# @note {Statement} treats symbols as interned {Node} instances, in a {Pattern}, they are treated as {Variable}.
|
36
38
|
def initialize(subject = nil, predicate = nil, object = nil, options = {})
|
37
39
|
super
|
38
40
|
end
|
data/lib/rdf/reader.rb
CHANGED
@@ -115,9 +115,18 @@ module RDF
|
|
115
115
|
##
|
116
116
|
# Parses input from the given file name or URL.
|
117
117
|
#
|
118
|
+
# @note A reader returned via this method may not be readable depending on the processing model of the specific reader, as the file is only open during the scope of `open`. The reader is intended to be accessed through a block.
|
119
|
+
#
|
120
|
+
# @example Parsing RDF statements from a file
|
121
|
+
# RDF::Reader.open("etc/doap.nt") do |reader|
|
122
|
+
# reader.each_statement do |statement|
|
123
|
+
# puts statement.inspect
|
124
|
+
# end
|
125
|
+
# end
|
126
|
+
#
|
118
127
|
# @param [String, #to_s] filename
|
119
128
|
# @param [Hash{Symbol => Object}] options
|
120
|
-
# any additional options (see {RDF::Reader#initialize} and {RDF::Format.for})
|
129
|
+
# any additional options (see {RDF::Util::File.open_file}, {RDF::Reader#initialize} and {RDF::Format.for})
|
121
130
|
# @option options [Symbol] :format (:ntriples)
|
122
131
|
# @yield [reader]
|
123
132
|
# @yieldparam [RDF::Reader] reader
|
@@ -138,7 +147,7 @@ module RDF
|
|
138
147
|
if reader
|
139
148
|
reader.new(file, options, &block)
|
140
149
|
else
|
141
|
-
raise FormatError, "unknown RDF format: #{format_options.inspect}"
|
150
|
+
raise FormatError, "unknown RDF format: #{format_options.inspect}\nThis may be resolved with a require of the 'linkeddata' gem."
|
142
151
|
end
|
143
152
|
end
|
144
153
|
end
|
data/lib/rdf/repository.rb
CHANGED
@@ -71,7 +71,7 @@ module RDF
|
|
71
71
|
#
|
72
72
|
# @param [String, Array<String>] filenames
|
73
73
|
# @param [Hash{Symbol => Object}] options
|
74
|
-
# Options from {RDF::
|
74
|
+
# Options from {RDF::Repository#initialize} and {RDF::Mutable#load}
|
75
75
|
# @yield [repository]
|
76
76
|
# @yieldparam [Repository]
|
77
77
|
# @return [void]
|
data/lib/rdf/vocab.rb
CHANGED
@@ -2,6 +2,11 @@ module RDF
|
|
2
2
|
##
|
3
3
|
# A {Vocabulary} represents an RDFS or OWL vocabulary.
|
4
4
|
#
|
5
|
+
# A {Vocabulary} can also serve as a Domain Specific Language (DSL) for generating an RDF Graph definition for the vocabulary (see {RDF::Vocabulary#to_graph}).
|
6
|
+
#
|
7
|
+
# ### Defining a vocabulary using the DSL
|
8
|
+
# Vocabularies can be defined based on {RDF::Vocabulary} or {RDF::StrictVocabulary} using a simple Domain Specific Language (DSL). Terms of the vocabulary are specified using either `property` or `term` (alias), with the attributes of the term listed in a hash. See {property} for description of the hash.
|
9
|
+
#
|
5
10
|
# ### Vocabularies:
|
6
11
|
#
|
7
12
|
# The following vocabularies are pre-defined for your convenience:
|
@@ -16,7 +21,7 @@ module RDF
|
|
16
21
|
# * {RDF::FOAF} - Friend of a Friend (FOAF)
|
17
22
|
# * {RDF::GEO} - WGS84 Geo Positioning (GEO)
|
18
23
|
# * {RDF::GR} - Good Relations
|
19
|
-
# * {RDF::
|
24
|
+
# * {RDF::HT} - Hypertext Transfer Protocol (HTTP)
|
20
25
|
# * {RDF::ICAL} - iCal
|
21
26
|
# * {RDF::MA} - W3C Meda Annotations
|
22
27
|
# * {RDF::OG} - FaceBook OpenGraph
|
@@ -55,6 +60,19 @@ module RDF
|
|
55
60
|
# foaf[:name] #=> RDF::URI("http://xmlns.com/foaf/0.1/name")
|
56
61
|
# foaf['mbox'] #=> RDF::URI("http://xmlns.com/foaf/0.1/mbox")
|
57
62
|
#
|
63
|
+
# @example Generating RDF from a vocabulary definition
|
64
|
+
# graph = RDF::RDFS.to_graph
|
65
|
+
# graph.dump(:ntriples)
|
66
|
+
#
|
67
|
+
# @example Defining a simple vocabulary
|
68
|
+
# class EX < RDF::StrictVocabulay("http://example/ns#")
|
69
|
+
# term :Class,
|
70
|
+
# label: "My Class",
|
71
|
+
# comment: "Good to use as an example",
|
72
|
+
# "rdf:type" => "rdfs:Class",
|
73
|
+
# "rdfs:subClassOf" => "http://example/SuperClass"
|
74
|
+
# end
|
75
|
+
#
|
58
76
|
# @see http://www.w3.org/TR/curie/
|
59
77
|
# @see http://en.wikipedia.org/wiki/QName
|
60
78
|
class Vocabulary
|
@@ -73,56 +91,125 @@ module RDF
|
|
73
91
|
# Ruby's autoloading facility, meaning that `@@subclasses` will be
|
74
92
|
# empty until each subclass has been touched or require'd.
|
75
93
|
RDF::VOCABS.each { |v| require "rdf/vocab/#{v}" unless v == :rdf }
|
76
|
-
@@subclasses.each(&block)
|
94
|
+
@@subclasses.select(&:name).each(&block)
|
77
95
|
else
|
78
|
-
|
96
|
+
__properties__.each(&block)
|
79
97
|
end
|
80
98
|
end
|
81
99
|
|
100
|
+
##
|
101
|
+
# Is this a strict vocabulary, or a liberal vocabulary allowing arbitrary properties?
|
102
|
+
def strict?; false; end
|
103
|
+
|
82
104
|
##
|
83
105
|
# @overload property
|
84
106
|
# Returns `property` in the current vocabulary
|
85
|
-
# @return [RDF::
|
107
|
+
# @return [RDF::Vocabulary::Term]
|
86
108
|
#
|
87
109
|
# @overload property(name, options)
|
88
110
|
# Defines a new property or class in the vocabulary.
|
89
|
-
# Optional labels and comments are stripped of unnecessary whitespace.
|
90
111
|
#
|
91
112
|
# @param [String, #to_s] name
|
92
113
|
# @param [Hash{Symbol => Object}] options
|
93
|
-
#
|
94
|
-
# @option options [String,
|
114
|
+
# Any other values are expected to be String which expands to a {URI} using built-in vocabulary prefixes. The value is a `String` or `Array<String>` which is interpreted according to the `range` of the associated property.
|
115
|
+
# @option options [String, Array<String>] :label
|
116
|
+
# Shortcut for `rdfs:label`, values are String interpreted as a {Literal}.
|
117
|
+
# @option options [String, Array<String>] :comment
|
118
|
+
# Shortcut for `rdfs:comment`, values are String interpreted as a {Literal}.
|
119
|
+
# @option options [String, Array<String>] :subClassOf
|
120
|
+
# Shortcut for `rdfs:subClassOf`, values are String interpreted as a {URI}.
|
121
|
+
# @option options [String, Array<String>] :subPropertyOf
|
122
|
+
# Shortcut for `rdfs:subPropertyOf`, values are String interpreted as a {URI}.
|
123
|
+
# @option options [String, Array<String>] :domain
|
124
|
+
# Shortcut for `rdfs:domain`, values are String interpreted as a {URI}.
|
125
|
+
# @option options [String, Array<String>] :range
|
126
|
+
# Shortcut for `rdfs:range`, values are String interpreted as a {URI}.
|
127
|
+
# @option options [String, Array<String>] :type
|
128
|
+
# Shortcut for `rdf:type`, values are String interpreted as a {URI}.
|
129
|
+
# @return [RDF::Vocabulary::Term]
|
95
130
|
def property(*args)
|
96
131
|
case args.length
|
97
132
|
when 0
|
98
|
-
|
133
|
+
Term.intern("#{self}property", attributes: {label: "property", vocab: self})
|
99
134
|
else
|
100
135
|
name, options = args
|
101
|
-
options
|
102
|
-
prop =
|
103
|
-
|
104
|
-
@@comments[prop] = options[:comment].to_s.strip.gsub(/\s+/m, ' ') if options[:comment]
|
136
|
+
options = {:label => name.to_s, vocab: self}.merge(options || {})
|
137
|
+
prop = Term.intern([to_s, name.to_s].join(''), attributes: options)
|
138
|
+
props[prop] = options
|
105
139
|
(class << self; self; end).send(:define_method, name) { prop } unless name.to_s == "property"
|
140
|
+
prop
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
# Alternate use for vocabulary terms, functionally equivalent to {#property}.
|
145
|
+
alias_method :term, :property
|
146
|
+
alias_method :__property__, :property
|
147
|
+
|
148
|
+
##
|
149
|
+
# @return [Array<RDF::URI>] a list of properties in the current vocabulary
|
150
|
+
def properties
|
151
|
+
props.keys
|
152
|
+
end
|
153
|
+
alias_method :__properties__, :properties
|
154
|
+
|
155
|
+
##
|
156
|
+
# Attempt to expand a Compact IRI/PName/QName using loaded vocabularies
|
157
|
+
#
|
158
|
+
# @param [String, #to_s] pname
|
159
|
+
# @return [RDF::URI]
|
160
|
+
def expand_pname(pname)
|
161
|
+
prefix, suffix = pname.to_s.split(":", 2)
|
162
|
+
if prefix == "rdf"
|
163
|
+
RDF[suffix]
|
164
|
+
elsif vocab = RDF::Vocabulary.each.detect {|v| v.__name__ && v.__prefix__ == prefix.to_sym}
|
165
|
+
suffix.to_s.empty? ? vocab.to_uri : vocab[suffix]
|
166
|
+
else
|
167
|
+
RDF::Vocabulary.find_term(pname) || RDF::URI(pname)
|
106
168
|
end
|
107
169
|
end
|
108
170
|
|
171
|
+
##
|
172
|
+
# Return the Vocabulary associated with a URI
|
173
|
+
#
|
174
|
+
# @param [RDF::URI] uri
|
175
|
+
# @return [Vocabulary]
|
176
|
+
def find(uri)
|
177
|
+
RDF::Vocabulary.detect {|v| RDF::URI(uri).start_with?(v.to_uri)}
|
178
|
+
end
|
179
|
+
|
180
|
+
##
|
181
|
+
# Return the Vocabulary term associated with a URI
|
182
|
+
#
|
183
|
+
# @param [RDF::URI] uri
|
184
|
+
# @return [Vocabulary::Term]
|
185
|
+
def find_term(uri)
|
186
|
+
uri = RDF::URI(uri)
|
187
|
+
return uri if uri.is_a?(Vocabulary::Term)
|
188
|
+
vocab = RDF::Vocabulary.detect {|v| uri.start_with?(v.to_uri)}
|
189
|
+
term = vocab[uri.to_s[vocab.to_uri.to_s.length..-1]] if vocab
|
190
|
+
end
|
191
|
+
|
109
192
|
##
|
110
193
|
# Returns the URI for the term `property` in this vocabulary.
|
111
194
|
#
|
112
195
|
# @param [#to_s] property
|
113
196
|
# @return [RDF::URI]
|
114
197
|
def [](property)
|
115
|
-
|
198
|
+
if self.respond_to?(property.to_sym)
|
199
|
+
self.send(property.to_sym)
|
200
|
+
else
|
201
|
+
Term.intern([to_s, property.to_s].join(''), attributes: {vocab: self})
|
202
|
+
end
|
116
203
|
end
|
117
204
|
|
118
205
|
# @return [String] The label for the named property
|
119
206
|
def label_for(name)
|
120
|
-
|
207
|
+
props.fetch(self[name], {}).fetch(:label, "")
|
121
208
|
end
|
122
209
|
|
123
210
|
# @return [String] The comment for the named property
|
124
211
|
def comment_for(name)
|
125
|
-
|
212
|
+
props.fetch(self[name], {}).fetch(:comment, "")
|
126
213
|
end
|
127
214
|
|
128
215
|
##
|
@@ -133,6 +220,65 @@ module RDF
|
|
133
220
|
RDF::URI.intern(to_s)
|
134
221
|
end
|
135
222
|
|
223
|
+
# For IRI compatibility
|
224
|
+
alias_method :to_iri, :to_uri
|
225
|
+
|
226
|
+
##
|
227
|
+
# Return an enumerator over {RDF::Statement} defined for this vocabulary.
|
228
|
+
# @return [RDF::Enumerable::Enumerator]
|
229
|
+
# @see Object#enum_for
|
230
|
+
def enum_for(method = :each_statement, *args)
|
231
|
+
# Ensure that enumerators are, themselves, queryable
|
232
|
+
this = self
|
233
|
+
Enumerable::Enumerator.new do |yielder|
|
234
|
+
this.send(method, *args) {|*y| yielder << (y.length > 1 ? y : y.first)}
|
235
|
+
end
|
236
|
+
end
|
237
|
+
alias_method :to_enum, :enum_for
|
238
|
+
|
239
|
+
##
|
240
|
+
# Enumerate each statement constructed from the defined vocabulary terms
|
241
|
+
#
|
242
|
+
# If a property value is known to be a {URI}, or expands to a {URI}, the `object` is a URI, otherwise, it will be a {Literal}.
|
243
|
+
#
|
244
|
+
# @yield statement
|
245
|
+
# @yieldparam [RDF::Statement]
|
246
|
+
def each_statement(&block)
|
247
|
+
props.each do |subject, attributes|
|
248
|
+
attributes.each do |prop, values|
|
249
|
+
prop = RDF::Vocabulary.expand_pname(prop) unless prop.is_a?(Symbol)
|
250
|
+
next unless prop
|
251
|
+
Array(values).each do |value|
|
252
|
+
case prop
|
253
|
+
when :type
|
254
|
+
prop = RDF.type
|
255
|
+
value = expand_pname(value)
|
256
|
+
when :subClassOf
|
257
|
+
prop = RDFS.subClassOf
|
258
|
+
value = expand_pname(value)
|
259
|
+
when :subPropertyOf
|
260
|
+
prop = RDFS.subPropertyOf
|
261
|
+
value = expand_pname(value)
|
262
|
+
when :domain
|
263
|
+
prop = RDFS.domain
|
264
|
+
value = expand_pname(value)
|
265
|
+
when :range
|
266
|
+
prop = RDFS.range
|
267
|
+
value = expand_pname(value)
|
268
|
+
when :label
|
269
|
+
prop = RDFS.label
|
270
|
+
when :comment
|
271
|
+
prop = RDFS.comment
|
272
|
+
else
|
273
|
+
value = RDF::Vocabulary.expand_pname(value)
|
274
|
+
end
|
275
|
+
|
276
|
+
block.call RDF::Statement(subject, prop, value)
|
277
|
+
end
|
278
|
+
end
|
279
|
+
end
|
280
|
+
end
|
281
|
+
|
136
282
|
##
|
137
283
|
# Returns a string representation of this vocabulary class.
|
138
284
|
#
|
@@ -141,6 +287,71 @@ module RDF
|
|
141
287
|
@@uris.has_key?(self) ? @@uris[self].to_s : super
|
142
288
|
end
|
143
289
|
|
290
|
+
##
|
291
|
+
# Load a vocabulary, optionally from a separate location.
|
292
|
+
#
|
293
|
+
# @param [URI, #to_s] uri
|
294
|
+
# @param [Hash{Symbol => Object}] options
|
295
|
+
# @option options [String] class_name
|
296
|
+
# The class_name associated with the vocabulary, used for creating the class name of the vocabulary. This will create a new class named with a top-level constant based on `class_name`.
|
297
|
+
# @option options [URI, #to_s] :location
|
298
|
+
# Location from which to load the vocabulary, if not from `uri`.
|
299
|
+
# @option options [Array<Symbol>, Hash{Symbol => Hash}] :extra
|
300
|
+
# Extra terms to add to the vocabulary. In the first form, it is an array of symbols, for which terms are created. In the second, it is a Hash mapping symbols to property attributes, as described in {#property}.
|
301
|
+
# @return [RDF::Vocabulary] the loaded vocabulary
|
302
|
+
def load(uri, options = {})
|
303
|
+
source = options.fetch(:location, uri)
|
304
|
+
class_name = options[:class_name]
|
305
|
+
vocab = if class_name
|
306
|
+
Object.const_set(class_name, Class.new(self.create(uri)))
|
307
|
+
else
|
308
|
+
Class.new(self.create(uri))
|
309
|
+
end
|
310
|
+
|
311
|
+
graph = RDF::Graph.load(source)
|
312
|
+
term_defs = {}
|
313
|
+
graph.each do |statement|
|
314
|
+
next unless statement.subject.uri? && statement.subject.start_with?(uri)
|
315
|
+
name = statement.subject.to_s[uri.to_s.length..-1]
|
316
|
+
term = (term_defs[name.to_sym] ||= {})
|
317
|
+
key = case statement.predicate
|
318
|
+
when RDF.type then :type
|
319
|
+
when RDF::RDFS.subClassOf then :subClassOf
|
320
|
+
when RDF::RDFS.subPropertyOf then :subPropertyOf
|
321
|
+
when RDF::RDFS.range then :range
|
322
|
+
when RDF::RDFS.domain then :domain
|
323
|
+
when RDF::RDFS.comment then :comment
|
324
|
+
when RDF::RDFS.label then :label
|
325
|
+
else statement.predicate.pname
|
326
|
+
end
|
327
|
+
|
328
|
+
value = if statement.object.uri?
|
329
|
+
statement.object.pname
|
330
|
+
elsif statement.object.literal? && (statement.object.language || :en) == :en
|
331
|
+
statement.object.to_s
|
332
|
+
end
|
333
|
+
|
334
|
+
(term[key] ||= []) << value if value
|
335
|
+
end
|
336
|
+
|
337
|
+
# Create extra terms
|
338
|
+
term_defs = case options[:extra]
|
339
|
+
when Array
|
340
|
+
options[:extra].inject({}) {|memo, s| memo[s.to_sym] = {label: s.to_s}; memo}.merge(term_defs)
|
341
|
+
when Hash
|
342
|
+
options[:extra].merge(term_defs)
|
343
|
+
else
|
344
|
+
term_defs
|
345
|
+
end
|
346
|
+
|
347
|
+
# Create each term
|
348
|
+
term_defs.each do |term, attributes|
|
349
|
+
vocab.term term, attributes
|
350
|
+
end
|
351
|
+
|
352
|
+
vocab
|
353
|
+
end
|
354
|
+
|
144
355
|
##
|
145
356
|
# Returns a developer-friendly representation of this vocabulary class.
|
146
357
|
#
|
@@ -156,15 +367,39 @@ module RDF
|
|
156
367
|
# Preserve the class name so that it can be obtained even for
|
157
368
|
# vocabularies that define a `name` property:
|
158
369
|
alias_method :__name__, :name
|
159
|
-
end
|
160
370
|
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
371
|
+
##
|
372
|
+
# Returns a suggested CURIE/PName prefix for this vocabulary class.
|
373
|
+
#
|
374
|
+
# @return [Symbol]
|
375
|
+
# @since 0.3.0
|
376
|
+
def __prefix__
|
377
|
+
__name__.split('::').last.downcase.to_sym
|
378
|
+
end
|
379
|
+
|
380
|
+
protected
|
381
|
+
def inherited(subclass) # @private
|
382
|
+
unless @@uri.nil?
|
383
|
+
@@subclasses << subclass unless %w(http://www.w3.org/1999/02/22-rdf-syntax-ns#).include?(@@uri)
|
384
|
+
subclass.send(:private_class_method, :new)
|
385
|
+
@@uris[subclass] = @@uri
|
386
|
+
@@uri = nil
|
387
|
+
end
|
388
|
+
super
|
389
|
+
end
|
390
|
+
|
391
|
+
def method_missing(property, *args, &block)
|
392
|
+
if %w(to_ary).include?(property.to_s)
|
393
|
+
super
|
394
|
+
elsif args.empty? && !to_s.empty?
|
395
|
+
Term.intern([to_s, property.to_s].join(''), attributes: {vocab: self})
|
396
|
+
else
|
397
|
+
super
|
398
|
+
end
|
399
|
+
end
|
400
|
+
|
401
|
+
private
|
402
|
+
def props; @properties ||= {}; end
|
168
403
|
end
|
169
404
|
|
170
405
|
# Undefine all superfluous instance methods:
|
@@ -189,7 +424,7 @@ module RDF
|
|
189
424
|
# @param [#to_s] property
|
190
425
|
# @return [URI]
|
191
426
|
def [](property)
|
192
|
-
|
427
|
+
Term.intern([to_s, property.to_s].join(''), attributes: {vocab: self.class})
|
193
428
|
end
|
194
429
|
|
195
430
|
##
|
@@ -200,6 +435,9 @@ module RDF
|
|
200
435
|
RDF::URI.intern(to_s)
|
201
436
|
end
|
202
437
|
|
438
|
+
# For IRI compatibility
|
439
|
+
alias_method :to_iri, :to_uri
|
440
|
+
|
203
441
|
##
|
204
442
|
# Returns a string representation of this vocabulary.
|
205
443
|
#
|
@@ -223,29 +461,13 @@ module RDF
|
|
223
461
|
self
|
224
462
|
end
|
225
463
|
|
226
|
-
def self.inherited(subclass) # @private
|
227
|
-
@@subclasses << subclass
|
228
|
-
unless @@uri.nil?
|
229
|
-
subclass.send(:private_class_method, :new)
|
230
|
-
@@uris[subclass] = @@uri
|
231
|
-
@@uri = nil
|
232
|
-
end
|
233
|
-
super
|
234
|
-
end
|
235
|
-
|
236
|
-
def self.method_missing(property, *args, &block)
|
237
|
-
if args.empty? && @@uris.has_key?(self)
|
238
|
-
self[property]
|
239
|
-
else
|
240
|
-
super
|
241
|
-
end
|
242
|
-
end
|
243
|
-
|
244
464
|
def method_missing(property, *args, &block)
|
245
|
-
if
|
465
|
+
if %w(to_ary).include?(property.to_s)
|
466
|
+
super
|
467
|
+
elsif args.empty?
|
246
468
|
self[property]
|
247
469
|
else
|
248
|
-
|
470
|
+
super
|
249
471
|
end
|
250
472
|
end
|
251
473
|
|
@@ -254,73 +476,151 @@ module RDF
|
|
254
476
|
@@subclasses = [::RDF] # @private
|
255
477
|
@@uris = {} # @private
|
256
478
|
@@uri = nil # @private
|
257
|
-
@@labels = {}
|
258
|
-
@@comments = {}
|
259
|
-
end # Vocabulary
|
260
479
|
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
480
|
+
# A Vocabulary Term is a URI that can also act as an {Enumerable} to generate the RDF definition of vocabulary terms as defined within the vocabulary definition.
|
481
|
+
class Term < RDF::URI
|
482
|
+
# Attributes of this vocabulary term, used for finding `label` and `comment` and to serialize the term back to RDF.
|
483
|
+
# @return [Hash{Symbol,Resource => Term, #to_s}]
|
484
|
+
attr_accessor :attributes
|
485
|
+
|
486
|
+
##
|
487
|
+
# @overload URI(uri, options = {})
|
488
|
+
# @param [URI, String, #to_s] uri
|
489
|
+
# @param [Hash{Symbol => Object}] options
|
490
|
+
# @option options [Boolean] :validate (false)
|
491
|
+
# @option options [Boolean] :canonicalize (false)
|
492
|
+
# @option options [Hash{Symbol,Resource => Term, #to_s}] :attributes
|
493
|
+
# Attributes of this vocabulary term, used for finding `label` and `comment` and to serialize the term back to RDF
|
494
|
+
#
|
495
|
+
# @overload URI(options = {})
|
496
|
+
# @param [Hash{Symbol => Object}] options
|
497
|
+
# @option options [Boolean] :validate (false)
|
498
|
+
# @option options [Boolean] :canonicalize (false)
|
499
|
+
# @option [Vocabulary] :vocab The {Vocabulary} associated with this term.
|
500
|
+
# @option [String, #to_s] :scheme The scheme component.
|
501
|
+
# @option [String, #to_s] :user The user component.
|
502
|
+
# @option [String, #to_s] :password The password component.
|
503
|
+
# @option [String, #to_s] :userinfo
|
504
|
+
# The userinfo component. If this is supplied, the user and password
|
505
|
+
# components must be omitted.
|
506
|
+
# @option [String, #to_s] :host The host component.
|
507
|
+
# @option [String, #to_s] :port The port component.
|
508
|
+
# @option [String, #to_s] :authority
|
509
|
+
# The authority component. If this is supplied, the user, password,
|
510
|
+
# userinfo, host, and port components must be omitted.
|
511
|
+
# @option [String, #to_s] :path The path component.
|
512
|
+
# @option [String, #to_s] :query The query component.
|
513
|
+
# @option [String, #to_s] :fragment The fragment component.
|
514
|
+
# @option options [Hash{Symbol,Resource => Term, #to_s}] :attributes
|
515
|
+
# Attributes of this vocabulary term, used for finding `label` and `comment` and to serialize the term back to RDF
|
516
|
+
def initialize(*args)
|
517
|
+
options = args.last.is_a?(Hash) ? args.last : {}
|
518
|
+
@attributes = options.fetch(:attributes)
|
519
|
+
super
|
274
520
|
end
|
275
521
|
|
276
522
|
##
|
277
|
-
#
|
278
|
-
# Returns `property` in the current vocabulary
|
279
|
-
# @return [RDF::URI]
|
523
|
+
# Vocabulary of this term.
|
280
524
|
#
|
281
|
-
# @
|
282
|
-
|
283
|
-
|
525
|
+
# @return [RDF::Vocabulary]
|
526
|
+
def vocab; @attributes.fetch(:vocab); end
|
527
|
+
|
528
|
+
##
|
529
|
+
# Returns a duplicate copy of `self`.
|
284
530
|
#
|
285
|
-
#
|
286
|
-
|
287
|
-
|
288
|
-
# @option options [String, #to_s] :comment
|
289
|
-
def property(*args)
|
290
|
-
case args.length
|
291
|
-
when 0
|
292
|
-
RDF::URI.intern("#{self}property")
|
293
|
-
else
|
294
|
-
name, options = args
|
295
|
-
options ||= {}
|
296
|
-
prop = RDF::URI.intern([to_s, name.to_s].join(''))
|
297
|
-
@@properties[prop] = true
|
298
|
-
@@labels[prop] = options[:label].to_s.strip.gsub(/\s+/m, ' ') if options[:label]
|
299
|
-
@@comments[prop] = options[:comment].to_s.strip.gsub(/\s+/m, ' ') if options[:comment]
|
300
|
-
(class << self; self; end).send(:define_method, name) { prop } unless name.to_s == "property"
|
301
|
-
end
|
531
|
+
# @return [RDF::URI]
|
532
|
+
def dup
|
533
|
+
self.class.new((@value || @object).dup, attributes: @attributes)
|
302
534
|
end
|
303
535
|
|
304
536
|
##
|
305
|
-
#
|
306
|
-
|
307
|
-
|
537
|
+
# Determine if the URI is a valid according to RFC3987
|
538
|
+
#
|
539
|
+
# @return [Boolean] `true` or `false`
|
540
|
+
# @since 0.3.9
|
541
|
+
def valid?
|
542
|
+
# Validate relative to RFC3987
|
543
|
+
to_s.match(RDF::URI::IRI) || false
|
308
544
|
end
|
309
545
|
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
546
|
+
##
|
547
|
+
# Is this a class term?
|
548
|
+
# @return [Boolean]
|
549
|
+
def class?
|
550
|
+
!!(self.type.to_s =~ /Class/)
|
551
|
+
end
|
552
|
+
|
553
|
+
##
|
554
|
+
# Is this a class term?
|
555
|
+
# @return [Boolean]
|
556
|
+
def property?
|
557
|
+
!!(self.type.to_s =~ /Property/)
|
558
|
+
end
|
559
|
+
|
560
|
+
##
|
561
|
+
# Is this a class term?
|
562
|
+
# @return [Boolean]
|
563
|
+
def datatype?
|
564
|
+
!!(self.type.to_s =~ /Datatype/)
|
565
|
+
end
|
566
|
+
|
567
|
+
##
|
568
|
+
# Is this neither a class, property or datatype term?
|
569
|
+
# @return [Boolean]
|
570
|
+
def other?
|
571
|
+
!!(self.type.to_s !~ /(Class|Property|Datatype)/)
|
572
|
+
end
|
573
|
+
|
574
|
+
##
|
575
|
+
# Returns a <code>String</code> representation of the URI object's state.
|
576
|
+
#
|
577
|
+
# @return [String] The URI object's state, as a <code>String</code>.
|
578
|
+
def inspect
|
579
|
+
sprintf("#<%s:%#0x URI:%s>", Term.to_s, self.object_id, self.to_s)
|
580
|
+
end
|
581
|
+
|
582
|
+
# Implement accessor to symbol attributes
|
583
|
+
def respond_to?(method)
|
584
|
+
@attributes.has_key?(method) || super
|
585
|
+
end
|
586
|
+
|
587
|
+
protected
|
588
|
+
# Implement accessor to symbol attributes
|
589
|
+
def method_missing(method, *args, &block)
|
590
|
+
case method
|
591
|
+
when :comment
|
592
|
+
@attributes.fetch(method, "")
|
593
|
+
when :label
|
594
|
+
@attributes.fetch(method, to_s.split(/[\/\#]/).last)
|
595
|
+
when :type, :subClassOf, :subPropertyOf, :domain, :range
|
596
|
+
Array(@attributes[method]).map {|v| RDF::Vocabulary.expand_pname(v)}
|
597
|
+
else
|
598
|
+
super
|
599
|
+
end
|
314
600
|
end
|
315
601
|
end
|
602
|
+
end # Vocabulary
|
316
603
|
|
317
|
-
|
604
|
+
# Represents an RDF Vocabulary. The difference from {RDF::Vocabulary} is that
|
605
|
+
# that every concept in the vocabulary is required to be declared. To assist
|
606
|
+
# in this, an existing RDF representation of the vocabulary can be loaded as
|
607
|
+
# the basis for concepts being available
|
608
|
+
class StrictVocabulary < Vocabulary
|
609
|
+
class << self
|
610
|
+
# Redefines method_missing to the original definition
|
611
|
+
# By remaining a subclass of Vocabulary, we remain available to
|
612
|
+
# Vocabulary::each etc.
|
318
613
|
define_method(:method_missing, BasicObject.instance_method(:method_missing))
|
319
|
-
rescue NameError
|
320
|
-
define_method(:method_missing, Kernel.instance_method(:method_missing))
|
321
|
-
end
|
322
614
|
|
323
|
-
|
324
|
-
|
615
|
+
##
|
616
|
+
# Is this a strict vocabulary, or a liberal vocabulary allowing arbitrary properties?
|
617
|
+
def strict?; true; end
|
618
|
+
|
619
|
+
def [](name)
|
620
|
+
prop = super
|
621
|
+
props.fetch(prop) #raises KeyError on missing value
|
622
|
+
return prop
|
623
|
+
end
|
624
|
+
end
|
325
625
|
end # StrictVocabulary
|
326
626
|
end # RDF
|