roadforest 0.0.3 → 0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. checksums.yaml +7 -0
  2. data/examples/file-management.rb +7 -9
  3. data/lib/roadforest/application/dispatcher.rb +44 -31
  4. data/lib/roadforest/application/parameters.rb +5 -4
  5. data/lib/roadforest/application/path-provider.rb +14 -1
  6. data/lib/roadforest/application/route-adapter.rb +15 -4
  7. data/lib/roadforest/application/services-host.rb +41 -7
  8. data/lib/roadforest/application.rb +4 -8
  9. data/lib/roadforest/authorization.rb +231 -0
  10. data/lib/roadforest/blob-model.rb +2 -11
  11. data/lib/roadforest/content-handling/engine.rb +12 -6
  12. data/lib/roadforest/content-handling/handler-wrap.rb +45 -0
  13. data/lib/roadforest/content-handling/media-type.rb +20 -12
  14. data/lib/roadforest/content-handling/type-handler.rb +76 -0
  15. data/lib/roadforest/content-handling/type-handlers/jsonld.rb +2 -146
  16. data/lib/roadforest/content-handling/type-handlers/rdf-handler.rb +38 -0
  17. data/lib/roadforest/content-handling/type-handlers/rdfa-writer/document-environment.rb +34 -0
  18. data/lib/roadforest/content-handling/type-handlers/rdfa-writer/object-environment.rb +62 -0
  19. data/lib/roadforest/content-handling/type-handlers/rdfa-writer/property-environment.rb +46 -0
  20. data/lib/roadforest/content-handling/type-handlers/rdfa-writer/render-engine.rb +574 -0
  21. data/lib/roadforest/content-handling/type-handlers/rdfa-writer/render-environment.rb +144 -0
  22. data/lib/roadforest/content-handling/type-handlers/rdfa-writer/subject-environment.rb +80 -0
  23. data/lib/roadforest/content-handling/type-handlers/rdfa-writer.rb +163 -0
  24. data/lib/roadforest/content-handling/type-handlers/rdfa.rb +175 -0
  25. data/lib/roadforest/content-handling/type-handlers/rdfpost.rb +297 -0
  26. data/lib/roadforest/debug.rb +10 -0
  27. data/lib/roadforest/http/graph-response.rb +3 -7
  28. data/lib/roadforest/http/graph-transfer.rb +28 -106
  29. data/lib/roadforest/http/keychain.rb +79 -0
  30. data/lib/roadforest/http/message.rb +9 -1
  31. data/lib/roadforest/http/user-agent.rb +115 -0
  32. data/lib/roadforest/http.rb +8 -0
  33. data/lib/roadforest/model.rb +48 -3
  34. data/lib/roadforest/rdf/graph-focus.rb +5 -3
  35. data/lib/roadforest/rdf/graph-store.rb +4 -2
  36. data/lib/roadforest/rdf/normalization.rb +6 -1
  37. data/lib/roadforest/remote-host.rb +22 -7
  38. data/lib/roadforest/resource/rdf/read-only.rb +15 -1
  39. data/lib/roadforest/templates/base/doc.haml +13 -0
  40. data/lib/roadforest/templates/base/property_value.haml +12 -0
  41. data/lib/roadforest/templates/base/property_values.haml +6 -0
  42. data/lib/roadforest/templates/base/subject.haml +4 -0
  43. data/lib/roadforest/templates/distiller/doc.haml +20 -0
  44. data/lib/roadforest/templates/distiller/nil-object.haml +1 -0
  45. data/lib/roadforest/templates/distiller/property_value.haml +7 -0
  46. data/lib/roadforest/templates/distiller/property_values.haml +7 -0
  47. data/lib/roadforest/templates/distiller/subject.haml +5 -0
  48. data/lib/roadforest/templates/min/doc.haml +10 -0
  49. data/lib/roadforest/templates/min/property_values.haml +7 -0
  50. data/lib/roadforest/templates/min/subject.haml +2 -0
  51. data/lib/roadforest/templates/nil-object.haml +0 -0
  52. data/lib/roadforest/templates/node-object.haml +1 -0
  53. data/lib/roadforest/templates/object.haml +1 -0
  54. data/lib/roadforest/templates/uri-object.haml +1 -0
  55. data/lib/roadforest/templates/xml-literal-object.haml +1 -0
  56. data/lib/roadforest/utility/class-registry.rb +4 -0
  57. data/spec/client.rb +119 -77
  58. data/spec/{excon-adapater.rb → excon-adapter.rb} +4 -0
  59. data/spec/full-integration.rb +6 -2
  60. data/spec/graph-store.rb +1 -1
  61. data/spec/media-types.rb +29 -2
  62. metadata +102 -125
@@ -0,0 +1,574 @@
1
+ require 'roadforest/content-handling/type-handlers/rdfa-writer'
2
+ require 'roadforest/content-handling/type-handlers/rdfa-writer/document-environment'
3
+ require 'roadforest/content-handling/type-handlers/rdfa-writer/subject-environment'
4
+ require 'roadforest/content-handling/type-handlers/rdfa-writer/property-environment'
5
+ require 'roadforest/content-handling/type-handlers/rdfa-writer/object-environment'
6
+ require 'haml'
7
+
8
+ module RoadForest::MediaType
9
+ class RDFaWriter
10
+ class RenderEngine
11
+ # Defines rdf:type of subjects to be emitted at the beginning of the
12
+ # document.
13
+ # @return [Array<URI>]
14
+ attr_accessor :top_classes
15
+
16
+ # Defines order of predicates to to emit at begninning of a resource description. Defaults to `[rdf:type, rdfs:label, dc:title]`
17
+ # @return [Array<URI>]
18
+ attr_accessor :predicate_order
19
+
20
+ # Defines order of predicates to use in heading.
21
+ # @return [Array<URI>]
22
+ attr_accessor :heading_predicates
23
+
24
+ attr_accessor :prefixes, :base_uri, :lang, :standard_prefixes, :graph, :titles, :doc_title
25
+ attr_accessor :valise, :resource_name, :style_name, :template_cache, :haml_options
26
+ attr_reader :debug
27
+
28
+ def initialize(graph, debug=nil)
29
+ @debug = debug
30
+ @graph = graph
31
+
32
+ reset
33
+
34
+ yield self
35
+
36
+ setup
37
+ end
38
+
39
+ # Reset parser to run again
40
+ def reset
41
+ @debug_indent = 0
42
+ @uri_to_term_or_curie = {}
43
+ @uri_to_prefix = {}
44
+ @references = Hash.new{|h,k| h[k] = 0}
45
+ @prefixes = {}
46
+ @serialized = {}
47
+ @subjects = {}
48
+ @ordered_subjects = []
49
+ @titles = {}
50
+ @doc_title = ""
51
+ end
52
+
53
+ def template_cache
54
+ @template_cache ||= ::Tilt::Cache.new
55
+ end
56
+
57
+ def style_name
58
+ @style_name ||= "base"
59
+ end
60
+
61
+ def setup_env(env)
62
+ env.heading_predicates = heading_predicates
63
+ env.lang = lang
64
+ end
65
+
66
+ # Increase depth around a method invocation
67
+ # @yield
68
+ # Yields with no arguments
69
+ # @yieldreturn [Object] returns the result of yielding
70
+ # @return [Object]
71
+ def depth
72
+ @debug_indent += 1
73
+ ret = yield
74
+ @debug_indent -= 1
75
+ ret
76
+ end
77
+
78
+ def templates
79
+ @templates ||= [resource_name, style_name, nil].uniq.map do |name|
80
+ valise.sub_set(["templates", name].compact.join("/"))
81
+ end.inject do |left, right|
82
+ left + right
83
+ end.handle_templates do |config|
84
+ config.add_type("haml", { :template_cache => template_cache, :template_options => haml_options })
85
+ end
86
+ end
87
+
88
+ ##
89
+ # Find a template appropriate for the subject.
90
+ # Override this method to provide templates based on attributes of a given subject
91
+ #
92
+ # @param [RDF::URI] subject
93
+ # @return [Hash] # return matched matched template
94
+ def find_template(kinds)
95
+ kind = kinds.shift
96
+ templates.contents(kind)
97
+ rescue Valise::Errors::NotFound
98
+ if kinds.empty?
99
+ raise RDF::WriterError, "Missing template for #{context.class.name}" if template.nil?
100
+ else
101
+ retry
102
+ end
103
+ end
104
+
105
+ def find_environment_template(env)
106
+ find_template(env.template_kinds)
107
+ end
108
+
109
+ # Increase the reference count of this resource
110
+ # @param [RDF::Resource] resource
111
+ # @return [Integer] resulting reference count
112
+ def bump_reference(resource)
113
+ @references[resource] += 1
114
+ end
115
+
116
+ # Return the number of times this node has been referenced in the object position
117
+ # @param [RDF::Node] node
118
+ # @return [Boolean]
119
+ def ref_count(node)
120
+ @references[node]
121
+ end
122
+
123
+ # Add debug event to debug array, if specified
124
+ #
125
+ # @param [String] message
126
+ # @yieldreturn [String] appended to message, to allow for lazy-evaulation of message
127
+ def add_debug(message = nil)
128
+ return unless ::RoadForest.debug_io || @debug
129
+ message ||= ""
130
+ message = message + yield if block_given?
131
+ msg = "#{' ' * @debug_indent}#{message}"
132
+ RoadForest::debug(msg)
133
+ @debug << msg.force_encoding("utf-8") if @debug.is_a?(Array)
134
+ end
135
+
136
+ def setup
137
+ add_debug {"\nserialize setup: graph size: #{@graph.size}"}
138
+
139
+ preprocess
140
+
141
+ @ordered_subjects = order_subjects
142
+
143
+ # Take title from first subject having a heading predicate
144
+ @doc_title = nil
145
+ heading_predicates.each do |pred|
146
+ @graph.query(:predicate => pred) do |statement|
147
+ titles[statement.subject] ||= statement.object
148
+ end
149
+ end
150
+ title_subject = @ordered_subjects.detect {|subject| titles[subject]}
151
+ @doc_title = titles[title_subject]
152
+ end
153
+
154
+ # Perform any preprocessing of statements required
155
+ # @return [ignored]
156
+ def preprocess
157
+ # Load initial contexts
158
+ # Add terms and prefixes to local store for converting URIs
159
+ # Keep track of vocabulary from left-most context
160
+ [RDF::RDFa::XML_RDFA_CONTEXT, RDF::RDFa::HTML_RDFA_CONTEXT].each do |uri|
161
+ ctx = RDF::RDFa::Context.find(uri)
162
+ ctx.prefixes.each_pair do |k, v|
163
+ @uri_to_prefix[v] = k unless k.to_s == "dcterms"
164
+ end
165
+
166
+ ctx.terms.each_pair do |k, v|
167
+ @uri_to_term_or_curie[v] = k
168
+ end
169
+
170
+ @vocabulary = ctx.vocabulary.to_s if ctx.vocabulary
171
+ end
172
+
173
+ # Load defined prefixes
174
+ (@prefixes || {}).each_pair do |k, v|
175
+ @uri_to_prefix[v.to_s] = k
176
+ end
177
+ @prefixes = {} # Will define actual used when matched
178
+
179
+ # Process each statement to establish CURIEs and Terms
180
+ @graph.each {|statement| preprocess_statement(statement)}
181
+ add_debug{ "preprocess prefixes: #{@prefixes.inspect}" }
182
+ end
183
+
184
+ # Order subjects for output. Override this to output subjects in another order.
185
+ #
186
+ # Uses #top_classes and #base_uri.
187
+ # @return [Array<Resource>] Ordered list of subjects
188
+ def order_subjects
189
+ seen = {}
190
+ subjects = []
191
+
192
+ # Start with base_uri
193
+ if base_uri && @subjects.keys.include?(base_uri)
194
+ subjects << base_uri
195
+ seen[base_uri] = true
196
+ end
197
+
198
+ # Add distinguished classes
199
+ top_classes.select do |s|
200
+ !seen.include?(s)
201
+ end.each do |class_uri|
202
+ graph.query(:predicate => RDF.type, :object => class_uri).map {|st| st.subject}.sort.uniq.each do |subject|
203
+ #add_debug {"order_subjects: #{subject.inspect}"}
204
+ subjects << subject
205
+ seen[subject] = true
206
+ end
207
+ end
208
+
209
+ # Sort subjects by resources over nodes, ref_counts and the subject URI itself
210
+ recursable = @subjects.keys.select do |s|
211
+ !seen.include?(s)
212
+ end.map do |r|
213
+ [r.is_a?(RDF::Node) ? 1 : 0, ref_count(r), r]
214
+ end.sort
215
+
216
+ add_debug {"order_subjects: #{recursable.inspect}"}
217
+
218
+ subjects += recursable.map{|r| r.last}
219
+ end
220
+
221
+ # Take a hash from predicate uris to lists of values.
222
+ # Sort the lists of values. Return a sorted list of properties.
223
+ #
224
+ # @param [Hash{String => Array<Resource>}] properties A hash of Property to Resource mappings
225
+ # @return [Array<String>}] Ordered list of properties. Uses predicate_order.
226
+ def order_properties(properties)
227
+ # Make sorted list of properties
228
+ prop_list = []
229
+
230
+ predicate_order.each do |prop|
231
+ next unless properties[prop.to_s]
232
+ prop_list << prop.to_s
233
+ end
234
+
235
+ properties.keys.sort.each do |prop|
236
+ next if prop_list.include?(prop.to_s)
237
+ prop_list << prop.to_s
238
+ end
239
+
240
+ add_debug {"order_properties: #{prop_list.join(', ')}"}
241
+ prop_list
242
+ end
243
+
244
+ # Perform any statement preprocessing required. This is used to perform reference counts and determine required prefixes.
245
+ # @param [RDF::Statement] statement
246
+ # @return [ignored]
247
+ def preprocess_statement(statement)
248
+ #add_debug {"preprocess: #{statement.inspect}"}
249
+ bump_reference(statement.subject)
250
+ bump_reference(statement.object)
251
+ @subjects[statement.subject] = true
252
+ get_curie(statement.subject)
253
+ get_curie(statement.predicate)
254
+ get_curie(statement.object)
255
+ get_curie(statement.object.datatype) if statement.object.literal? && statement.object.has_datatype?
256
+ end
257
+
258
+ def get_curie(resource)
259
+ raise RDF::WriterError, "Getting CURIE for #{resource.inspect}, which must be an RDF value" unless resource.is_a? RDF::Value
260
+ return resource.to_s unless resource.uri?
261
+
262
+ uri = resource.to_s
263
+
264
+ curie =
265
+ case
266
+ when @uri_to_term_or_curie.has_key?(uri)
267
+ add_debug {"get_curie(#{uri}): uri_to_term_or_curie #{@uri_to_term_or_curie[uri].inspect}"}
268
+ return @uri_to_term_or_curie[uri]
269
+ when base_uri && uri.index(base_uri.to_s) == 0
270
+ add_debug {"get_curie(#{uri}): base_uri (#{uri.sub(base_uri.to_s, "")})"}
271
+ uri.sub(base_uri.to_s, "")
272
+ when @vocabulary && uri.index(@vocabulary) == 0
273
+ add_debug {"get_curie(#{uri}): vocabulary"}
274
+ uri.sub(@vocabulary, "")
275
+ when u = @uri_to_prefix.keys.detect {|u| uri.index(u.to_s) == 0}
276
+ add_debug {"get_curie(#{uri}): uri_to_prefix"}
277
+ prefix = @uri_to_prefix[u]
278
+ @prefixes[prefix] = u
279
+ uri.sub(u.to_s, "#{prefix}:")
280
+ when @standard_prefixes && vocab = RDF::Vocabulary.detect {|v| uri.index(v.to_uri.to_s) == 0}
281
+ add_debug {"get_curie(#{uri}): standard_prefixes"}
282
+ prefix = vocab.__name__.to_s.split('::').last.downcase
283
+ @prefixes[prefix] = vocab.to_uri
284
+ uri.sub(vocab.to_uri.to_s, "#{prefix}:")
285
+ else
286
+ add_debug {"get_curie(#{uri}): none"}
287
+ uri
288
+ end
289
+
290
+ add_debug {"get_curie(#{resource}) => #{curie}"}
291
+
292
+ @uri_to_term_or_curie[uri] = curie
293
+ rescue ArgumentError => e
294
+ raise RDF::WriterError, "Invalid URI #{uri.inspect}: #{e.message}"
295
+ end
296
+
297
+ def render(context)
298
+ add_debug "render"
299
+ if context.render_checked
300
+ return ""
301
+ end
302
+ template = find_environment_template(context)
303
+ depth do
304
+ add_debug{ "template: #{template.file}" }
305
+ add_debug{ "context: #{context.inspect}"}
306
+
307
+ template.render(context) do |item|
308
+ context.yielded(item)
309
+ end.sub(/\n\Z/,'')
310
+ end
311
+ end
312
+
313
+ # Mark a subject as done.
314
+ # @param [RDF::Resource] subject
315
+ # @return [Boolean]
316
+ def subject_done(subject)
317
+ @serialized[subject] = true
318
+ end
319
+
320
+ # Determine if the subject has been completed
321
+ # @param [RDF::Resource] subject
322
+ # @return [Boolean]
323
+ def is_done?(subject)
324
+ @serialized.include?(subject)
325
+ end
326
+
327
+
328
+ # @param [RDF::Resource] subject
329
+ # @return [Hash{String => Object}]
330
+ def properties_for_subject(subject)
331
+ properties = {}
332
+ @graph.query(:subject => subject) do |st|
333
+ key = st.predicate.to_s.freeze
334
+ properties[key] ||= []
335
+ properties[key] << st.object
336
+ end
337
+ properties
338
+ end
339
+
340
+ # @param [Array,NilClass] type
341
+ # @param [RDF::Resource] subject
342
+ # @return [String] string representation of the specific RDF.type uri
343
+ def type_of(type, subject)
344
+ # Find appropriate template
345
+ curie = case
346
+ when subject.node?
347
+ subject.to_s if ref_count(subject) > 1
348
+ else
349
+ get_curie(subject)
350
+ end
351
+
352
+ typeof = Array(type).map {|r| get_curie(r)}.join(" ")
353
+ typeof = nil if typeof.empty?
354
+
355
+ # Nodes without a curie need a blank @typeof to generate a subject
356
+ typeof ||= "" unless curie
357
+
358
+ add_debug {"subject: #{curie.inspect}, typeof: #{typeof.inspect}" }
359
+
360
+ typeof.freeze
361
+ end
362
+
363
+ def list_property_envs(predicate, list_objects)
364
+ return list_objects.map do |object|
365
+ # Render each list as multiple properties and set :inlist to true
366
+ list = RDF::List.new(object, @graph)
367
+ list.each_statement {|st| subject_done(st.subject)}
368
+
369
+ add_debug {"list: #{list.inspect} #{list.to_a}"}
370
+ env = simple_property_env(predicate, list.to_a)
371
+ env.inlist = "true"
372
+ env
373
+ end
374
+ end
375
+
376
+ def object_env(predicate, object)
377
+ subj = subject_env(object)
378
+ unless subj.nil?
379
+ subj.rel = get_curie(predicate)
380
+ return subj
381
+ end
382
+
383
+ env =
384
+ if get_curie(object) == 'rdf:nil'
385
+ NilObjectEnvironment.new(self)
386
+ elsif object.node?
387
+ NodeObjectEnvironment.new(self)
388
+ elsif object.uri?
389
+ UriObjectEnvironment.new(self)
390
+ elsif object.datatype == RDF.XMLLiteral
391
+ XMLLiteralObjectEnvironment.new(self)
392
+ else
393
+ ObjectEnvironment.new(self)
394
+ end
395
+ env.predicate = predicate
396
+ env.object = object
397
+ env.inlist = nil
398
+
399
+ env
400
+ end
401
+
402
+ def simple_property_env(predicate, objects)
403
+ return nil if objects.to_a.empty?
404
+
405
+ env = PropertyEnvironment.new(self)
406
+ setup_env(env)
407
+ env.object_terms = objects
408
+ env.predicate = predicate
409
+ env.inlist = nil
410
+
411
+ env
412
+ end
413
+
414
+ def subject_env(subject)
415
+ return unless @subjects.include?(subject)
416
+ properties = properties_for_subject(subject)
417
+
418
+ env = SubjectEnvironment.new(self)
419
+ env.base = base_uri
420
+ env.predicate_terms = order_properties(properties)
421
+ env.property_objects = properties
422
+ env.subject = subject
423
+ env.typeof = type_of(properties.delete(RDF.type.to_s), subject)
424
+
425
+ env
426
+ end
427
+
428
+ def document_env
429
+ env = DocumentEnvironment.new(self)
430
+ env.subject_terms = @ordered_subjects
431
+ env.title = doc_title
432
+ env.prefixes = prefixes
433
+ env.lang = lang
434
+ env.base = base_uri
435
+ env
436
+ end
437
+
438
+ # Render a single- or multi-valued predicate using
439
+ # `haml_template[:property_value]` or `haml_template[:property_values]`.
440
+ # Yields each object for optional rendering. The block should only render
441
+ # for recursive subject definitions (i.e., where the object is also a
442
+ # subject and is rendered underneath the first referencing subject).
443
+ #
444
+ # If a multi-valued property definition is not found within the template, the writer will use the single-valued property definition multiple times.
445
+ #
446
+ # @param [Array<RDF::Resource>] predicate
447
+ # Predicate to render.
448
+ # @param [Array<RDF::Resource>] objects
449
+ # List of objects to render. If the list contains only a single element, the :property_value template will be used. Otherwise, the :property_values template is used.
450
+ # @param [Hash{Symbol => Object}] options Rendering options passed to Haml render.
451
+ # @option options [String] :haml (haml_template[:property_value], haml_template[:property_values])
452
+ # Haml template to render. Otherwise, uses `haml_template[:property_value] or haml_template[:property_values]`
453
+ # depending on the cardinality of objects.
454
+ # @yield object, inlist
455
+ # Yields object and if it is contained in a list.
456
+ # @yieldparam [RDF::Resource] object
457
+ # @yieldparam [Boolean] inlist
458
+ # @yieldreturn [String, nil]
459
+ # The block should only return a string for recursive object definitions.
460
+ # @return String
461
+ # The rendered document is returned as a string
462
+ #
463
+ #
464
+ def render_predicate(subject, pred)
465
+ pred = RDF::URI(pred) if pred.is_a?(String)
466
+ objects = properties_for_subject(subject)[pred.to_s]
467
+
468
+ add_debug {"predicate: #{pred.inspect}, objects: #{objects}"}
469
+
470
+ return if objects.to_a.empty?
471
+
472
+ nonlists, lists = objects.partition do |object|
473
+ object == RDF.nil || (l = RDF::List.new(object, @graph)).invalid?
474
+ end
475
+
476
+ add_debug {"properties with lists: #{lists} non-lists: #{nonlists}"}
477
+
478
+ return ([simple_property_env(pred, nonlists)] + list_property_envs(pred, lists)).compact.map do |env|
479
+ render(env)
480
+ end.join(" ")
481
+ end
482
+
483
+ def is_list?(object)
484
+ !(object == RDF.nil || (l = RDF::List.new(object, @graph)).invalid?)
485
+ end
486
+
487
+ # @param [RDF::Resource] subject
488
+ # @param [Array] prop_list
489
+ # @param [Hash] render_opts
490
+ # @return [String]
491
+ def render_subject(subject)
492
+ # See if there's a template based on the sorted concatenation of all types of this subject
493
+ # or any type of this subject
494
+
495
+ env = subject_env(subject)
496
+
497
+ return if env.nil?
498
+
499
+ yield env if block_given?
500
+
501
+ add_debug {"props: #{env.predicates.inspect}"}
502
+
503
+ render(env)
504
+ end
505
+
506
+ # Render document using `haml_template[:doc]`. Yields each subject to be
507
+ # rendered separately.
508
+ #
509
+ # @param [Array<RDF::Resource>] subjects
510
+ # Ordered list of subjects. Template must yield to each subject, which returns
511
+ # the serialization of that subject (@see #subject_template)
512
+ # @param [Hash{Symbol => Object}] options Rendering options passed to Haml render.
513
+ # @option options [RDF::URI] base (nil)
514
+ # Base URI added to document, used for shortening URIs within the document.
515
+ # @option options [Symbol, String] language (nil)
516
+ # Value of @lang attribute in document, also allows included literals to omit
517
+ # an @lang attribute if it is equivalent to that of the document.
518
+ # @option options [String] title (nil)
519
+ # Value of html>head>title element.
520
+ # @option options [String] prefix (nil)
521
+ # Value of @prefix attribute.
522
+ # @option options [String] haml (haml_template[:doc])
523
+ # Haml template to render.
524
+ # @yield [subject]
525
+ # Yields each subject
526
+ # @yieldparam [RDF::URI] subject
527
+ # @yieldreturn [:ignored]
528
+ # @return String
529
+ # The rendered document is returned as a string
530
+ def render_document
531
+ add_debug{ "engine prefixes: #{prefixes.inspect}"}
532
+ env = document_env
533
+
534
+ yield env if block_given?
535
+
536
+ render(env)
537
+ end
538
+
539
+ # Render a subject using `haml_template[:subject]`.
540
+ #
541
+ # The _subject_ template may be called either as a top-level element, or recursively under another element if the _rel_ local is not nil.
542
+ #
543
+ # Yields each predicate/property to be rendered separately (@see #render_property_value and `#render_property_values`).
544
+ #
545
+ # @param [Array<RDF::Resource>] subject
546
+ # Subject to render
547
+ # @param [Array<RDF::Resource>] predicates
548
+ # Predicates of subject. Each property is yielded for separate rendering.
549
+ # @param [Hash{Symbol => Object}] options Rendering options passed to Haml render.
550
+ # @option options [String] about (nil)
551
+ # About description, a CURIE, URI or Node definition.
552
+ # May be nil if no @about is rendered (e.g. unreferenced Nodes)
553
+ # @option options [String] resource (nil)
554
+ # Resource description, a CURIE, URI or Node definition.
555
+ # May be nil if no @resource is rendered
556
+ # @option options [String] rel (nil)
557
+ # Optional @rel property description, a CURIE, URI or Node definition.
558
+ # @option options [String] typeof (nil)
559
+ # RDF type as a CURIE, URI or Node definition.
560
+ # If :about is nil, this defaults to the empty string ("").
561
+ # @option options [:li, nil] element (nil)
562
+ # Render with &lt;li&gt;, otherwise with template default.
563
+ # @option options [String] haml (haml_template[:subject])
564
+ # Haml template to render.
565
+ # @yield [predicate]
566
+ # Yields each predicate
567
+ # @yieldparam [RDF::URI] predicate
568
+ # @yieldreturn [:ignored]
569
+ # @return String
570
+ # The rendered document is returned as a string
571
+ # Return Haml template for document from `haml_template[:subject]`
572
+ end
573
+ end
574
+ end