Scalanvas is a Scala library for creating Shared Canvas manifests from other document representations (TEI, etc.). It's built on the W3C's banana-rdf library, and uses jsonld-java for JSON-LD serialization.
Once you've checked out this repository, all you need is an installation
of the Java Runtime Environment (version 6 or newer). Running ./sbt
and then typing project scalanvas-core
in the console will load a shell
that will allow you to interactively use these libraries.
See the edu.umd.mith.sga.frankenstein.Builder
object for sample programmatic usage.
If you just need to build the Shelley-Godwin Archive manifests,
see the builder.scala
file linked in the preceding subsection.
At the top of this file you'll find a configuration trait with
a local path to the Shelley-Godwin Archive TEI files. Change the
value of this path to match the location on your local system.
After making this change, run ./sbt
to launch the SBT console.
At the prompt, run project scalanvas-core
, and then run
. You'll
be asked whether you want the development or production manifests:
> run
Multiple main classes detected, select one to run:
[1] edu.umd.mith.sga.frankenstein.DevelopmentBuilder
[2] edu.umd.mith.sga.frankenstein.ProductionBuilder
Enter number:
Type 1
or 2
as appropriate and hit enter. After a few minutes you'll have your
files in the ./output
directory.
For production we want to compact the JSON by removing unnecessary
whitespace and then compress the files with Gzip to allow Nginx to
avoid compressing the files on every request. This process is taken
care of by the scripts/compact.sh
script, which you can run from the
project root, and which will give you a compact.tgz
file ready for
deployment.
I know this process is a mess, but we're under the gun, and it'll be easy to streamline in the near future.
This repository also includes a demonstration of how Scala 2.10's macro system can be used to parse RDF schemas at compile time to produce Scala bindings. So, for example, instead of writing something like this:
class OREPrefix[Rdf <: RDF](ops: RDFOps[Rdf])
extends PrefixBuilder("ore", "http://www.openarchives.org/ore/terms/")(ops) {
val aggregates = apply("aggregates")
val describes = apply("describes")
val isDescribedBy = apply("isDescribedBy")
val Aggregation = apply("Aggregation")
val ResourceMap = apply("ResourceMap")
// And so on...
}
object OREPrefix {
def apply[Rdf <: RDF](implicit ops: RDFOps[Rdf]) = new OREPrefix[Rdf](ops)
}
And then eventually:
val ore = OREPrefix[Rdf]
We can just write the following:
val ore = PrefixGenerator.fromSchema(
"http://www.openarchives.org/ore/terms/",
"ore",
"/edu/umd/mith/scalanvas/schemas/oreterms.rdf"
)
Now the RDF schema at the indicated resource path will be parsed at
compile time, and we'll have an anonymous subclass of Prefix
with
all of the members of our OREPrefix
above added for us. This approach
is less tedious, less error-prone, and much easier to maintain in the
case of changing schemas.