class RDF::N3::Reader
A Notation-3/Turtle parser in Ruby
N3
Parser, based in librdf version of predictiveParser.py @see www.w3.org/2000/10/swap/grammar/predictiveParser.py @see www.w3.org/2000/10/swap/grammar/n3-selectors.n3
Separate pass to create branch_table from n3-selectors.n3
This implementation only supports quickVars at the document scope.
Non-distinguished blank node variables are created as part of reasoning.
@todo
-
Formulae as
RDF::Query
representations -
Formula expansion similar to
SPARQL
Construct
@author [Gregg Kellogg](greggkellogg.net/)
Attributes
All nodes allocated to formulae
@return [Hash{RDF::Node => RDF::Graph}]
Nodes used as Formulae graph names
@return [Array<RDF::Node>]
Allocated variables by formula
@return [Hash{Symbol => RDF::Node
}]
Public Class Methods
Source
# File lib/rdf/n3/reader.rb, line 83 def initialize(input = $stdin, **options, &block) super do @options = { anon_base: "b0", whitespace: WS, depth: 0, }.merge(@options) @prod_stack = [] @formulae = [] @formula_nodes = {} @label_uniquifier = "0" @bnodes = {} @bn_labler = @options[:anon_base].dup @bn_mapper = {} @variables = {} if options[:base_uri] progress("base_uri") { base_uri.inspect} namespace(nil, iri(base_uri.to_s.match?(%r{[#/]$}) ? base_uri : "#{base_uri}#")) end # Prepopulate operator namespaces unless validating unless validate? namespace(:rdf, RDF.to_uri) namespace(:rdfs, RDF::RDFS.to_uri) namespace(:xsd, RDF::XSD.to_uri) namespace(:crypto, RDF::N3::Crypto.to_uri) namespace(:list, RDF::N3::List.to_uri) namespace(:log, RDF::N3::Log.to_uri) namespace(:math, RDF::N3::Math.to_uri) namespace(:rei, RDF::N3::Rei.to_uri) #namespace(:string, RDF::N3::String.to_uri) namespace(:time, RDF::N3::Time.to_uri) end progress("validate") {validate?.inspect} progress("canonicalize") {canonicalize?.inspect} @lexer = EBNF::LL1::Lexer.new(input, self.class.patterns, **@options) if block_given? case block.arity when 0 then instance_eval(&block) else block.call(self) end end end end
Initializes the N3
reader instance.
@param [IO, File, String] input
the input stream to read
@option options [#to_s] :base_uri (nil)
the base URI to use when resolving relative URIs (not supported by all readers)
@option options [Boolean] :validate (false)
whether to validate the parsed statements and values
@option options [Boolean] :canonicalize (false)
whether to canonicalize parsed literals and URIs.
@option options [Hash] :prefixes (Hash.new)
the prefix mappings to use (not supported by all readers)
@option options [Hash] :list_terms (false)
represent collections as an `RDF::Term`, rather than an rdf:first/rest ladder.
@return [reader] @yield [reader] ‘self` @yieldparam [RDF::Reader] reader @yieldreturn [void] ignored
- @raise [Error]
-
Raises RDF::ReaderError if validating and an error is found
Source
# File lib/rdf/n3/reader.rb, line 50 def self.options super + [ RDF::CLI::Option.new( symbol: :list_terms, datatype: TrueClass, default: true, control: :checkbox, on: ["--list-terms CONTEXT"], description: "Use native collections (lists), not first/rest ladder.") ] end
N3
Reader
options @see ruby-rdf.github.io/rdf/RDF/Reader#options-class_method
Public Instance Methods
Source
# File lib/rdf/n3/reader.rb, line 141 def each_statement(&block) if block_given? log_recover @callback = block begin while (@lexer.first rescue true) read_n3Doc end rescue EBNF::LL1::Lexer::Error, SyntaxError, EOFError, Recovery # Terminate loop if EOF found while recovering end if validate? && log_statistics[:error] raise RDF::ReaderError, "Errors found during processing" end end enum_for(:each_statement) end
Iterates the given block for each RDF
statement in the input. @yield [statement] @yieldparam [RDF::Statement] statement @return [void]
Source
# File lib/rdf/n3/reader.rb, line 169 def each_triple if block_given? each_statement do |statement| yield(*statement.to_triple) end end enum_for(:each_triple) end
Iterates the given block for each RDF
triple in the input.
@yield [subject, predicate, object] @yieldparam [RDF::Resource] subject @yieldparam [RDF::URI] predicate @yieldparam [RDF::Value] object @return [void]
Source
# File lib/rdf/n3/reader.rb, line 132 def inspect sprintf("#<%s:%#0x(%s)>", self.class.name, __id__, base_uri.to_s) end
Private Instance Methods
Source
# File lib/rdf/n3/reader.rb, line 774 def add_statement(node, subject, predicate, object) statement = if @formulae.last # It's a pattern in a formula RDF::Query::Pattern.new(subject, predicate, object, graph_name: @formulae.last) else RDF::Statement(subject, predicate, object) end debug("statement(#{node})", depth: @options[:depth]) {statement.to_s} error("statement(#{node})", "Statement is invalid: #{statement.inspect}") if validate? && statement.invalid? @callback.call(statement) end
add a pattern or statement
@param [any] node string for showing graph_name @param [RDF::Term] subject the subject of the statement @param [RDF::URI] predicate the predicate of the statement @param [RDF::Term] object the object of the statement @return [Statement] Added statement @raise [RDF::ReaderError] Checks parameter types and raises if they are incorrect if parsing mode is validate.
Source
# File lib/rdf/n3/reader.rb, line 743 def bnode(label = nil) form_id = formulae.last ? formulae.last.id : '_bn_ground' if label # Return previously allocated blank node for. @bn_mapper[form_id] ||= {} return @bn_mapper[form_id][label] if @bn_mapper[form_id][label] end # Get a fresh label @bn_labler.succ! while @bnodes[@bn_labler] bn = RDF::Node.intern(@bn_labler.to_sym) @bnodes[@bn_labler] = bn @bn_mapper[form_id][label] = bn if label bn end
Keep track of allocated BNodes. Blank nodes are allocated to the formula. Unnnamed bnodes are created using an incrementing labeler for repeatability.
Source
# File lib/rdf/n3/reader.rb, line 918 def debug(*args, &block) lineno = (options[:token].lineno if options[:token].respond_to?(:lineno)) || (@lexer && @lexer.lineno) opts = args.last.is_a?(Hash) ? args.pop : {} opts[:level] ||= 0 opts[:lineno] ||= lineno log_debug(*args, **opts, &block) end
Source
# File lib/rdf/n3/reader.rb, line 936 def error(*args) ctx = "" ctx += "(found #{options[:token].inspect})" if options[:token] ctx += ", production = #{options[:production].inspect}" if options[:production] lineno = (options[:token].lineno if options[:token].respond_to?(:lineno)) || (@lexer && @lexer.lineno) log_error(*args, ctx, lineno: lineno, token: options[:token], production: options[:production], depth: options[:depth], exception: SyntaxError,) end
Error information, used as level ‘0` debug messages.
@overload error(node, message, options)
@param [String] node Relevant location associated with message @param [String] message Error string @param [Hash] options @option options [URI, #to_s] :production @option options [Token] :token @see {#debug}
Source
# File lib/rdf/n3/reader.rb, line 844 def find_var(name) variables[name.to_s] end
Find any variable that may be defined identified by ‘name` @param [RDF::Node] name of formula @return [RDF::Query::Variable]
Source
# File lib/rdf/n3/reader.rb, line 796 def iri(value, append = nil) value = RDF::URI(value) value = value.join(append) if append value.validate! if validate? && value.respond_to?(:validate) value.canonicalize! if canonicalize? # Variable substitution for in-scope variables. Variables are in scope if they are defined in anthing other than the current formula var = find_var(value) value = var if var value rescue ArgumentError => e error("iri", e.message) end
Create IRIs
Source
# File lib/rdf/n3/reader.rb, line 812 def literal(value, **options) debug("literal", depth: @options[:depth]) do "value: #{value.inspect}, " + "options: #{options.inspect}, " + "validate: #{validate?.inspect}, " + "c14n?: #{canonicalize?.inspect}" end RDF::Literal.new(value, validate: validate?, canonicalize: canonicalize?, **options) rescue ArgumentError => e error("Argument Error #{e.message}", production: :literal, token: @lexer.first) end
Create a literal
Source
# File lib/rdf/n3/reader.rb, line 786 def namespace(prefix, iri) iri = iri.to_s if iri == '#' iri = prefix(nil).to_s + '#' end debug("namespace", depth: @options[:depth]) {"'#{prefix}' <#{iri}>"} prefix(prefix, iri(iri)) end
Source
# File lib/rdf/n3/reader.rb, line 825 def ns(prefix = nil, suffix = nil) namespace(nil, iri("#{base_uri}#")) if prefix.nil? && !prefix(nil) base = prefix(prefix).to_s suffix = suffix.gsub(PN_LOCAL_ESC) {|esc| esc[1]} if suffix.match?(PN_LOCAL_ESC) suffix = suffix.to_s.sub(/^\#/, "") if base.index("#") iri(base + suffix.to_s) end
Decode a PName
Source
# File lib/rdf/n3/reader.rb, line 721 def process_iri(iri) iri(base_uri, iri.to_s) end
Source
# File lib/rdf/n3/reader.rb, line 702 def process_path(path) pathitem, direction, pathtail = path[:pathitem], path[:direction], path[:pathtail] debug("process_path", depth: @options[:depth]) {path.inspect} while pathtail bnode = bnode() pred = pathtail.is_a?(RDF::Term) ? pathtail : pathtail[:pathitem] if direction == :reverse add_statement("process_path(reverse)", bnode, pred, pathitem) else add_statement("process_path(forward)", pathitem, pred, bnode) end pathitem = bnode direction = pathtail[:direction] if pathtail.is_a?(Hash) pathtail = pathtail.is_a?(Hash) && pathtail[:pathtail] end pathitem end
Process a path, such as:
:a!:b means [is :b of :a] => :a :b [] :a^:b means [:b :a] => [] :b :a
Create triple and return property used for next iteration
Result is last created bnode
Source
# File lib/rdf/n3/reader.rb, line 725 def process_pname(value) prefix, name = value.split(":", 2) iri = if prefix(prefix) #debug('process_pname(ns)', depth: @options[:depth]) {"#{prefix(prefix)}, #{name}"} ns(prefix, name) elsif prefix && !prefix.empty? error("process_pname", "Use of undefined prefix #{prefix.inspect}") ns(nil, name) else ns(nil, name) end debug('process_pname', depth: @options[:depth]) {iri.inspect} iri end
Source
# File lib/rdf/n3/reader.rb, line 848 def prod(production, recover_to = []) @prod_stack << {prod: production, recover_to: recover_to} @options[:depth] += 1 recover("#{production}(start)", depth: options[:depth], token: @lexer.first) yield rescue EBNF::LL1::Lexer::Error, SyntaxError, Recovery => e # Lexer encountered an illegal token or the parser encountered # a terminal which is inappropriate for the current production. # Perform error recovery to find a reasonable terminal based # on the follow sets of the relevant productions. This includes # remaining terms from the current production and the stacked # productions case e when EBNF::LL1::Lexer::Error @lexer.recover begin error("Lexer error", "With input '#{e.input}': #{e.message}", production: production, token: e.token) rescue SyntaxError end end raise EOFError, "End of input found when recovering" if @lexer.first.nil? debug("recovery", "current token: #{@lexer.first.inspect}", depth: @options[:depth]) unless e.is_a?(Recovery) # Get the list of follows for this sequence, this production and the stacked productions. debug("recovery", "stack follows:", depth: @options[:depth]) @prod_stack.reverse.each do |prod| debug("recovery", level: 1, depth: @options[:depth]) {" #{prod[:prod]}: #{prod[:recover_to].inspect}"} end end # Find all follows to the top of the stack follows = @prod_stack.map {|prod| Array(prod[:recover_to])}.flatten.compact.uniq # Skip tokens until one is found in follows while (token = (@lexer.first rescue @lexer.recover)) && follows.none? {|t| token === t} skipped = @lexer.shift debug("recovery", depth: @options[:depth]) {"skip #{skipped.inspect}"} end debug("recovery", depth: @options[:depth]) {"found #{token.inspect} in follows"} # Re-raise the error unless token is a follows of this production raise Recovery unless Array(recover_to).any? {|t| token === t} # Skip that token to get something reasonable to start the next production with @lexer.shift ensure progress("#{production}(finish)", depth: options[:depth]) @options[:depth] -= 1 @prod_stack.pop end
Source
# File lib/rdf/n3/reader.rb, line 902 def progress(*args, &block) lineno = (options[:token].lineno if options[:token].respond_to?(:lineno)) || (@lexer && @lexer.lineno) opts = args.last.is_a?(Hash) ? args.pop : {} opts[:level] ||= 1 opts[:lineno] ||= lineno log_info(*args, **opts, &block) end
Source
# File lib/rdf/n3/reader.rb, line 667 def read_blankNode token = @lexer.first case token && token.type when :BLANK_NODE_LABEL then prod(:blankNode) {bnode(@lexer.shift.value[2..-1])} when :ANON then @lexer.shift && prod(:blankNode) {bnode} end end
Read a blank node
[29] blankNode ::= BLANK_NODE_LABEL | ANON
@return [RDF::Node]
Source
# File lib/rdf/n3/reader.rb, line 515 def read_blankNodePropertyList token = @lexer.first if token === '[' prod(:blankNodePropertyList, %{]}) do @lexer.shift progress("blankNodePropertyList", depth: options[:depth], token: token) node = bnode debug("blankNodePropertyList: subject", depth: options[:depth]) {node.to_sxp} read_predicateObjectList(node) error("blankNodePropertyList", "Expected closing ']'") unless @lexer.first === ']' @lexer.shift node end end end
Read a blankNodePropertyList
[20] blankNodePropertyList ::= '[' predicateObjectList ']'
@return [RDF::Node]
Source
# File lib/rdf/n3/reader.rb, line 560 def read_collection if @lexer.first === '(' prod(:collection, %{)}) do @lexer.shift token = @lexer.first progress("collection", depth: options[:depth]) {"token: #{token.inspect}"} objects = [] while @lexer.first.value != ')' && (object = read_path) objects << object end error("collection", "Expected closing ')'") unless @lexer.first === ')' @lexer.shift list = RDF::N3::List.new(values: objects) if options[:list_terms] list else list.each_statement do |statement| add_statement("collection", *statement.to_a) end list.subject end end end end
Read a collection (‘RDF::List`)
[21] collection ::= '(' object* ')'
If the ‘list_terms` option is given, the resulting resource is a list, otherwise, it is the list subject, and the first/rest entries are also emitted. @return [RDF::Node]
Source
# File lib/rdf/n3/reader.rb, line 258 def read_directive prod(:directive, %w{.}) do token = @lexer.first case token.type when :BASE prod(:base) do @lexer.shift terminated = token.value == '@base' iri = @lexer.shift error("Expected IRIREF", production: :base, token: iri) unless iri === :IRIREF @options[:base_uri] = process_iri(iri.value[1..-2].gsub(/\s/, '')) namespace(nil, base_uri.to_s.end_with?('#') ? base_uri : iri("#{base_uri}#")) error("base", "#{token} should be downcased") if token.value.start_with?('@') && token.value != '@base' if terminated error("base", "Expected #{token} to be terminated") unless @lexer.first === '.' @lexer.shift elsif @lexer.first === '.' error("base", "Expected #{token} not to be terminated") else true end end when :PREFIX prod(:prefixID, %w{.}) do @lexer.shift pfx, iri = @lexer.shift, @lexer.shift terminated = token.value == '@prefix' error("Expected PNAME_NS", production: :prefix, token: pfx) unless pfx === :PNAME_NS error("Expected IRIREF", production: :prefix, token: iri) unless iri === :IRIREF debug("prefixID", depth: options[:depth]) {"Defined prefix #{pfx.inspect} mapping to #{iri.inspect}"} namespace(pfx.value[0..-2], process_iri(iri.value[1..-2].gsub(/\s/, ''))) error("prefixId", "#{token} should be downcased") if token.value.start_with?('@') && token.value != '@prefix' if terminated error("prefixID", "Expected #{token} to be terminated") unless @lexer.first === '.' @lexer.shift elsif @lexer.first === '.' error("prefixID", "Expected #{token} not to be terminated") else true end end end end end
Read base and prefix directives
[3] n3Directive ::= prefixID | base
@return [void]
Source
# File lib/rdf/n3/reader.rb, line 592 def read_formula if @lexer.first === '{' prod(:formula, %(})) do @lexer.shift node = RDF::Node.intern("_form_#{unique_label}") formulae.push(node) formula_nodes[node] = true debug(:formula, depth: @options[:depth]) {"id: #{node}, depth: #{formulae.length}"} read_formulaContent # Pop off the formula # Result is the BNode associated with the formula debug(:formula, depth: @options[:depth]) {"pop: #{formulae.last}, depth: #{formulae.length}"} error("collection", "Expected closing '}'") unless @lexer.shift === '}' formulae.pop end end end
Read a formula
[22] formula ::= '{' formulaContent? '}' [23] formulaContent ::= n3Statement ('.' formulaContent?)?
@return [RDF::Node]
Source
# File lib/rdf/n3/reader.rb, line 619 def read_formulaContent return if @lexer.first === '}' # Allow empty formula prod(:formulaContent, %w(. })) do loop do token = @lexer.first error("read_formulaContent", "Unexpected end of file") unless token case token.type when :BASE, :PREFIX read_directive || error("Failed to parse directive", production: :directive, token: token) break if @lexer.first === '}' else read_n3Statement token = @lexer.first case token.value when '.' @lexer.shift # '.' optional at end of formulaContent break if @lexer.first === '}' when '}' break else error("Expected '.' or '}' following n3Statement", production: :formulaContent, token: token) end end end end end
Read formula content, similaer to n3Statement
[23] formulaContent ::= n3Statement ('.' formulaContent?)?
@return [void]
Source
# File lib/rdf/n3/reader.rb, line 653 def read_iri token = @lexer.first case token && token.type when :IRIREF then prod(:iri) {process_iri(@lexer.shift.value[1..-2].gsub(/\s+/m, ''))} when :PNAME_LN, :PNAME_NS then prod(:prefixedName) {process_pname(*@lexer.shift.value)} end end
Read an IRI
(rule iri "26" (alt IRIREF prefixedName))
@return [RDF::URI]
Source
# File lib/rdf/n3/reader.rb, line 537 def read_iriPropertyList token = @lexer.first if token.type == :IPLSTART prod(:iriPropertyList, %{]}) do @lexer.shift progress("iriPropertyList", depth: options[:depth], token: token) node = read_iri debug("iriPropertyList: subject", depth: options[:depth]) {node.to_sxp} read_predicateObjectList(node) error("iriPropertyList", "Expected closing ']'") unless @lexer.first === ']' @lexer.shift node end end end
Read a iriPropertyList
[21] iriPropertyList ::= IPLSTART iri predicateObjectList ']'
@return [RDF::Node]
Source
# File lib/rdf/n3/reader.rb, line 466 def read_literal error("Unexpected end of file", production: :literal) unless token = @lexer.first case token.type || token.value when :INTEGER then prod(:literal) {literal(@lexer.shift.value, datatype: RDF::XSD.integer, canonicalize: canonicalize?)} when :DECIMAL prod(:literal) do value = @lexer.shift.value value = "0#{value}" if value.start_with?(".") literal(value, datatype: RDF::XSD.decimal, canonicalize: canonicalize?) end when :DOUBLE then prod(:literal) {literal(@lexer.shift.value.sub(/\.([eE])/, '.0\1'), datatype: RDF::XSD.double, canonicalize: canonicalize?)} when "true", "false" then prod(:literal) {literal(@lexer.shift.value, datatype: RDF::XSD.boolean, canonicalize: canonicalize?)} when :STRING_LITERAL_QUOTE, :STRING_LITERAL_SINGLE_QUOTE prod(:literal) do value = @lexer.shift.value[1..-2] error("read_literal", "Unexpected end of file") unless token = @lexer.first case token.type || token.value when :LANGTAG literal(value, language: @lexer.shift.value[1..-1].to_sym) when '^^' @lexer.shift literal(value, datatype: read_iri) else literal(value) end end when :STRING_LITERAL_LONG_QUOTE, :STRING_LITERAL_LONG_SINGLE_QUOTE prod(:literal) do value = @lexer.shift.value[3..-4] error("read_literal", "Unexpected end of file") unless token = @lexer.first case token.type || token.value when :LANGTAG literal(value, language: @lexer.shift.value[1..-1].to_sym) when '^^' @lexer.shift literal(value, datatype: read_iri) else literal(value) end end end end
Read a literal
[19] literal ::= rdfLiteral | numericLiteral | BOOLEAN_LITERAL
@return [RDF::Literal]
Source
# File lib/rdf/n3/reader.rb, line 218 def read_n3Doc prod(:n3Doc, %w{.}) do error("read_n3Doc", "Unexpected end of file") unless token = @lexer.first case token.type when :BASE, :PREFIX read_directive || error("Failed to parse directive", production: :directive, token: token) else read_n3Statement if !log_recovering? || @lexer.first === '.' # If recovering, we will have eaten the closing '.' token = @lexer.shift unless token && token.value == '.' error("Expected '.' following n3Statement", production: :n3Statement, token: token) end end end end end
Read statements and directives
[1] n3Doc ::= (n3Statement '.' | sparqlDirective)*
@return [void]
Source
# File lib/rdf/n3/reader.rb, line 244 def read_n3Statement prod(:n3Statement, %w{.}) do error("read_n3Doc", "Unexpected end of file") unless token = @lexer.first read_triples || error("Expected token", production: :statement, token: token) end end
Read statements and directives
[2] n3Statement ::= n3Directive | triples | existential | universal
@return [void]
Source
# File lib/rdf/n3/reader.rb, line 360 def read_objectList(subject, predicate, invert) prod(:objectList, %{,}) do last_object = nil while object = prod(:_objectList_2) {read_path} last_object = object if invert add_statement(:objectList, object, predicate, subject) else add_statement(:objectList, subject, predicate, object) end break unless @lexer.first === ',' @lexer.shift while @lexer.first === ',' end last_object end end
Read objectList
[11] objectList ::= object (',' object)*
@return [RDF::Term] the last matched subject
Source
# File lib/rdf/n3/reader.rb, line 431 def read_path return if @lexer.first.nil? || %w/. } ) ]/.include?(@lexer.first.value) prod(:path) do pathtail = path = {} loop do pathtail[:pathitem] = prod(:pathItem) do read_iri || read_blankNode || read_quickVar || read_collection || read_blankNodePropertyList || read_iriPropertyList || read_literal || read_formula end break if @lexer.first.nil? || !%w(! ^).include?(@lexer.first.value) prod(:_path_2) do pathtail[:direction] = @lexer.shift.value == '!' ? :forward : :reverse pathtail = pathtail[:pathtail] = {} end end # Returns the first object in the path # FIXME: what if it's a verb? process_path(path) end end
subjects, predicates and objects are all expressions, which are all paths
[13] subject ::= expression [14] predicate ::= expression [16] expression ::= path [17] path ::= pathItem ('!' path | '^' path)?
@return [RDF::Resource]
Source
# File lib/rdf/n3/reader.rb, line 336 def read_predicateObjectList(subject) return if @lexer.first.nil? || %w(. }).include?(@lexer.first.value) prod(:predicateObjectList, %{;}) do last_verb = nil loop do verb, invert = read_verb break unless verb last_verb = verb prod(:_predicateObjectList_2) do read_objectList(subject, verb, invert) || error("Expected objectList", production: :predicateObjectList, token: @lexer.first) end break unless @lexer.first === ';' @lexer.shift while @lexer.first === ';' end last_verb end end
Read predicateObjectList
[10] predicateObjectList ::= verb objectList (';' (verb objectList)?)*
@param [RDF::Resource] subject @return [RDF::URI] the last matched verb
Source
# File lib/rdf/n3/reader.rb, line 681 def read_quickVar if @lexer.first.type == :QUICK_VAR_NAME prod(:quickVar) do token = @lexer.shift value = token.value.sub('?', '') variables[value] ||= RDF::Query::Variable.new(value) end end end
Read a quickVar, having global scope.
[30] quickVar ::= QUICK_VAR_NAME
@return [RDF::Query::Variable]
Source
# File lib/rdf/n3/reader.rb, line 311 def read_triples prod(:triples, %w{.}) do error("read_triples", "Unexpected end of file") unless token = @lexer.first subject = case token.type || token.value when IPLSTART # iriPropertyList predicateObjectList? read_iriPropertyList || error("Failed to parse iriPropertyList", production: :triples, token: @lexer.first) when '[' # blankNodePropertyList predicateObjectList? read_blankNodePropertyList || error("Failed to parse blankNodePropertyList", production: :triples, token: @lexer.first) else # subject predicateObjectList read_path || error("Failed to parse subject", production: :triples, token: @lexer.first) end read_predicateObjectList(subject) || subject end end
Read triples
[9] triples ::= subject predicateObjectList?
@return [Object] returns the last IRI matched, or subject BNode on predicateObjectList?
Source
# File lib/rdf/n3/reader.rb, line 392 def read_verb invert = false error("read_verb", "Unexpected end of file") unless token = @lexer.first verb = case token.type || token.value when 'a' then prod(:verb) {@lexer.shift && RDF.type} when 'has' then prod(:verb) {@lexer.shift && read_path} when 'is' then prod(:verb) { @lexer.shift invert, v = true, read_path error( "Expected 'of'", production: :verb, token: @lexer.first) unless @lexer.first.value == 'of' @lexer.shift v } when '<-' then prod(:verb) { @lexer.shift invert = true read_path } when '<=' then prod(:verb) { @lexer.shift invert = true RDF::N3::Log.implies } when '=>' then prod(:verb) {@lexer.shift && RDF::N3::Log.implies} when '=' then prod(:verb) {@lexer.shift && RDF::OWL.sameAs} else read_path end [verb, invert] end
Read a verb
[12] verb = predicate | 'a' | 'has' expression | 'is' expression 'of' | '<-' expression | '<=' | '=>' | '='
@return [RDF::Resource, Boolean] verb and invert?
Source
# File lib/rdf/n3/reader.rb, line 910 def recover(*args, &block) lineno = (options[:token].lineno if options[:token].respond_to?(:lineno)) || (@lexer && @lexer.lineno) opts = args.last.is_a?(Hash) ? args.pop : {} opts[:level] ||= 1 opts[:lineno] ||= lineno log_recover(*args, **opts, &block) end
Source
# File lib/rdf/n3/reader.rb, line 836 def unique_label label, @label_uniquifier = @label_uniquifier, @label_uniquifier.succ label end
Returns a unique label
Source
# File lib/rdf/n3/reader.rb, line 761 def univar(label, scope:) value = label RDF::Query::Variable.new(value) end
If not in ground formula, note scope, and if existential