Class: RDF::RDFa::Writer

Inherits:
Writer show all
Includes:
Util::Logger
Defined in:
vendor/bundler/ruby/3.3.0/bundler/gems/rdf-rdfa-d2c5c7c66c23/lib/rdf/rdfa/writer.rb,
vendor/bundler/ruby/3.3.0/bundler/gems/rdf-rdfa-d2c5c7c66c23/lib/rdf/rdfa/writer/haml_templates.rb

Overview

An RDFa 1.1 serialiser in Ruby. The RDFa serializer makes use of Haml templates, allowing runtime-replacement with alternate templates. Note, however, that templates should be checked against the W3C test suite to ensure that valid RDFa is emitted.

Note that the natural interface is to write a whole graph at a time. Writing statements or Triples will create a graph to add them to and then serialize the graph.

The writer will add prefix definitions, and use them for creating @prefix definitions, and minting CURIEs

Examples:

Obtaining a RDFa writer class

RDF::Writer.for(:html)          => RDF::RDFa::Writer
RDF::Writer.for("etc/test.html")
RDF::Writer.for(file_name:      "etc/test.html")
RDF::Writer.for(file_extension: "html")
RDF::Writer.for(content_type:   "application/xhtml+xml")
RDF::Writer.for(content_type:   "text/html")

Serializing RDF graph into an XHTML+RDFa file

RDF::RDFa::Write.open("etc/test.html") do |writer|
  writer << graph
end

Serializing RDF statements into an XHTML+RDFa file

RDF::RDFa::Writer.open("etc/test.html") do |writer|
  graph.each_statement do |statement|
    writer << statement
  end
end

Serializing RDF statements into an XHTML+RDFa string

RDF::RDFa::Writer.buffer do |writer|
  graph.each_statement do |statement|
    writer << statement
  end
end

Creating @base and @prefix definitions in output

RDF::RDFa::Writer.buffer(base_uri: "http://example.com/", prefixes: {
    foaf: "http://xmlns.com/foaf/0.1/"}
) do |writer|
  graph.each_statement do |statement|
    writer << statement
  end
end

Author:

Constant Summary collapse

HAML_OPTIONS =
{
  format: :xhtml
}
BASE_HAML =

The default set of HAML templates used for RDFa code generation

{
 identifier: "base",
  # Document
  # Locals: language, title, prefix, base, subjects
  # Yield: subjects.each
  doc: %q(
    !!! XML
    !!! 5
    %html{**{xmlns: "http://www.w3.org/1999/xhtml", lang: lang, prefix: prefix}.compact}
      - if base || title
        %head
          - if base
            %base{**{href: base}.compact}
          - if title
            %title= title
      %body
        - subjects.map do |subject|
          != yield(subject)
  ),

  # Output for non-leaf resources
  # Note that @about may be omitted for Nodes that are not referenced
  #
  # If _rel_ and _resource_ are not nil, the tag will be written relative
  # to a previous subject. If _element_ is :li, the tag will be written
  # with <li> instead of <div>.
  #
  # Locals: subject, typeof, predicates, rel, element, inlist
  # Yield: predicates.each
  subject: %q(
    - if element == :li
      %li{**{rel: rel, resource: (about || resource), typeof: typeof, inlist: inlist}.compact}
        - if typeof
          %span.type!= typeof
        - predicates.each do |predicate|
          != yield(predicate)
    - else
      %div{**{rel: rel, resource: (about || resource), typeof: typeof, inlist: inlist}.compact}
        - if typeof
          %span.type!= typeof
        - predicates.each do |predicate|
          != yield(predicate)
  ),

  # Output for single-valued properties
  # Locals: predicate, object, inlist
  # Yields: object
  # If nil is returned, render as a leaf
  # Otherwise, render result
  property_value: %q(
    - if heading_predicates.include?(predicate) && object.literal?
      %h1{**{property: get_curie(predicate), content: get_content(object), lang: get_lang(object), datatype: get_dt_curie(object), inlist: inlist}.compact}= escape_entities(get_value(object))
    - else
      %div.property
        %span.label
          = get_predicate_name(predicate)
        - if res = yield(object)
          != res
        - elsif get_curie(object) == 'rdf:nil'
          %span{rel: get_curie(predicate), inlist: ''}
        - elsif object.node?
          %span{**{property: get_curie(predicate), resource: get_curie(object), inlist: inlist}.compact}= get_curie(object)
        - elsif object.uri?
          %a{**{property: get_curie(predicate), href: object.to_s, inlist: inlist}.compact}= object.to_s
        - elsif object.datatype == RDF.XMLLiteral
          %span{**{property: get_curie(predicate), lang: get_lang(object), datatype: get_dt_curie(object), inlist: inlist}.compact}<!= get_value(object)
        - else
          %span{**{property: get_curie(predicate), content: get_content(object), lang: get_lang(object), datatype: get_dt_curie(object), inlist: inlist}.compact}= escape_entities(get_value(object))
  ),

  # Output for multi-valued properties
  # Locals: predicate, :objects, :inlist
  # Yields: object for leaf resource rendering
  property_values:  %q(
    %div.property
      %span.label
        = get_predicate_name(predicate)
      %ul
        - objects.each do |object|
          - if res = yield(object)
            != res
          - elsif object.node?
            %li{**{property: get_curie(predicate), resource: get_curie(object), inlist: inlist}.compact}= get_curie(object)
          - elsif object.uri?
            %li
              %a{**{property: get_curie(predicate), href: object.to_s, inlist: inlist}.compact}= object.to_s
          - elsif object.datatype == RDF.XMLLiteral
            %li{**{property: get_curie(predicate), lang: get_lang(object), datatype: get_curie(object.datatype), inlist: inlist}.compact}<!= get_value(object)
          - else
            %li{**{property: get_curie(predicate), content: get_content(object), lang: get_lang(object), datatype: get_dt_curie(object), inlist: inlist}.compact}= escape_entities(get_value(object))
  ),
}
MIN_HAML =

An alternative, minimal HAML template for RDFa code generation. This version does not perform recursive object generation and does not attempt to create human readable output.

{
  identifier: "min",
  # Document
  # Locals: language, title, prefix, base, subjects
  # Yield: subjects.each
  doc: %q(
    !!! XML
    !!! 5
    %html{**{xmlns: "http://www.w3.org/1999/xhtml", lang: lang, prefix: prefix}.compact}
      - if base
        %head
          %base{*{href: base}.compact}
      %body
        - subjects.each do |subject|
          != yield(subject)
  ),

  # Output for non-leaf resources
  # Note that @about may be omitted for Nodes that are not referenced
  #
  # Locals: about, typeof, predicates, :inlist
  # Yield: predicates.each
  subject: %q(
    %div{**{rel: rel, resource: (about || resource), typeof: typeof}.compact}
      - predicates.each do |predicate|
        != yield(predicate)
  ),

  # Output for single-valued properties.
  # This version does not perform a recursive call, and renders all objects as leafs.
  # Locals: predicate, object, inlist
  # Yields: object
  # If nil is returned, render as a leaf
  # Otherwise, render result
  property_value: %q(
  - if res = yield(object)
    != res
  - elsif get_curie(object) == 'rdf:nil'
    %span{rel: get_curie(predicate), inlist: ''}
  - elsif object.node?
    %span{**{property: get_curie(predicate), resource: get_curie(object), inlist: inlist}.compact}= get_curie(object)
  - elsif object.uri?
    %a{**{property: get_curie(predicate), href: object.to_s, inlist: inlist}.compact}= object.to_s
  - elsif object.datatype == RDF.XMLLiteral
    %span{**{property: get_curie(predicate), lang: get_lang(object), datatype: get_dt_curie(object), inlist: inlist}.compact}<!= get_value(object)
  - else
    %span{**{property: get_curie(predicate), content: get_content(object), lang: get_lang(object), datatype: get_dt_curie(object), inlist: inlist}.compact}= escape_entities(get_value(object))
  )
}
DISTILLER_HAML =
{
  identifier: "distiller",
  # Document
  # Locals: language, title, prefix, base, subjects
  # Yield: subjects.each
  doc: %q(
    !!! XML
    !!! 5
    %html{**{xmlns: "http://www.w3.org/1999/xhtml", lang: lang, prefix: prefix}.compact}
      - if base || title
        %head
          - if base
            %base{href: base}
          - if title
            %title= title
          %link{rel: "stylesheet", href: "http://rdf.greggkellogg.net/css/distiller.css", type: "text/css"}
          %script{src: "https://ajax.googleapis.com/ajax/libs/jquery/1.5.1/jquery.min.js", type: "text/javascript"}
          %script{src: "http://rdf.greggkellogg.net/js/distiller.js", type: "text/javascript"}
      %body
        - if base
          %p= "RDFa serialization URI base: &lt;#{base}&gt;"
        - subjects.each do |subject|
          != yield(subject)
        %footer
          %p= "Written by <a href='https://rubygems.org/gems/rdf-rdfa'>RDF::RDFa</a> version #{RDF::RDFa::VERSION}"
  ),

  # Output for non-leaf resources
  # Note that @about may be omitted for Nodes that are not referenced
  #
  # If _rel_ and _resource_ are not nil, the tag will be written relative
  # to a previous subject. If _element_ is :li, the tag will be written
  # with <li> instead of <div>.
  #
  # Note that @rel and @resource can be used together, or @about and @typeof, but
  # not both.
  #
  # Locals: subject, typeof, predicates, rel, element, inlist
  # Yield: predicates.each
  subject: %q(
    - if element == :li
      %li{**{rel: rel, resource: (about || resource), typeof: typeof, inlist: inlist}.compact}
        - if typeof
          %span.type!= typeof
        %table.properties
          - predicates.each do |predicate|
            != yield(predicate)
    - elsif rel
      %td{**{rel: rel, resource: (about || resource), typeof: typeof, inlist: inlist}.compact}
        - if typeof
          %span.type!= typeof
        %table.properties
          - predicates.each do |predicate|
            != yield(predicate)
    - else
      %div{**{resource: (about || resource), typeof: typeof, inlist: inlist}.compact}
        - if typeof
          %span.type!= typeof
        %table.properties
          - predicates.each do |predicate|
            != yield(predicate)
  ),

  # Output for single-valued properties
  # Locals: predicate, object, inlist
  # Yields: object
  # If nil is returned, render as a leaf
  # Otherwise, render result
  property_value: %q(
    - if heading_predicates.include?(predicate) && object.literal?
      %h1{**{property: get_curie(predicate), content: get_content(object), lang: get_lang(object), datatype: get_dt_curie(object), inlist: inlist}.compact}= escape_entities(get_value(object))
    - else
      %tr.property
        %td.label
          = get_predicate_name(predicate)
        - if res = yield(object)
          != res
        - elsif get_curie(object) == 'rdf:nil'
          %td{rel: get_curie(predicate), inlist: ''}= "Empty"
        - elsif object.node?
          %td{**{property: get_curie(predicate), resource: get_curie(object), inlist: inlist}.compact}= get_curie(object)
        - elsif object.uri?
          %td
            %a{**{property: get_curie(predicate), href: object.to_s, inlist: inlist}.compact}= object.to_s
        - elsif object.datatype == RDF.XMLLiteral
          %td{**{property: get_curie(predicate), lang: get_lang(object), datatype: get_dt_curie(object), inlist: inlist}.compact}<!= get_value(object)
        - else
          %td{**{property: get_curie(predicate), content: get_content(object), lang: get_lang(object), datatype: get_dt_curie(object), inlist: inlist}.compact}= escape_entities(get_value(object))
  ),

  # Output for multi-valued properties
  # Locals: predicate, objects, inliste
  # Yields: object for leaf resource rendering
  property_values:  %q(
    %tr.property
      %td.label
        = get_predicate_name(predicate)
      %td
        %ul
          - objects.each do |object|
            - if res = yield(object)
              != res
            - elsif object.node?
              %li{**{property: get_curie(predicate), resource: get_curie(object), inlist: inlist}.compact}= get_curie(object)
            - elsif object.uri?
              %li
                %a{**{property: get_curie(predicate), href: object.to_s, inlist: inlist}.compact}= object.to_s
            - elsif object.datatype == RDF.XMLLiteral
              %li{**{property: get_curie(predicate), lang: get_lang(object), datatype: get_curie(object.datatype), inlist: inlist}.compact}<!= get_value(object)
            - else
              %li{**{property: get_curie(predicate), content: get_content(object), lang: get_lang(object), datatype: get_dt_curie(object), inlist: inlist}.compact}= escape_entities(get_value(object))
  ),
}
HAML_TEMPLATES =
{base: BASE_HAML, min: MIN_HAML, distiller: DISTILLER_HAML}
DEFAULT_HAML =
BASE_HAML

Constants included from Util::Logger

Util::Logger::IOWrapper

Instance Attribute Summary collapse

Attributes inherited from Writer

#options

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Util::Logger

#log_debug, #log_depth, #log_error, #log_fatal, #log_info, #log_recover, #log_recovering?, #log_statistics, #log_warn, #logger

Methods inherited from Writer

accept?, buffer, #canonicalize?, dump, each, #encoding, #escaped, #flush, for, format, #format_list, #format_literal, #format_node, #format_quotedTriple, #format_term, #format_tripleTerm, #format_uri, #node_id, open, #prefix, #prefixes, #prefixes=, #puts, #quoted, #to_sym, to_sym, #uri_for, #validate?, #write_comment, #write_prologue, #write_statement, #write_triples

Methods included from Util::Aliasing::LateBound

#alias_method

Methods included from Writable

#<<, #insert, #insert_graph, #insert_reader, #insert_statement, #insert_statements, #writable?

Methods included from Util::Coercions

#coerce_statements

Constructor Details

#initialize(output = $stdout, **options) {|writer| ... } ⇒ Writer

Initializes the RDFa writer instance.

Parameters:

  • output (IO, File) (defaults to: $stdout)

    the output stream

  • options (Hash{Symbol => Object})

    any additional options

Options Hash (**options):

  • :canonicalize (Boolean) — default: false

    whether to canonicalize literals when serializing

  • :prefixes (Hash) — default: Hash.new

    the prefix mappings to use

  • :base_uri (#to_s) — default: nil

    the base URI to use when constructing relative URIs, set as html>head>base.href

  • :validate (Boolean) — default: false

    whether to validate terms when serializing

  • :lang (#to_s) — default: nil

    Output as root @lang attribute, and avoid generation @lang where possible

  • :standard_prefixes (Boolean) — default: false

    Add standard prefixes to prefixes, if necessary.

  • :top_classes (Array<RDF::URI>) — default: [RDF::RDFS.Class]

    Defines rdf:type of subjects to be emitted at the beginning of the document.

  • :predicate_order (Array<RDF::URI>) — default: [RDF.type, RDF::RDFS.label, RDF::Vocab::DC.title]

    Defines order of predicates to to emit at begninning of a resource description..

  • :heading_predicates (Array<RDF::URI>) — default: [RDF::RDFS.label, RDF::Vocab::DC.title]

    Defines order of predicates to use in heading.

  • :haml (String, Symbol, Hash{Symbol => String}) — default: DEFAULT_HAML

    HAML templates used for generating code

  • :haml_options (Hash) — default: HAML_OPTIONS

    Options to pass to Haml::Engine.new.

Yields:

  • (writer)

Yield Parameters:



122
123
124
125
126
127
128
129
130
131
132
133
# File 'vendor/bundler/ruby/3.3.0/bundler/gems/rdf-rdfa-d2c5c7c66c23/lib/rdf/rdfa/writer.rb', line 122

def initialize(output = $stdout, **options, &block)
  super do
    @uri_to_term_or_curie = {}
    @uri_to_prefix = {}
    @top_classes = options[:top_classes] || [RDF::RDFS.Class]
    @predicate_order = options[:predicate_order] || [RDF.type, RDF::RDFS.label, RDF::URI("http://purl.org/dc/terms/title")]
    @heading_predicates = options[:heading_predicates] || [RDF::RDFS.label, RDF::URI("http://purl.org/dc/terms/title")]
    @graph = RDF::Graph.new

    block.call(self) if block_given?
  end
end

Instance Attribute Details

#base_uriRDF::URI

Returns Base URI used for relativizing URIs.

Returns:

  • (RDF::URI)

    Base URI used for relativizing URIs



74
75
76
# File 'vendor/bundler/ruby/3.3.0/bundler/gems/rdf-rdfa-d2c5c7c66c23/lib/rdf/rdfa/writer.rb', line 74

def base_uri
  @base_uri
end

#graphGraph

Returns Graph of statements serialized.

Returns:

  • (Graph)

    Graph of statements serialized



71
72
73
# File 'vendor/bundler/ruby/3.3.0/bundler/gems/rdf-rdfa-d2c5c7c66c23/lib/rdf/rdfa/writer.rb', line 71

def graph
  @graph
end

#heading_predicatesArray<URI> (readonly)

Defines order of predicates to use in heading.

Returns:



64
65
66
# File 'vendor/bundler/ruby/3.3.0/bundler/gems/rdf-rdfa-d2c5c7c66c23/lib/rdf/rdfa/writer.rb', line 64

def heading_predicates
  @heading_predicates
end

#predicate_orderArray<URI> (readonly)

Defines order of predicates to to emit at begninning of a resource description. Defaults to [rdf:type, rdfs:label, dc:title]

Returns:



60
61
62
# File 'vendor/bundler/ruby/3.3.0/bundler/gems/rdf-rdfa-d2c5c7c66c23/lib/rdf/rdfa/writer.rb', line 60

def predicate_order
  @predicate_order
end

#top_classesArray<URI> (readonly)

Defines rdf:type of subjects to be emitted at the beginning of the document.

Returns:



56
57
58
# File 'vendor/bundler/ruby/3.3.0/bundler/gems/rdf-rdfa-d2c5c7c66c23/lib/rdf/rdfa/writer.rb', line 56

def top_classes
  @top_classes
end

Class Method Details

.optionsObject

RDFa Writer options



79
80
81
82
83
84
85
86
87
88
89
90
# File 'vendor/bundler/ruby/3.3.0/bundler/gems/rdf-rdfa-d2c5c7c66c23/lib/rdf/rdfa/writer.rb', line 79

def self.options
  super + [
    RDF::CLI::Option.new(
      symbol: :lang,
      datatype: String,
      on: ["--lang"],
      datatype: TrueClass,
      default: false,
      control: :checkbox,
      description: "Output as root @lang attribute, and avoid generation _@lang_ where possible."),
  ]
end

Instance Method Details

#get_content(literal) ⇒ String? (protected)

Haml rendering helper. Data to be added to a @content value, for specific datatypes

Parameters:

Returns:

Raises:



626
627
628
629
630
631
632
633
634
635
# File 'vendor/bundler/ruby/3.3.0/bundler/gems/rdf-rdfa-d2c5c7c66c23/lib/rdf/rdfa/writer.rb', line 626

def get_content(literal)
  case literal
  when RDF::Literal::Date, RDF::Literal::Time, RDF::Literal::DateTime, RDF::Literal::Duration
    literal.to_s
  when RDF::Literal then nil
  else
    log_error("Getting content for #{literal.inspect}, which must be a literal")
    nil
  end
end

#get_curie(resource) ⇒ String (protected)

Haml rendering helper. Return appropriate, term, CURIE or URI for the given resource.

Parameters:

Returns:

  • (String)

    value to use to identify URI

Raises:



670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
# File 'vendor/bundler/ruby/3.3.0/bundler/gems/rdf-rdfa-d2c5c7c66c23/lib/rdf/rdfa/writer.rb', line 670

def get_curie(resource)
  case resource
  when RDF::URI
    begin
      uri = resource.to_s

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

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

      @uri_to_term_or_curie[uri] = curie
    rescue ArgumentError => e
      log_error("Invalid URI #{uri.inspect}: #{e.message}")
      nil
    end
  when RDF::Node then resource.to_s
  when RDF::Literal then nil
  else
    log_error("Getting CURIE for #{resource.inspect}, which must be a resource")
    nil
  end
end

#get_dt_curie(literal) ⇒ String? (protected)

Haml rendering helper. Return CURIE for the literal datatype, if the literal is a typed literal.

Parameters:

Returns:

Raises:



598
599
600
601
602
603
604
605
# File 'vendor/bundler/ruby/3.3.0/bundler/gems/rdf-rdfa-d2c5c7c66c23/lib/rdf/rdfa/writer.rb', line 598

def get_dt_curie(literal)
  if literal.is_a?(RDF::Literal)
    get_curie(literal.datatype) if literal.literal? && literal.datatype?
  else
    log_error("Getting datatype CURIE for #{literal.inspect}, which must be a literal")
    nil
  end
end

#get_lang(literal) ⇒ Symbol? (protected)

Haml rendering helper. Return language for plain literal, if there is no language, or it is the same as the document, return nil

Parameters:

Returns:

Raises:



612
613
614
615
616
617
618
619
# File 'vendor/bundler/ruby/3.3.0/bundler/gems/rdf-rdfa-d2c5c7c66c23/lib/rdf/rdfa/writer.rb', line 612

def get_lang(literal)
  if literal.is_a?(RDF::Literal)
    literal.language if literal.literal? && literal.language && literal.language.to_s != @lang.to_s
  else
    log_error("Getting language for #{literal.inspect}, which must be a literal")
    nil
  end
end

#get_predicate_name(resource) ⇒ String (protected)

Haml rendering helper. Return an appropriate label for a resource.

Parameters:

Returns:

Raises:



656
657
658
659
660
661
662
663
# File 'vendor/bundler/ruby/3.3.0/bundler/gems/rdf-rdfa-d2c5c7c66c23/lib/rdf/rdfa/writer.rb', line 656

def get_predicate_name(resource)
  if resource.is_a?(RDF::URI)
    get_curie(resource)
  else
    log_error("Getting predicate name for #{resource.inspect}, which must be a URI")
    nil
  end
end

#get_value(literal) ⇒ String (protected)

Haml rendering helper. Display value for object, may be humanized into a non-canonical form

Parameters:

Returns:

Raises:



642
643
644
645
646
647
648
649
# File 'vendor/bundler/ruby/3.3.0/bundler/gems/rdf-rdfa-d2c5c7c66c23/lib/rdf/rdfa/writer.rb', line 642

def get_value(literal)
  if literal.is_a?(RDF::Literal)
    literal.humanize
  else
    log_error("Getting value for #{literal.inspect}, which must be a literal")
    nil
  end
end

#haml_templateHash<Symbol => String>

Returns:



136
137
138
139
140
141
142
143
# File 'vendor/bundler/ruby/3.3.0/bundler/gems/rdf-rdfa-d2c5c7c66c23/lib/rdf/rdfa/writer.rb', line 136

def haml_template
  return @haml_template if @haml_template
  case @options[:haml]
  when Symbol, String   then HAML_TEMPLATES.fetch(@options[:haml].to_sym, DEFAULT_HAML)
  when Hash             then @options[:haml]
  else                       DEFAULT_HAML
  end
end

#order_properties(properties) ⇒ Array<String> (protected)

Take a hash from predicate uris to lists of values. Sort the lists of values. Return a sorted list of properties.

Parameters:

Returns:

  • (Array<String>)

    ] Ordered list of properties. Uses predicate_order.



435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
# File 'vendor/bundler/ruby/3.3.0/bundler/gems/rdf-rdfa-d2c5c7c66c23/lib/rdf/rdfa/writer.rb', line 435

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

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

#order_subjectsArray<Resource> (protected)

Order subjects for output. Override this to output subjects in another order.

Uses #top_classes and #base_uri.

Returns:



398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
# File 'vendor/bundler/ruby/3.3.0/bundler/gems/rdf-rdfa-d2c5c7c66c23/lib/rdf/rdfa/writer.rb', line 398

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 {|s| !seen.include?(s)}.
  each do |class_uri|
    graph.query({predicate: RDF.type, object: class_uri}).map {|st| st.subject}.sort.uniq.each do |subject|
      #log_debug {"order_subjects: #{subject.inspect}"}
      subjects << subject
      seen[subject] = true
    end
  end

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

  log_debug {"order_subjects: #{recursable.inspect}"}

  subjects += recursable.map{|r| r.last}
end

#predicate(predicate, objects) ⇒ String (protected)

Write a predicate with one or more values.

Values may be a combination of Literal and Resource (Node or URI).

Parameters:

Returns:



580
581
582
583
584
585
586
587
588
589
590
591
# File 'vendor/bundler/ruby/3.3.0/bundler/gems/rdf-rdfa-d2c5c7c66c23/lib/rdf/rdfa/writer.rb', line 580

def predicate(predicate, objects)
  log_debug {"predicate: #{predicate.inspect}, objects: #{objects}"}

  return if objects.to_a.empty?

  log_debug {"predicate: #{get_curie(predicate)}"}
  render_property(predicate, objects) do |o, inlist=nil|
    # Yields each object, for potential recursive definition.
    # If nil is returned, a leaf is produced
    log_depth {subject(o, rel: get_curie(predicate), inlist: inlist, element: (:li if objects.length > 1 || inlist))} if !is_done?(o) && @subjects.include?(o)
  end
end

#preprocessignored (protected)

Perform any preprocessing of statements required

Returns:

  • (ignored)


367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
# File 'vendor/bundler/ruby/3.3.0/bundler/gems/rdf-rdfa-d2c5c7c66c23/lib/rdf/rdfa/writer.rb', line 367

def preprocess
  # Load initial contexts
  # Add terms and prefixes to local store for converting URIs
  # Keep track of vocabulary from left-most context
  [XML_RDFA_CONTEXT, HTML_RDFA_CONTEXT].each do |uri|
    ctx = 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.to_s
    end

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

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

  # Process each statement to establish CURIEs and Terms
  @graph.each {|statement| preprocess_statement(statement)}
end

#preprocess_statement(statement) ⇒ ignored (protected)

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

Parameters:

Returns:

  • (ignored)


456
457
458
459
460
461
462
463
464
# File 'vendor/bundler/ruby/3.3.0/bundler/gems/rdf-rdfa-d2c5c7c66c23/lib/rdf/rdfa/writer.rb', line 456

def preprocess_statement(statement)
  #log_debug {"preprocess: #{statement.inspect}"}
  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) ⇒ Hash{String => Object} (protected)

Parameters:

Returns:



514
515
516
517
518
519
520
521
522
# File 'vendor/bundler/ruby/3.3.0/bundler/gems/rdf-rdfa-d2c5c7c66c23/lib/rdf/rdfa/writer.rb', line 514

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

#render_document(subjects, **options) {|subject| ... } ⇒ Object (protected)

Render document using haml_template[:doc]. Yields each subject to be rendered separately.

Parameters:

  • subjects (Array<RDF::Resource>)

    Ordered list of subjects. Template must yield to each subject, which returns the serialization of that subject (@see #subject_template)

  • options (Hash{Symbol => Object})

    Rendering options passed to Haml render.

Options Hash (**options):

  • base (RDF::URI) — default: nil

    Base URI added to document, used for shortening URIs within the document.

  • language (Symbol, String) — default: nil

    Value of @lang attribute in document, also allows included literals to omit an @lang attribute if it is equivalent to that of the document.

  • title (String) — default: nil

    Value of html>head>title element.

  • prefix (String) — default: nil

    Value of @prefix attribute.

  • haml (String) — default: haml_template[:doc]

    Haml template to render.

Yields:

  • (subject)

    Yields each subject

Yield Parameters:

Yield Returns:

  • (:ignored)

Returns:

  • String The rendered document is returned as a string



226
227
228
229
230
231
232
233
234
235
236
# File 'vendor/bundler/ruby/3.3.0/bundler/gems/rdf-rdfa-d2c5c7c66c23/lib/rdf/rdfa/writer.rb', line 226

def render_document(subjects, **options)
  template = options[:haml] || :doc
  options = {
    prefix: nil,
    subjects: subjects,
    title: nil,
  }.merge(options)
  hamlify(template, **options) do |subject|
    yield(subject) if block_given?
  end.gsub(/^\s+$/m, '')
end

#render_property(predicate, objects, **options) {|object, inlist| ... } ⇒ Object (protected)

Render a single- or multi-valued predicate using haml_template[:property_value] or haml_template[:property_values]. Yields each object for optional rendering. The block should only render for recursive subject definitions (i.e., where the object is also a subject and is rendered underneath the first referencing subject).

If a multi-valued property definition is not found within the template, the writer will use the single-valued property definition multiple times.

Parameters:

  • predicate (Array<RDF::Resource>)

    Predicate to render.

  • objects (Array<RDF::Resource>)

    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.

  • options (Hash{Symbol => Object})

    Rendering options passed to Haml render.

Options Hash (**options):

  • :haml (String) — default: haml_template[:property_value], haml_template[:property_values]

    Haml template to render. Otherwise, uses haml_template[:property_value] or haml_template[:property_values] depending on the cardinality of objects.

Yields:

  • object, inlist Yields object and if it is contained in a list.

Yield Parameters:

Yield Returns:

  • (String, nil)

    The block should only return a string for recursive object definitions.

Returns:

  • String The rendered document is returned as a string



309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
# File 'vendor/bundler/ruby/3.3.0/bundler/gems/rdf-rdfa-d2c5c7c66c23/lib/rdf/rdfa/writer.rb', line 309

def render_property(predicate, objects, **options, &block)
  log_debug {"render_property(#{predicate}): #{objects.inspect}, #{options.inspect}"}
  # If there are multiple objects, and no :property_values is defined, call recursively with
  # each object

  template = options[:haml]
  template ||= objects.length > 1 ? haml_template[:property_values] : haml_template[:property_value]

  # Separate out the objects which are lists and render separately
  list_objects = objects.reject do |o|
    o == RDF.nil ||
    (l = RDF::List.new(subject: o, graph: @graph)).invalid?
  end
  unless list_objects.empty?
    # Render non-list objects
    log_debug {"properties with lists: #{list_objects} non-lists: #{objects - list_objects}"}
    nl = log_depth {render_property(predicate, objects - list_objects, **options, &block)} unless objects == list_objects
    return nl.to_s + list_objects.map do |object|
      # Render each list as multiple properties and set :inlist to true
      list = RDF::List.new(subject: object, graph: @graph)
      list.each_statement {|st| subject_done(st.subject)}

      log_debug {"list: #{list.inspect} #{list.to_a}"}
      log_depth do
        render_property(predicate, list.to_a, **options.merge(inlist: "true")) do |object|
          yield(object, true) if block_given?
        end
      end
    end.join(" ")
  end

  if objects.length > 1 && template.nil?
    # If there is no property_values template, render each property using property_value template
    objects.map do |object|
      log_depth {render_property(predicate, [object], **options, &block)}
    end.join(" ")
  else
    log_fatal("Missing property template", exception: RDF::WriterError) if template.nil?

    template = options[:haml] || (
      objects.to_a.length > 1 &&
      haml_template.has_key?(:property_values) ?
        :property_values :
        :property_value)
    options = {
      objects:    objects,
      object:     objects.first,
      predicate:  predicate,
      property:   get_curie(predicate),
      rel:        get_curie(predicate),
      inlist:     nil,
    }.merge(options)
    hamlify(template, options, &block)
  end
end

#render_subject(subject, predicates, **options) {|predicate| ... } ⇒ Object (protected)

Render a subject using haml_template[:subject].

The subject template may be called either as a top-level element, or recursively under another element if the rel local is not nil.

Yields each predicate/property to be rendered separately (@see #render_property_value and #render_property_values).

Return Haml template for document from haml_template[:subject]

Parameters:

Options Hash (**options):

  • about (String) — default: nil

    About description, a CURIE, URI or Node definition. May be nil if no @about is rendered (e.g. unreferenced Nodes)

  • resource (String) — default: nil

    Resource description, a CURIE, URI or Node definition. May be nil if no @resource is rendered

  • rel (String) — default: nil

    Optional @rel property description, a CURIE, URI or Node definition.

  • typeof (String) — default: nil

    RDF type as a CURIE, URI or Node definition. If :about is nil, this defaults to the empty string ("").

  • element (:li, nil) — default: nil

    Render with <li>, otherwise with template default.

  • haml (String) — default: haml_template[:subject]

    Haml template to render.

Yields:

Yield Parameters:

Yield Returns:

  • (:ignored)

Returns:

  • String The rendered document is returned as a string



271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
# File 'vendor/bundler/ruby/3.3.0/bundler/gems/rdf-rdfa-d2c5c7c66c23/lib/rdf/rdfa/writer.rb', line 271

def render_subject(subject, predicates, **options)
  template = options[:haml] || :subject
  options = {
    about:      (get_curie(subject) unless options[:rel]),
    base:       base_uri,
    element:    nil,
    predicates: predicates,
    rel:        nil,
    inlist:     nil,
    resource:   (get_curie(subject) if options[:rel]),
    subject:    subject,
    typeof:     nil,
  }.merge(options)
  hamlify(template, **options) do |predicate|
    yield(predicate) if block_given?
  end
end

#render_subject_template(subject, prop_list, **render_opts) ⇒ String (protected)

Parameters:

Returns:



551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
# File 'vendor/bundler/ruby/3.3.0/bundler/gems/rdf-rdfa-d2c5c7c66c23/lib/rdf/rdfa/writer.rb', line 551

def render_subject_template(subject, prop_list, **render_opts)
  # See if there's a template based on the sorted concatenation of all types of this subject
  # or any type of this subject
  tmpl = find_template(subject)
  log_debug {"subject: found template #{tmpl[:identifier] || tmpl.inspect}"} if tmpl

  # Render this subject
  # If :rel is specified and :typeof is nil, use @resource instead of @about.
  # Pass other options from calling context
  with_template(tmpl) do
    render_subject(subject, prop_list, **render_opts) do |pred|
      log_depth do
        pred = RDF::URI(pred) if pred.is_a?(String)
        values = render_opts[:property_values][pred.to_s]
        log_debug {"subject: #{get_curie(subject)}, pred: #{get_curie(pred)}, values: #{values.inspect}"}
        predicate(pred, values)
      end
    end
  end
end

#resetObject (protected)

Reset parser to run again



467
468
469
470
471
472
473
# File 'vendor/bundler/ruby/3.3.0/bundler/gems/rdf-rdfa-d2c5c7c66c23/lib/rdf/rdfa/writer.rb', line 467

def reset
  @options[:log_depth] = 0
  prefixes = {}
  @references = {}
  @serialized = {}
  @subjects = {}
end

#subject(subject, **options) ⇒ String (protected)

Display a subject.

If the Haml template contains an entry matching the subject's rdf:type URI, that entry will be used as the template for this subject and it's properties.

Examples:

Displays a subject as a Resource Definition:

<div typeof="rdfs:Resource" about="http://example.com/resource">
  <h1 property="dc:title">label</h1>
  <ul>
    <li content="2009-04-30T06:15:51Z" property="dc:created">2009-04-30T06:15:51+00:00</li>
  </ul>
</div>

Parameters:

Options Hash (**options):

  • :element(:div) (:li, nil)

    Serialize using <li> rather than template default element

  • :rel (RDF::Resource) — default: nil

    Optional @rel property

Returns:



496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
# File 'vendor/bundler/ruby/3.3.0/bundler/gems/rdf-rdfa-d2c5c7c66c23/lib/rdf/rdfa/writer.rb', line 496

def subject(subject, **options)
  return if is_done?(subject)

  subject_done(subject)

  properties = properties_for_subject(subject)
  typeof = type_of(properties.delete(RDF.type.to_s), subject)
  prop_list = order_properties(properties)

  log_debug {"props: #{prop_list.inspect}"}

  render_opts = {typeof: typeof, property_values: properties}.merge(options)

  render_subject_template(subject, prop_list, **render_opts)
end

#type_of(type, subject) ⇒ String (protected)

Returns string representation of the specific RDF.type uri.

Parameters:

Returns:

  • (String)

    string representation of the specific RDF.type uri



527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
# File 'vendor/bundler/ruby/3.3.0/bundler/gems/rdf-rdfa-d2c5c7c66c23/lib/rdf/rdfa/writer.rb', line 527

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

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

  typeof.freeze
end

#write_epilogue

This method returns an undefined value.

Outputs the XHTML+RDFa representation of all stored triples.



162
163
164
165
166
167
168
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 'vendor/bundler/ruby/3.3.0/bundler/gems/rdf-rdfa-d2c5c7c66c23/lib/rdf/rdfa/writer.rb', line 162

def write_epilogue
  @base_uri = RDF::URI(@options[:base_uri]) if @options[:base_uri]
  @lang = @options[:lang]
  self.reset

  log_debug {"\nserialize: graph size: #{@graph.size}"}

  preprocess

  # Prefixes
  prefix = prefixes.keys.map {|pk| "#{pk}: #{prefixes[pk]}"}.sort.join(" ") unless prefixes.empty?
  log_debug {"\nserialize: prefixes: #{prefix.inspect}"}

  subjects = order_subjects

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

  # Generate document
  doc = render_document(subjects,
    lang:     @lang,
    base:     base_uri,
    title:    doc_title,
    prefix:   prefix) do |s|
    subject(s)
  end
  @output.write(doc)

  super
end

#write_triple(subject, predicate, object)

This method is abstract.

This method returns an undefined value.

Addes a triple to be serialized

Parameters:

Raises:

  • (NotImplementedError)

    unless implemented in subclass

  • (RDF::WriterError)

    if validating and attempting to write an invalid Term.



154
155
156
# File 'vendor/bundler/ruby/3.3.0/bundler/gems/rdf-rdfa-d2c5c7c66c23/lib/rdf/rdfa/writer.rb', line 154

def write_triple(subject, predicate, object)
  @graph.insert(RDF::Statement(subject, predicate, object))
end