Class: RDF::Turtle::Reader

Inherits:
Reader show all
Includes:
EBNF::LL1::Parser, Terminals, Util::Logger
Defined in:
vendor/bundler/ruby/3.3.0/bundler/gems/rdf-turtle-6506e92ccd8e/lib/rdf/turtle/reader.rb

Overview

A parser for the Turtle 2

Direct Known Subclasses

RDF::TriG::Reader

Defined Under Namespace

Classes: Recovery, SyntaxError

Constant Summary

Constants included from Util::Logger

Util::Logger::IOWrapper

Constants included from Terminals

Terminals::ANON, Terminals::BASE, Terminals::BLANK_NODE_LABEL, Terminals::DECIMAL, Terminals::DOUBLE, Terminals::ECHAR, Terminals::EXPONENT, Terminals::INTEGER, Terminals::IRIREF, Terminals::IRI_RANGE, Terminals::LANG_DIR, Terminals::PERCENT, Terminals::PLX, Terminals::PNAME_LN, Terminals::PNAME_NS, Terminals::PN_CHARS, Terminals::PN_CHARS_BASE, Terminals::PN_CHARS_BODY, Terminals::PN_CHARS_U, Terminals::PN_LOCAL, Terminals::PN_LOCAL_BODY, Terminals::PN_LOCAL_ESC, Terminals::PN_PREFIX, Terminals::PREFIX, Terminals::STRING_LITERAL_LONG_QUOTE, Terminals::STRING_LITERAL_LONG_SINGLE_QUOTE, Terminals::STRING_LITERAL_QUOTE, Terminals::STRING_LITERAL_SINGLE_QUOTE, Terminals::UCHAR, Terminals::U_CHARS1, Terminals::U_CHARS2, Terminals::WS

Instance Attribute Summary

Attributes included from EBNF::LL1::Parser

#lineno

Attributes inherited from Reader

#options

Attributes included from Enumerable

#existentials, #universals

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 included from EBNF::LL1::Parser

#add_prod_data, #add_prod_datum, #depth, #parse, #prod_data, #warn

Methods inherited from Reader

#base_uri, #canonicalize?, #close, each, #each_pg_statement, #encoding, #fail_object, #fail_predicate, #fail_subject, for, format, #intern?, #lineno, open, #prefixes, #prefixes=, #read_triple, #rewind, #to_sym, to_sym, #valid?, #validate?

Methods included from Util::Aliasing::LateBound

#alias_method

Methods included from Enumerable

add_entailment, #canonicalize, #canonicalize!, #dump, #each_graph, #each_object, #each_predicate, #each_quad, #each_subject, #each_term, #entail, #enum_graph, #enum_object, #enum_predicate, #enum_quad, #enum_statement, #enum_subject, #enum_term, #enum_triple, #graph?, #graph_names, #invalid?, #method_missing, #object?, #objects, #predicate?, #predicates, #project_graph, #quad?, #quads, #respond_to_missing?, #statement?, #statements, #subject?, #subjects, #supports?, #term?, #terms, #to_a, #to_h, #to_set, #triple?, #triples, #valid?, #validate!

Methods included from Isomorphic

#bijection_to, #isomorphic_with?

Methods included from Countable

#count, #empty?

Methods included from Readable

#readable?

Constructor Details

#initialize(input = nil, **options, &block) ⇒ RDF::Turtle::Reader

Initializes a new reader instance.

Note, the spec does not define a default mapping for the empty prefix, but it is so commonly used in examples that we define it to be the empty string anyway, except when validating.

Parameters:

Options Hash (**options):

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

    the prefix mappings to use (for acessing intermediate parser productions)

  • :base_uri (#to_s) — default: nil

    the base URI to use when resolving relative URIs (for acessing intermediate parser productions)

  • :anon_base (#to_s) — default: "b0"

    Basis for generating anonymous Nodes

  • :validate (Boolean) — default: false

    whether to validate the parsed statements and values. If not validating, the parser will attempt to recover from errors.

  • :logger (Logger, #write, #<<)

    Record error/info/debug output

  • :freebase (Boolean) — default: false

    Use optimized Freebase reader



94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
# File 'vendor/bundler/ruby/3.3.0/bundler/gems/rdf-turtle-6506e92ccd8e/lib/rdf/turtle/reader.rb', line 94

def initialize(input = nil, **options, &block)
  super do
    @options = {
      anon_base:  "b0",
      whitespace:  WS,
      depth: 0,
    }.merge(@options)
    @prod_stack = []

    @options[:base_uri] = RDF::URI(base_uri || "")
    debug("base IRI") {base_uri.inspect}
    
    debug("validate") {validate?.inspect}
    debug("canonicalize") {canonicalize?.inspect}
    debug("intern") {intern?.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

Dynamic Method Handling

This class handles dynamic methods through the method_missing method in the class RDF::Enumerable

Class Method Details

.optionsObject

Reader options



46
47
48
49
50
51
52
53
54
# File 'vendor/bundler/ruby/3.3.0/bundler/gems/rdf-turtle-6506e92ccd8e/lib/rdf/turtle/reader.rb', line 46

def self.options
  super + [
    RDF::CLI::Option.new(
      symbol: :freebase,
      datatype: TrueClass,
      on: ["--freebase"],
      description: "Use optimized Freebase reader.") {true},
  ]
end

Instance Method Details

#add_statement(production, statement) ⇒ RDF::Statement

add a statement, object can be literal or URI or bnode

Parameters:

Returns:

Raises:

  • (RDF::ReaderError)

    Checks parameter types and raises if they are incorrect if parsing mode is validate.



174
175
176
177
178
179
180
# File 'vendor/bundler/ruby/3.3.0/bundler/gems/rdf-turtle-6506e92ccd8e/lib/rdf/turtle/reader.rb', line 174

def add_statement(production, statement)
  error("Statement is invalid: #{statement.inspect}", production: produciton) if validate? && statement.invalid?
  @callback.call(statement) if statement.subject &&
                               statement.predicate &&
                               statement.object &&
                               (validate? ? statement.valid? : true)
end

#bnode(value = nil) ⇒ Object

Keep track of allocated BNodes



245
246
247
248
249
# File 'vendor/bundler/ruby/3.3.0/bundler/gems/rdf-turtle-6506e92ccd8e/lib/rdf/turtle/reader.rb', line 245

def bnode(value = nil)
  return RDF::Node.new unless value
  @bnode_cache ||= {}
  @bnode_cache[value.to_s] ||= RDF::Node.new(value)
end

#debug(*args, &block) ⇒ Object (protected)



750
751
752
753
754
755
756
# File 'vendor/bundler/ruby/3.3.0/bundler/gems/rdf-turtle-6506e92ccd8e/lib/rdf/turtle/reader.rb', line 750

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

#each_statement {|statement| ... }

This method returns an undefined value.

Iterates the given block for each RDF statement in the input.

Yields:

  • (statement)

Yield Parameters:



131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
# File 'vendor/bundler/ruby/3.3.0/bundler/gems/rdf-turtle-6506e92ccd8e/lib/rdf/turtle/reader.rb', line 131

def each_statement(&block)
  if block_given?
    log_recover
    @callback = block

    begin
      while (@lexer.first rescue true)
        read_statement
      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

#each_triple {|subject, predicate, object| ... }

This method returns an undefined value.

Iterates the given block for each RDF triple in the input.

Yields:

  • (subject, predicate, object)

Yield Parameters:



159
160
161
162
163
164
165
166
# File 'vendor/bundler/ruby/3.3.0/bundler/gems/rdf-turtle-6506e92ccd8e/lib/rdf/turtle/reader.rb', line 159

def each_triple(&block)
  if block_given?
    each_statement do |statement|
      block.call(*statement.to_triple)
    end
  end
  enum_for(:each_triple)
end

#error(node, message, options) ⇒ Object (protected)

Error information, used as level 0 debug messages.

Parameters:

  • node (String)

    Relevant location associated with message

  • message (String)

    Error string

  • options (Hash)

Options Hash (options):

  • :production (URI, #to_s)
  • :token (Token)

See Also:

  • RDF::Turtle::Reader.{{#debug}


768
769
770
771
772
773
774
775
776
777
778
779
# File 'vendor/bundler/ruby/3.3.0/bundler/gems/rdf-turtle-6506e92ccd8e/lib/rdf/turtle/reader.rb', line 768

def error(*args)
  ctx = ""
  ctx += "(found #{options[:token].inspect})" if options[:token]
  ctx += ", production = #{options[:production].inspect}" if options[:production]
  lineno = @lineno || (options[:token].lineno if options[:token].respond_to?(:lineno)) || @lexer.lineno
  log_error(*args, ctx,
    lineno:     lineno,
    token:      options[:token],
    production: options[:production],
    depth:      options[:depth],
    exception:  SyntaxError,)
end

#inspectObject



121
122
123
# File 'vendor/bundler/ruby/3.3.0/bundler/gems/rdf-turtle-6506e92ccd8e/lib/rdf/turtle/reader.rb', line 121

def inspect
  sprintf("#<%s:%#0x(%s)>", self.class.name, __id__, base_uri.to_s)
end

#literal(value, **options) ⇒ Object

Create a literal



196
197
198
199
200
201
202
203
204
205
206
# File 'vendor/bundler/ruby/3.3.0/bundler/gems/rdf-turtle-6506e92ccd8e/lib/rdf/turtle/reader.rb', line 196

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

#pname(prefix, suffix) ⇒ Object

Expand a PNAME using string concatenation



222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
# File 'vendor/bundler/ruby/3.3.0/bundler/gems/rdf-turtle-6506e92ccd8e/lib/rdf/turtle/reader.rb', line 222

def pname(prefix, suffix)
  # Prefixes must be defined, except special case for empty prefix being alias for current @base
  base = if prefix(prefix)
    prefix(prefix).to_s
  elsif prefix.to_s.empty? && !validate?
    base_uri.to_s
  else
    error("undefined prefix", production: :pname, token: prefix)
    ''
  end

  # Unescape PN_LOCAL_ESC
  suffix = suffix.gsub(PN_LOCAL_ESC) {|esc| esc[1]} if
    suffix.match?(PN_LOCAL_ESC)

  # Remove any redundant leading hash from suffix
  suffix = suffix.sub(/^\#/, "") if base.index("#")

  debug("pname", depth: options[:depth]) {"base: '#{base}', suffix: '#{suffix}'"}
  process_iri(base + suffix.to_s)
end

#prefix(prefix, iri = nil) ⇒ Object

Override #prefix to take a relative IRI

prefix directives map a local name to an IRI, also resolved against the current In-Scope Base URI. Spec confusion, presume that an undefined empty prefix has an empty relative IRI, which uses string contatnation rules against the in-scope IRI at the time of use



214
215
216
217
218
# File 'vendor/bundler/ruby/3.3.0/bundler/gems/rdf-turtle-6506e92ccd8e/lib/rdf/turtle/reader.rb', line 214

def prefix(prefix, iri = nil)
  # Relative IRIs are resolved against @base
  iri = process_iri(iri) if iri
  super(prefix, iri)
end

#process_iri(iri) ⇒ Object

Process a URI against base



183
184
185
186
187
188
189
190
191
192
193
# File 'vendor/bundler/ruby/3.3.0/bundler/gems/rdf-turtle-6506e92ccd8e/lib/rdf/turtle/reader.rb', line 183

def process_iri(iri)
  iri = iri.value[1..-2] if iri === :IRIREF
  value = RDF::URI(iri)
  value = base_uri.join(value) if value.relative?
  value.validate! if validate?
  value.canonicalize! if canonicalize? && !value.frozen?
  value = RDF::URI.intern(value) if intern?
  value
rescue ArgumentError => e
  error("process_iri", e)
end

#prod(production, recover_to = []) ⇒ Object (protected)



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
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
# File 'vendor/bundler/ruby/3.3.0/bundler/gems/rdf-turtle-6506e92ccd8e/lib/rdf/turtle/reader.rb', line 680

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: 4, 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

#progress(*args, &block) ⇒ Object (protected)



734
735
736
737
738
739
740
# File 'vendor/bundler/ruby/3.3.0/bundler/gems/rdf-turtle-6506e92ccd8e/lib/rdf/turtle/reader.rb', line 734

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

#read_annotation(subject, predicate, object) ⇒ Object (protected)

Read an annotation on a triple

 annotation := (reifier | annotationBlock)*

The reifier becomes the identifier for a subsequent annotation block (if it exists). If there is no reifier, then a blank node is created.



543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
# File 'vendor/bundler/ruby/3.3.0/bundler/gems/rdf-turtle-6506e92ccd8e/lib/rdf/turtle/reader.rb', line 543

def read_annotation(subject, predicate, object)
  error("Unexpected end of file", production: :annotation) unless @lexer.first

  tt = RDF::Statement(subject, predicate, object, tripleTerm: true)
  reifier = nil

  while %w(~ {|).include? @lexer.first.to_s
    if @lexer.first === '~'
      prod(:annotation, %(~)) do
        @lexer.shift # eat '~'
        reifier = read_iri || read_BlankNode || bnode
        add_statement('annotation', RDF::Statement(reifier, RDF.reifies, tt))
      end
    else
      prod(:annotation, %({||})) do
        @lexer.shift # eat '{|'
        unless reifier
          # Emit the reifiedTriple
          reifier = bnode
          add_statement('annotation', RDF::Statement(reifier, RDF.reifies, tt))
        end

        # id becomes subject for predicateObjectList
        read_predicateObjectList(reifier) ||
          error("Expected predicateObjectList", production: :annotation, token: @lexer.first)
        error("annotation", "Expected closing '|}'") unless @lexer.first === '|}'
        @lexer.shift # eat '|}'
        reifier = nil
      end
    end
  end
end

#read_BlankNodeRDF::Node (protected)

Returns:



672
673
674
675
676
677
678
# File 'vendor/bundler/ruby/3.3.0/bundler/gems/rdf-turtle-6506e92ccd8e/lib/rdf/turtle/reader.rb', line 672

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_blankNodePropertyListRDF::Node (protected)

Returns:



625
626
627
628
629
630
631
632
633
634
635
636
637
638
# File 'vendor/bundler/ruby/3.3.0/bundler/gems/rdf-turtle-6506e92ccd8e/lib/rdf/turtle/reader.rb', line 625

def read_blankNodePropertyList
  token = @lexer.first
  if token === '['
    prod(:blankNodePropertyList, %{]}) do
      @lexer.shift
      progress("blankNodePropertyList", depth: options[:depth]) {"token: #{token.inspect}"}
      node = bnode
      read_predicateObjectList(node)
      error("blankNodePropertyList", "Expected closing ']'") unless @lexer.first === ']'
      @lexer.shift
      node
    end
  end
end

#read_collectionRDF::Node (protected)

Returns:



641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
# File 'vendor/bundler/ruby/3.3.0/bundler/gems/rdf-turtle-6506e92ccd8e/lib/rdf/turtle/reader.rb', line 641

def read_collection
  if @lexer.first === '('
    prod(:collection, %{)}) do
      @lexer.shift
      token = @lexer.first
      progress("collection", depth: options[:depth]) {"token: #{token.inspect}"}
      objects = []
      while object = read_object
        objects << object
      end
      list = RDF::List.new(values: objects)
      list.each_statement do |statement|
        add_statement("collection", statement)
      end
      error("collection", "Expected closing ')'") unless @lexer.first === ')'
      @lexer.shift
      list.subject
    end
  end
end

#read_directive (protected)

This method returns an undefined value.

Read directive

directive ::= prefixID | base | sparqlPrefix | sparqlBase


283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
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
325
326
327
# File 'vendor/bundler/ruby/3.3.0/bundler/gems/rdf-turtle-6506e92ccd8e/lib/rdf/turtle/reader.rb', line 283

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)
        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}"}
        prefix(pfx.value[0..-2], process_iri(iri))
        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_iriRDF::URI (protected)

Returns:



663
664
665
666
667
668
669
# File 'vendor/bundler/ruby/3.3.0/bundler/gems/rdf-turtle-6506e92ccd8e/lib/rdf/turtle/reader.rb', line 663

def read_iri
  token = @lexer.first
  case token && token.type
  when :IRIREF then prod(:iri)  {process_iri(@lexer.shift)}
  when :PNAME_LN, :PNAME_NS then prod(:iri) {pname(*@lexer.shift.value.split(':', 2))}
  end
end

#read_literalRDF::Literal (protected)

Returns:



577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
# File 'vendor/bundler/ruby/3.3.0/bundler/gems/rdf-turtle-6506e92ccd8e/lib/rdf/turtle/reader.rb', line 577

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)}
  when :DECIMAL
    prod(:literal) do
      value = @lexer.shift.value
      value = "0#{value}" if value.start_with?(".")
      literal(value, datatype:  RDF::XSD.decimal)
    end
  when :DOUBLE then prod(:literal) {literal(@lexer.shift.value.sub(/\.([eE])/, '.0\1'), datatype:  RDF::XSD.double)}
  when "true", "false" then prod(:literal) {literal(@lexer.shift.value, datatype: RDF::XSD.boolean)}
  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 :LANG_DIR
        lang_dir = @lexer.shift.value[1..-1]
        language, direction = lang_dir.split('--')
        literal(value, language: language, direction: direction)
      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 :LANG_DIR
        lang_dir = @lexer.shift.value[1..-1]
        language, direction = lang_dir.split('--')
        literal(value, language: language, direction: direction)
      when '^^'
        @lexer.shift
        literal(value, datatype: read_iri)
      else
        literal(value)
      end
    end
  end
end

#read_object(subject = nil, predicate = nil) (protected)

This method returns an undefined value.

Read object

 object ::= iri | BlankNode | collection | blankNodePropertyList
          | literal | tripleTerm | reifiedTriple


435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
# File 'vendor/bundler/ruby/3.3.0/bundler/gems/rdf-turtle-6506e92ccd8e/lib/rdf/turtle/reader.rb', line 435

def read_object(subject = nil, predicate = nil)
  prod(:object) do
    if object = read_iri ||
      read_BlankNode ||
      read_collection ||
      read_blankNodePropertyList ||
      read_literal ||
      read_tripleTerm ||
      read_reifiedTriple

      add_statement(:object, RDF::Statement(subject, predicate, object)) if subject && predicate
      object
    end
  end
end

#read_objectList(subject, predicate) ⇒ RDF::Term (protected)

Read objectList

objectList ::= object annotation* ( ',' object annotation* )*

Returns:



382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
# File 'vendor/bundler/ruby/3.3.0/bundler/gems/rdf-turtle-6506e92ccd8e/lib/rdf/turtle/reader.rb', line 382

def read_objectList(subject, predicate)
  prod(:objectList, %{,}) do
    last_object = nil
    while object = prod(:_objectList_2) {read_object(subject, predicate)}
      last_object = object

      # If object is followed by annotations, read them.
      read_annotation(subject, predicate, object)

      break unless @lexer.first === ','
      @lexer.shift while @lexer.first === ','
    end
    last_object
  end
end

#read_predicateObjectList(subject) ⇒ RDF::URI (protected)

Read predicateObjectList

 predicateObjectList ::= verb objectList (';' (verb objectList)? )*

Parameters:

Returns:



361
362
363
364
365
366
367
368
369
370
371
372
373
374
# File 'vendor/bundler/ruby/3.3.0/bundler/gems/rdf-turtle-6506e92ccd8e/lib/rdf/turtle/reader.rb', line 361

def read_predicateObjectList(subject)
  prod(:predicateObjectList, %{;}) do
    last_verb = nil
    while verb = read_verb
      last_verb = verb
      prod(:_predicateObjectList_5) do
        read_objectList(subject, verb) || error("Expected objectList", production: :predicateObjectList, token: @lexer.first)
      end
      break unless @lexer.first === ';'
      @lexer.shift while @lexer.first === ';'
    end
    last_verb
  end
end

#read_reifiedTripleRDF::Term (protected)

Read reifiedTriple

 reifiedTriple ::= '<<' (subject | reifiedTriple) predicate object reifier? '>>'

Returns:



457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
# File 'vendor/bundler/ruby/3.3.0/bundler/gems/rdf-turtle-6506e92ccd8e/lib/rdf/turtle/reader.rb', line 457

def read_reifiedTriple
  return unless @options[:rdfstar]
  if @lexer.first.value == '<<'
    prod(:reifiedTriple) do
      @lexer.shift # eat <<
      subject = read_ttSubject || read_reifiedTriple || error("Failed to parse subject", production: :reifiedTriple, token: @lexer.first)
      predicate = read_verb || error("Failed to parse predicate", production: :reifiedTriple, token: @lexer.first)
      object = read_ttObject || read_tripleTerm || read_reifiedTriple || error("Failed to parse object", production: :reifiedTriple, token: @lexer.first)
      tt = RDF::Statement(subject, predicate, object, tripleTerm: true)

      # An optional reifier. If not specified it is a new blank node.
      id = if @lexer.first.value == '~'
        @lexer.shift
        read_iri || read_BlankNode
      end || bnode

      statement = RDF::Statement(id, RDF.to_uri + 'reifies', tt)
      add_statement('reifiedTriple', statement)

      unless @lexer.first.value == '>>'
        error("Failed to end of triple occurence", production: :reifiedTriple, token: @lexer.first)
      end
      @lexer.shift
      id
    end
  end
end

#read_statement (protected)

This method returns an undefined value.

Read objectList

statement ::= directive | triples '.'


258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
# File 'vendor/bundler/ruby/3.3.0/bundler/gems/rdf-turtle-6506e92ccd8e/lib/rdf/turtle/reader.rb', line 258

def read_statement
  prod(:statement, %w{.}) do
    error("read_statement", "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_triples || error("Expected token", production: :statement, token: token)
      if !log_recovering? || @lexer.first === '.'
        # If recovering, we will have eaten the closing '.'
        token = @lexer.shift
        unless token && token.value == '.'
          error("Expected '.' following triple", production: :statement, token: token)
        end
      end
    end
  end
end

#read_subjectRDF::Resource (protected)

subject ::= iri | BlankNode | collection

Returns:



419
420
421
422
423
424
425
426
# File 'vendor/bundler/ruby/3.3.0/bundler/gems/rdf-turtle-6506e92ccd8e/lib/rdf/turtle/reader.rb', line 419

def read_subject
  prod(:subject) do
    read_iri ||
    read_BlankNode ||
    read_collection ||
    error( "Expected subject", production: :subject, token: @lexer.first)
  end
end

#read_triplesObject (protected)

Read triples

 triples ::= subject predicateObjectList | blankNodePropertyList predicateObjectList?

Returns:

  • (Object)

    returns the last verb matched, or subject BNode on predicateObjectList?



335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
# File 'vendor/bundler/ruby/3.3.0/bundler/gems/rdf-turtle-6506e92ccd8e/lib/rdf/turtle/reader.rb', line 335

def read_triples
  prod(:triples, %w{.}) do
    error("read_triples", "Unexpected end of file") unless token = @lexer.first
    case token.type || token.value
    when '['
      # blankNodePropertyList predicateObjectList? 
      subject = read_blankNodePropertyList || error("Failed to parse blankNodePropertyList", production: :triples, token: @lexer.first)
      read_predicateObjectList(subject) || subject
    when '<<'
      subject = read_reifiedTriple || error("Failed to parse reifiedTriple", production: :triples, token: @lexer.first)
      read_predicateObjectList(subject) || subject
    else
      # subject predicateObjectList
      subject = read_subject || error("Failed to parse subject", production: :triples, token: @lexer.first)
      read_predicateObjectList(subject) || error("Expected predicateObjectList", production: :triples, token: @lexer.first)
    end
  end
end

#read_tripleTermRDF::Statement (protected)

Read triple term

 tripleTerm ::= '<<(' ttSubject predicate ttObject ')>>'

Returns:



491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
# File 'vendor/bundler/ruby/3.3.0/bundler/gems/rdf-turtle-6506e92ccd8e/lib/rdf/turtle/reader.rb', line 491

def read_tripleTerm
  return unless @options[:rdfstar]
  if @lexer.first.value == '<<('
    prod(:tripleTerm) do
      @lexer.shift # eat <<(
      subject = read_ttSubject || error("Failed to parse subject", production: :tripleTerm, token: @lexer.first)
      predicate = read_verb || error("Failed to parse predicate", production: :tripleTerm, token: @lexer.first)
      object = read_ttObject || error("Failed to parse object", production: :tripleTerm, token: @lexer.first)
      unless @lexer.first.value == ')>>'
        error("Failed to end of triple term", production: :tripleTerm, token: @lexer.first)
      end
      @lexer.shift
      statement = RDF::Statement(subject, predicate, object, tripleTerm: true)
      statement
    end
  end
end

#read_ttObject(subject = nil, predicate = nil) ⇒ RDF::Term (protected)

Read ttObject

 ttObject::=    iri | BlankNode | literal | tripleTerm

Returns:



528
529
530
531
532
533
534
535
# File 'vendor/bundler/ruby/3.3.0/bundler/gems/rdf-turtle-6506e92ccd8e/lib/rdf/turtle/reader.rb', line 528

def read_ttObject(subject = nil, predicate = nil)
  prod(:ttObject) do
    read_iri ||
    read_BlankNode ||
    read_literal ||
    read_tripleTerm
  end
end

#read_ttSubjectRDF::Term (protected)

Read ttSubject

 ttSubject::=   iri | BlankNode

Returns:



515
516
517
518
519
520
# File 'vendor/bundler/ruby/3.3.0/bundler/gems/rdf-turtle-6506e92ccd8e/lib/rdf/turtle/reader.rb', line 515

def read_ttSubject
  prod(:ttSubject) do
    read_iri ||
    read_BlankNode
  end
end

#read_verbRDF::URI (protected)

Read verb

verb ::= predicate | 'a'

Returns:



404
405
406
407
408
409
410
411
412
413
414
# File 'vendor/bundler/ruby/3.3.0/bundler/gems/rdf-turtle-6506e92ccd8e/lib/rdf/turtle/reader.rb', line 404

def read_verb
  if @cached_verb
    v, @cached_verb = @cached_verb, nil
    return v
  end
  error("read_verb", "Unexpected end of file") unless token = @lexer.first
  case token.type || token.value
  when 'a' then prod(:verb) {@lexer.shift && RDF.type}
  else prod(:verb) {read_iri}
  end
end

#recover(*args, &block) ⇒ Object (protected)



742
743
744
745
746
747
748
# File 'vendor/bundler/ruby/3.3.0/bundler/gems/rdf-turtle-6506e92ccd8e/lib/rdf/turtle/reader.rb', line 742

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