Skip to content

Commit 9fb42b6

Browse files
committed
* When reading a vocabulary, don't skip non-english literals.
* When writing a vocabulary, use language-map form for language-tagged literals with any in english serialized as the first entry of the map, Fixes #432.
1 parent 2caa5f5 commit 9fb42b6

3 files changed

Lines changed: 38 additions & 8 deletions

File tree

lib/rdf/vocab/writer.rb

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,19 @@ class Format < RDF::Format
5050
# range: "xsd:float",
5151
# type: "owl:DatatypeProperty",
5252
# "vs:term_status": "testing"
53+
#
54+
# @example term definition with language-tagged strings
55+
# @example A term definition with tagged values
56+
# property :actor,
57+
# comment: {en: "Subproperty of as:attributedTo that identifies the primary actor"},
58+
# domain: "https://www.w3.org/ns/activitystreams#Activity",
59+
# label: {en: "actor"},
60+
# range: term(
61+
# type: "http://www.w3.org/2002/07/owl#Class",
62+
# unionOf: list("https://www.w3.org/ns/activitystreams#Object", "https://www.w3.org/ns/activitystreams#Link")
63+
# ),
64+
# subPropertyOf: "https://www.w3.org/ns/activitystreams#attributedTo",
65+
# type: "http://www.w3.org/2002/07/owl#ObjectProperty"
5366
class Writer < RDF::Writer
5467
include RDF::Util::Logger
5568
format RDF::Vocabulary::Format
@@ -272,9 +285,17 @@ def from_node(name, attributes, term_type)
272285
attributes.keys.sort_by(&:to_s).map(&:to_sym).each do |key|
273286
value = Array(attributes[key])
274287
component = key.inspect.start_with?(':"') ? "#{key.to_s.inspect}: " : "#{key}: "
275-
value = value.first if value.length == 1
288+
value = value.first if value.length == 1 && value.none? {|v| v.is_a?(RDF::Literal) && v.language?}
276289
component << if value.is_a?(Array)
277-
'[' + value.map {|v| serialize_value(v, key, indent: " ")}.sort.join(", ") + "]"
290+
# Represent language-tagged literals as a hash
291+
lang_vals, vals = value.partition {|v| v.literal? && v.language?}
292+
hash_val = lang_vals.inject({}) {|memo, obj| memo.merge(obj.language => obj.to_s)}
293+
vals << hash_val unless hash_val.empty?
294+
if vals.length > 1
295+
'[' + vals.map {|v| serialize_value(v, key, indent: " ")}.sort.join(", ") + "]"
296+
else
297+
serialize_value(vals.first, key, indent: " ")
298+
end
278299
else
279300
serialize_value(value, key, indent: " ")
280301
end
@@ -284,7 +305,14 @@ def from_node(name, attributes, term_type)
284305
end
285306

286307
def serialize_value(value, key, indent: "")
287-
if value.is_a?(Literal) && %w(: comment definition notation note editorialNote).include?(key.to_s)
308+
if value.is_a?(Hash)
309+
# Favor English
310+
keys = value.keys
311+
keys = keys.include?(:en) ? (keys - [:en]).sort.unshift(:en) : keys.sort
312+
'{' + keys.map do |k|
313+
"#{k.inspect[1..-1]}: #{value[k].inspect}"
314+
end.join(', ') + '}'
315+
elsif value.is_a?(Literal) && %w(: comment definition notation note editorialNote).include?(key.to_s)
288316
"#{value.to_s.inspect}"
289317
elsif value.is_a?(RDF::URI)
290318
"#{value.to_s.inspect}"

lib/rdf/vocabulary.rb

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -521,10 +521,6 @@ def from_graph(graph, url: nil, class_name: nil, extra: nil)
521521
statement.predicate.to_s.to_sym
522522
end
523523

524-
# Skip literals other than plain or english
525-
# This is because the ruby representation does not preserve language
526-
next if statement.object.literal? && (statement.object.language || :en).to_s !~ /^en-?/
527-
528524
(term[key] ||= []) << statement.object
529525
end
530526

spec/vocab_writer_spec.rb

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@
1010
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
1111
<http://example.org/Class> a rdfs:Class ; rdfs:Datatype "Class" .
1212
<http://example.org/prop> a rdf:Property ; rdfs:Datatype "prop" .
13+
<http://example.org/lang_prop> a rdf:Property ; rdfs:label "prop"@en .
14+
<http://example.org/lang_props> a rdf:Property ; rdfs:label "eigen"@de, "prop"@en .
15+
<http://example.org/mixed_props> a rdf:Property ; rdfs:label "prop"@en, "eigen"@de, "none" .
1316
}}
1417
let!(:graph) {
1518
RDF::Graph.new << RDF::Turtle::Reader.new(ttl)
@@ -21,6 +24,9 @@
2124
/class Foo/,
2225
%r{term :Class,\s+"http://www.w3.org/2000/01/rdf-schema#Datatype": "Class",\s+type: "http://www.w3.org/2000/01/rdf-schema#Class"}m.freeze,
2326
%r{property :prop,\s+"http://www.w3.org/2000/01/rdf-schema#Datatype": "prop",\s+type: "http://www.w3.org/1999/02/22-rdf-syntax-ns#Property"}m.freeze,
27+
%r{property :lang_prop,\s+label: {en: "prop"}}m.freeze,
28+
%r{property :lang_props,\s+label: {en: "prop", de: "eigen"}}m.freeze,
29+
%r{property :mixed_props,\s+label: \["none", {en: "prop", de: "eigen"}\]}m.freeze,
2430
].each do |regexp,|
2531
it "matches #{regexp}" do
2632
expect(serialization).to match(regexp)
@@ -57,7 +63,7 @@
5763
%r{inScheme: "http://eulersharp.sourceforge.net/2003/03swap/countries#iso3166-1-alpha-2"}.freeze,
5864
/notation: %\(afg\)/.freeze,
5965
%r{inScheme: "http://eulersharp.sourceforge.net/2003/03swap/countries#iso3166-1-alpha-3"}.freeze,
60-
%r{"http://xmlns.com/foaf/0.1/name": "Afghanistan"}.freeze,
66+
%r{"http://xmlns.com/foaf/0.1/name": {en: "Afghanistan"}}.freeze,
6167
%r{isDefinedBy: "http://eulersharp.sourceforge.net/2003/03swap/countries#"}.freeze,
6268
%r{type: "http://sweet.jpl.nasa.gov/2.3/humanJurisdiction.owl#Country"}.freeze,
6369
].each do |regexp,|

0 commit comments

Comments
 (0)