rdf 2.2.12 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/README.md +1 -1
- data/VERSION +1 -1
- data/lib/rdf.rb +1 -1
- data/lib/rdf/format.rb +97 -66
- data/lib/rdf/mixin/enumerable.rb +0 -17
- data/lib/rdf/mixin/enumerator.rb +0 -34
- data/lib/rdf/model/literal/date.rb +1 -1
- data/lib/rdf/model/literal/datetime.rb +1 -1
- data/lib/rdf/model/literal/decimal.rb +1 -1
- data/lib/rdf/model/literal/double.rb +1 -1
- data/lib/rdf/model/literal/integer.rb +1 -1
- data/lib/rdf/model/literal/time.rb +1 -1
- data/lib/rdf/model/node.rb +3 -14
- data/lib/rdf/model/statement.rb +0 -28
- data/lib/rdf/model/uri.rb +3 -24
- data/lib/rdf/query.rb +23 -8
- data/lib/rdf/query/pattern.rb +6 -12
- data/lib/rdf/query/solution.rb +2 -14
- data/lib/rdf/query/variable.rb +0 -21
- data/lib/rdf/util/file.rb +1 -2
- data/lib/rdf/vocab/owl.rb +84 -84
- data/lib/rdf/vocab/rdfs.rb +17 -17
- data/lib/rdf/vocab/rdfv.rb +23 -23
- data/lib/rdf/vocab/writer.rb +50 -8
- data/lib/rdf/vocabulary.rb +554 -191
- metadata +23 -24
- data/lib/df.rb +0 -1
data/lib/rdf/vocab/rdfs.rb
CHANGED
@@ -11,46 +11,46 @@ module RDF
|
|
11
11
|
|
12
12
|
# Ontology definition
|
13
13
|
ontology :"http://www.w3.org/2000/01/rdf-schema#",
|
14
|
-
|
15
|
-
|
14
|
+
"dc11:title": %(The RDF Schema vocabulary \(RDFS\)).freeze,
|
15
|
+
"rdfs:seeAlso": %(http://www.w3.org/2000/01/rdf-schema-more).freeze,
|
16
16
|
type: "owl:Ontology".freeze
|
17
17
|
|
18
18
|
# Class definitions
|
19
19
|
term :Class,
|
20
20
|
comment: %(The class of classes.).freeze,
|
21
21
|
label: "Class".freeze,
|
22
|
-
:
|
22
|
+
isDefinedBy: %(rdfs:).freeze,
|
23
23
|
subClassOf: "rdfs:Resource".freeze,
|
24
24
|
type: "rdfs:Class".freeze
|
25
25
|
term :Container,
|
26
26
|
comment: %(The class of RDF containers.).freeze,
|
27
27
|
label: "Container".freeze,
|
28
|
-
:
|
28
|
+
isDefinedBy: %(rdfs:).freeze,
|
29
29
|
subClassOf: "rdfs:Resource".freeze,
|
30
30
|
type: "rdfs:Class".freeze
|
31
31
|
term :ContainerMembershipProperty,
|
32
32
|
comment: %(The class of container membership properties, rdf:_1, rdf:_2, ...,
|
33
33
|
all of which are sub-properties of 'member'.).freeze,
|
34
34
|
label: "ContainerMembershipProperty".freeze,
|
35
|
-
:
|
35
|
+
isDefinedBy: %(rdfs:).freeze,
|
36
36
|
subClassOf: "rdf:Property".freeze,
|
37
37
|
type: "rdfs:Class".freeze
|
38
38
|
term :Datatype,
|
39
39
|
comment: %(The class of RDF datatypes.).freeze,
|
40
40
|
label: "Datatype".freeze,
|
41
|
-
:
|
41
|
+
isDefinedBy: %(rdfs:).freeze,
|
42
42
|
subClassOf: "rdfs:Class".freeze,
|
43
43
|
type: "rdfs:Class".freeze
|
44
44
|
term :Literal,
|
45
45
|
comment: %(The class of literal values, eg. textual strings and integers.).freeze,
|
46
46
|
label: "Literal".freeze,
|
47
|
-
:
|
47
|
+
isDefinedBy: %(rdfs:).freeze,
|
48
48
|
subClassOf: "rdfs:Resource".freeze,
|
49
49
|
type: "rdfs:Class".freeze
|
50
50
|
term :Resource,
|
51
51
|
comment: %(The class resource, everything.).freeze,
|
52
52
|
label: "Resource".freeze,
|
53
|
-
:
|
53
|
+
isDefinedBy: %(rdfs:).freeze,
|
54
54
|
type: "rdfs:Class".freeze
|
55
55
|
|
56
56
|
# Property definitions
|
@@ -59,21 +59,21 @@ module RDF
|
|
59
59
|
domain: "rdfs:Resource".freeze,
|
60
60
|
label: "comment".freeze,
|
61
61
|
range: "rdfs:Literal".freeze,
|
62
|
-
:
|
62
|
+
isDefinedBy: %(rdfs:).freeze,
|
63
63
|
type: "rdf:Property".freeze
|
64
64
|
property :domain,
|
65
65
|
comment: %(A domain of the subject property.).freeze,
|
66
66
|
domain: "rdf:Property".freeze,
|
67
67
|
label: "domain".freeze,
|
68
68
|
range: "rdfs:Class".freeze,
|
69
|
-
:
|
69
|
+
isDefinedBy: %(rdfs:).freeze,
|
70
70
|
type: "rdf:Property".freeze
|
71
71
|
property :isDefinedBy,
|
72
72
|
comment: %(The defininition of the subject resource.).freeze,
|
73
73
|
domain: "rdfs:Resource".freeze,
|
74
74
|
label: "isDefinedBy".freeze,
|
75
75
|
range: "rdfs:Resource".freeze,
|
76
|
-
:
|
76
|
+
isDefinedBy: %(rdfs:).freeze,
|
77
77
|
subPropertyOf: "rdfs:seeAlso".freeze,
|
78
78
|
type: "rdf:Property".freeze
|
79
79
|
property :label,
|
@@ -81,42 +81,42 @@ module RDF
|
|
81
81
|
domain: "rdfs:Resource".freeze,
|
82
82
|
label: "label".freeze,
|
83
83
|
range: "rdfs:Literal".freeze,
|
84
|
-
:
|
84
|
+
isDefinedBy: %(rdfs:).freeze,
|
85
85
|
type: "rdf:Property".freeze
|
86
86
|
property :member,
|
87
87
|
comment: %(A member of the subject resource.).freeze,
|
88
88
|
domain: "rdfs:Resource".freeze,
|
89
89
|
label: "member".freeze,
|
90
90
|
range: "rdfs:Resource".freeze,
|
91
|
-
:
|
91
|
+
isDefinedBy: %(rdfs:).freeze,
|
92
92
|
type: "rdf:Property".freeze
|
93
93
|
property :range,
|
94
94
|
comment: %(A range of the subject property.).freeze,
|
95
95
|
domain: "rdf:Property".freeze,
|
96
96
|
label: "range".freeze,
|
97
97
|
range: "rdfs:Class".freeze,
|
98
|
-
:
|
98
|
+
isDefinedBy: %(rdfs:).freeze,
|
99
99
|
type: "rdf:Property".freeze
|
100
100
|
property :seeAlso,
|
101
101
|
comment: %(Further information about the subject resource.).freeze,
|
102
102
|
domain: "rdfs:Resource".freeze,
|
103
103
|
label: "seeAlso".freeze,
|
104
104
|
range: "rdfs:Resource".freeze,
|
105
|
-
:
|
105
|
+
isDefinedBy: %(rdfs:).freeze,
|
106
106
|
type: "rdf:Property".freeze
|
107
107
|
property :subClassOf,
|
108
108
|
comment: %(The subject is a subclass of a class.).freeze,
|
109
109
|
domain: "rdfs:Class".freeze,
|
110
110
|
label: "subClassOf".freeze,
|
111
111
|
range: "rdfs:Class".freeze,
|
112
|
-
:
|
112
|
+
isDefinedBy: %(rdfs:).freeze,
|
113
113
|
type: "rdf:Property".freeze
|
114
114
|
property :subPropertyOf,
|
115
115
|
comment: %(The subject is a subproperty of a property.).freeze,
|
116
116
|
domain: "rdf:Property".freeze,
|
117
117
|
label: "subPropertyOf".freeze,
|
118
118
|
range: "rdf:Property".freeze,
|
119
|
-
:
|
119
|
+
isDefinedBy: %(rdfs:).freeze,
|
120
120
|
type: "rdf:Property".freeze
|
121
121
|
end
|
122
122
|
end
|
data/lib/rdf/vocab/rdfv.rb
CHANGED
@@ -16,45 +16,45 @@ module RDF
|
|
16
16
|
|
17
17
|
# Ontology definition
|
18
18
|
ontology :"http://www.w3.org/1999/02/22-rdf-syntax-ns#",
|
19
|
-
|
20
|
-
|
19
|
+
"dc11:description": %(This is the RDF Schema for the RDF vocabulary terms in the RDF Namespace, defined in RDF 1.1 Concepts.).freeze,
|
20
|
+
"dc11:title": %(The RDF Concepts Vocabulary \(RDF\)).freeze,
|
21
21
|
type: "owl:Ontology".freeze
|
22
22
|
|
23
23
|
# Class definitions
|
24
24
|
term :Alt,
|
25
25
|
comment: %(The class of containers of alternatives.).freeze,
|
26
26
|
label: "Alt".freeze,
|
27
|
-
:
|
27
|
+
isDefinedBy: %(rdf:).freeze,
|
28
28
|
subClassOf: "rdfs:Container".freeze,
|
29
29
|
type: "rdfs:Class".freeze
|
30
30
|
term :Bag,
|
31
31
|
comment: %(The class of unordered containers.).freeze,
|
32
32
|
label: "Bag".freeze,
|
33
|
-
:
|
33
|
+
isDefinedBy: %(rdf:).freeze,
|
34
34
|
subClassOf: "rdfs:Container".freeze,
|
35
35
|
type: "rdfs:Class".freeze
|
36
36
|
term :List,
|
37
37
|
comment: %(The class of RDF Lists.).freeze,
|
38
38
|
label: "List".freeze,
|
39
|
-
:
|
39
|
+
isDefinedBy: %(rdf:).freeze,
|
40
40
|
subClassOf: "rdfs:Resource".freeze,
|
41
41
|
type: "rdfs:Class".freeze
|
42
42
|
term :Property,
|
43
43
|
comment: %(The class of RDF properties.).freeze,
|
44
44
|
label: "Property".freeze,
|
45
|
-
:
|
45
|
+
isDefinedBy: %(rdf:).freeze,
|
46
46
|
subClassOf: "rdfs:Resource".freeze,
|
47
47
|
type: "rdfs:Class".freeze
|
48
48
|
term :Seq,
|
49
49
|
comment: %(The class of ordered containers.).freeze,
|
50
50
|
label: "Seq".freeze,
|
51
|
-
:
|
51
|
+
isDefinedBy: %(rdf:).freeze,
|
52
52
|
subClassOf: "rdfs:Container".freeze,
|
53
53
|
type: "rdfs:Class".freeze
|
54
54
|
term :Statement,
|
55
55
|
comment: %(The class of RDF statements.).freeze,
|
56
56
|
label: "Statement".freeze,
|
57
|
-
:
|
57
|
+
isDefinedBy: %(rdf:).freeze,
|
58
58
|
subClassOf: "rdfs:Resource".freeze,
|
59
59
|
type: "rdfs:Class".freeze
|
60
60
|
|
@@ -64,77 +64,77 @@ module RDF
|
|
64
64
|
domain: "rdf:List".freeze,
|
65
65
|
label: "first".freeze,
|
66
66
|
range: "rdfs:Resource".freeze,
|
67
|
-
:
|
67
|
+
isDefinedBy: %(rdf:).freeze,
|
68
68
|
type: "rdf:Property".freeze
|
69
69
|
property :object,
|
70
70
|
comment: %(The object of the subject RDF statement.).freeze,
|
71
71
|
domain: "rdf:Statement".freeze,
|
72
72
|
label: "object".freeze,
|
73
73
|
range: "rdfs:Resource".freeze,
|
74
|
-
:
|
74
|
+
isDefinedBy: %(rdf:).freeze,
|
75
75
|
type: "rdf:Property".freeze
|
76
76
|
property :predicate,
|
77
77
|
comment: %(The predicate of the subject RDF statement.).freeze,
|
78
78
|
domain: "rdf:Statement".freeze,
|
79
79
|
label: "predicate".freeze,
|
80
80
|
range: "rdfs:Resource".freeze,
|
81
|
-
:
|
81
|
+
isDefinedBy: %(rdf:).freeze,
|
82
82
|
type: "rdf:Property".freeze
|
83
83
|
property :rest,
|
84
84
|
comment: %(The rest of the subject RDF list after the first item.).freeze,
|
85
85
|
domain: "rdf:List".freeze,
|
86
86
|
label: "rest".freeze,
|
87
87
|
range: "rdf:List".freeze,
|
88
|
-
:
|
88
|
+
isDefinedBy: %(rdf:).freeze,
|
89
89
|
type: "rdf:Property".freeze
|
90
90
|
property :subject,
|
91
91
|
comment: %(The subject of the subject RDF statement.).freeze,
|
92
92
|
domain: "rdf:Statement".freeze,
|
93
93
|
label: "subject".freeze,
|
94
94
|
range: "rdfs:Resource".freeze,
|
95
|
-
:
|
95
|
+
isDefinedBy: %(rdf:).freeze,
|
96
96
|
type: "rdf:Property".freeze
|
97
97
|
property :type,
|
98
98
|
comment: %(The subject is an instance of a class.).freeze,
|
99
99
|
domain: "rdfs:Resource".freeze,
|
100
100
|
label: "type".freeze,
|
101
101
|
range: "rdfs:Class".freeze,
|
102
|
-
:
|
102
|
+
isDefinedBy: %(rdf:).freeze,
|
103
103
|
type: "rdf:Property".freeze
|
104
104
|
property :value,
|
105
105
|
comment: %(Idiomatic property used for structured values.).freeze,
|
106
106
|
domain: "rdfs:Resource".freeze,
|
107
107
|
label: "value".freeze,
|
108
108
|
range: "rdfs:Resource".freeze,
|
109
|
-
:
|
109
|
+
isDefinedBy: %(rdf:).freeze,
|
110
110
|
type: "rdf:Property".freeze
|
111
111
|
|
112
112
|
# Datatype definitions
|
113
113
|
term :HTML,
|
114
114
|
comment: %(The datatype of RDF literals storing fragments of HTML content).freeze,
|
115
115
|
label: "HTML".freeze,
|
116
|
-
:
|
117
|
-
|
116
|
+
isDefinedBy: %(rdf:).freeze,
|
117
|
+
"rdfs:seeAlso": %(http://www.w3.org/TR/rdf11-concepts/#section-html).freeze,
|
118
118
|
subClassOf: "rdfs:Literal".freeze,
|
119
119
|
type: "rdfs:Datatype".freeze
|
120
120
|
term :PlainLiteral,
|
121
121
|
comment: %(The class of plain \(i.e. untyped\) literal values, as used in RIF and OWL 2).freeze,
|
122
122
|
label: "PlainLiteral".freeze,
|
123
|
-
:
|
124
|
-
|
123
|
+
isDefinedBy: %(rdf:).freeze,
|
124
|
+
"rdfs:seeAlso": %(http://www.w3.org/TR/rdf-plain-literal/).freeze,
|
125
125
|
subClassOf: "rdfs:Literal".freeze,
|
126
126
|
type: "rdfs:Datatype".freeze
|
127
127
|
term :XMLLiteral,
|
128
128
|
comment: %(The datatype of XML literal values.).freeze,
|
129
129
|
label: "XMLLiteral".freeze,
|
130
|
-
:
|
130
|
+
isDefinedBy: %(rdf:).freeze,
|
131
131
|
subClassOf: "rdfs:Literal".freeze,
|
132
132
|
type: "rdfs:Datatype".freeze
|
133
133
|
term :langString,
|
134
134
|
comment: %(The datatype of language-tagged string values).freeze,
|
135
135
|
label: "langString".freeze,
|
136
|
-
:
|
137
|
-
|
136
|
+
isDefinedBy: %(rdf:).freeze,
|
137
|
+
"rdfs:seeAlso": %(http://www.w3.org/TR/rdf11-concepts/#section-Graph-Literal).freeze,
|
138
138
|
subClassOf: "rdfs:Literal".freeze,
|
139
139
|
type: "rdfs:Datatype".freeze
|
140
140
|
|
@@ -157,7 +157,7 @@ module RDF
|
|
157
157
|
term :nil,
|
158
158
|
comment: %(The empty list, with no items in it. If the rest of a list is nil then the list has no more items in it.).freeze,
|
159
159
|
label: "nil".freeze,
|
160
|
-
:
|
160
|
+
isDefinedBy: %(rdf:).freeze,
|
161
161
|
type: "rdf:List".freeze
|
162
162
|
term :nodeID,
|
163
163
|
comment: %(RDF/XML Blank Node identifier).freeze,
|
data/lib/rdf/vocab/writer.rb
CHANGED
@@ -5,6 +5,44 @@ module RDF
|
|
5
5
|
##
|
6
6
|
# Vocabulary format specification. This can be used to generate a Ruby class definition from a loaded vocabulary.
|
7
7
|
#
|
8
|
+
# Definitions can include recursive term definitions, when the value of a property is a blank-node term. They can also include list definitions, to provide a reasonable way to represent `owl:unionOf`-type relationships.
|
9
|
+
#
|
10
|
+
# @example a simple term definition
|
11
|
+
# property :comment,
|
12
|
+
# comment: %(A description of the subject resource.).freeze,
|
13
|
+
# domain: "rdfs:Resource".freeze,
|
14
|
+
# label: "comment".freeze,
|
15
|
+
# range: "rdfs:Literal".freeze,
|
16
|
+
# isDefinedBy: %(rdfs:).freeze,
|
17
|
+
# type: "rdf:Property".freeze
|
18
|
+
#
|
19
|
+
# @example an embedded skos:Concept
|
20
|
+
# term :ad,
|
21
|
+
# exactMatch: [term(
|
22
|
+
# type: "skos:Concept".freeze,
|
23
|
+
# inScheme: "country:iso3166-1-alpha-2".freeze,
|
24
|
+
# notation: %(ad).freeze
|
25
|
+
# ), term(
|
26
|
+
# type: "skos:Concept".freeze,
|
27
|
+
# inScheme: "country:iso3166-1-alpha-3".freeze,
|
28
|
+
# notation: %(and).freeze
|
29
|
+
# )],
|
30
|
+
# "foaf:name": "Andorra".freeze,
|
31
|
+
# isDefinedBy: "country:".freeze,
|
32
|
+
# type: "http://sweet.jpl.nasa.gov/2.3/humanJurisdiction.owl#Country".freeze
|
33
|
+
#
|
34
|
+
# @example owl:unionOf
|
35
|
+
# property :duration,
|
36
|
+
# comment: %(The duration of a track or a signal in ms).freeze,
|
37
|
+
# domain: term(
|
38
|
+
# "owl:unionOf": list("mo:Track".freeze, "mo:Signal".freeze),
|
39
|
+
# type: "owl:Class".freeze
|
40
|
+
# ),
|
41
|
+
# isDefinedBy: "mo:".freeze,
|
42
|
+
# "mo:level": "1".freeze,
|
43
|
+
# range: "xsd:float".freeze,
|
44
|
+
# type: "owl:DatatypeProperty".freeze,
|
45
|
+
# "vs:term_status": "testing".freeze
|
8
46
|
class Vocabulary
|
9
47
|
class Format < RDF::Format
|
10
48
|
content_encoding 'utf-8'
|
@@ -171,24 +209,28 @@ module RDF
|
|
171
209
|
|
172
210
|
components = [" #{op} #{name.to_sym.inspect}"]
|
173
211
|
attributes.keys.sort_by(&:to_s).map(&:to_sym).each do |key|
|
174
|
-
next if key == :vocab
|
175
212
|
value = Array(attributes[key])
|
176
|
-
component = key.inspect.start_with?(':"') ? "#{key.inspect}
|
213
|
+
component = key.inspect.start_with?(':"') ? "#{key.to_s.inspect}: " : "#{key}: "
|
177
214
|
value = value.first if value.length == 1
|
178
215
|
component << if value.is_a?(Array)
|
179
|
-
'[' + value.map {|v| serialize_value(v, key)}.sort.join(", ") + "]"
|
216
|
+
'[' + value.map {|v| serialize_value(v, key, indent: " ")}.sort.join(", ") + "]"
|
180
217
|
else
|
181
|
-
serialize_value(value, key)
|
218
|
+
serialize_value(value, key, indent: " ")
|
182
219
|
end
|
183
220
|
components << component
|
184
221
|
end
|
185
222
|
@output.puts components.join(",\n ")
|
186
223
|
end
|
187
224
|
|
188
|
-
def serialize_value(value, key)
|
189
|
-
|
190
|
-
|
191
|
-
|
225
|
+
def serialize_value(value, key, indent: "")
|
226
|
+
if value.is_a?(Literal) && %w(: comment definition notation note editorialNote).include?(key.to_s)
|
227
|
+
"%(#{value.to_s.gsub('(', '\(').gsub(')', '\)')}).freeze"
|
228
|
+
elsif value.is_a?(RDF::URI)
|
229
|
+
"#{value.pname.inspect}.freeze"
|
230
|
+
elsif value.is_a?(RDF::Vocabulary::Term)
|
231
|
+
value.to_ruby(indent: indent + " ")
|
232
|
+
elsif value.is_a?(RDF::Term)
|
233
|
+
"#{value.to_s.inspect}.freeze"
|
192
234
|
else
|
193
235
|
"#{value.inspect}.freeze"
|
194
236
|
end
|
data/lib/rdf/vocabulary.rb
CHANGED
@@ -40,8 +40,6 @@ module RDF
|
|
40
40
|
# foaf['family_name'] #=> RDF::URI("http://xmlns.com/foaf/0.1/family_name")
|
41
41
|
# foaf[:family_name] #=> RDF::URI("http://xmlns.com/foaf/0.1/family_name")
|
42
42
|
#
|
43
|
-
#
|
44
|
-
#
|
45
43
|
# @example Generating RDF from a vocabulary definition
|
46
44
|
# graph = RDF::Graph.new << RDF::RDFS.to_enum
|
47
45
|
# graph.dump(:ntriples)
|
@@ -91,41 +89,128 @@ module RDF
|
|
91
89
|
# @overload property(name, options)
|
92
90
|
# Defines a new property or class in the vocabulary.
|
93
91
|
#
|
92
|
+
# @example A simple term definition
|
93
|
+
# property :domain,
|
94
|
+
# comment: %(A domain of the subject property.).freeze,
|
95
|
+
# domain: "rdf:Property".freeze,
|
96
|
+
# label: "domain".freeze,
|
97
|
+
# range: "rdfs:Class".freeze,
|
98
|
+
# isDefinedBy: %(rdfs:).freeze,
|
99
|
+
# type: "rdf:Property".freeze
|
100
|
+
#
|
101
|
+
# @example A SKOS term with anonymous values
|
102
|
+
# term: :af,
|
103
|
+
# type: "jur:Country",
|
104
|
+
# isDefinedBy: "http://eulersharp.sourceforge.net/2003/03swap/countries#",
|
105
|
+
# "skos:exactMatch": [
|
106
|
+
# Term.new(
|
107
|
+
# type: "skos:Concept",
|
108
|
+
# inScheme: "iso3166-1-alpha-2",
|
109
|
+
# notation: "ax"),
|
110
|
+
# Term.new(
|
111
|
+
# type: "skos:Concept",
|
112
|
+
# inScheme: "iso3166-1-alpha-3",
|
113
|
+
# notation: "ala")
|
114
|
+
# ],
|
115
|
+
# "foaf:name": "Aland Islands"
|
116
|
+
#
|
94
117
|
# @param [String, #to_s] name
|
95
|
-
# @param [Hash{Symbol
|
96
|
-
# Any other values are expected to
|
97
|
-
# @option options [String, Array<String>] :
|
98
|
-
# Shortcut for `
|
118
|
+
# @param [Hash{Symbol=>String,Array<String,Term>}] options
|
119
|
+
# Any other values are expected to expands to a {URI} using built-in vocabulary prefixes. The value is a `String`, `Array<String>` or `Array<Term>` which is interpreted according to the `range` of the associated property.
|
120
|
+
# @option options [String, Array<String,Term>] :type
|
121
|
+
# Shortcut for `rdf:type`, values are interpreted as a {Term}.
|
99
122
|
# @option options [String, Array<String>] :comment
|
100
|
-
# Shortcut for `rdfs:comment`, values are
|
101
|
-
# @option options [String, Array<String>] :
|
102
|
-
# Shortcut for `rdfs:
|
103
|
-
# @option options [String, Array<String>] :
|
104
|
-
# Shortcut for `rdfs:
|
105
|
-
# @option options [String, Array<String>] :
|
106
|
-
# Shortcut for `rdfs:
|
107
|
-
# @option options [String, Array<String>] :range
|
108
|
-
# Shortcut for `rdfs:range`, values are
|
109
|
-
# @option options [String, Array<String>] :
|
110
|
-
# Shortcut for `
|
123
|
+
# Shortcut for `rdfs:comment`, values are interpreted as a {Literal}.
|
124
|
+
# @option options [String, Array<String,Term>] :domain
|
125
|
+
# Shortcut for `rdfs:domain`, values are interpreted as a {Term}.
|
126
|
+
# @option options [String, Array<String,Term>] :isDefinedBy
|
127
|
+
# Shortcut for `rdfs:isDefinedBy`, values are interpreted as a {Term}.
|
128
|
+
# @option options [String, Array<String>] :label
|
129
|
+
# Shortcut for `rdfs:label`, values are interpreted as a {Literal}.
|
130
|
+
# @option options [String, Array<String,Term>] :range
|
131
|
+
# Shortcut for `rdfs:range`, values are interpreted as a {Term}.
|
132
|
+
# @option options [String, Array<String,Term>] :subClassOf
|
133
|
+
# Shortcut for `rdfs:subClassOf`, values are interpreted as a {Term}.
|
134
|
+
# @option options [String, Array<String,Term>] :subPropertyOf
|
135
|
+
# Shortcut for `rdfs:subPropertyOf`, values are interpreted as a {Term}.
|
136
|
+
# @option options [String, Array<String,Term>] :allValuesFrom
|
137
|
+
# Shortcut for `owl:allValuesFrom`, values are interpreted as a {Term}.
|
138
|
+
# @option options [String, Array<String,Term>] :cardinality
|
139
|
+
# Shortcut for `owl:cardinality`, values are interpreted as a {Literal}.
|
140
|
+
# @option options [String, Array<String,Term>] :equivalentClass
|
141
|
+
# Shortcut for `owl:equivalentClass`, values are interpreted as a {Term}.
|
142
|
+
# @option options [String, Array<String,Term>] :equivalentProperty
|
143
|
+
# Shortcut for `owl:equivalentProperty`, values are interpreted as a {Term}.
|
144
|
+
# @option options [String, Array<String,Term>] :intersectionOf
|
145
|
+
# Shortcut for `owl:intersectionOf`, values are interpreted as a {Term}.
|
146
|
+
# @option options [String, Array<String,Term>] :inverseOf
|
147
|
+
# Shortcut for `owl:inverseOf`, values are interpreted as a {Term}.
|
148
|
+
# @option options [String, Array<String,Term>] :maxCardinality
|
149
|
+
# Shortcut for `owl:maxCardinality`, values are interpreted as a {Literal}.
|
150
|
+
# @option options [String, Array<String,Term>] :minCardinality
|
151
|
+
# Shortcut for `owl:minCardinality`, values are interpreted as a {Literal}.
|
152
|
+
# @option options [String, Array<String,Term>] :onProperty
|
153
|
+
# Shortcut for `owl:onProperty`, values are interpreted as a {Term}.
|
154
|
+
# @option options [String, Array<String,Term>] :someValuesFrom
|
155
|
+
# Shortcut for `owl:someValuesFrom`, values are interpreted as a {Term}.
|
156
|
+
# @option options [String, Array<String,Term>] :unionOf
|
157
|
+
# Shortcut for `owl:unionOf`, values are interpreted as a {Term}.
|
158
|
+
# @option options [String, Array<String,Term>] :domainIncludes
|
159
|
+
# Shortcut for `schema:domainIncludes`, values are interpreted as a {Term}.
|
160
|
+
# @option options [String, Array<String,Term>] :rangeIncludes
|
161
|
+
# Shortcut for `schema:rangeIncludes`, values are interpreted as a {Term}.
|
162
|
+
# @option options [String, Array<String>] :altLabel
|
163
|
+
# Shortcut for `skos:altLabel`, values are interpreted as a {Literal}.
|
164
|
+
# @option options [String, Array<String,Term>] :broader
|
165
|
+
# Shortcut for `skos:broader`, values are interpreted as a {Term}.
|
166
|
+
# @option options [String, Array<String>] :definition
|
167
|
+
# Shortcut for `skos:definition`, values are interpreted as a {Literal}.
|
168
|
+
# @option options [String, Array<String>] :editorialNote
|
169
|
+
# Shortcut for `skos:editorialNote`, values are interpreted as a {Literal}.
|
170
|
+
# @option options [String, Array<String,Term>] :exactMatch
|
171
|
+
# Shortcut for `skos:exactMatch`, values are interpreted as a {Term}.
|
172
|
+
# @option options [String, Array<String,Term>] :hasTopConcept
|
173
|
+
# Shortcut for `skos:hasTopConcept`, values are interpreted as a {Term}.
|
174
|
+
# @option options [String, Array<String,Term>] :inScheme
|
175
|
+
# Shortcut for `skos:inScheme`, values are interpreted as a {Term}.
|
176
|
+
# @option options [String, Array<String,Term>] :member
|
177
|
+
# Shortcut for `skos:member`, values are interpreted as a {Term}.
|
178
|
+
# @option options [String, Array<String,Term>] :narrower
|
179
|
+
# Shortcut for `skos:narrower`, values are interpreted as a {Term}.
|
180
|
+
# @option options [String, Array<String>] :notation
|
181
|
+
# Shortcut for `skos:notation`, values are interpreted as a {Literal}.
|
182
|
+
# @option options [String, Array<String>] :note
|
183
|
+
# Shortcut for `skos:note`, values are interpreted as a {Literal}.
|
184
|
+
# @option options [String, Array<String>] :prefLabel
|
185
|
+
# Shortcut for `skos:prefLabel`, values are interpreted as a {Literal}.
|
186
|
+
# @option options [String, Array<String,Term>] :related
|
187
|
+
# Shortcut for `skos:related`, values are interpreted as a {Term}.
|
111
188
|
# @return [RDF::Vocabulary::Term]
|
112
189
|
def property(*args)
|
113
190
|
case args.length
|
114
191
|
when 0
|
115
|
-
Term.intern("#{self}property",
|
192
|
+
Term.intern("#{self}property", vocab: self, attributes: {})
|
116
193
|
else
|
117
|
-
name
|
118
|
-
options =
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
194
|
+
name = args.shift unless args.first.is_a?(Hash)
|
195
|
+
options = args.last
|
196
|
+
if name
|
197
|
+
uri_str = [to_s, name.to_s].join('')
|
198
|
+
URI.cache.delete(uri_str.to_sym) # Clear any previous entry
|
199
|
+
|
200
|
+
# Term attributes passed in a block for lazy evaluation. This helps to avoid load-time circular dependencies
|
201
|
+
prop = Term.intern(uri_str, vocab: self, attributes: options)
|
202
|
+
props[name.to_sym] = prop
|
203
|
+
|
204
|
+
# If name is empty, also treat it as the ontology
|
205
|
+
@ontology ||= prop if name.to_s.empty?
|
206
|
+
|
207
|
+
# Define an accessor, except for problematic properties
|
208
|
+
(class << self; self; end).send(:define_method, name) { prop } unless %w(property hash).include?(name.to_s)
|
209
|
+
else
|
210
|
+
# Define the term without a name
|
211
|
+
# Term attributes passed in a block for lazy evaluation. This helps to avoid load-time circular dependencies
|
212
|
+
prop = Term.new(vocab: self, attributes: options)
|
213
|
+
end
|
129
214
|
prop
|
130
215
|
end
|
131
216
|
end
|
@@ -145,13 +230,27 @@ module RDF
|
|
145
230
|
# @param [String, #to_s] uri
|
146
231
|
# The URI of the ontology.
|
147
232
|
# @param [Hash{Symbol => Object}] options
|
148
|
-
#
|
149
|
-
# @
|
150
|
-
#
|
233
|
+
# See {property}
|
234
|
+
# @param [Hash{Symbol=>String,Array<String,Term>}] options
|
235
|
+
# Any other values are expected to expands to a {URI} using built-in vocabulary prefixes. The value is a `String`, `Array<String>` or `Array<Term>` which is interpreted according to the `range` of the associated property.
|
236
|
+
# @option options [String, Array<String,Term>] :type
|
237
|
+
# Shortcut for `rdf:type`, values are interpreted as a {Term}.
|
151
238
|
# @option options [String, Array<String>] :comment
|
152
|
-
# Shortcut for `rdfs:comment`, values are
|
153
|
-
# @option options [String, Array<String>] :
|
154
|
-
# Shortcut for `
|
239
|
+
# Shortcut for `rdfs:comment`, values are interpreted as a {Literal}.
|
240
|
+
# @option options [String, Array<String,Term>] :isDefinedBy
|
241
|
+
# Shortcut for `rdfs:isDefinedBy`, values are interpreted as a {Term}.
|
242
|
+
# @option options [String, Array<String>] :label
|
243
|
+
# Shortcut for `rdfs:label`, values are interpreted as a {Literal}.
|
244
|
+
# @option options [String, Array<String>] :altLabel
|
245
|
+
# Shortcut for `skos:altLabel`, values are interpreted as a {Literal}.
|
246
|
+
# @option options [String, Array<String>] :definition
|
247
|
+
# Shortcut for `skos:definition`, values are interpreted as a {Literal}.
|
248
|
+
# @option options [String, Array<String>] :editorialNote
|
249
|
+
# Shortcut for `skos:editorialNote`, values are interpreted as a {Literal}.
|
250
|
+
# @option options [String, Array<String>] :note
|
251
|
+
# Shortcut for `skos:note`, values are interpreted as a {Literal}.
|
252
|
+
# @option options [String, Array<String>] :prefLabel
|
253
|
+
# Shortcut for `skos:prefLabel`, values are interpreted as a {Literal}.
|
155
254
|
# @return [RDF::Vocabulary::Term]
|
156
255
|
#
|
157
256
|
# @note If the ontology URI has the vocabulary namespace URI as a prefix, it may also be defined using `#property` or `#term`
|
@@ -161,9 +260,9 @@ module RDF
|
|
161
260
|
@ontology
|
162
261
|
else
|
163
262
|
uri, options = args
|
164
|
-
|
165
|
-
Term.
|
166
|
-
@ontology = Term.intern(uri.to_s, attributes: options)
|
263
|
+
URI.cache.delete(uri.to_s.to_sym) # Clear any previous entry
|
264
|
+
# Term attributes passed in a block for lazy evaluation. This helps to avoid load-time circular dependencies
|
265
|
+
@ontology = Term.intern(uri.to_s, vocab: self, attributes: options)
|
167
266
|
|
168
267
|
# If the URI is the same as the vocabulary namespace, also define it as a term
|
169
268
|
props[:""] ||= @ontology if self.to_s == uri.to_s
|
@@ -184,16 +283,18 @@ module RDF
|
|
184
283
|
# Attempt to expand a Compact IRI/PName/QName using loaded vocabularies
|
185
284
|
#
|
186
285
|
# @param [String, #to_s] pname
|
187
|
-
# @return [
|
286
|
+
# @return [Term]
|
188
287
|
# @raise [KeyError] if pname suffix not found in identified vocabulary
|
288
|
+
# @raise [ArgumentError] if resulting URI is not valid
|
189
289
|
def expand_pname(pname)
|
290
|
+
return pname unless pname.is_a?(String) || pname.is_a?(Symbol)
|
190
291
|
prefix, suffix = pname.to_s.split(":", 2)
|
191
292
|
if prefix == "rdf"
|
192
293
|
RDF[suffix]
|
193
294
|
elsif vocab = RDF::Vocabulary.each.detect {|v| v.__name__ && v.__prefix__ == prefix.to_sym}
|
194
295
|
suffix.to_s.empty? ? vocab.to_uri : vocab[suffix]
|
195
296
|
else
|
196
|
-
(RDF::Vocabulary.find_term(pname) rescue nil) || RDF::URI(pname)
|
297
|
+
(RDF::Vocabulary.find_term(pname) rescue nil) || RDF::URI(pname, validate: true)
|
197
298
|
end
|
198
299
|
end
|
199
300
|
|
@@ -238,7 +339,7 @@ module RDF
|
|
238
339
|
if props.has_key?(property.to_sym)
|
239
340
|
props[property.to_sym]
|
240
341
|
else
|
241
|
-
Term.intern([to_s, property.to_s].join(''), attributes: {
|
342
|
+
Term.intern([to_s, property.to_s].join(''), vocab: self, attributes: {})
|
242
343
|
end
|
243
344
|
end
|
244
345
|
|
@@ -340,50 +441,111 @@ module RDF
|
|
340
441
|
|
341
442
|
ont_url = url.to_s.sub(%r([/#]$), '')
|
342
443
|
term_defs = {}
|
444
|
+
embedded_defs = {}
|
343
445
|
graph.each do |statement|
|
344
|
-
next unless statement.subject.uri?
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
446
|
+
#next unless statement.subject.uri?
|
447
|
+
if statement.subject.start_with?(url) || statement.subject == ont_url
|
448
|
+
name = statement.subject.to_s[url.to_s.length..-1].to_s
|
449
|
+
term = (term_defs[name.to_sym] ||= {})
|
450
|
+
else
|
451
|
+
# subject is not a URI or is not associated with the vocabulary
|
452
|
+
term = (embedded_defs[statement.subject] ||= {})
|
453
|
+
end
|
349
454
|
|
350
455
|
key = case statement.predicate
|
351
456
|
when RDF.type then :type
|
352
|
-
when RDF::RDFS.subClassOf then :subClassOf
|
353
|
-
when RDF::RDFS.subPropertyOf then :subPropertyOf
|
354
|
-
when RDF::RDFS.range then :range
|
355
|
-
when RDF::RDFS.domain then :domain
|
356
457
|
when RDF::RDFS.comment then :comment
|
458
|
+
when RDF::RDFS.domain then :domain
|
459
|
+
when RDF::RDFS.isDefinedBy then :isDefinedBy
|
357
460
|
when RDF::RDFS.label then :label
|
358
|
-
when RDF::
|
461
|
+
when RDF::RDFS.range then :range
|
462
|
+
when RDF::RDFS.subClassOf then :subClassOf
|
463
|
+
when RDF::RDFS.subPropertyOf then :subPropertyOf
|
359
464
|
when RDF::URI("http://schema.org/domainIncludes") then :domainIncludes
|
360
465
|
when RDF::URI("http://schema.org/rangeIncludes") then :rangeIncludes
|
466
|
+
when RDF::URI("http://www.w3.org/2002/07/owl#allValuesFrom") then :allValuesFrom
|
467
|
+
when RDF::URI("http://www.w3.org/2002/07/owl#cardinality") then :cardinality
|
468
|
+
when RDF::URI("http://www.w3.org/2002/07/owl#equivalentClass") then :equivalentClass
|
469
|
+
when RDF::URI("http://www.w3.org/2002/07/owl#equivalentProperty") then :equivalentProperty
|
470
|
+
when RDF::URI("http://www.w3.org/2002/07/owl#intersectionOf") then :intersectionOf
|
471
|
+
when RDF::URI("http://www.w3.org/2002/07/owl#inverseOf") then :inverseOf
|
472
|
+
when RDF::URI("http://www.w3.org/2002/07/owl#maxCardinality") then :maxCardinality
|
473
|
+
when RDF::URI("http://www.w3.org/2002/07/owl#minCardinality") then :minCardinality
|
474
|
+
when RDF::URI("http://www.w3.org/2002/07/owl#onProperty") then :onProperty
|
475
|
+
when RDF::URI("http://www.w3.org/2002/07/owl#someValuesFrom") then :someValuesFrom
|
476
|
+
when RDF::URI("http://www.w3.org/2002/07/owl#unionOf") then :unionOf
|
477
|
+
when RDF::URI("http://www.w3.org/2004/02/skos/core#altLabel") then :altLabel
|
478
|
+
when RDF::URI("http://www.w3.org/2004/02/skos/core#broader") then :broader
|
479
|
+
when RDF::URI("http://www.w3.org/2004/02/skos/core#definition") then :definition
|
480
|
+
when RDF::URI("http://www.w3.org/2004/02/skos/core#editorialNote") then :editorialNote
|
481
|
+
when RDF::URI("http://www.w3.org/2004/02/skos/core#exactMatch") then :exactMatch
|
482
|
+
when RDF::URI("http://www.w3.org/2004/02/skos/core#hasTopConcept") then :hasTopConcept
|
483
|
+
when RDF::URI("http://www.w3.org/2004/02/skos/core#inScheme") then :inScheme
|
484
|
+
when RDF::URI("http://www.w3.org/2004/02/skos/core#member") then :member
|
485
|
+
when RDF::URI("http://www.w3.org/2004/02/skos/core#narrower") then :narrower
|
486
|
+
when RDF::URI("http://www.w3.org/2004/02/skos/core#notation") then :notation
|
487
|
+
when RDF::URI("http://www.w3.org/2004/02/skos/core#note") then :note
|
488
|
+
when RDF::URI("http://www.w3.org/2004/02/skos/core#prefLabel") then :prefLabel
|
489
|
+
when RDF::URI("http://www.w3.org/2004/02/skos/core#related") then :related
|
361
490
|
else statement.predicate.pname.to_sym
|
362
491
|
end
|
363
492
|
|
364
|
-
|
365
|
-
statement.object.pname
|
366
|
-
elsif statement.object.literal? && (statement.object.language || :en).to_s =~ /^en-?/
|
367
|
-
statement.object.to_s
|
368
|
-
end
|
369
|
-
|
370
|
-
(term[key] ||= []) << value if value
|
493
|
+
(term[key] ||= []) << statement.object
|
371
494
|
end
|
372
495
|
|
373
496
|
# Create extra terms
|
374
497
|
term_defs = case extra
|
375
498
|
when Array
|
376
|
-
extra.inject({}) {|memo, s| memo[s.to_sym] = {
|
499
|
+
extra.inject({}) {|memo, s| memo[s.to_sym] = {}; memo}.merge(term_defs)
|
377
500
|
when Hash
|
378
501
|
extra.merge(term_defs)
|
379
502
|
else
|
380
503
|
term_defs
|
381
504
|
end
|
382
505
|
|
506
|
+
# Pass over embedded_defs with anonymous references, once
|
507
|
+
embedded_defs.each do |term, attributes|
|
508
|
+
attributes.each do |ak, avs|
|
509
|
+
# Turn embedded BNodes into either their Term definition or a List
|
510
|
+
avs = [avs] unless avs.is_a?(Array)
|
511
|
+
attributes[ak] = avs.map do |av|
|
512
|
+
l = RDF::List.new(subject: av, graph: graph)
|
513
|
+
if l.valid?
|
514
|
+
RDF::List.new(subject: av) do |nl|
|
515
|
+
l.each do |lv|
|
516
|
+
nl << (embedded_defs[lv] ? Term.new(vocab: vocab, attributes: embedded_defs[lv]) : lv)
|
517
|
+
end
|
518
|
+
end
|
519
|
+
elsif av.is_a?(RDF::Node)
|
520
|
+
Term.new(vocab: vocab, attributes: embedded_defs[av]) if embedded_defs[av]
|
521
|
+
else
|
522
|
+
av
|
523
|
+
end
|
524
|
+
end.compact
|
525
|
+
end
|
526
|
+
end
|
527
|
+
|
383
528
|
term_defs.each do |term, attributes|
|
529
|
+
# Turn embedded BNodes into either their Term definition or a List
|
530
|
+
attributes.each do |ak, avs|
|
531
|
+
attributes[ak] = avs.is_a?(Array) ? avs.map do |av|
|
532
|
+
l = RDF::List.new(subject: av, graph: graph)
|
533
|
+
if l.valid?
|
534
|
+
RDF::List.new(subject: av) do |nl|
|
535
|
+
l.each do |lv|
|
536
|
+
nl << (embedded_defs[lv] ? Term.new(vocab: vocab, attributes: embedded_defs[lv]) : lv)
|
537
|
+
end
|
538
|
+
end
|
539
|
+
elsif av.is_a?(RDF::Node)
|
540
|
+
Term.new(vocab: vocab, attributes: embedded_defs[av]) if embedded_defs[av]
|
541
|
+
else
|
542
|
+
av
|
543
|
+
end
|
544
|
+
end.compact : avs
|
545
|
+
end
|
546
|
+
|
384
547
|
if term == :""
|
385
|
-
|
386
|
-
vocab.__ontology__ uri, attributes
|
548
|
+
vocab.__ontology__ vocab, attributes
|
387
549
|
else
|
388
550
|
vocab.__property__ term, attributes
|
389
551
|
end
|
@@ -430,15 +592,20 @@ module RDF
|
|
430
592
|
|
431
593
|
def method_missing(property, *args, &block)
|
432
594
|
property = RDF::Vocabulary.camelize(property.to_s)
|
433
|
-
if
|
434
|
-
|
435
|
-
elsif args.empty? && !to_s.empty?
|
436
|
-
Term.intern([to_s, property.to_s].join(''), attributes: {vocab: self})
|
595
|
+
if args.empty? && !to_s.empty?
|
596
|
+
Term.intern([to_s, property.to_s].join(''), vocab: self, attributes: {})
|
437
597
|
else
|
438
598
|
super
|
439
599
|
end
|
440
600
|
end
|
441
601
|
|
602
|
+
# Create a list of terms
|
603
|
+
# @param [Array<String>] values
|
604
|
+
# Each value treated as a URI or PName
|
605
|
+
# @return [RDF::List]
|
606
|
+
def list(*values)
|
607
|
+
RDF::List[*values.map {|v| expand_pname(v) rescue RDF::Literal(v)}]
|
608
|
+
end
|
442
609
|
private
|
443
610
|
|
444
611
|
def props; @properties ||= {}; end
|
@@ -466,7 +633,7 @@ module RDF
|
|
466
633
|
# @param [#to_s] property
|
467
634
|
# @return [URI]
|
468
635
|
def [](property)
|
469
|
-
Term.intern([to_s, property.to_s].join(''),
|
636
|
+
Term.intern([to_s, property.to_s].join(''), vocab: self.class, attributes: {})
|
470
637
|
end
|
471
638
|
|
472
639
|
##
|
@@ -526,94 +693,190 @@ module RDF
|
|
526
693
|
@@uris = {} # @private
|
527
694
|
@@uri = nil # @private
|
528
695
|
|
529
|
-
# A Vocabulary Term is a
|
530
|
-
|
531
|
-
|
696
|
+
# A Vocabulary Term is a {RDF::Resource} that can also act as an {Enumerable} to generate the RDF definition of vocabulary terms as defined within the vocabulary definition.
|
697
|
+
#
|
698
|
+
# Terms include `attributes` where values a embedded resources, lists or other terms. This allows, for example, navigation of a concept heirarchy.
|
699
|
+
module Term
|
700
|
+
include RDF::Resource
|
701
|
+
|
702
|
+
# @!attribute [r] comment
|
532
703
|
# `rdfs:comment` accessor
|
533
|
-
# @return [
|
534
|
-
# @!
|
704
|
+
# @return [Literal, Array<Literal>]
|
705
|
+
# @!attribute [r] label
|
535
706
|
# `rdfs:label` accessor
|
536
|
-
# @return [
|
537
|
-
# @!
|
707
|
+
# @return [Literal]
|
708
|
+
# @!attribute [r] type
|
538
709
|
# `rdf:type` accessor
|
539
|
-
# @return [
|
540
|
-
# @!
|
710
|
+
# @return [Array<Term>]
|
711
|
+
# @!attribute [r] subClassOf
|
541
712
|
# `rdfs:subClassOf` accessor
|
542
|
-
# @return [
|
543
|
-
# @!
|
713
|
+
# @return [Array<Term>]
|
714
|
+
# @!attribute [r] subPropertyOf
|
544
715
|
# `rdfs:subPropertyOf` accessor
|
545
|
-
# @return [
|
546
|
-
# @!
|
716
|
+
# @return [Array<Term>]
|
717
|
+
# @!attribute [r] domain
|
547
718
|
# `rdfs:domain` accessor
|
548
|
-
# @return [
|
549
|
-
# @!
|
719
|
+
# @return [Array<Term>]
|
720
|
+
# @!attribute [r] range
|
550
721
|
# `rdfs:range` accessor
|
551
|
-
# @return [
|
552
|
-
# @!
|
722
|
+
# @return [Array<Term>]
|
723
|
+
# @!attribute [r] isDefinedBy
|
724
|
+
# `rdfs:isDefinedBy` accessor
|
725
|
+
# @return [Array<Term>]
|
726
|
+
|
727
|
+
# @!attribute [r] allValuesFrom
|
728
|
+
# `owl:allValuesFrom` accessor
|
729
|
+
# @return [Array<Term>]
|
730
|
+
# @!attribute [r] cardinality
|
731
|
+
# `owl:cardinality` accessor
|
732
|
+
# @return [Array<Literal>]
|
733
|
+
# @!attribute [r] equivalentClass
|
734
|
+
# `owl:equivalentClass` accessor
|
735
|
+
# @return [Array<Term>]
|
736
|
+
# @!attribute [r] equivalentProperty
|
737
|
+
# `owl:equivalentProperty` accessor
|
738
|
+
# @return [Array<Term>]
|
739
|
+
# @!attribute [r] intersectionOf
|
740
|
+
# `owl:intersectionOf` accessor
|
741
|
+
# @return [Array<Term>]
|
742
|
+
# @!attribute [r] inverseOf
|
553
743
|
# `owl:inverseOf` accessor
|
554
|
-
# @return [
|
555
|
-
# @!
|
744
|
+
# @return [Array<Term>]
|
745
|
+
# @!attribute [r] maxCardinality
|
746
|
+
# `owl:maxCardinality` accessor
|
747
|
+
# @return [Array<Literal>]
|
748
|
+
# @!attribute [r] minCardinality
|
749
|
+
# `owl:minCardinality` accessor
|
750
|
+
# @return [Array<Literal>]
|
751
|
+
# @!attribute [r] onProperty
|
752
|
+
# `owl:onProperty` accessor
|
753
|
+
# @return [Array<Term>]
|
754
|
+
# @!attribute [r] someValuesFrom
|
755
|
+
# `owl:someValuesFrom` accessor
|
756
|
+
# @return [Array<Term>]
|
757
|
+
# @!attribute [r] unionOf
|
758
|
+
# `owl:unionOf` accessor
|
759
|
+
# @return [List<Term>, Array<Term>]
|
760
|
+
|
761
|
+
# @!attribute [r] domainIncludes
|
556
762
|
# `schema:domainIncludes` accessor
|
557
|
-
# @return [
|
558
|
-
# @!
|
559
|
-
# `schema:rangeIncludes`
|
560
|
-
# @return [
|
561
|
-
|
763
|
+
# @return [Array<Term>]
|
764
|
+
# @!attribute [r] rangeIncludes
|
765
|
+
# `schema:rangeIncludes` accessor
|
766
|
+
# @return [Array<Term>]
|
767
|
+
|
768
|
+
# @!attribute [r] altLabel
|
769
|
+
# `skos:altLabel` accessor
|
770
|
+
# @return [Literal, Array<Literal>]
|
771
|
+
# @!attribute [r] broader
|
772
|
+
# `skos:broader` accessor
|
773
|
+
# @return [Array<Term>]
|
774
|
+
# @!attribute [r] definition
|
775
|
+
# `skos:definition` accessor
|
776
|
+
# @return [Literal, Array<Literal>]
|
777
|
+
# @!attribute [r] editorialNote
|
778
|
+
# `skos:editorialNote` accessor
|
779
|
+
# @return [Literal, Array<Literal>]
|
780
|
+
# @!attribute [r] exactMatch
|
781
|
+
# `skos:exactMatch` accessor
|
782
|
+
# @return [Array<Term>]
|
783
|
+
# @!attribute [r] hasTopConcept
|
784
|
+
# `skos:hasTopConcept` accessor
|
785
|
+
# @return [Array<Term>]
|
786
|
+
# @!attribute [r] inScheme
|
787
|
+
# `skos:inScheme` accessor
|
788
|
+
# @return [Array<Term>]
|
789
|
+
# @!attribute [r] member
|
790
|
+
# `skos:member` accessor
|
791
|
+
# @return [Array<Term>]
|
792
|
+
# @!attribute [r] narrower
|
793
|
+
# `skos:narrower` accessor
|
794
|
+
# @return [Array<Term>]
|
795
|
+
# @!attribute [r] notation
|
796
|
+
# `skos:notation` accessor
|
797
|
+
# @return [Literal, Array<Literal>]
|
798
|
+
# @!attribute [r] note
|
799
|
+
# `skos:note` accessor
|
800
|
+
# @return [Literal, Array<Literal>]
|
801
|
+
# @!attribute [r] prefLabel
|
802
|
+
# `skos:prefLabel` accessor
|
803
|
+
# @return [Literal]
|
804
|
+
# @!attribute [r] related
|
805
|
+
# `skos:related` accessor
|
806
|
+
# @return [Array<Term>]
|
807
|
+
|
808
|
+
##
|
809
|
+
# Vocabulary of this term.
|
810
|
+
#
|
811
|
+
# @return [RDF::Vocabulary]
|
812
|
+
attr_reader :vocab
|
813
|
+
|
562
814
|
# Attributes of this vocabulary term, used for finding `label` and `comment` and to serialize the term back to RDF.
|
563
815
|
# @return [Hash{Symbol,Resource => Term, #to_s}]
|
564
|
-
|
816
|
+
attr_reader :attributes
|
817
|
+
|
565
818
|
|
566
819
|
##
|
567
|
-
# @overload
|
820
|
+
# @overload new(uri, attributes:, **options)
|
568
821
|
# @param [URI, String, #to_s] uri
|
822
|
+
# @param [Vocabulary] vocab Vocabulary of this term.
|
569
823
|
# @param [Hash{Symbol,Resource => Term, #to_s}] attributes
|
570
824
|
# Attributes of this vocabulary term, used for finding `label` and `comment` and to serialize the term back to RDF
|
571
825
|
# @param [Hash{Symbol => Object}] options
|
572
|
-
#
|
573
|
-
# @option options [Boolean] :canonicalize (false)
|
826
|
+
# Options from {URI#initialize}
|
574
827
|
#
|
575
|
-
# @overload
|
828
|
+
# @overload new(attributes:, **options)
|
576
829
|
# @param [Hash{Symbol => Object}] options
|
577
|
-
# @param [
|
578
|
-
#
|
579
|
-
#
|
580
|
-
# @
|
581
|
-
#
|
582
|
-
|
583
|
-
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
|
589
|
-
|
590
|
-
|
591
|
-
|
592
|
-
# useri optionsnfo, host, and port components must be omitted.
|
593
|
-
# @option options [String, #to_s] :path The path component.
|
594
|
-
# @option options [String, #to_s] :query The query component.
|
595
|
-
# @option options [String, #to_s] :fragment The fragment component.
|
596
|
-
def initialize(*args, attributes:, **options)
|
597
|
-
@attributes = attributes
|
598
|
-
if RUBY_ENGINE == "rbx"
|
599
|
-
super(*args, **options)
|
600
|
-
else
|
601
|
-
super
|
830
|
+
# @param [Vocabulary] vocab Vocabulary of this term.
|
831
|
+
# @param [Hash{Symbol => String,Array<String,Term>}] attributes
|
832
|
+
# Attributes of this vocabulary term, used for finding `label` and `comment` and to serialize the term back to RDF.
|
833
|
+
# @param [Hash{Symbol => Object}] options
|
834
|
+
# Options from {URI#initialize}
|
835
|
+
def self.new(*args, vocab: nil, attributes: {}, **options)
|
836
|
+
klass = if args.first.nil?
|
837
|
+
RDF::Node
|
838
|
+
elsif args.first.is_a?(Hash)
|
839
|
+
args.unshift(nil)
|
840
|
+
RDF::Node
|
841
|
+
elsif args.first.to_s.start_with?("_:")
|
842
|
+
args = args[1..-1].unshift($1)
|
843
|
+
RDF::Node
|
844
|
+
else RDF::URI
|
602
845
|
end
|
846
|
+
term = klass.allocate.extend(Term)
|
847
|
+
term.send(:initialize, *args)
|
848
|
+
term.instance_variable_set(:@vocab, vocab)
|
849
|
+
term.instance_variable_set(:@attributes, attributes)
|
850
|
+
term
|
603
851
|
end
|
604
852
|
|
605
853
|
##
|
606
|
-
#
|
854
|
+
# Returns an interned `RDF::URI` instance based on the given `uri`
|
855
|
+
# string.
|
607
856
|
#
|
608
|
-
#
|
609
|
-
|
857
|
+
# The maximum number of cached interned URI references is given by the
|
858
|
+
# `CACHE_SIZE` constant. This value is unlimited by default, in which
|
859
|
+
# case an interned URI object will be purged only when the last strong
|
860
|
+
# reference to it is garbage collected (i.e., when its finalizer runs).
|
861
|
+
#
|
862
|
+
# Excepting special memory-limited circumstances, it should always be
|
863
|
+
# safe and preferred to construct new URI references using
|
864
|
+
# `RDF::URI.intern` instead of `RDF::URI.new`, since if an interned
|
865
|
+
# object can't be returned for some reason, this method will fall back
|
866
|
+
# to returning a freshly-allocated one.
|
867
|
+
#
|
868
|
+
# @param (see #initialize)
|
869
|
+
# @return [RDF::URI] an immutable, frozen URI object
|
870
|
+
def self.intern(str, *args)
|
871
|
+
(URI.cache[(str = str.to_s).to_sym] ||= self.new(str, *args)).freeze
|
872
|
+
end
|
610
873
|
|
611
874
|
##
|
612
875
|
# Returns a duplicate copy of `self`.
|
613
876
|
#
|
614
877
|
# @return [RDF::URI]
|
615
878
|
def dup
|
616
|
-
self.class.new((@value || @object).dup, attributes:
|
879
|
+
self.class.new((@value || @object).dup, attributes: attributes).extend(Term)
|
617
880
|
end
|
618
881
|
|
619
882
|
##
|
@@ -623,35 +886,88 @@ module RDF
|
|
623
886
|
# @since 0.3.9
|
624
887
|
def valid?
|
625
888
|
# Validate relative to RFC3987
|
626
|
-
RDF::URI::IRI.match(to_s) || false
|
889
|
+
node? || RDF::URI::IRI.match(to_s) || false
|
627
890
|
end
|
628
891
|
|
629
892
|
##
|
630
893
|
# Is this a class term?
|
631
894
|
# @return [Boolean]
|
632
895
|
def class?
|
633
|
-
|
896
|
+
Array(self.type).any? {|t| t.to_s.include?('Class')}
|
634
897
|
end
|
635
898
|
|
636
899
|
##
|
637
900
|
# Is this a class term?
|
638
901
|
# @return [Boolean]
|
639
902
|
def property?
|
640
|
-
|
903
|
+
Array(self.type).any? {|t| t.to_s.include?('Property')}
|
641
904
|
end
|
642
905
|
|
643
906
|
##
|
644
907
|
# Is this a class term?
|
645
908
|
# @return [Boolean]
|
646
909
|
def datatype?
|
647
|
-
|
910
|
+
Array(self.type).any? {|t| t.to_s.include?('Datatype')}
|
911
|
+
end
|
912
|
+
|
913
|
+
##
|
914
|
+
# Is this a Restriction term?
|
915
|
+
# @return [Boolean]
|
916
|
+
def restriction?
|
917
|
+
Array(self.type).any? {|t| t.to_s.include?('Restriction')}
|
648
918
|
end
|
649
919
|
|
650
920
|
##
|
651
921
|
# Is this neither a class, property or datatype term?
|
652
922
|
# @return [Boolean]
|
653
923
|
def other?
|
654
|
-
|
924
|
+
Array(self.type).none? {|t| t.to_s =~ /(Class|Property|Datatype|Restriction)/}
|
925
|
+
end
|
926
|
+
|
927
|
+
##
|
928
|
+
# Enumerate attributes with values transformed into {RDF::Value} instances
|
929
|
+
#
|
930
|
+
# @return [Hash{Symbol => Array<RDF::Value>}]
|
931
|
+
def properties
|
932
|
+
attributes.keys.inject({}) do |memo, p|
|
933
|
+
memo.merge(p => attribute_value(p))
|
934
|
+
end
|
935
|
+
end
|
936
|
+
|
937
|
+
##
|
938
|
+
# Values of an attributes as {RDF::Value}
|
939
|
+
#
|
940
|
+
# @property [Symbol] prop
|
941
|
+
# @return [RDF::Value, Array<RDF::Value>]
|
942
|
+
def attribute_value(prop)
|
943
|
+
values = attributes[prop]
|
944
|
+
values = [values].compact unless values.is_a?(Array)
|
945
|
+
prop_values = values.map do |value|
|
946
|
+
v = value.is_a?(Symbol) ? value.to_s : value
|
947
|
+
value = (RDF::Vocabulary.expand_pname(v) rescue nil) if v.is_a?(String) && v.include?(':')
|
948
|
+
value = value.to_uri if value.respond_to?(:to_uri)
|
949
|
+
unless value.is_a?(RDF::Value) && value.valid?
|
950
|
+
# Use as most appropriate literal
|
951
|
+
value = [
|
952
|
+
RDF::Literal::Date,
|
953
|
+
RDF::Literal::DateTime,
|
954
|
+
RDF::Literal::Integer,
|
955
|
+
RDF::Literal::Decimal,
|
956
|
+
RDF::Literal::Double,
|
957
|
+
RDF::Literal::Boolean,
|
958
|
+
RDF::Literal
|
959
|
+
].inject(nil) do |m, klass|
|
960
|
+
m || begin
|
961
|
+
l = klass.new(v)
|
962
|
+
l if l.valid?
|
963
|
+
end
|
964
|
+
end
|
965
|
+
end
|
966
|
+
|
967
|
+
value
|
968
|
+
end
|
969
|
+
|
970
|
+
prop_values.length <= 1 ? prop_values.first : prop_values
|
655
971
|
end
|
656
972
|
|
657
973
|
##
|
@@ -662,61 +978,36 @@ module RDF
|
|
662
978
|
# @yield statement
|
663
979
|
# @yieldparam [RDF::Statement]
|
664
980
|
def each_statement
|
665
|
-
attributes.
|
666
|
-
|
981
|
+
attributes.keys.each do |p|
|
982
|
+
values = attribute_value(p)
|
983
|
+
values = [values].compact unless values.is_a?(Array)
|
984
|
+
values.each do |value|
|
667
985
|
begin
|
668
|
-
case
|
986
|
+
prop = case p
|
669
987
|
when :type
|
670
|
-
|
671
|
-
|
672
|
-
|
673
|
-
|
674
|
-
|
675
|
-
|
676
|
-
|
677
|
-
|
678
|
-
|
679
|
-
|
680
|
-
|
681
|
-
|
682
|
-
|
683
|
-
value = RDF::Vocabulary.expand_pname(value)
|
684
|
-
when :inverseOf
|
685
|
-
prop = RDF::URI("http://schema.org/inverseOf")
|
686
|
-
value = RDF::Vocabulary.expand_pname(value)
|
687
|
-
when :domainIncludes
|
688
|
-
prop = RDF::URI("http://schema.org/domainIncludes")
|
689
|
-
value = RDF::Vocabulary.expand_pname(value)
|
690
|
-
when :rangeIncludes
|
691
|
-
prop = RDF::URI("http://schema.org/rangeIncludes")
|
692
|
-
value = RDF::Vocabulary.expand_pname(value)
|
693
|
-
when :label
|
694
|
-
prop = RDF::RDFS.label
|
695
|
-
when :comment
|
696
|
-
prop = RDF::RDFS.comment
|
988
|
+
RDF::RDFV[p]
|
989
|
+
when :subClassOf, :subPropertyOf, :domain, :range, :isDefinedBy, :label, :comment
|
990
|
+
RDF::RDFS[p]
|
991
|
+
when :allValuesFrom, :cardinality, :equivalentClass, :equivalentProperty,
|
992
|
+
:intersectionOf, :inverseOf, :maxCardinality, :minCardinality,
|
993
|
+
:onProperty, :someValuesFrom, :unionOf
|
994
|
+
RDF::OWL[p]
|
995
|
+
when :domainIncludes, :rangeIncludes
|
996
|
+
RDF::Vocabulary.find_term("http://schema.org/#{p}")
|
997
|
+
when :broader, :definition, :exactMatch, :hasTopConcept, :inScheme,
|
998
|
+
:member, :narrower, :related, :altLabel, :definition, :editorialNote,
|
999
|
+
:notation, :note, :prefLabel
|
1000
|
+
RDF::Vocabulary.find_term("http://www.w3.org/2004/02/skos/core##{p}")
|
697
1001
|
else
|
698
|
-
|
699
|
-
|
700
|
-
|
701
|
-
|
702
|
-
|
703
|
-
|
704
|
-
|
705
|
-
|
706
|
-
RDF::Literal::Date,
|
707
|
-
RDF::Literal::DateTime,
|
708
|
-
RDF::Literal::Integer,
|
709
|
-
RDF::Literal::Decimal,
|
710
|
-
RDF::Literal::Double,
|
711
|
-
RDF::Literal::Boolean,
|
712
|
-
RDF::Literal
|
713
|
-
].inject(nil) do |memo, klass|
|
714
|
-
l = klass.new(v)
|
715
|
-
memo || (l if l.valid?)
|
716
|
-
end
|
717
|
-
end
|
1002
|
+
RDF::Vocabulary.expand_pname(p)
|
1003
|
+
end
|
1004
|
+
|
1005
|
+
yield RDF::Statement(self, prop, value) if prop.is_a?(RDF::URI)
|
1006
|
+
|
1007
|
+
# Enumerate over value statements, if enumerable
|
1008
|
+
if value.is_a?(RDF::Enumerable) || (value.is_a?(Term) && value.node?)
|
1009
|
+
value.each_statement {|s| yield s}
|
718
1010
|
end
|
719
|
-
yield RDF::Statement(self, prop, value)
|
720
1011
|
rescue KeyError
|
721
1012
|
# Skip things eroneously defined in the vocabulary
|
722
1013
|
end
|
@@ -742,36 +1033,108 @@ module RDF
|
|
742
1033
|
#
|
743
1034
|
# @return [String] The URI object's state, as a <code>String</code>.
|
744
1035
|
def inspect
|
745
|
-
sprintf("#<%s:%#0x
|
1036
|
+
sprintf("#<%s:%#0x ID:%s>", Term.to_s, self.object_id, self.to_s)
|
746
1037
|
end
|
747
1038
|
|
748
1039
|
# Implement accessor to symbol attributes
|
749
1040
|
def respond_to?(method, include_all = false)
|
750
|
-
|
1041
|
+
case method
|
1042
|
+
when :comment, :notation, :note, :editorialNote, :definition,
|
1043
|
+
:label, :altLabel, :prefLabel, :type, :isDefinedBy
|
1044
|
+
true
|
1045
|
+
when :subClassOf, :subPropertyOf,
|
1046
|
+
:domainIncludes, :rangeIncludes,
|
1047
|
+
:equivalentClass, :intersectionOf, :unionOf
|
1048
|
+
self.class?
|
1049
|
+
when :domain, :range, :equivalentProperty, :inverseOf
|
1050
|
+
self.property?
|
1051
|
+
when :allValuesFrom, :cardinality,
|
1052
|
+
:maxCardinality, :minCardinality,
|
1053
|
+
:onProperty, :someValuesFrom
|
1054
|
+
self.restriction?
|
1055
|
+
when :broader, :exactMatch, :hasTopConcept, :inScheme, :member, :narrower, :related
|
1056
|
+
@attributes.has_key?(method)
|
1057
|
+
else
|
1058
|
+
super
|
1059
|
+
end
|
751
1060
|
end
|
752
1061
|
|
753
1062
|
# Accessor for `schema:domainIncludes`
|
754
1063
|
# @return [RDF::URI]
|
755
1064
|
def domain_includes
|
756
|
-
|
1065
|
+
domainIncludes
|
757
1066
|
end
|
758
1067
|
|
759
1068
|
# Accessor for `schema:rangeIncludes`
|
760
1069
|
# @return [RDF::URI]
|
761
1070
|
def range_includes
|
762
|
-
|
1071
|
+
rangeIncludes
|
763
1072
|
end
|
764
1073
|
|
1074
|
+
# Serialize back to a Ruby source initializer
|
1075
|
+
# @param [String] indent
|
1076
|
+
# @return [String]
|
1077
|
+
def to_ruby(indent: "")
|
1078
|
+
"term(" +
|
1079
|
+
(self.uri? ? self.to_s.inspect + ",\n" : "\n") +
|
1080
|
+
"#{indent} " +
|
1081
|
+
attributes.keys.map do |k|
|
1082
|
+
values = attribute_value(k)
|
1083
|
+
values = [values].compact unless values.is_a?(Array)
|
1084
|
+
values = values.map do |value|
|
1085
|
+
if value.is_a?(Literal) && %w(: comment definition notation note editorialNote).include?(k.to_s)
|
1086
|
+
"%(#{value.to_s.gsub('(', '\(').gsub(')', '\)')}).freeze"
|
1087
|
+
elsif value.is_a?(RDF::URI)
|
1088
|
+
"#{value.pname.inspect}.freeze"
|
1089
|
+
elsif value.is_a?(RDF::Vocabulary::Term)
|
1090
|
+
value.to_ruby(indent: indent + " ")
|
1091
|
+
elsif value.is_a?(RDF::Term)
|
1092
|
+
"#{value.to_s.inspect}.freeze"
|
1093
|
+
elsif value.is_a?(RDF::List)
|
1094
|
+
list_elements = value.map do |u|
|
1095
|
+
if u.uri?
|
1096
|
+
"#{u.pname.inspect}.freeze"
|
1097
|
+
elsif u.respond_to?(:to_ruby)
|
1098
|
+
u.to_ruby(indent: indent + " ")
|
1099
|
+
else
|
1100
|
+
"#{u.to_s.inspect}.freeze"
|
1101
|
+
end
|
1102
|
+
end
|
1103
|
+
"list(#{list_elements.join(', ')})"
|
1104
|
+
else
|
1105
|
+
"#{value.inspect}.freeze"
|
1106
|
+
end
|
1107
|
+
end
|
1108
|
+
"#{k.to_s.include?(':') ? k.to_s.inspect : k}: " +
|
1109
|
+
(values.length == 1 ? values.first : ('[' + values.join(',') + ']'))
|
1110
|
+
end.join(",\n#{indent} ") + "\n#{indent})"
|
1111
|
+
|
1112
|
+
end
|
765
1113
|
protected
|
766
1114
|
# Implement accessor to symbol attributes
|
767
1115
|
def method_missing(method, *args, &block)
|
768
1116
|
case method
|
769
|
-
when :comment
|
770
|
-
|
771
|
-
when :label
|
772
|
-
|
773
|
-
|
774
|
-
|
1117
|
+
when :comment, :notation, :note, :editorialNote, :definition
|
1118
|
+
attribute_value(method)
|
1119
|
+
when :label, :altLabel, :prefLabel
|
1120
|
+
# Defaults to URI fragment or path tail
|
1121
|
+
begin
|
1122
|
+
attribute_value(method)
|
1123
|
+
rescue KeyError
|
1124
|
+
to_s.split(/[\/\#]/).last
|
1125
|
+
end
|
1126
|
+
when :type, :subClassOf, :subPropertyOf, :domain, :range, :isDefinedBy,
|
1127
|
+
:allValuesFrom, :cardinality, :equivalentClass, :equivalentProperty,
|
1128
|
+
:intersectionOf, :inverseOf, :maxCardinality, :minCardinality,
|
1129
|
+
:onProperty, :someValuesFrom, :unionOf,
|
1130
|
+
:domainIncludes, :rangeIncludes,
|
1131
|
+
:broader, :exactMatch, :hasTopConcept, :inScheme, :member, :narrower, :related
|
1132
|
+
|
1133
|
+
# Return value as an Array, unless it is a list
|
1134
|
+
case value = attribute_value(method)
|
1135
|
+
when Array, RDF::List then value
|
1136
|
+
else [value].compact
|
1137
|
+
end
|
775
1138
|
else
|
776
1139
|
super
|
777
1140
|
end
|