rdf_context 0.5.0 → 0.5.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,236 @@
1
+ require File.join(File.dirname(__FILE__), 'abstract_serializer')
2
+
3
+ module RdfContext
4
+ # Serialize RDF graphs in NTriples format
5
+ class XmlSerializer < RecursiveSerializer
6
+ VALID_ATTRIBUTES = [:none, :untyped, :typed]
7
+
8
+ def initialize(graph)
9
+ super
10
+ @force_RDF_about = {}
11
+ end
12
+
13
+ # Serialize the graph
14
+ #
15
+ # @param [IO, StreamIO] stream:: Stream in which to place serialized graph
16
+ # @param [Hash] options:: Options for parser
17
+ # <em>options[:base]</em>:: Base URI of graph, used to shorting URI references
18
+ # <em>options[:max_depth]</em>:: Maximum depth for recursively defining resources, defaults to 3
19
+ # <em>options[:lang]</em>:: Output as root xml:lang attribute, and avoid generation xml:lang where possible
20
+ # <em>options[:attributes]</em>:: How to use XML attributes when serializing, one of :none, :untyped, :typed. The default is none.
21
+ #
22
+ # -- Serialization Examples
23
+ # attributes == :none
24
+ #
25
+ # serialize(io, :attributes => none)
26
+ def serialize(stream, options = {})
27
+ @max_depth = options[:max_depth] || 3
28
+ @base = options[:base]
29
+ @lang = options[:lang]
30
+ @attributes = options[:attributes] || :none
31
+ raise "Invalid attribute option '#{@attributes}', should be one of #{VALID_ATTRIBUTES.to_sentence}" unless VALID_ATTRIBUTES.include?(@attributes.to_sym)
32
+
33
+ doc = Nokogiri::XML::Document.new
34
+
35
+ preprocess
36
+
37
+ predicates = @graph.predicates.uniq
38
+ possible = predicates | @graph.objects.uniq
39
+ namespaces = {}
40
+ required_namespaces = {}
41
+ possible.each do |res|
42
+ next unless res.is_a?(URIRef)
43
+ if !get_qname(res) # Creates Namespace mappings
44
+ [RDF_NS, DC_NS, OWL_NS, LOG_NS, RDF_NS, RDFS_NS, XHV_NS, XML_NS, XSD_NS, XSI_NS].each do |ns|
45
+ # Bind a standard namespace to the graph and try the lookup again
46
+ @graph.bind(ns) if ns.uri == res.base
47
+ required_namespaces[res.base] = true if !get_qname(res) && predicates.include?(res)
48
+ end
49
+ end
50
+ end
51
+ add_namespace(RDF_NS)
52
+ add_namespace(XML_NS) if @base || @lang
53
+
54
+ # See if there's a default namespace, and favor it when generating element names.
55
+ # Lookup an equivalent prefixed namespace for use in generating attributes
56
+ @default_ns = @graph.namespace("")
57
+ if @default_ns
58
+ add_namespace(@default_ns)
59
+ prefix = @graph.prefix(@default_ns.uri)
60
+ @prefixed_default_ns = @graph.namespace(prefix)
61
+ add_namespace(@prefixed_default_ns) if @prefixed_default_ns
62
+ end
63
+
64
+ # Add bindings for predicates not already having bindings
65
+ tmp_ns = "ns0"
66
+ required_namespaces.keys.each do |uri|
67
+ puts "serialize: create temporary namespace for <#{uri}>" if $DEBUG
68
+ add_namespace(Namespace.new(uri, tmp_ns))
69
+ tmp_ns = tmp_ns.succ
70
+ end
71
+
72
+ doc.root = Nokogiri::XML::Element.new("rdf:RDF", doc)
73
+ @namespaces.each_pair do |p, ns|
74
+ if p.to_s.empty?
75
+ doc.root.default_namespace = ns.uri.to_s
76
+ else
77
+ doc.root.add_namespace(p, ns.uri.to_s)
78
+ end
79
+ end
80
+ doc.root["xml:lang"] = @lang if @lang
81
+ doc.root["xml:base"] = @base if @base
82
+
83
+ # Add statements for each subject
84
+ order_subjects.each do |subject|
85
+ #puts "subj: #{subject.inspect}"
86
+ subject(subject, doc.root)
87
+ end
88
+
89
+ doc.write_xml_to(stream, :encoding => "UTF-8", :indent => 2)
90
+ end
91
+
92
+ protected
93
+ def subject(subject, parent_node)
94
+ node = nil
95
+
96
+ if !is_done?(subject)
97
+ subject_done(subject)
98
+ properties = @graph.properties(subject)
99
+ prop_list = sort_properties(properties)
100
+ puts "subject: #{subject.to_n3}, props: #{properties.inspect}" if $DEBUG
101
+
102
+ rdf_type, *rest = properties.fetch(RDF_TYPE.to_s, [])
103
+ properties[RDF_TYPE.to_s] = rest
104
+ if rdf_type.is_a?(URIRef)
105
+ element = get_qname(rdf_type)
106
+ if rdf_type.namespace && @default_ns && rdf_type.namespace.uri == @default_ns.uri
107
+ element = rdf_type.short_name
108
+ end
109
+ end
110
+ element ||= "rdf:Description"
111
+
112
+ node = Nokogiri::XML::Element.new(element, parent_node.document)
113
+
114
+ if subject.is_a?(BNode)
115
+ # Only need nodeID if it's referenced elsewhere
116
+ node["rdf:nodeID"] = subject.to_s if ref_count(subject) > (@depth == 0 ? 0 : 1)
117
+ else
118
+ node["rdf:about"] = relativize(subject)
119
+ end
120
+
121
+ prop_list.each do |prop|
122
+ prop_ref = URIRef.new(prop)
123
+
124
+ properties[prop].each do |object|
125
+ @depth += 1
126
+ predicate(prop_ref, object, node, properties[prop].length == 1)
127
+ @depth -= 1
128
+ end
129
+ end
130
+ elsif @force_RDF_about.include?(subject)
131
+ puts "subject: #{subject.to_n3}, force about" if $DEBUG
132
+ node = Nokogiri::XML::Element.new("rdf:Description", parent_node.document)
133
+ node["rdf:about"] = relativize(subject)
134
+ @force_RDF_about.delete(subject)
135
+ end
136
+
137
+ parent_node.add_child(node) if node
138
+ end
139
+
140
+ # Output a predicate into the specified node.
141
+ #
142
+ # If _is_unique_ is true, this predicate may be able to be serialized as an attribute
143
+ def predicate(prop, object, node, is_unique)
144
+ qname = prop.to_qname(uri_binding)
145
+
146
+ # See if we can serialize as attribute.
147
+ # * untyped attributes that aren't duplicated where xml:lang == @lang
148
+ # * typed attributes that aren't duplicated if @dt_as_attr is true
149
+ # * rdf:type
150
+ as_attr = false
151
+ as_attr ||= true if [:untyped, :typed].include?(@attributes) && prop == RDF_TYPE
152
+
153
+ # Untyped attribute with no lang, or whos lang is the same as the default and RDF_TYPE
154
+ as_attr ||= true if [:untyped, :typed].include?(@attributes) &&
155
+ (object.is_a?(Literal) && object.untyped? && (object.lang.nil? || object.lang == @lang))
156
+
157
+ as_attr ||= true if [:typed].include?(@attributes) && object.is_a?(Literal) && object.typed?
158
+
159
+ as_attr = false unless is_unique
160
+
161
+ # Can't do as an attr if the qname has no prefix and there is no prefixed version
162
+ if @default_ns && prop.namespace.uri == @default_ns.uri
163
+ if as_attr
164
+ if @prefixed_default_ns
165
+ qname = "#{@prefixed_default_ns.prefix}:#{prop.short_name}"
166
+ else
167
+ as_attr = false
168
+ end
169
+ else
170
+ qname = prop.short_name
171
+ end
172
+ end
173
+
174
+ puts "predicate: #{qname}, as_attr: #{as_attr}, object: #{object.inspect}, done: #{is_done?(object)}, sub: #{@subjects.include?(object)}" if $DEBUG
175
+ qname = "rdf:li" if qname.match(/rdf:_\d+/)
176
+ pred_node = Nokogiri::XML::Element.new(qname, node.document)
177
+
178
+ if object.is_a?(Literal) || is_done?(object) || !@subjects.include?(object)
179
+ # Literals or references to objects that aren't subjects, or that have already been serialized
180
+
181
+ args = object.xml_args
182
+ puts "predicate: args=#{args.inspect}" if $DEBUG
183
+ attrs = args.pop
184
+
185
+ if as_attr
186
+ # Serialize as attribute
187
+ pred_node.unlink
188
+ pred_node = nil
189
+ node[qname] = object.is_a?(URIRef) ? relativize(object) : object.to_s
190
+ else
191
+ # Serialize as element
192
+ attrs.each_pair do |a, av|
193
+ next if a == "xml:lang" && av == @lang # Lang already specified, don't repeat
194
+ av = relativize(object) if a == "#{RDF_NS.prefix}:resource"
195
+ puts " elt attr #{a}=#{av}" if $DEBUG
196
+ pred_node[a] = av.to_s
197
+ end
198
+ puts " elt #{'xmllit ' if object.is_a?(Literal) && object.xmlliteral?}content=#{args.first}" if $DEBUG && !args.empty?
199
+ if object.is_a?(Literal) && object.xmlliteral?
200
+ pred_node.add_child(Nokogiri::XML::CharacterData.new(args.first, node.document))
201
+ elsif args.first
202
+ pred_node.content = args.first unless args.empty?
203
+ end
204
+ end
205
+ else
206
+ # Check to see if it can be serialized as a collection
207
+ col = @graph.seq(object)
208
+ conformant_list = col.all? {|item| !item.is_a?(Literal)}
209
+ o_props = @graph.properties(object)
210
+ if conformant_list && o_props[RDF_NS.first.to_s]
211
+ # Serialize list as parseType="Collection"
212
+ pred_node["rdf:parseType"] = "Collection"
213
+ col.each do |item|
214
+ # Mark the BNode subject of each item as being complete, so that it is not serialized
215
+ @graph.triples(Triple.new(nil, RDF_NS.first, item)) do |triple, ctx|
216
+ subject_done(triple.subject)
217
+ end
218
+ @force_RDF_about[item] = true
219
+ subject(item, pred_node)
220
+ end
221
+ else
222
+ if @depth < @max_depth
223
+ @depth += 1
224
+ subject(object, pred_node)
225
+ @depth -= 1
226
+ elsif object.is_a?(BNode)
227
+ pred_node["rdf:nodeID"] = object.identifier
228
+ else
229
+ pred_node["rdf:resource"] = relativize(object)
230
+ end
231
+ end
232
+ end
233
+ node.add_child(pred_node) if pred_node
234
+ end
235
+ end
236
+ end
@@ -29,6 +29,7 @@ module RdfContext
29
29
 
30
30
  def destroy(configuration = {}); end
31
31
  def open(configuration = {}); end
32
+ def close(commit_pending_transactions = false); end
32
33
  def commit; end
33
34
  def rollback; end
34
35
 
@@ -252,7 +252,7 @@ module RdfContext
252
252
  end
253
253
 
254
254
  def size(context = nil)
255
- context = nil if context == @identifier || (context.respond_to?(:identifier) && context.identifier == @identifier)
255
+ context = nil if (context.respond_to?(:identifier) ? context.identifier : context) == @identifier
256
256
 
257
257
  triples(Triple.new(nil, nil, nil), context).length
258
258
  end
@@ -102,7 +102,7 @@ class String
102
102
  (?:\\[\\bfnrt"/]) # Escaped control characters, " and /
103
103
  |(?:\\U00\h{6}) # 6 byte escaped Unicode
104
104
  |(?:\\u\h{4}) # 4 byte escaped Unicode
105
- )xn
105
+ )x
106
106
  else
107
107
  UNESCAPE_RE = %r((?:\\[\\bfnrt"/]|(?:\\u(?:[A-Fa-f\d]{4}))+|\\[\x20-\xff]))n
108
108
  end
@@ -72,6 +72,10 @@ module RdfContext
72
72
  self.to_s == other.to_s
73
73
  end
74
74
  alias_method :==, :eql?
75
+
76
+ def <=>(other)
77
+ self.to_s <=> other.to_s
78
+ end
75
79
 
76
80
  # Needed for uniq
77
81
  def hash; to_s.hash; end
@@ -88,8 +92,7 @@ module RdfContext
88
92
  # Output URI as QName using URI binding
89
93
  def to_qname(uri_binding = {})
90
94
  ns = namespace(uri_binding)
91
- sn = self.to_s.sub(ns.uri.to_s, "")
92
- "#{ns.prefix}:#{sn}"
95
+ "#{ns.prefix}:#{short_name}"
93
96
  end
94
97
 
95
98
  def namespace(uri_binding = {})
data/spec/bnode_spec.rb CHANGED
@@ -47,7 +47,7 @@ describe "Blank nodes" do
47
47
  describe "which has a blank identifier" do
48
48
  subject { BNode.new("", @context) }
49
49
  it "should not be the same as an anonymous identifier" do should_not == BNode.new end
50
- it "should be the same as another blank identifier" do should == BNode.new("", @context) end
50
+ it "should not be the same as another blank identifier" do should_not == BNode.new("", @context) end
51
51
  end
52
52
 
53
53
  describe "which are anonymous" do
data/spec/graph_spec.rb CHANGED
@@ -299,6 +299,62 @@ HERE
299
299
  subject.size.should == 0
300
300
  end
301
301
 
302
+ describe "properties" do
303
+ subject { Graph.new }
304
+
305
+ it "should get asserted properties" do
306
+ subject.add_triple(@ex.a, @ex.b, @ex.c)
307
+ subject.properties(@ex.a).should be_a(Hash)
308
+ subject.properties(@ex.a).size.should == 1
309
+ subject.properties(@ex.a).has_key?(@ex.b.to_s).should be_true
310
+ subject.properties(@ex.a)[@ex.b.to_s].should == [@ex.c]
311
+ end
312
+
313
+ it "should get asserted properties with 2 properties" do
314
+ subject.add_triple(@ex.a, @ex.b, @ex.c)
315
+ subject.add_triple(@ex.a, @ex.b, @ex.d)
316
+ subject.properties(@ex.a).should be_a(Hash)
317
+ subject.properties(@ex.a).size.should == 1
318
+ subject.properties(@ex.a).has_key?(@ex.b.to_s).should be_true
319
+ subject.properties(@ex.a)[@ex.b.to_s].should include(@ex.c, @ex.d)
320
+ end
321
+
322
+ it "should get asserted properties with 3 properties" do
323
+ subject.add_triple(@ex.a, @ex.b, @ex.c)
324
+ subject.add_triple(@ex.a, @ex.b, @ex.d)
325
+ subject.add_triple(@ex.a, @ex.b, @ex.e)
326
+ subject.properties(@ex.a).should be_a(Hash)
327
+ subject.properties(@ex.a).size.should == 1
328
+ subject.properties(@ex.a).has_key?(@ex.b.to_s).should be_true
329
+ subject.properties(@ex.a)[@ex.b.to_s].should include(@ex.c, @ex.d, @ex.e)
330
+ end
331
+
332
+ it "should get asserted type with single type" do
333
+ subject.add_triple(@ex.a, RDF_TYPE, @ex.Audio)
334
+ subject.properties(@ex.a)[RDF_TYPE.to_s].should == [@ex.Audio]
335
+ subject.type_of(@ex.a).should == [@ex.Audio]
336
+ end
337
+
338
+ it "should get nil with no type" do
339
+ subject.add_triple(@ex.a, @ex.b, @ex.c)
340
+ subject.properties(@ex.a)[RDF_TYPE.to_s].should == nil
341
+ subject.type_of(@ex.a).should == []
342
+ end
343
+
344
+ it "should sync properties to graph" do
345
+ props = subject.properties(@ex.a)
346
+ props.should be_a(Hash)
347
+ props[RDF_TYPE.to_s] = @ex.Audio
348
+ props[DC_NS.title.to_s] = "title"
349
+ props[@ex.b.to_s] = [@ex.c, @ex.d]
350
+ subject.sync_properties(@ex.a)
351
+ subject.contains?(Triple.new(@ex.a, RDF_TYPE, @ex.Audio)).should be_true
352
+ subject.contains?(Triple.new(@ex.a, DC_NS.title, "title")).should be_true
353
+ subject.contains?(Triple.new(@ex.a, @ex.b, @ex.c)).should be_true
354
+ subject.contains?(Triple.new(@ex.a, @ex.b, @ex.d)).should be_true
355
+ end
356
+ end
357
+
302
358
  describe "find triples" do
303
359
  it "should find subjects" do
304
360
  subject.triples(Triple.new(@ex.john, nil, nil)).size.should == 2
@@ -331,12 +387,13 @@ HERE
331
387
  it "should output RDF/XML" do
332
388
  rdfxml = <<-HERE
333
389
  <?xml version="1.0" encoding="UTF-8"?>
334
- <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:foaf="http://xmlns.com/foaf/0.1/" xmlns:xml="http://www.w3.org/XML/1998/namespace" xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#" xmlns:xhv="http://www.w3.org/1999/xhtml/vocab#">
390
+ <rdf:RDF xmlns:foaf="http://xmlns.com/foaf/0.1/" xmlns:ex="http://example.org/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
335
391
  <rdf:Description rdf:about="http://example.org/john">
336
- <foaf:knows rdf:resource="http://example.org/jane"/>
337
- <foaf:knows rdf:resource="http://example.org/rick"/>
338
- </rdf:Description>
339
- <rdf:Description rdf:about="http://example.org/jane">
392
+ <foaf:knows>
393
+ <rdf:Description rdf:about="http://example.org/jane">
394
+ <foaf:knows rdf:resource="http://example.org/rick"/>
395
+ </rdf:Description>
396
+ </foaf:knows>
340
397
  <foaf:knows rdf:resource="http://example.org/rick"/>
341
398
  </rdf:Description>
342
399
  </rdf:RDF>
@@ -362,7 +419,7 @@ HERE
362
419
  end
363
420
 
364
421
  describe "rdf:first/rdf:rest sequences" do
365
- subject {
422
+ it "should return object list" do
366
423
  a, b = BNode.new("a"), BNode.new("b"), BNode.new("c")
367
424
  g = Graph.new(:store => ListStore.new)
368
425
  g.add_triple(@ex.List, RDF_NS.first, @ex.john)
@@ -372,11 +429,21 @@ HERE
372
429
  g.add_triple(b, RDF_NS.first, @ex.rick)
373
430
  g.add_triple(b, RDF_NS.rest, RDF_NS.nil)
374
431
  g.bind(@ex)
375
- g
376
- }
432
+
433
+ #puts g.seq(@ex.List).inspect
434
+ g.seq(@ex.List).should == [@ex.john, @ex.jane, @ex.rick]
435
+ end
377
436
 
378
- it "should return object list" do
379
- subject.seq(@ex.List).should == [@ex.john, @ex.jane, @ex.rick]
437
+ it "should generate a list of resources" do
438
+ g = Graph.new(:store => ListStore.new)
439
+ g.add_seq(@ex.List, RDF_NS.first, [@ex.john, @ex.jane, @ex.rick])
440
+ g.seq(@ex.List).should == [@ex.john, @ex.jane, @ex.rick]
441
+ end
442
+
443
+ it "should generate an empty list" do
444
+ g = Graph.new(:store => ListStore.new)
445
+ g.add_seq(@ex.List, RDF_NS.first, [])
446
+ g.seq(@ex.List).should == []
380
447
  end
381
448
  end
382
449
  end
data/spec/rdf_helper.rb CHANGED
@@ -105,7 +105,10 @@ module RdfHelper
105
105
 
106
106
  return unless output
107
107
 
108
- if self.compare == :array
108
+ case self.compare
109
+ when :none
110
+ # Don't check output, just parse to graph
111
+ when :array
109
112
  @parser.graph.should be_equivalent_graph(self.output, self)
110
113
  else
111
114
  output_parser = Parser.new
@@ -0,0 +1,227 @@
1
+ require File.join(File.dirname(__FILE__), 'spec_helper')
2
+ include RdfContext
3
+
4
+ describe "Turtle Serializer" do
5
+ describe "simple tests" do
6
+ it "should use full URIs without base" do
7
+ input = %(<http://a/b> <http://a/c> <http://a/d> .)
8
+ serialize(input, nil, %r(^<http://a/b> <http://a/c> <http://a/d> \.$))
9
+ end
10
+
11
+ it "should use relative URIs with base" do
12
+ input = %(<http://a/b> <http://a/c> <http://a/d> .)
13
+ serialize(input, "http://a/",
14
+ %r(^@base <http://a/> \.$),
15
+ %r(^<b> <c> <d> \.$)
16
+ )
17
+ end
18
+
19
+ it "should use qname URIs with prefix" do
20
+ input = %(@prefix a: <http://a/> . <http://a/b> <http://a/c> <http://a/d> .)
21
+ serialize(input, nil,
22
+ %r(^@prefix a: <http://a/> \.$),
23
+ %r(^a:b a:c a:d \.$)
24
+ )
25
+ end
26
+
27
+ it "should use qname URIs with empty prefix" do
28
+ input = %(@prefix : <http://a/> . <http://a/b> <http://a/c> <http://a/d> .)
29
+ serialize(input, nil,
30
+ %r(^@prefix : <http://a/> \.$),
31
+ %r(^:b :c :d \.$)
32
+ )
33
+ end
34
+
35
+ it "should order properties" do
36
+ input = %(
37
+ @prefix : <http://a/> .
38
+ @prefix dc: <http://purl.org/dc/elements/1.1/> .
39
+ @prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
40
+ :b :c :d .
41
+ :b dc:title "title" .
42
+ :b a :class .
43
+ :b rdfs:label "label" .
44
+ )
45
+ serialize(input, nil,
46
+ %r(^:b a :class;$),
47
+ %r(^\s+rdfs:label "label";$),
48
+ %r(^\s+dc:title \"title\";$),
49
+ %r(^\s+:c :d \.$),
50
+ %r(a :class.*label.*title.*:c :d)m
51
+ )
52
+ end
53
+
54
+ it "should generate object list" do
55
+ input = %(@prefix : <http://a/> . :b :c :d, :e .)
56
+ serialize(input, nil,
57
+ %r(^@prefix : <http://a/> \.$),
58
+ %r(^:b :c :d,$),
59
+ %r(^\s+:e \.$)
60
+ )
61
+ end
62
+
63
+ it "should generate property list" do
64
+ input = %(@prefix : <http://a/> . :b :c :d; :e :f .)
65
+ serialize(input, nil,
66
+ %r(^@prefix : <http://a/> \.$),
67
+ %r(^:b :c :d;$),
68
+ %r(^\s+:e :f \.$)
69
+ )
70
+ end
71
+ end
72
+
73
+ describe "anons" do
74
+ it "should generate bare anon" do
75
+ input = %(@prefix : <http://a/> . [:a :b] .)
76
+ serialize(input, nil,
77
+ %r(^\s*\[ :a :b\] \.$)
78
+ )
79
+ end
80
+
81
+ it "should generate anon as subject" do
82
+ input = %(@prefix : <http://a/> . [:a :b] :c :d .)
83
+ serialize(input, nil,
84
+ %r(^\s*\[ :a :b;$),
85
+ %r(^\s+:c :d\] \.$)
86
+ )
87
+ end
88
+
89
+ it "should generate anon as object" do
90
+ input = %(@prefix : <http://a/> . :a :b [:c :d] .)
91
+ serialize(input, nil,
92
+ %r(^\s*\:a :b \[ :c :d\] \.$)
93
+ )
94
+ end
95
+ end
96
+
97
+ describe "lists" do
98
+ it "should generate bare list" do
99
+ input = %(@prefix : <http://a/> . (:a :b) .)
100
+ serialize(input, nil,
101
+ %r(^\(:a :b\) \.$)
102
+ )
103
+ end
104
+
105
+ it "should generate literal list" do
106
+ input = %(@prefix : <http://a/> . :a :b ( "apple" "banana" ) .)
107
+ serialize(input, nil,
108
+ %r(^:a :b \("apple" "banana"\) \.$)
109
+ )
110
+ end
111
+
112
+ it "should generate empty list" do
113
+ input = %(@prefix : <http://a/> . :a :b () .)
114
+ serialize(input, nil,
115
+ %r(^:a :b \(\) \.$)
116
+ )
117
+ end
118
+
119
+ it "should generate empty list(2)" do
120
+ input = %(@prefix : <http://a/> . :emptyList = () .)
121
+ serialize(input, nil,
122
+ %r(^:emptyList <.*sameAs> \(\) \.$)
123
+ )
124
+ end
125
+
126
+ it "should generate empty list as subject" do
127
+ input = %(@prefix : <http://a/> . () :a :b .)
128
+ serialize(input, nil,
129
+ %r(^\(\) :a :b \.$)
130
+ )
131
+ end
132
+
133
+ it "should generate list as subject" do
134
+ input = %(@prefix : <http://a/> . (:a) :b :c .)
135
+ serialize(input, nil,
136
+ %r(^\(:a\) :b :c \.$)
137
+ )
138
+ end
139
+
140
+ it "should generate list of empties" do
141
+ input = %(@prefix : <http://a/> . :listOf2Empties = (() ()) .)
142
+ serialize(input, nil,
143
+ %r(^:listOf2Empties <.*sameAs> \(\(\) \(\)\) \.$)
144
+ )
145
+ end
146
+
147
+ it "should generate list anon" do
148
+ input = %(@prefix : <http://a/> . :twoAnons = ([a :mother] [a :father]) .)
149
+ serialize(input, nil,
150
+ %r(^:twoAnons <.*sameAs> \(\[\s*a :mother\] \[\s*a :father\]\) \.$)
151
+ )
152
+ end
153
+
154
+ it "should generate owl:unionOf list" do
155
+ input = %(
156
+ @prefix : <http://a/> .
157
+ @prefix owl: <http://www.w3.org/2002/07/owl#> .
158
+ @prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
159
+ @prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
160
+ :a rdfs:domain [
161
+ a owl:Class;
162
+ owl:unionOf [
163
+ a owl:Class;
164
+ rdf:first :b;
165
+ rdf:rest [
166
+ a owl:Class;
167
+ rdf:first :c;
168
+ rdf:rest rdf:nil
169
+ ]
170
+ ]
171
+ ] .
172
+ )
173
+ serialize(input, nil,
174
+ %r(:a rdfs:domain \[\s*a owl:Class;\s+owl:unionOf\s+\(:b\s+:c\)\]\s*\.$)m
175
+ )
176
+ end
177
+ end
178
+
179
+ # W3C Turtle Test suite from http://www.w3.org/2000/10/swap/test/regression.n3
180
+ describe "w3c turtle tests" do
181
+ require 'rdf_helper'
182
+
183
+ def self.positive_tests
184
+ RdfHelper::TestCase.test_cases(TURTLE_TEST, TURTLE_DIR) rescue []
185
+ end
186
+
187
+ positive_tests.each do |t|
188
+ #puts t.inspect
189
+ #next unless t.name == "test-04"
190
+
191
+ specify "#{t.name}: " + (t.description || "#{t.inputDocument}") do
192
+ # Skip tests for very long files, too long
193
+ if %w(test-14 test-15 test-16 rdfq-results).include?(t.name)
194
+ pending("Skip very long input file")
195
+ elsif !defined?(::Encoding) && %w(test-18).include?(t.name)
196
+ pending("Not supported in Ruby 1.8")
197
+ elsif %w(test-29).include?(t.name)
198
+ pending("Silly test")
199
+ else
200
+ begin
201
+ t.run_test do |rdf_string, parser|
202
+ parser.parse(rdf_string, t.about.uri.to_s, :strict => true, :debug => [])
203
+ parser.graph.serialize(:format => :ttl, :base => t.about.uri.to_s)
204
+ t.compare = :none
205
+ end
206
+ #rescue #Spec::Expectations::ExpectationNotMetError => e
207
+ # pending() { raise }
208
+ end
209
+ end
210
+ end
211
+ end
212
+ end
213
+
214
+ # Serialize ntstr to a string and compare against regexps
215
+ def serialize(ntstr, base = nil, *regexps)
216
+ g = Graph.new
217
+ g.parse(ntstr, base)
218
+ result = g.serialize(:format => :ttl, :base => base)
219
+ puts result if $verbose
220
+
221
+ regexps.each do |re|
222
+ result.should =~ re
223
+ end
224
+
225
+ result
226
+ end
227
+ end