lib/rdf/kv.rb in rdf-kv-0.1.0 vs lib/rdf/kv.rb in rdf-kv-0.1.1
- old
+ new
@@ -33,11 +33,11 @@
"(#{TERM})\\s+(#{TERM})(?:\\s+(#{DESIGNATOR}))?\\s(#{TERM}))" \
"(?:\\s+(\\$))?\\s*$".freeze
GRAMMAR = /#{PARTIAL_STMT}/o
MAP = %i[modifier term1 term2 designator term1 designator graph
- term1 term2 designator graph deref]
+ term1 term2 designator graph deref].freeze
# these should be instance_exec'd
SPECIALS = {
SUBJECT: -> val {
@subject = resolve_term val[-1] unless val.empty? },
@@ -45,42 +45,41 @@
@graph = resolve_term val[-1] unless val.empty? },
PREFIX: -> val {
val.each do |v, _|
next unless m = /^\s*(#{NCNAME}):\s+(.*)$/o.match(v)
prefix, uri = m.captures
- @namespaces[prefix.to_sym] = RDF::Vocabulary.new uri
+ @prefixes[prefix.to_sym] = RDF::Vocabulary.new uri
end
},
- }
+ }.freeze
# macros are initially represented as a pair: the macro value and a
# flag denoting whether or not the macro itself contains macros and to
# try to dereference it.
GENERATED = {
NEW_UUID: [[-> { UUIDTools::UUID.random_create.to_s }, false]],
NEW_UUID_URN: [[-> { UUIDTools::UUID.random_create.to_uri }, false]],
NEW_BNODE: [[-> { "_:#{UUID::NCName.to_ncname_64(
UUIDTools::UUID.random_create.to_s, version: 1) }" }, false]],
- }
+ }.freeze
# just the classics
DEFAULT_NS = {
rdf: RDF::RDFV,
rdfs: RDF::RDFS,
owl: RDF::OWL,
xsd: RDF::XSD,
}.freeze
+ # Given a (massaged) set of macros, dereference the given array of
+ # strings and return it.
def deref_content strings, macros
strings = [strings] unless strings.is_a? Array
# bail out early if there is nothing to do
return strings unless strings.any? { |s| /#{MACRO}/o.match s }
out = []
strings.each do |s|
- # sometimes these are arrays of arrays
- #s = s.first if s.is_a? Array
-
# chunks are parallel output; each element is a value
chunks = []
s.scan(/\G#{MACROS}/o) do |m|
pre = m.first
macro = m[1] || m[2]
@@ -123,10 +122,14 @@
end
out
end
+ # Given the structure of macro declarations, dereference any
+ # recursively-defined macros, and return a new structure with a key
+ # and array of _values_, rather than an array of `[value, deref]`
+ # pairs.
def massage_macros macros
seen = {}
done = GENERATED.transform_values { |v| v.map { |w| w.first } }
pending = macros.reject { |k, _| GENERATED.key? k }
queue = pending.keys.slice 0..0 # take a zero-or-one-element slice
@@ -145,13 +148,11 @@
val, deref = pair
next unless deref
if deref.is_a? Array
- deref.each do |m|
- done[m] ? dm[m] = true : pm[m] = true
- end
+ deref.each { |m| done[m] ? dm[m] = true : pm[m] = true }
else
m = {}
val.scan(/#{MACRO}/o).compact.each do |x|
x = x.to_sym
next unless macros[x]
@@ -159,11 +160,12 @@
m[x] = true
done[m] ? dm[m] = true : pm[m] = true
end
- # push the deref
+
+ # replace the deref flag with the elements to deref with
pair[1] = m.empty? ? false : m.keys.sort
end
end
# macro values have pending matches
@@ -172,10 +174,11 @@
pm.keys.each do |m|
raise "Cycle detected between #{k} and #{m}" if seen[m]
q << m
end
+ # put the current key back on the queue but put the dependencies first
queue = q + [k] + queue
next
end
unless dm.empty?
@@ -203,11 +206,11 @@
return RDF::Node.new term.delete_prefix '_:' if term.start_with? '_:'
# ugh now we gotta do urls
if m = /^(#{NCNAME}):(\S*)$/o.match(term)
prefix, slug = m.captures
- if !slug.start_with?(?/) and vocab = namespaces[prefix.to_sym]
+ if !slug.start_with?(?/) and vocab = prefixes[prefix.to_sym]
return vocab[slug]
end
end
# now resolve against base
@@ -236,41 +239,43 @@
raise ArgumentError, "Unrecognized hint (#{hint})"
end
# call the callback if we have one
term = callback.call term if callback
-
+
term
end
public
- attr_reader :subject, :graph, :namespaces, :callback
+ attr_reader :subject, :graph, :prefixes, :callback
+ # why is this :target, :source
+ alias_method :namespaces, :prefixes
# Initialize the processor.
#
- # @param subject [RDF::URI] The default subject. Required.
- # @param graph [RDF::URI] The default context. Optional.
- # @param namespaces [Hash] Namespace/prefix mappings. Optional.
- # @param callback [#call] A callback that expects and returns a term.
+ # @param subject [RDF::URI] The default subject. Required.
+ # @param graph [RDF::URI] The default context. Optional.
+ # @param prefixes [Hash] Namespace/prefix mappings. Optional.
+ # @param callback [#call] A callback that expects and returns a term.
# Optional.
#
- def initialize subject: nil, graph: nil, namespaces: {}, callback: nil
+ def initialize subject: nil, graph: nil, prefixes: {}, callback: nil
# look at all of our pretty assertions
raise ArgumentError, 'subject must be an RDF::Resource' unless
subject.is_a? RDF::Resource
raise ArgumentError, 'graph must be an RDF::Resource' unless
graph.nil? or graph.is_a? RDF::Resource
- raise ArgumentError, 'namespaces must be hashable' unless
- namespaces.respond_to? :to_h
+ raise ArgumentError, 'prefixes must be hashable' unless
+ prefixes.respond_to? :to_h
rase ArgumentError, 'callback must be callable' unless
callback.nil? or callback.respond_to? :call
- @subject = subject
- @graph = graph
- @callback = callback
- @namespaces = DEFAULT_NS.merge(namespaces.to_h.map do |k, v|
+ @subject = subject
+ @graph = graph
+ @callback = callback
+ @prefixes = DEFAULT_NS.merge(prefixes.to_h.map do |k, v|
k = k.to_s.to_sym unless k.is_a? Symbol
# coerce to uri
v = RDF::URI(v.to_s) unless v.is_a? RDF::Resource
# now coerce to vocabulary
v = RDF::Vocabulary.new v unless v.is_a? RDF::Vocabulary
@@ -325,11 +330,11 @@
SPECIALS.each do |k, macro|
instance_exec macros[k], ¯o if macros[k]
end
rescue Exception => e
# again this should be nicer
- raise e
+ raise Error.new e
end
# this will be our output
patch = RDF::Changeset.new
@@ -416,6 +421,8 @@
end
end
patch
end
+
+ class Error < RuntimeError; end
end