diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9991f94..d80d483 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -26,16 +26,10 @@ jobs: strategy: fail-fast: false matrix: - ruby: - - 2.6 - - 2.7 - - "3.0" - - 3.1 - - ruby-head - - jruby + ruby: ['3.0', 3.1, 3.2, ruby-head, jruby] steps: - name: Clone repository - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Set up Ruby uses: ruby/setup-ruby@v1 with: @@ -45,7 +39,7 @@ jobs: - name: Run tests run: ruby --version; bundle exec rspec spec || $ALLOW_FAILURES - name: Coveralls GitHub Action - uses: coverallsapp/github-action@v1.1.2 - if: "matrix.ruby == '3.0'" + uses: coverallsapp/github-action@v2 + if: "matrix.ruby == '3.2'" with: github-token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/generate-docs.yml b/.github/workflows/generate-docs.yml index b8d16ed..65aea93 100644 --- a/.github/workflows/generate-docs.yml +++ b/.github/workflows/generate-docs.yml @@ -10,7 +10,7 @@ jobs: name: Update gh-pages with docs steps: - name: Clone repository - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Set up Ruby uses: ruby/setup-ruby@v1 with: diff --git a/Gemfile b/Gemfile index 5af72e4..ba0246c 100644 --- a/Gemfile +++ b/Gemfile @@ -20,7 +20,7 @@ group :development do end group :development, :test do - gem 'simplecov', '~> 0.21', platforms: :mri + gem 'simplecov', '~> 0.22', platforms: :mri gem 'simplecov-lcov', '~> 0.8', platforms: :mri end diff --git a/README.md b/README.md index e117b32..8efecd8 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # RDF::N3 reader/writer and reasoner Notation-3 reader/writer for [RDF.rb][RDF.rb] . -[![Gem Version](https://badge.fury.io/rb/rdf-n3.png)](https://badge.fury.io/rb/rdf-n3) +[![Gem Version](https://badge.fury.io/rb/rdf-n3.svg)](https://badge.fury.io/rb/rdf-n3) [![Build Status](https://github.com/ruby-rdf/rdf-n3/workflows/CI/badge.svg?branch=develop)](https://github.com/ruby-rdf/rdf-n3/actions?query=workflow%3ACI) [![Coverage Status](https://coveralls.io/repos/github/ruby-rdf/rdf-n3/badge.svg?branch=develop)](https://coveralls.io/github/ruby-rdf/rdf-n3?branch=develop) [![Gitter chat](https://badges.gitter.im/ruby-rdf/rdf.png)](https://gitter.im/ruby-rdf/rdf) @@ -159,6 +159,27 @@ Reasoning is discussed in the [Design Issues][] document. * `time:timeZone` (See {RDF::N3::Algebra::Time::Timezone}) * `time:year` (See {RDF::N3::Algebra::Time::Year}) +## Parser features + +### Chaining with `iriPropertyList` + +Adds a proposed syntactic extension for _subject embedding_ similar to a `blankNodePropertyList`. An `iriPropertyList` begins with `[ id _id_`, instead of a simple `[`. This sets _id_ as the **subject** to be used for the following `propertyList`. This provides a mechanisms similar to [JSON-LD Embedding](https://www.w3.org/TR/json-ld11/#embedding). + + @prefix dc: . + @prefix : . + + :SummerReadingList a :OrderedListOfBooks ; + :toRead ( + [id :mobyDick dc:title "Moby Dick"; :setting :WhaleIntestines ] + [ + id :jaws + dc:title "Jaws"; + :setting :Beach + ] + ). + +Note that the _id_ used in the `iriPropertyList` is not delimited by a `;` + ### Formulae / Quoted Graphs N3 Formulae are introduced with the `{ statement-list }` syntax. A given formula is assigned an `RDF::Node` instance, which is also used as the graph_name for `RDF::Statement` instances provided to `RDF::N3::Reader#each_statement`. For example, the following N3 generates the associated statements: @@ -193,11 +214,11 @@ Formulae are typically used to query the knowledge-base, which is set from the b Blank nodes associated with rdf:List statements used as part of a built-in are made _non-distinguished_ existential variables, and patters containing these variables become optional. If they are not bound as part of the query, the implicitly are bound as the original blank nodes defined within the formula, which allows for both constant list arguments, list arguments that contain variables, or arguments which are variables expanding to lists. ## Dependencies -* [Ruby](https://ruby-lang.org/) (>= 2.6) -* [RDF.rb](https://rubygems.org/gems/rdf) (~> 3.2) -* [EBNF][EBNF gem] (~> 2.2) -* [SPARQL][SPARQL gem] (~> 3.1) -* [SXP][SXP gem] (~> 1.2) +* [Ruby](https://ruby-lang.org/) (>= 3.0) +* [RDF.rb](https://rubygems.org/gems/rdf) (~> 3.3) +* [EBNF][EBNF gem] (~> 2.4) +* [SPARQL][SPARQL gem] (~> 3.3) +* [SXP][SXP gem] (~> 1.3) ## Documentation Full documentation available on [RubyDoc.info](https://ruby-rdf.github.io/rdf-n3) diff --git a/VERSION b/VERSION index e4604e3..15a2799 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -3.2.1 +3.3.0 diff --git a/etc/n3.ebnf b/etc/n3.ebnf index 87d514d..54f5f16 100644 --- a/etc/n3.ebnf +++ b/etc/n3.ebnf @@ -27,14 +27,14 @@ | 'a' | 'has' expression | 'is' expression 'of' - | '<-' expression # Synonym for is expression of + | '=' | '<=' | '=>' - | '=' [13] subject ::= expression - [14] predicate ::= expression + [14] predicate ::= (expression | '<-' expression) + /* allow inverting first predicate in a path */ [15] object ::= expression @@ -47,6 +47,7 @@ | quickVar | collection | blankNodePropertyList + | iriPropertyList | literal | formula @@ -56,45 +57,50 @@ [20] blankNodePropertyList ::= '[' predicateObjectList ']' - [21] collection ::= '(' object* ')' + [21] iriPropertyList ::= IPLSTART iri predicateObjectList ']' + + [22] collection ::= '(' object* ')' - [22] formula ::= '{' formulaContent? '}' + [23] formula ::= '{' formulaContent? '}' - [23] formulaContent ::= n3Statement ('.' formulaContent?)? + [24] formulaContent ::= n3Statement ('.' formulaContent?)? | sparqlDirective formulaContent? - [24] numericLiteral ::= DOUBLE | DECIMAL | INTEGER + [25] numericLiteral ::= DOUBLE | DECIMAL | INTEGER - [25] rdfLiteral ::= STRING (LANGTAG | '^^' iri)? + [26] rdfLiteral ::= STRING (LANGTAG | '^^' iri)? - [26] iri ::= IRIREF | prefixedName + [27] iri ::= IRIREF | prefixedName - [27] prefixedName ::= PNAME_LN | PNAME_NS + [28] prefixedName ::= PNAME_LN | PNAME_NS # PNAME_NS will be matched for ':' (i.e., "empty") prefixedNames # hence this cannot be a lexer rule; for s/p/o of only ':', PNAME_NS will be returned # instead of PrefixedName token - [28] blankNode ::= BLANK_NODE_LABEL | ANON + [29] blankNode ::= BLANK_NODE_LABEL | ANON - [29] quickVar ::= QUICK_VAR_NAME + [30] quickVar ::= QUICK_VAR_NAME # only made this a parser rule for consistency # (all other path-items are also parser rules) @terminals - [30] BOOLEAN_LITERAL ::= 'true' | 'false' + [31] BOOLEAN_LITERAL ::= 'true' | 'false' - [31] STRING ::= STRING_LITERAL_LONG_SINGLE_QUOTE + [32] STRING ::= STRING_LITERAL_LONG_SINGLE_QUOTE | STRING_LITERAL_LONG_QUOTE | STRING_LITERAL_QUOTE | STRING_LITERAL_SINGLE_QUOTE + /* Note, this must be matched before '[' */ + [33] IPLSTART ::= '[' WS* 'id' + /* borrowed from SPARQL spec, which excludes newlines and other nastiness */ - [139s] IRIREF ::= '<' ([^<>"{}|^`\]-[#x00-#x20] | UCHAR | WS)* '>' + [139s] IRIREF ::= '<' ([^<>"{}|^`\]-[#x00-#x20] | UCHAR)* '>' [140s] PNAME_NS ::= PN_PREFIX? ':' [141s] PNAME_LN ::= PNAME_NS PN_LOCAL [142s] BLANK_NODE_LABEL ::= '_:' ( PN_CHARS_U | [0-9] ) ((PN_CHARS|'.')* PN_CHARS)? - [145s] LANGTAG ::= "@" ([a-zA-Z]+ ( "-" [a-zA-Z0-9]+ )*) - ("is" | "has") + [145s] LANGTAG ::= "@" ([a-zA-Z]+ ( "-" [a-zA-Z0-9]+ )*) [146s] INTEGER ::= [0-9]+ [147s] DECIMAL ::= [0-9]* '.' [0-9]+ [148s] DOUBLE ::= [0-9]+ '.' [0-9]* EXPONENT @@ -131,5 +137,3 @@ # Ignore all whitespace and comments between non-terminals @pass ( WS | COMMENT )* - - diff --git a/etc/n3.sxp b/etc/n3.sxp index eee7211..9d2cbbb 100644 --- a/etc/n3.sxp +++ b/etc/n3.sxp @@ -12,45 +12,44 @@ (seq verb objectList (star (seq ";" (opt (seq verb objectList)))))) (rule objectList "11" (seq object (star (seq "," object)))) (rule verb "12" - (alt predicate "a" - (seq "has" expression) - (seq "is" expression "of") - (seq "<-" expression) "<=" "=>" "=" )) + (alt predicate "a" (seq "has" expression) (seq "is" expression "of") "=" "<=" "=>")) (rule subject "13" (seq expression)) - (rule predicate "14" (seq expression)) + (rule predicate "14" (alt expression (seq "<-" expression))) (rule object "15" (seq expression)) (rule expression "16" (seq path)) (rule path "17" (seq pathItem (opt (alt (seq "!" path) (seq "^" path))))) (rule pathItem "18" - (alt iri blankNode quickVar collection blankNodePropertyList literal formula)) + (alt iri blankNode quickVar collection blankNodePropertyList iriPropertyList + literal formula )) (rule literal "19" (alt rdfLiteral numericLiteral BOOLEAN_LITERAL)) (rule blankNodePropertyList "20" (seq "[" predicateObjectList "]")) - (rule collection "21" (seq "(" (star object) ")")) - (rule formula "22" (seq "{" (opt formulaContent) "}")) - (rule formulaContent "23" + (rule iriPropertyList "21" (seq IPLSTART iri predicateObjectList "]")) + (rule collection "22" (seq "(" (star object) ")")) + (rule formula "23" (seq "{" (opt formulaContent) "}")) + (rule formulaContent "24" (alt (seq n3Statement (opt (seq "." (opt formulaContent)))) (seq sparqlDirective (opt formulaContent))) ) - (rule numericLiteral "24" (alt DOUBLE DECIMAL INTEGER)) - (rule rdfLiteral "25" (seq STRING (opt (alt LANGTAG (seq "^^" iri))))) - (rule iri "26" (alt IRIREF prefixedName)) - (rule prefixedName "27" (alt PNAME_LN PNAME_NS)) - (rule blankNode "28" (alt BLANK_NODE_LABEL ANON)) - (rule quickVar "29" (seq QUICK_VAR_NAME)) + (rule numericLiteral "25" (alt DOUBLE DECIMAL INTEGER)) + (rule rdfLiteral "26" (seq STRING (opt (alt LANGTAG (seq "^^" iri))))) + (rule iri "27" (alt IRIREF prefixedName)) + (rule prefixedName "28" (alt PNAME_LN PNAME_NS)) + (rule blankNode "29" (alt BLANK_NODE_LABEL ANON)) + (rule quickVar "30" (seq QUICK_VAR_NAME)) (terminals _terminals (seq)) - (terminal BOOLEAN_LITERAL "30" (alt "true" "false")) - (terminal STRING "31" + (terminal BOOLEAN_LITERAL "31" (alt "true" "false")) + (terminal STRING "32" (alt STRING_LITERAL_LONG_SINGLE_QUOTE STRING_LITERAL_LONG_QUOTE STRING_LITERAL_QUOTE STRING_LITERAL_SINGLE_QUOTE )) + (terminal IPLSTART "33" (seq "[" (star WS) "id")) (terminal IRIREF "139s" - (seq "<" (star (alt (diff (range "^<>\"{}|^`\\") (range "#x00-#x20")) UCHAR WS)) ">")) + (seq "<" (star (alt (diff (range "^<>\"{}|^`\\") (range "#x00-#x20")) UCHAR)) ">")) (terminal PNAME_NS "140s" (seq (opt PN_PREFIX) ":")) (terminal PNAME_LN "141s" (seq PNAME_NS PN_LOCAL)) (terminal BLANK_NODE_LABEL "142s" (seq "_:" (alt PN_CHARS_U (range "0-9")) (opt (seq (star (alt PN_CHARS ".")) PN_CHARS)))) (terminal LANGTAG "145s" - (seq "@" - (diff (seq (plus (range "a-zA-Z")) (star (seq "-" (plus (range "a-zA-Z0-9"))))) (alt "is" "has"))) ) + (seq "@" (seq (plus (range "a-zA-Z")) (star (seq "-" (plus (range "a-zA-Z0-9"))))))) (terminal INTEGER "146s" (plus (range "0-9"))) (terminal DECIMAL "147s" (seq (star (range "0-9")) "." (plus (range "0-9")))) (terminal DOUBLE "148s" diff --git a/lib/rdf/n3/algebra/time/day.rb b/lib/rdf/n3/algebra/time/day.rb index 4e15591..43eb7ea 100644 --- a/lib/rdf/n3/algebra/time/day.rb +++ b/lib/rdf/n3/algebra/time/day.rb @@ -18,8 +18,7 @@ def resolve(resource, position:) case position when :subject return nil unless resource.literal? - resource = resource.as_datetime - RDF::Literal(resource.object.strftime("%d").to_i) + resource.as_datetime.day when :object return nil unless resource.literal? || resource.variable? resource diff --git a/lib/rdf/n3/algebra/time/hour.rb b/lib/rdf/n3/algebra/time/hour.rb index 1a36e8c..068a29e 100644 --- a/lib/rdf/n3/algebra/time/hour.rb +++ b/lib/rdf/n3/algebra/time/hour.rb @@ -18,8 +18,7 @@ def resolve(resource, position:) case position when :subject return nil unless resource.literal? - resource = resource.as_datetime - RDF::Literal(resource.object.strftime("%H").to_i) + resource.as_datetime.hours when :object return nil unless resource.literal? || resource.variable? resource diff --git a/lib/rdf/n3/algebra/time/in_seconds.rb b/lib/rdf/n3/algebra/time/in_seconds.rb index 8fc346b..3e8c88d 100644 --- a/lib/rdf/n3/algebra/time/in_seconds.rb +++ b/lib/rdf/n3/algebra/time/in_seconds.rb @@ -21,9 +21,8 @@ def resolve(resource, position:) when RDF::Query::Variable resource when RDF::Literal - resource = resource.as_datetime # Subject evaluates to seconds from the epoc - RDF::Literal::Integer.new(resource.object.strftime("%s")) + RDF::Literal::Integer.new(resource.as_datetime.object.strftime("%s")) else nil end diff --git a/lib/rdf/n3/algebra/time/minute.rb b/lib/rdf/n3/algebra/time/minute.rb index 02dc5cf..093e9aa 100644 --- a/lib/rdf/n3/algebra/time/minute.rb +++ b/lib/rdf/n3/algebra/time/minute.rb @@ -18,8 +18,7 @@ def resolve(resource, position:) case position when :subject return nil unless resource.literal? - resource = resource.as_datetime - RDF::Literal(resource.object.strftime("%M").to_i) + resource.as_datetime.minutes when :object return nil unless resource.literal? || resource.variable? resource diff --git a/lib/rdf/n3/algebra/time/month.rb b/lib/rdf/n3/algebra/time/month.rb index 222fa54..bae1c84 100644 --- a/lib/rdf/n3/algebra/time/month.rb +++ b/lib/rdf/n3/algebra/time/month.rb @@ -18,8 +18,7 @@ def resolve(resource, position:) case position when :subject return nil unless resource.literal? - resource = resource.as_datetime - RDF::Literal(resource.object.strftime("%m").to_i) + resource.as_datetime.month when :object return nil unless resource.literal? || resource.variable? resource diff --git a/lib/rdf/n3/algebra/time/second.rb b/lib/rdf/n3/algebra/time/second.rb index db1a4b1..cb4b3da 100644 --- a/lib/rdf/n3/algebra/time/second.rb +++ b/lib/rdf/n3/algebra/time/second.rb @@ -18,8 +18,7 @@ def resolve(resource, position:) case position when :subject return nil unless resource.literal? - resource = resource.as_datetime - RDF::Literal(resource.object.strftime("%S").to_i) + RDF::Literal(resource.as_datetime.seconds.to_i) when :object return nil unless resource.literal? || resource.variable? resource diff --git a/lib/rdf/n3/algebra/time/timezone.rb b/lib/rdf/n3/algebra/time/timezone.rb index f1de423..61e305e 100644 --- a/lib/rdf/n3/algebra/time/timezone.rb +++ b/lib/rdf/n3/algebra/time/timezone.rb @@ -18,8 +18,7 @@ def resolve(resource, position:) case position when :subject return nil unless resource.literal? - resource = resource.as_datetime - RDF::Literal(resource.object.strftime("%Z")) + resource.as_datetime.tz when :object return nil unless resource.literal? || resource.variable? resource diff --git a/lib/rdf/n3/algebra/time/year.rb b/lib/rdf/n3/algebra/time/year.rb index 58832bd..3f9c6f6 100644 --- a/lib/rdf/n3/algebra/time/year.rb +++ b/lib/rdf/n3/algebra/time/year.rb @@ -18,8 +18,7 @@ def resolve(resource, position:) case position when :subject return nil unless resource.literal? - resource = resource.as_datetime - RDF::Literal(resource.object.strftime("%Y").to_i) + resource.as_datetime.year when :object return nil unless resource.literal? || resource.variable? resource diff --git a/lib/rdf/n3/format.rb b/lib/rdf/n3/format.rb index b67ac76..5712e24 100644 --- a/lib/rdf/n3/format.rb +++ b/lib/rdf/n3/format.rb @@ -17,7 +17,10 @@ module RDF::N3 # # @see https://www.w3.org/TR/rdf-testcases/#ntriples class Format < RDF::Format - content_type 'text/n3', extension: :n3, aliases: %w(text/rdf+n3;q=0.2 application/rdf+n3;q=0.2) + content_type 'text/n3', + extension: :n3, + aliases: %w(text/rdf+n3;q=0.2 application/rdf+n3;q=0.2), + uri: 'http://www.w3.org/ns/formats/N3' content_encoding 'utf-8' reader { RDF::N3::Reader } diff --git a/lib/rdf/n3/reader.rb b/lib/rdf/n3/reader.rb index ddd3d48..8149ed0 100644 --- a/lib/rdf/n3/reader.rb +++ b/lib/rdf/n3/reader.rb @@ -181,6 +181,7 @@ def each_triple # @!parse none terminal(:ANON, ANON) + terminal(:IPLSTART, IPLSTART) terminal(:BLANK_NODE_LABEL, BLANK_NODE_LABEL) terminal(:IRIREF, IRIREF, unescape: true) terminal(:DOUBLE, DOUBLE) @@ -311,6 +312,9 @@ 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) @@ -435,6 +439,7 @@ def read_path read_quickVar || read_collection || read_blankNodePropertyList || + read_iriPropertyList || read_literal || read_formula end @@ -523,6 +528,28 @@ def read_blankNodePropertyList end end + ## + # Read a iriPropertyList + # + # [21] iriPropertyList ::= IPLSTART iri predicateObjectList ']' + # + # @return [RDF::Node] + 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 collection (`RDF::List`) # diff --git a/lib/rdf/n3/terminals.rb b/lib/rdf/n3/terminals.rb index cc6968b..21dd9ce 100644 --- a/lib/rdf/n3/terminals.rb +++ b/lib/rdf/n3/terminals.rb @@ -64,6 +64,9 @@ module Terminals # 25 STRING_LITERAL_LONG_QUOTE = /"""(?:(?:"|"")?(?:[^"\\]|#{ECHAR}|#{UCHAR}))*"""/um.freeze + # 33 + IPLSTART = /\[\s*id/um.freeze + # 28t PREFIX = /@?prefix/ui.freeze # 29t diff --git a/rdf-n3.gemspec b/rdf-n3.gemspec index 5eb93d8..fc73156 100755 --- a/rdf-n3.gemspec +++ b/rdf-n3.gemspec @@ -25,20 +25,20 @@ Gem::Specification.new do |gem| gem.files = %w(README.md VERSION UNLICENSE) + Dir.glob('lib/**/*.rb') gem.require_paths = %w(lib) - gem.required_ruby_version = '>= 2.6' + gem.required_ruby_version = '>= 3.0' gem.requirements = [] - gem.add_dependency 'ebnf', '~> 2.2' - gem.add_dependency 'rdf', '~> 3.2' - gem.add_dependency 'sparql', '~> 3.2' - gem.add_runtime_dependency 'sxp', '~> 1.2' - - gem.add_development_dependency 'json-ld', '~> 3.2' - gem.add_development_dependency 'rdf-spec', '~> 3.2' - gem.add_development_dependency 'rdf-isomorphic', '~> 3.2' - gem.add_development_dependency 'rdf-trig', '~> 3.2' - gem.add_development_dependency 'rdf-vocab', '~> 3.2' - gem.add_development_dependency 'rspec', '~> 3.10' + gem.add_dependency 'ebnf', '~> 2.4' + gem.add_dependency 'rdf', '~> 3.3' + gem.add_dependency 'sparql', '~> 3.3' + gem.add_runtime_dependency 'sxp', '~> 1.3' + + gem.add_development_dependency 'json-ld', '~> 3.3' + gem.add_development_dependency 'rdf-spec', '~> 3.3' + gem.add_development_dependency 'rdf-isomorphic', '~> 3.3' + gem.add_development_dependency 'rdf-trig', '~> 3.3' + gem.add_development_dependency 'rdf-vocab', '~> 3.3' + gem.add_development_dependency 'rspec', '~> 3.12' gem.add_development_dependency 'rspec-its', '~> 1.3' gem.add_development_dependency 'yard' , '~> 0.9' diff --git a/spec/format_spec.rb b/spec/format_spec.rb index e008b9d..2365bd8 100644 --- a/spec/format_spec.rb +++ b/spec/format_spec.rb @@ -42,6 +42,10 @@ specify {expect(described_class.to_sym).to eq :n3} end + describe "#to_uri" do + specify {expect(described_class.to_uri).to eq RDF::URI('http://www.w3.org/ns/formats/N3')} + end + describe ".detect" do { ntriples: " .", diff --git a/spec/reader_spec.rb b/spec/reader_spec.rb index b6668ba..cc225f0 100644 --- a/spec/reader_spec.rb +++ b/spec/reader_spec.rb @@ -8,6 +8,7 @@ let!(:doap_nt) {File.expand_path("../../etc/doap.nt", __FILE__)} let!(:doap_count) {File.open(doap_nt).each_line.to_a.length} let(:logger) {RDF::Spec.logger} + before {logger.level = Logger::INFO if ENV['CI']} after(:each) do |example| puts logger.to_s if @@ -982,6 +983,85 @@ end end + describe "iriPropertyList" do + { + "not embedded": [ + %([id :s :p :o] .), + %(:s :p :o .) + ], + "with whitespace": [ + %([ id :s :p :o] .), + %(:s :p :o .) + ], + "with linefeed": [ + %([ + id :s + :p :o + ] .), + %(:s :p :o .) + ], + "as a single object": [ + %( + @prefix a: . + a:b a:oneRef [ + id a:node0 + a:pp "1" ; + a:qq "2" + ] . + ), + %( + "1" . + "2" . + . + ) + ], + "nested resources": [ + %( + @prefix a: . + + a:a a:p [ + id a:node1 + a:p2 [ + id a:node0 + a:p3 "v1" , "v2" ; + a:p4 "v3" ] ; + a:p5 "v4" ] . + ), + %( + "v1" . + "v2" . + "v3" . + . + "v4" . + . + ), + ], + "illegal semicolon": [ + %([ id :s ; :p :o]), + :error + ], + "illegal subject list": [ + %([ id :s1, :s2 :p :o]), + :error + ], + "illegal bnode subject": [ + %([ id _:bn :p :o]), + :error + ], + }.each do |title, (n3, res)| + it title do + if res == :error + expect { + parse(n3, base_uri: "http://a/b", validate: true) + }.to raise_error(RDF::ReaderError) + else + expected = RDF::Graph.new {|g| g << RDF::N3::Reader.new(res, base_uri: "http://a/b")} + expect(parse(n3, base_uri: "http://a/b")).to be_equivalent_graph(expected, logger: logger, format: :n3) + end + end + end + end + describe "formulae" do before(:each) { @repo = RDF::N3:: Repository.new } diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 894213f..42d4288 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,13 +1,12 @@ -$:.unshift(File.join(File.dirname(__FILE__), '..', 'lib')) -$:.unshift File.dirname(__FILE__) +$:.unshift(File.expand_path('../../lib', __FILE__)) require "bundler/setup" require 'rspec' -require 'matchers' require 'rdf/isomorphic' require 'rdf/ntriples' require 'rdf/spec' require 'rdf/spec/matchers' +require_relative 'matchers' begin require 'simplecov' diff --git a/spec/suite_extended_spec.rb b/spec/suite_extended_spec.rb index b6efb63..b2fac3e 100644 --- a/spec/suite_extended_spec.rb +++ b/spec/suite_extended_spec.rb @@ -6,6 +6,7 @@ # W3C N3 Test suite from http://www.w3.org/2000/10/swap/test/n3parser.tests describe "w3c n3 tests" do let(:logger) {RDF::Spec.logger} + before {logger.level = Logger::INFO if ENV['CI']} after(:each) do |example| puts logger.to_s if diff --git a/spec/suite_parser_spec.rb b/spec/suite_parser_spec.rb index 3e66336..8871445 100644 --- a/spec/suite_parser_spec.rb +++ b/spec/suite_parser_spec.rb @@ -5,6 +5,7 @@ # W3C N3 Test suite from http://www.w3.org/2000/10/swap/test/n3parser.tests describe "w3c n3 tests" do let(:logger) {RDF::Spec.logger} + before {logger.level = Logger::INFO if ENV['CI']} after(:each) do |example| puts logger.to_s if diff --git a/spec/suite_turtle_spec.rb b/spec/suite_turtle_spec.rb index 3cdc0d7..c7a75d9 100644 --- a/spec/suite_turtle_spec.rb +++ b/spec/suite_turtle_spec.rb @@ -1,5 +1,4 @@ -$:.unshift "." -require 'spec_helper' +require_relative 'spec_helper' describe RDF::N3::Reader do # W3C Turtle Test suite from http://w3c.github.io/rdf-tests/turtle/manifest.ttl @@ -12,6 +11,7 @@ next if t.approval == 'rdft:Rejected' specify "#{t.rel}: #{t.name}: #{t.comment}" do t.logger = RDF::Spec.logger + t.logger.level = Logger::INFO if ENV['CI'] t.logger.info t.inspect t.logger.info "source:\n#{t.input}" diff --git a/spec/writer_spec.rb b/spec/writer_spec.rb index e1184b7..188f026 100644 --- a/spec/writer_spec.rb +++ b/spec/writer_spec.rb @@ -6,6 +6,7 @@ describe RDF::N3::Writer do let(:logger) {RDF::Spec.logger} + before {logger.level = Logger::INFO if ENV['CI']} #after(:each) do |example| # puts logger.to_s if