lib/rdf/rdfa/writer.rb in rdf-rdfa-0.3.5.1 vs lib/rdf/rdfa/writer.rb in rdf-rdfa-0.3.6
- old
+ new
@@ -1,10 +1,8 @@
require 'haml'
require 'cgi'
-require 'rdf/rdfa/patches/graph_properties'
-
module RDF::RDFa
##
# 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.
@@ -49,17 +47,10 @@
# graph.each_statement do |statement|
# writer << statement
# end
# end
#
- # @example Creating @profile definitions in output
- # RDF::RDFa::Writer.buffer(:profile => "http://example.com/profile") do |writer|
- # graph.each_statement do |statement|
- # writer << statement
- # end
- # end
- #
# @author [Gregg Kellogg](http://kellogg-assoc.com/)
class Writer < RDF::Writer
format RDF::RDFa::Format
# Defines rdf:type of subjects to be emitted at the beginning of the document.
@@ -94,21 +85,16 @@
# any additional options
# @option options [Boolean] :canonicalize (false)
# whether to canonicalize literals when serializing
# @option options [Hash] :prefixes (Hash.new)
# the prefix mappings to use
- # @option options [#to_a] :profiles (Array.new)
- # List of profiles to add to document. This will use terms, prefix definitions and default-vocabularies
- # identified within the profiles (taken in reverse order) to determine how to serialize terms
# @option options [#to_s] :base_uri (nil)
# the base URI to use when constructing relative URIs, set as html>head>base.href
# @option options [#to_s] :lang (nil)
# Output as root @lang attribute, and avoid generation _@lang_ where possible
# @option options [Boolean] :standard_prefixes (false)
# Add standard prefixes to _prefixes_, if necessary.
- # @option options [Repository] :profile_repository (nil)
- # Repository to find and save profile graphs.
# @option options [Array<RDF::URI>] :top_classes ([RDF::RDFS.Class])
# Defines rdf:type of subjects to be emitted at the beginning of the document.
# @option options [Array<RDF::URI>] :predicate_order ([RDF.type, RDF::RDFS.label, RDF::DC.title])
# Defines order of predicates to to emit at begninning of a resource description..
# @option options [Array<RDF::URI>] :heading_predicates ([RDF::RDFS.label, RDF::DC.title])
@@ -119,11 +105,10 @@
# Options to pass to Haml::Engine.new. Default options set :ugly => false
# to ensure that whitespace in literals with newlines is properly preserved.
# @yield [writer]
# @yieldparam [RDF::Writer] writer
def initialize(output = $stdout, options = {}, &block)
- self.profile_repository = options[:profile_repository] if options[:profile_repository]
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::DC.title]
@@ -142,21 +127,10 @@
when Hash then @options[:haml]
else DEFAULT_HAML
end
end
- # @return [RDF::Repository]
- def profile_repository
- Profile.repository
- end
-
- # @param [RDF::Repository] repo
- # @return [RDF::Repository]
- def profile_repository=(repo)
- Profile.repository = repo
- end
-
##
# Write whole graph
#
# @param [Graph] graph
# @return [void]
@@ -192,20 +166,17 @@
@base_uri = RDF::URI(@options[:base_uri]) if @options[:base_uri]
@lang = @options[:lang]
@debug = @options[:debug]
self.reset
- add_debug "\nserialize: graph size: #{@graph.size}"
+ add_debug {"\nserialize: graph size: #{@graph.size}"}
preprocess
- # Profiles
- profile = @options[:profiles].join(" ") if @options[:profiles]
-
# Prefixes
prefix = prefixes.keys.map {|pk| "#{pk}: #{prefixes[pk]}"}.sort.join(" ") unless prefixes.empty?
- add_debug "\nserialize: prefixes: #{prefix.inspect}"
+ add_debug {"\nserialize: prefixes: #{prefix.inspect}"}
subjects = order_subjects
# Take title from first subject having a heading predicate
doc_title = nil
@@ -221,11 +192,10 @@
# Generate document
doc = render_document(subjects,
:lang => @lang,
:base => @base_uri,
:title => doc_title,
- :profile => profile,
:prefix => prefix) do |s|
subject(s)
end
@output.write(doc)
end
@@ -236,11 +206,11 @@
# Yields each subject to be rendered separately.
#
# The default Haml template is:
# !!! XML
# !!! 5
- # %html{:xmlns => "http://www.w3.org/1999/xhtml", :lang => lang, :profile => profile, :prefix => prefix}
+ # %html{:xmlns => "http://www.w3.org/1999/xhtml", :lang => lang, :prefix => prefix}
# - if base || title
# %head
# - if base
# %base{:href => base}
# - if title
@@ -258,12 +228,10 @@
# @option options [Symbol, String] language (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.
# @option options [String] title (nil)
# Value of html>head>title element.
- # @option options [String] profile (nil)
- # Value of @profile attribute.
# @option options [String] prefix (nil)
# Value of @prefix attribute.
# @option options [String] haml (haml_template[:doc])
# Haml template to render.
# @yield [subject]
@@ -274,11 +242,10 @@
# The rendered document is returned as a string
def render_document(subjects, options = {})
template = options[:haml] || :doc
options = {
:prefix => nil,
- :profile => nil,
:subjects => subjects,
:title => nil,
}.merge(options)
hamlify(template, options) do |subject|
yield(subject) if block_given?
@@ -458,24 +425,24 @@
end
# Perform any preprocessing of statements required
# @return [ignored]
def preprocess
- # Load profiles
+ # Load default profiles
# Add terms and prefixes to local store for converting URIs
# Keep track of vocabulary from left-most profile
- [@options[:profiles]].flatten.compact.reverse.each do |uri|
+ [XML_RDFA_PROFILE, XHTML_RDFA_PROFILE].each do |uri|
prof = Profile.find(uri)
prof.prefixes.each_pair do |k, v|
@uri_to_prefix[v] = k
end
prof.terms.each_pair do |k, v|
- @uri_to_term_or_curie[v] = RDF::URI.intern(k)
+ @uri_to_term_or_curie[v] = k
end
- @vocabulary = prof.vocabulary.to_s
+ @vocabulary = prof.vocabulary.to_s if prof.vocabulary
end
# Load defined prefixes
(@options[:prefixes] || {}).each_pair do |k, v|
@uri_to_prefix[v.to_s] = k
@@ -503,11 +470,11 @@
# 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|
- #add_debug "order_subjects: #{subject.inspect}"
+ #add_debug {"order_subjects: #{subject.inspect}"}
subjects << subject
seen[subject] = true
end
end
@@ -515,54 +482,44 @@
recursable = @subjects.keys.
select {|s| !seen.include?(s)}.
map {|r| [r.is_a?(RDF::Node) ? 1 : 0, ref_count(r), r]}.
sort
- add_debug "order_subjects: #{recursable.inspect}"
+ add_debug {"order_subjects: #{recursable.inspect}"}
subjects += recursable.map{|r| r.last}
end
# Take a hash from predicate uris to lists of values.
# Sort the lists of values. Return a sorted list of properties.
#
# @param [Hash{String => Array<Resource>}] properties A hash of Property to Resource mappings
# @return [Array<String>}] Ordered list of properties. Uses predicate_order.
def order_properties(properties)
- properties.keys.each do |k|
- properties[k] = properties[k].sort do |a, b|
- a_li = a.is_a?(RDF::URI) && get_curie(a) && get_curie(a).to_s =~ /:_\d+$/ ? a.to_i : a.to_s
- b_li = b.is_a?(RDF::URI) && get_curie(b) && get_curie(b).to_s =~ /:_\d+$/ ? b.to_i : b.to_s
-
- a_li <=> b_li
- end
- end
-
# Make sorted list of properties
prop_list = []
predicate_order.each do |prop|
- next unless properties[prop]
+ next unless properties[prop.to_s]
prop_list << prop.to_s
end
properties.keys.sort.each do |prop|
- prop = prop =~ /^_:(.*)$/ ? RDF::Node.intern($1) : RDF::URI.intern(prop)
- next if prop_list.include?(prop)
- prop_list << prop
+ next if prop_list.include?(prop.to_s)
+ prop_list << prop.to_s
end
- add_debug "order_properties: #{prop_list.inspect}"
+ add_debug {"order_properties: #{prop_list.join(', ')}"}
prop_list
end
# Perform any statement preprocessing required. This is used to perform reference counts and determine required
# prefixes.
# @param [RDF::Statement] statement
# @return [ignored]
def preprocess_statement(statement)
- #add_debug "preprocess: #{statement.inspect}"
+ #add_debug {"preprocess: #{statement.inspect}"}
references = ref_count(statement.object) + 1
@references[statement.object] = references
@subjects[statement.subject] = true
get_curie(statement.subject)
get_curie(statement.predicate)
@@ -604,11 +561,15 @@
def subject(subject, options = {})
return if is_done?(subject)
subject_done(subject)
- properties = @graph.properties(subject)
+ properties = {}
+ @graph.query(:subject => subject) do |st|
+ properties[st.predicate.to_s] ||= []
+ properties[st.predicate.to_s] << st.object
+ end
prop_list = order_properties(properties)
# Find appropriate template
curie ||= case
when subject.node?
@@ -626,23 +587,23 @@
# Nodes without a curie need a blank @typeof to generate a subject
typeof ||= "" unless curie
prop_list -= [RDF.type.to_s]
- add_debug "subject: found template #{tmpl[:identifier] || tmpl.inspect}" if tmpl
- add_debug "subject: #{curie.inspect}, typeof: #{typeof.inspect}, props: #{prop_list.inspect}"
+ add_debug {"subject: found template #{tmpl[:identifier] || tmpl.inspect}"} if tmpl
+ add_debug {"subject: #{curie.inspect}, typeof: #{typeof.inspect}, props: #{prop_list.inspect}"}
# Render this subject
# If :rel is specified and :typeof is nil, use @resource instead of @about.
# Pass other options from calling context
render_opts = {:typeof => typeof}.merge(options)
with_template(tmpl) do
render_subject(subject, prop_list, render_opts) do |pred|
depth do
pred = RDF::URI(pred) if pred.is_a?(String)
values = properties[pred.to_s]
- add_debug "subject: #{get_curie(subject)}, pred: #{get_curie(pred)}, values: #{values.inspect}"
+ add_debug {"subject: #{get_curie(subject)}, pred: #{get_curie(pred)}, values: #{values.inspect}"}
predicate(pred, values)
end
end
end
end
@@ -654,15 +615,15 @@
# Predicate to serialize
# @param [Array<RDF::Resource>] objects
# Objects to serialize
# @return [String]
def predicate(predicate, objects)
- add_debug "predicate: #{predicate.inspect}, objects: #{objects}"
+ add_debug {"predicate: #{predicate.inspect}, objects: #{objects}"}
return if objects.to_a.empty?
- add_debug("predicate: #{get_curie(predicate)}")
+ add_debug {"predicate: #{get_curie(predicate)}"}
property = predicate if objects.any?(&:literal?)
rel = predicate if objects.any?(&:uri?) || objects.any?(&:node?)
render_property(predicate, objects, property, rel) do |o|
# Yields each object, for potential recursive definition.
# If nil is returned, a leaf is produced
@@ -741,47 +702,39 @@
# @raise [RDF::WriterError]
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?
- @rdfcore_prefixes ||= RDF::RDFa::Profile.find(RDF::URI("http://www.w3.org/profile/rdfa-1.1")).prefixes
-
uri = resource.to_s
curie = case
when @uri_to_term_or_curie.has_key?(uri)
- #add_debug("get_curie(#{uri}): uri_to_term_or_curie")
+ add_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
- #add_debug("get_curie(#{uri}): base_uri (#{uri.sub(@base_uri.to_s, "")})")
+ add_debug {"get_curie(#{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")
+ add_debug {"get_curie(#{uri}): vocabulary"}
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")
+ add_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 u = @rdfcore_prefixes.values.detect {|u| uri.index(u.to_s) == 0}
- #add_debug("get_curie(#{uri}): rdfcore_prefixes")
- # Use standard profile prefixes
- pfx = @rdfcore_prefixes.invert[u]
- prefix(pfx, u) # Define for output
- uri.sub(u.to_s, "#{pfx}:")
when @options[:standard_prefixes] && vocab = RDF::Vocabulary.detect {|v| uri.index(v.to_uri.to_s) == 0}
- #add_debug("get_curie(#{uri}): standard_prefixes")
+ add_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
- #add_debug("get_curie(#{uri}): none")
+ add_debug {"get_curie(#{uri}): none"}
uri
end
- #add_debug("get_curie(#{resource}) => #{curie}")
+ #add_debug {"get_curie(#{resource}) => #{curie}"}
@uri_to_term_or_curie[uri] = curie
rescue Addressable::URI::InvalidURIError => e
raise RDF::WriterError, "Invalid URI #{uri.inspect}: #{e.message}"
end
@@ -831,15 +784,15 @@
# @param [Hash{Symbol => Object}] locals
# Locals to pass to render
# @return [String]
# @raise [RDF::WriterError]
def hamlify(template, locals = {})
- add_debug "hamlify template: #{template}"
+ add_debug {"hamlify template: #{template}"}
template = haml_template[template] if template.is_a?(Symbol)
template = template.align_left
- add_debug "hamlify locals: #{locals.inspect}"
+ add_debug {"hamlify locals: #{locals.inspect}"}
Haml::Engine.new(template, @options[:haml_options] || HAML_OPTIONS).render(self, locals) do |*args|
yield(*args) if block_given?
end
rescue Haml::Error => e
@@ -872,10 +825,13 @@
end
# Add debug event to debug array, if specified
#
# @param [String] message::
- def add_debug(message)
+ # @yieldreturn [String] appended to message, to allow for lazy-evaulation of message
+ def add_debug(message = "")
+ return unless ::RDF::RDFa.debug? || @debug
+ message = message + yield if block_given?
msg = "#{' ' * @depth}#{message}"
STDERR.puts msg if ::RDF::RDFa.debug?
@debug << msg if @debug.is_a?(Array)
end
end