Class: RoadForest::TypeHandlers::RDFaWriter::RenderEngine

Inherits:
Object
  • Object
show all
Defined in:
lib/roadforest/type-handlers/rdfa-writer/render-engine.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(graph, debug = nil) {|_self| ... } ⇒ RenderEngine

Returns a new instance of RenderEngine.

Yields:

  • (_self)

Yield Parameters:



64
65
66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/roadforest/type-handlers/rdfa-writer/render-engine.rb', line 64

def initialize(graph, debug=nil)
  @debugging_comments = false
  @debug = debug
  @graph = graph
  @graph_name = nil
  @decoration_set = DecorationSet.new
  @render_stack = []

  reset

  yield self

  setup
end

Instance Attribute Details

#base_uriObject

Returns the value of attribute base_uri.



57
58
59
# File 'lib/roadforest/type-handlers/rdfa-writer/render-engine.rb', line 57

def base_uri
  @base_uri
end

#debugObject (readonly)

Returns the value of attribute debug.



59
60
61
# File 'lib/roadforest/type-handlers/rdfa-writer/render-engine.rb', line 59

def debug
  @debug
end

#debugging_commentsObject

Returns the value of attribute debugging_comments.



60
61
62
# File 'lib/roadforest/type-handlers/rdfa-writer/render-engine.rb', line 60

def debugging_comments
  @debugging_comments
end

#decoration_setObject (readonly)

Returns the value of attribute decoration_set.



62
63
64
# File 'lib/roadforest/type-handlers/rdfa-writer/render-engine.rb', line 62

def decoration_set
  @decoration_set
end

#doc_titleObject

Returns the value of attribute doc_title.



57
58
59
# File 'lib/roadforest/type-handlers/rdfa-writer/render-engine.rb', line 57

def doc_title
  @doc_title
end

#graphObject

Returns the value of attribute graph.



57
58
59
# File 'lib/roadforest/type-handlers/rdfa-writer/render-engine.rb', line 57

def graph
  @graph
end

#graph_nameObject

Returns the value of attribute graph_name.



57
58
59
# File 'lib/roadforest/type-handlers/rdfa-writer/render-engine.rb', line 57

def graph_name
  @graph_name
end

#heading_predicatesObject

Returns the value of attribute heading_predicates.



55
56
57
# File 'lib/roadforest/type-handlers/rdfa-writer/render-engine.rb', line 55

def heading_predicates
  @heading_predicates
end

#langObject

Returns the value of attribute lang.



57
58
59
# File 'lib/roadforest/type-handlers/rdfa-writer/render-engine.rb', line 57

def lang
  @lang
end

#predicate_orderObject

Returns the value of attribute predicate_order.



53
54
55
# File 'lib/roadforest/type-handlers/rdfa-writer/render-engine.rb', line 53

def predicate_order
  @predicate_order
end

#prefixesObject

Returns the value of attribute prefixes.



57
58
59
# File 'lib/roadforest/type-handlers/rdfa-writer/render-engine.rb', line 57

def prefixes
  @prefixes
end

#standard_prefixesObject

Returns the value of attribute standard_prefixes.



57
58
59
# File 'lib/roadforest/type-handlers/rdfa-writer/render-engine.rb', line 57

def standard_prefixes
  @standard_prefixes
end

#template_handlerObject

Returns the value of attribute template_handler.



58
59
60
# File 'lib/roadforest/type-handlers/rdfa-writer/render-engine.rb', line 58

def template_handler
  @template_handler
end

#titlesObject

Returns the value of attribute titles.



57
58
59
# File 'lib/roadforest/type-handlers/rdfa-writer/render-engine.rb', line 57

def titles
  @titles
end

#top_classesObject

Returns the value of attribute top_classes.



51
52
53
# File 'lib/roadforest/type-handlers/rdfa-writer/render-engine.rb', line 51

def top_classes
  @top_classes
end

Instance Method Details

#add_debug(message = nil) ⇒ Object



108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
# File 'lib/roadforest/type-handlers/rdfa-writer/render-engine.rb', line 108

def add_debug(message = nil)
  return unless ::RoadForest.debug_io || @debug
  message ||= "  " * @debug_indent
  begin
    message = message + yield if block_given?
  rescue => ex
    message += ex.inspect
    message += "\n"
    message += ex.backtrace[0...10].map do |line|
      ("  " * (@debug_indent + 1)) + line
    end.join("\n")
  end
  RoadForest::debug(message)
  @debug << message.force_encoding("utf-8") if @debug.is_a?(Array)
end

#build_env(klass) {|env| ... } ⇒ Object

Yields:

  • (env)


348
349
350
351
352
353
354
355
# File 'lib/roadforest/type-handlers/rdfa-writer/render-engine.rb', line 348

def build_env(klass)
  env = klass.new(self)
  env.heading_predicates = heading_predicates
  env.lang = lang
  env.parent = @render_stack.last
  yield(env)
  return decoration_set.decoration_for(env)
end

#bump_reference(resource) ⇒ Object



100
101
102
# File 'lib/roadforest/type-handlers/rdfa-writer/render-engine.rb', line 100

def bump_reference(resource)
  @references[resource] += 1
end

#depthObject



93
94
95
96
97
98
# File 'lib/roadforest/type-handlers/rdfa-writer/render-engine.rb', line 93

def depth
  @debug_indent += 1
  ret = yield
  @debug_indent -= 1
  ret
end

#document_envObject



357
358
359
360
361
362
363
364
365
# File 'lib/roadforest/type-handlers/rdfa-writer/render-engine.rb', line 357

def document_env
  build_env(DocumentEnvironment) do |env|
    env.subject_terms = @ordered_subjects
    env.title = doc_title
    env.prefixes = prefixes
    env.lang = lang
    env.base = base_uri
  end
end

#find_environment_template(env) ⇒ Object



293
294
295
296
297
# File 'lib/roadforest/type-handlers/rdfa-writer/render-engine.rb', line 293

def find_environment_template(env)
  template_handler.find_template(env.template_kinds)
rescue Valise::Errors::NotFound
  raise RDF::WriterError, "No template found for #{env.class} in #{template_handler.inspect}"
end

#get_curie(resource) ⇒ Object



234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
# File 'lib/roadforest/type-handlers/rdfa-writer/render-engine.rb', line 234

def get_curie(resource)
  raise RDF::WriterError, "Getting CURIE for #{resource.inspect}, which must be an RDF value" unless resource.is_a? RDF::Value
  return resource.to_s unless resource.uri?

  uri = resource.to_s

  curie =
    case
    when @uri_to_term_or_curie.has_key?(uri)
      add_debug {"get_curie(#{uri}): cached: #{@uri_to_term_or_curie[uri].inspect}"}
      return @uri_to_term_or_curie[uri]
    when base_uri && uri.index(base_uri.to_s) == 0
      add_debug {"get_curie(#{uri}): base_uri: (#{base_uri} + #{uri.sub(base_uri.to_s, "")})"}
      uri.sub(base_uri.to_s, "")
    when @vocabulary && uri.index(@vocabulary) == 0
      add_debug {"get_curie(#{uri}): vocabulary: #{@vocabulary.inspect}"}
      uri.sub(@vocabulary, "")
    when u = @uri_to_prefix.keys.detect {|u| uri.index(u.to_s) == 0}
      add_debug {"get_curie(#{uri}): uri_to_prefix: #{@uri_to_prefix[u]}"}
      prefix = @uri_to_prefix[u]
      @prefixes[prefix] = u
      uri.sub(u.to_s, "#{prefix}:")
    when @standard_prefixes && vocab = RDF::Vocabulary.detect {|v| uri.index(v.to_uri.to_s) == 0}
      add_debug {"get_curie(#{uri}): standard_prefixes: #{vocab}"}
      prefix = vocab.__name__.to_s.split('::').last.downcase
      @prefixes[prefix] = vocab.to_uri
      uri.sub(vocab.to_uri.to_s, "#{prefix}:")
    else
      add_debug {"get_curie(#{uri}): none"}
      uri
    end

  add_debug {"get_curie(#{resource}) => #{curie}"}

  @uri_to_term_or_curie[uri] = curie
rescue ArgumentError => e
  raise RDF::WriterError, "Invalid URI #{uri.inspect}: #{e.message}"
end

#is_done?(subject) ⇒ Boolean

Returns:

  • (Boolean)


334
335
336
# File 'lib/roadforest/type-handlers/rdfa-writer/render-engine.rb', line 334

def is_done?(subject)
  @serialized.include?(subject)
end

#is_list?(object) ⇒ Boolean

Returns:

  • (Boolean)


326
327
328
# File 'lib/roadforest/type-handlers/rdfa-writer/render-engine.rb', line 326

def is_list?(object)
  !(object == RDF.nil || (RDF::List.new(object, @graph)).invalid?)
end

#list_property_envs(predicate, list_objects) ⇒ Object



417
418
419
420
421
422
423
424
425
426
427
428
# File 'lib/roadforest/type-handlers/rdfa-writer/render-engine.rb', line 417

def list_property_envs(predicate, list_objects)
  return list_objects.map do |object|
    # Render each list as multiple properties and set :inlist to true
    list = RDF::List.new(object, @graph)
    list.each_statement {|st| subject_done(st.subject)}

    add_debug {"list: #{list.inspect} #{list.to_a}"}
    env = simple_property_env(predicate, list.to_a)
    env.inlist = "true"
    env
  end
end

#object_env(predicate, object) ⇒ Object



390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
# File 'lib/roadforest/type-handlers/rdfa-writer/render-engine.rb', line 390

def object_env(predicate, object)
  subj = subject_env(object)
  unless subj.nil?
    subj.rel = get_curie(predicate)
    return subj
  end

  env_klass =
    if get_curie(object) == 'rdf:nil'
      NilObjectEnvironment
    elsif object.node?
      NodeObjectEnvironment
    elsif object.uri?
      UriObjectEnvironment
    elsif object.datatype == RDF.XMLLiteral
      XMLLiteralObjectEnvironment
    else
      ObjectEnvironment
    end

  build_env(env_klass) do |env|
    env.predicate = predicate
    env.object = object
    env.inlist = nil
  end
end

#order_properties(properties) ⇒ Object



201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
# File 'lib/roadforest/type-handlers/rdfa-writer/render-engine.rb', line 201

def order_properties(properties)
  # Make sorted list of properties
  prop_list = []

  predicate_order.each do |prop|
    next unless properties[prop.to_s]
    prop_list << prop.to_s
  end

  properties.keys.sort.each do |prop|
    next if prop_list.include?(prop.to_s)
    prop_list << prop.to_s
  end

  add_debug {"order_properties: #{prop_list.join(', ')}"}
  prop_list
end

#order_subjectsObject



169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
# File 'lib/roadforest/type-handlers/rdfa-writer/render-engine.rb', line 169

def order_subjects
  seen = {}
  subjects = []

  # Start with base_uri
  if base_uri && @subjects.keys.include?(base_uri)
    subjects << base_uri
    seen[base_uri] = true
  end

  # Add distinguished classes
  top_classes.select do |s|
    !seen.include?(s)
  end.each do |class_uri|
    graph.query(:predicate => RDF.type, :object => class_uri).map {|st| st.subject}.sort.uniq.each do |subject|
      subjects << subject
      seen[subject] = true
    end
  end

  # Sort subjects by resources over nodes, ref_counts and the subject URI itself
  recursable = @subjects.keys.select do |s|
    !seen.include?(s)
  end.map do |r|
    [r.is_a?(RDF::Node) ? 1 : 0, ref_count(r), r]
  end.sort

  subjects += recursable.map{|r| r.last}
  add_debug {"order_subjects: (final) \n  #{subjects.join("\n  ")}"}
  return subjects
end

#preprocessObject



144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
# File 'lib/roadforest/type-handlers/rdfa-writer/render-engine.rb', line 144

def preprocess
  [RDF::RDFa::XML_RDFA_CONTEXT, RDF::RDFa::HTML_RDFA_CONTEXT].each do |uri|
    ctx = RDF::RDFa::Context.find(uri)
    ctx.prefixes.each_pair do |k, v|
      @uri_to_prefix[v] = k unless k.to_s == "dcterms"
    end

    ctx.terms.each_pair do |k, v|
      @uri_to_term_or_curie[v] = k
    end

    @vocabulary = ctx.vocabulary.to_s if ctx.vocabulary
  end

  # Load defined prefixes
  (@prefixes || {}).each_pair do |k, v|
    @uri_to_prefix[v.to_s] = k
  end
  @prefixes = {}  # Will define actual used when matched

  # Process each statement to establish CURIEs and Terms
  @graph.each {|statement| preprocess_statement(statement)}
  add_debug{ "preprocess prefixes: #{@prefixes.inspect}" }
end

#preprocess_statement(statement) ⇒ ignored

Perform any statement preprocessing required. This is used to perform reference counts and determine required prefixes.

Parameters:

  • statement (RDF::Statement)

Returns:

  • (ignored)


222
223
224
225
226
227
228
229
230
231
232
# File 'lib/roadforest/type-handlers/rdfa-writer/render-engine.rb', line 222

def preprocess_statement(statement)
  #add_debug {"preprocess: #{statement.inspect}"}
  return unless statement.context == graph_name
  bump_reference(statement.subject)
  bump_reference(statement.object)
  @subjects[statement.subject] = true
  get_curie(statement.subject)
  get_curie(statement.predicate)
  get_curie(statement.object)
  get_curie(statement.object.datatype) if statement.object.literal? && statement.object.has_datatype?
end

#properties_for_subject(subject) ⇒ Object



338
339
340
341
342
343
344
345
346
# File 'lib/roadforest/type-handlers/rdfa-writer/render-engine.rb', line 338

def properties_for_subject(subject)
  properties = {}
  @graph.query(:subject => subject, :context => false) do |st|
    key = st.predicate.to_s.freeze
    properties[key] ||= []
    properties[key] << st.object
  end
  properties
end

#ref_count(node) ⇒ Object



104
105
106
# File 'lib/roadforest/type-handlers/rdfa-writer/render-engine.rb', line 104

def ref_count(node)
  @references[node]
end

#render(context) ⇒ Object



299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
# File 'lib/roadforest/type-handlers/rdfa-writer/render-engine.rb', line 299

def render(context)
  add_debug "render"
  if context.render_checked
    return ""
  end
  template = find_environment_template(context)
  depth do
    add_debug{ "template: #{template.file}" }
    add_debug{ "options: #{template.options}" }
    add_debug{ "context: #{context.class.name}"}
    add_debug{ "  #{context.attrs}" } if context.respond_to?(:attrs)

    begin
      @render_stack.push context
      prefix = ""
      if debugging_comments
        prefix = "<!-- #{template.file} -->"
      end
      prefix + template.render(context) do |item|
        context.yielded(item)
      end.sub(/\n\Z/,'')
    ensure
      @render_stack.pop
    end
  end
end

#render_document {|env| ... } ⇒ Object

Yields:

  • (env)


430
431
432
433
434
435
436
437
# File 'lib/roadforest/type-handlers/rdfa-writer/render-engine.rb', line 430

def render_document
  add_debug{ "engine prefixes: #{prefixes.inspect}"}
  env = document_env

  yield env if block_given?

  render(env)
end

#resetObject

Reset parser to run again



80
81
82
83
84
85
86
87
88
89
90
91
# File 'lib/roadforest/type-handlers/rdfa-writer/render-engine.rb', line 80

def reset
  @debug_indent = 0
  @uri_to_term_or_curie = {}
  @uri_to_prefix = {}
  @references = Hash.new{|h,k| h[k] = 0}
  @prefixes = {}
  @serialized = {}
  @subjects = {}
  @ordered_subjects = []
  @titles = {}
  @doc_title = ""
end

#setupObject



124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
# File 'lib/roadforest/type-handlers/rdfa-writer/render-engine.rb', line 124

def setup
  add_debug {"\nserialize setup: graph size: #{@graph.size}"}

  @base_uri = ::RDF::URI.intern(@base_uri) unless @base_uri.nil? or @base_uri.is_a?(::RDF::URI)

  preprocess

  @ordered_subjects = order_subjects

  # Take title from first subject having a heading predicate
  @doc_title = nil
  heading_predicates.each do |pred|
    @graph.query(:predicate => pred) do |statement|
      titles[statement.subject] ||= statement.object
    end
  end
  title_subject = @ordered_subjects.detect {|subject| titles[subject]}
  @doc_title = titles[title_subject]
end

#simple_property_env(predicate, objects) ⇒ Object



380
381
382
383
384
385
386
387
388
# File 'lib/roadforest/type-handlers/rdfa-writer/render-engine.rb', line 380

def simple_property_env(predicate, objects)
  return nil if objects.to_a.empty?

  build_env(PropertyEnvironment) do |env|
    env.object_terms = objects
    env.predicate = predicate
    env.inlist = nil
  end
end

#subject_done(subject) ⇒ Object



330
331
332
# File 'lib/roadforest/type-handlers/rdfa-writer/render-engine.rb', line 330

def subject_done(subject)
  @serialized[subject] = true
end

#subject_env(subject) ⇒ Object



367
368
369
370
371
372
373
374
375
376
377
378
# File 'lib/roadforest/type-handlers/rdfa-writer/render-engine.rb', line 367

def subject_env(subject)
  return unless @subjects.include?(subject)
  properties = properties_for_subject(subject)

  build_env(SubjectEnvironment) do |env|
    env.base = base_uri
    env.predicate_terms = order_properties(properties)
    env.property_objects = properties
    env.subject = subject
    env.typeof = type_of(properties.delete(RDF.type.to_s), subject)
  end
end

#type_of(type, subject) ⇒ Object



273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
# File 'lib/roadforest/type-handlers/rdfa-writer/render-engine.rb', line 273

def type_of(type, subject)
  # Find appropriate template
  curie = case
          when subject.node?
            subject.to_s if ref_count(subject) > 1
          else
            get_curie(subject)
          end

  typeof = Array(type).map {|r| get_curie(r)}.join(" ")
  typeof = nil if typeof.empty?

  # Nodes without a curie need a blank @typeof to generate a subject
  typeof ||= "" unless curie

  add_debug {"subject: #{curie.inspect}, typeof: #{typeof.inspect}" }

  typeof.freeze
end