Skip to content

Commit

Permalink
Finish 3.3.0
Browse files Browse the repository at this point in the history
  • Loading branch information
gkellogg committed Sep 1, 2023
2 parents 8b2c69b + f228897 commit bffe6b6
Show file tree
Hide file tree
Showing 26 changed files with 220 additions and 91 deletions.
14 changes: 4 additions & 10 deletions .github/workflows/ci.yml
Expand Up @@ -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:
Expand All @@ -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 }}
2 changes: 1 addition & 1 deletion .github/workflows/generate-docs.yml
Expand Up @@ -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:
Expand Down
2 changes: 1 addition & 1 deletion Gemfile
Expand Up @@ -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

Expand Down
33 changes: 27 additions & 6 deletions 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)
Expand Down Expand Up @@ -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: <http://purl.org/dc/terms/>.
@prefix : <http://example.org/nd#>.

: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:
Expand Down Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion VERSION
@@ -1 +1 @@
3.2.1
3.3.0
40 changes: 22 additions & 18 deletions etc/n3.ebnf
Expand Up @@ -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

Expand All @@ -47,6 +47,7 @@
| quickVar
| collection
| blankNodePropertyList
| iriPropertyList
| literal
| formula

Expand All @@ -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
Expand Down Expand Up @@ -131,5 +137,3 @@

# Ignore all whitespace and comments between non-terminals
@pass ( WS | COMMENT )*


39 changes: 19 additions & 20 deletions etc/n3.sxp
Expand Up @@ -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"
Expand Down
3 changes: 1 addition & 2 deletions lib/rdf/n3/algebra/time/day.rb
Expand Up @@ -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
Expand Down
3 changes: 1 addition & 2 deletions lib/rdf/n3/algebra/time/hour.rb
Expand Up @@ -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
Expand Down
3 changes: 1 addition & 2 deletions lib/rdf/n3/algebra/time/in_seconds.rb
Expand Up @@ -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
Expand Down
3 changes: 1 addition & 2 deletions lib/rdf/n3/algebra/time/minute.rb
Expand Up @@ -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
Expand Down
3 changes: 1 addition & 2 deletions lib/rdf/n3/algebra/time/month.rb
Expand Up @@ -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
Expand Down
3 changes: 1 addition & 2 deletions lib/rdf/n3/algebra/time/second.rb
Expand Up @@ -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
Expand Down
3 changes: 1 addition & 2 deletions lib/rdf/n3/algebra/time/timezone.rb
Expand Up @@ -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
Expand Down
3 changes: 1 addition & 2 deletions lib/rdf/n3/algebra/time/year.rb
Expand Up @@ -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
Expand Down
5 changes: 4 additions & 1 deletion lib/rdf/n3/format.rb
Expand Up @@ -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 }
Expand Down

0 comments on commit bffe6b6

Please sign in to comment.