Ruben Taelman, Joachim Van Herwegen
Portorož, Slovenia, 3 June 2019
Ghent University – imec – IDLab, Belgium
The easiest way to add components is by manually adding instances.
const myCar = new Car();
myCar.add(new EngineV8());
myCar.add(new TireMichelin());
myCar.add(new TireMichelin());
myCar.add(new TireMichelin());
myCar.add(new TireMichelin());
Downside: swapping components requires code changes.
Dependency Injection: Components are supplied by something external.
Components can be defined declaratively via a configuration file.
const myCar = CarFactory.instantiateCar('car-config.json');
car-config.json:
[
"EngineV8",
"TireMichelin",
"TireMichelin",
"TireMichelin",
"TireMichelin"
]
Components.js: A dependency injection framework for JavaScript
Components are described in a semantic configuration file
→ A semantic layer on top of your source code
→ Configuration files could also be used for other programming languages
Comunica uses Components.js to wire actors, buses and mediators
Module: Collection of components (e.g., a software package)
↓
Component: Something that can be instantiated (e.g., a class)
↓
Instance: An instantiated Component
Each module is published as a separate NPM package.
@comunica/actor-query-operation-distinct-hash:ActorQueryOperationDistinctHash@comunica/actor-query-operation-construct:ActorQueryOperationConstructWe use import statements to refer to components in different files.
{
"@context": …,
"@id": "npmd:@comunica/actor-query-operation-distinct-hash",
"@type": "Module",
"requireName": "@comunica/actor-query-operation-distinct-hash",
"import": [
"files:components/Actor/QueryOperation/DistinctHash.jsonld",
…
]
}
{
…
"components": [
{
"@id": "Actor/QueryOperation/DistinctHash",
"requireElement": "ActorQueryOperationDistinctHash",
"parameters": [
{
"@id": "hashAlgorithm",
"default": "sha1"
},
{
"@id": "digestAlgorithm",
"default": "base64"
}
}
]
}
Components.js supports any kind of RDF serialization: Turtle, N-Triples, ...
For developers that are familiar with JSON
To achieve semantic RDF-based configurations:
Modules, components and instances have a unique URL.
Others can reuse them by simply linking to them → distributed config files
Fetch them from anywhere (browser, query engine, ...)
npmd:@comunica/actor-query-operation-distinct-hash expands to https://linkedsoftwaredependencies.org/bundles/npm/%40comunica%2Factor-query-operation-distinct-hash/1.4.4/components/Actor/QueryOperation/DistinctHash.jsonld
@type of an instance is a Component (IRI)
{
"@context": …,
"@id": "urn:comunica:my",
"actors": [
{
"@id": "#myDistinctQueryOperator",
"@type": "ActorQueryOperationDistinctHash",
"hashAlgorithm": "RSA-SHA256"
},
{
"@id": "#myConstructQueryOperator",
"@type": "ActorQueryOperationConstruct"
},
…
]
}
Goal: Implementing, configuring, and using a custom REDUCED actor.
REDUCED: A best-effort variant of SPARQL's DISTINCT.
Example:
?var: 'B'
?var: 'A'
?var: 'A'
?var: 'B'
?var: 'B'
REDUCED→
?var: 'B'
?var: 'A'
?var: 'B'
REDUCED implementation: Actual JavaScript implementation.
Each step can be skipped by checking out a different git tag.
For example, show the solution of step 2: git checkout tutorial-step/2
$ git clone https://github.com/comunica/Tutorial-Comunica-Reduced-Actor
$ cd Tutorial-Comunica-Reduced-Actor
$ git checkout tutorial-step/1
Each step is explained in detail on GitHub wiki:
https://github.com/comunica/Tutorial-Comunica-Reduced-Actor