ShEx: Shape Expression language for Ruby

This is a pure-Ruby library for working with the Shape Expressions Language to validate the shape of RDF graphs.

http://ruby-rdf.github.com/shex

Gem Version Build Status Coverage Status Join the chat at https://gitter.im/ruby-rdf/rdf

Features

Description

The ShEx gem implements a ShEx Shape Expression engine.

Examples

Validating a node using ShExC

require 'rubygems'
require 'rdf/turtle'
require 'shex'

shexc: %(
  PREFIX doap:  <http://usefulinc.com/ns/doap#>
  PREFIX dc:    <http://purl.org/dc/terms/>
  <TestShape> EXTRA a {
    a doap:Project;
    (doap:name;doap:description|dc:title;dc:description)+;
    doap:category*;
    doap:developer IRI;
    doap:implements    [<http://shex.io/shex-semantics/>]
  }
)
graph = RDF::Graph.load("etc/doap.ttl")
schema = ShEx.parse(shexc)
map = {
  "http://rubygems.org/gems/shex" => "TestShape"
}
schema.satisfies?("http://rubygems.org/gems/shex", graph, map)
# => true ### Validating a node using ShExJ

require 'rubygems'
require 'rdf/turtle'
require 'shex'

shexj: %({
  "type": "Schema",
  "prefixes": {
    "doap": "http://usefulinc.com/ns/doap#",
    "dc": "http://purl.org/dc/terms/"
  },
  "shapes": {
    "TestShape": {
      "type": "Shape",
      "extra": ["http://www.w3.org/1999/02/22-rdf-syntax-ns#type"],
      "expression": {
        "type": "EachOf",
        "expressions": [
          {
            "type": "TripleConstraint",
            "predicate": "http://www.w3.org/1999/02/22-rdf-syntax-ns#type",
            "valueExpr": {
              "type": "NodeConstraint",
              "values": ["http://usefulinc.com/ns/doap#Project"]
            }
          },
          {
            "type": "OneOf",
            "expressions": [
              {
                "type": "EachOf",
                "expressions": [
                  {
                    "type": "TripleConstraint",
                    "predicate": "http://usefulinc.com/ns/doap#name",
                    "valueExpr": {"type": "NodeConstraint", "nodeKind": "literal"}
                  },
                  {
                    "type": "TripleConstraint",
                    "predicate": "http://usefulinc.com/ns/doap#description",
                    "valueExpr": {"type": "NodeConstraint", "nodeKind": "literal"}
                  }
                ]
              },
              {
                "type": "EachOf",
                "expressions": [
                  {
                    "type": "TripleConstraint",
                    "predicate": "http://purl.org/dc/terms/title",
                    "valueExpr": {"type": "NodeConstraint", "nodeKind": "literal"}
                  },
                  {
                    "type": "TripleConstraint",
                    "predicate": "http://purl.org/dc/terms/description",
                    "valueExpr": {"type": "NodeConstraint", "nodeKind": "literal"}
                  }
                ]
              }
            ],
            "min": 1, "max": -1
          },
          {
            "type": "TripleConstraint",
            "predicate": "http://usefulinc.com/ns/doap#category",
            "valueExpr": {"type": "NodeConstraint", "nodeKind": "iri"},
            "min": 0, "max": -1
          },
          {
            "type": "TripleConstraint",
            "predicate": "http://usefulinc.com/ns/doap#developer",
            "valueExpr": {"type": "NodeConstraint", "nodeKind": "iri"},
            "min": 1, "max": -1
          },
          {
            "type": "TripleConstraint",
            "predicate": "http://usefulinc.com/ns/doap#implements",
            "valueExpr": {
              "type": "NodeConstraint",
              "values": ["http://shex.io/shex-semantics/"]
            }
          }
        ]
      }
    }
  }
})
graph = RDF::Graph.load("etc/doap.ttl")
schema = ShEx.parse(shexj, format: :shexj)
map = {"http://rubygems.org/gems/shex" => "TestShape"}
schema.satisfies?("http://rubygems.org/gems/shex", graph, map)
# => true

Extensions

ShEx has an extension mechanism using Semantic Actions. Extensions may be implemented in Ruby ShEx by sub-classing {ShEx::Extension} and implementing {ShEx::Extension#visit} and possibly {ShEx::Extension#initialize}, {ShEx::Extension#enter}, {ShEx::Extension#exit}, and {ShEx::Extension#close}. The #visit method will be called as part of the #satisfies? operation.

require 'shex'
class ShEx::Test < ShEx::Extension("http://shex.io/extensions/Test/")
  # (see ShEx::Extension#initialize)
  def initialize(schema: nil, logger: nil, depth: 0, **options)
    ...
  end

  # (see ShEx::Extension#visit)
  def visit(code: nil, matched: nil, expression: nil, depth: 0, **options)
    ...
  end
end

The #enter method will be called on any {ShEx::Algebra::TripleExpression} that includes a {ShEx::Algebra::SemAct} referencing the extension, while the #exit method will be called on exit, even if not satisfied.

The #initialize method is called when {ShEx::Algebra::Schema#execute} starts and #close called on exit, even if not satisfied.

To make sure your extension is found, make sure to require it before the shape is executed.

Documentation

http://rubydoc.info/github/ruby-rdf/shex

Implementation Notes

The ShExC parser uses the EBNF gem to generate first, follow and branch tables, and uses the Parser and Lexer modules to implement the ShExC parser.

The parser takes branch and follow tables generated from the ShEx Grammar described in the specification. Branch and Follow tables are specified in the generated {ShEx::Meta}.

The result of parsing either ShExC or ShExJ is the creation of a set of executable {ShEx::Algebra} Operators which are directly executed to perform shape validation.

Dependencies

Installation

The recommended installation method is via RubyGems. To install the latest official release of RDF.rb, do:

% [sudo] gem install shex

Download

To get a local working copy of the development repository, do:

% git clone git://github.com/ruby-rdf/shex.git

Alternatively, download the latest development version as a tarball as follows:

% wget http://github.com/ruby-rdf/shex/tarball/master

Resources

Mailing List

Author

Contributing

This repository uses Git Flow to mange development and release activity. All submissions must be on a feature branch based on the develop branch to ease staging and integration.

License

This is free and unencumbered public domain software. For more information, see http://unlicense.org/ or the accompanying {file:LICENSE} file.