rdf 1.99.1 → 2.0.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/{README → README.md} +9 -44
- data/VERSION +1 -1
- data/bin/rdf +1 -1
- data/lib/rdf.rb +40 -49
- data/lib/rdf/changeset.rb +161 -0
- data/lib/rdf/cli.rb +195 -33
- data/lib/rdf/cli/vocab-loader.rb +13 -3
- data/lib/rdf/format.rb +44 -26
- data/lib/rdf/mixin/enumerable.rb +133 -97
- data/lib/rdf/mixin/enumerator.rb +8 -0
- data/lib/rdf/mixin/indexable.rb +1 -1
- data/lib/rdf/mixin/mutable.rb +101 -22
- data/lib/rdf/mixin/queryable.rb +21 -32
- data/lib/rdf/mixin/transactable.rb +94 -0
- data/lib/rdf/mixin/writable.rb +12 -3
- data/lib/rdf/model/dataset.rb +48 -0
- data/lib/rdf/model/graph.rb +73 -43
- data/lib/rdf/model/list.rb +61 -33
- data/lib/rdf/model/literal.rb +20 -19
- data/lib/rdf/model/literal/double.rb +20 -4
- data/lib/rdf/model/literal/numeric.rb +15 -13
- data/lib/rdf/model/node.rb +15 -16
- data/lib/rdf/model/statement.rb +1 -43
- data/lib/rdf/model/term.rb +10 -8
- data/lib/rdf/model/uri.rb +35 -34
- data/lib/rdf/model/value.rb +1 -1
- data/lib/rdf/nquads.rb +2 -11
- data/lib/rdf/ntriples.rb +1 -1
- data/lib/rdf/ntriples/reader.rb +33 -46
- data/lib/rdf/ntriples/writer.rb +42 -5
- data/lib/rdf/query.rb +6 -40
- data/lib/rdf/query/pattern.rb +4 -17
- data/lib/rdf/query/solutions.rb +6 -6
- data/lib/rdf/reader.rb +65 -14
- data/lib/rdf/repository.rb +365 -229
- data/lib/rdf/transaction.rb +211 -84
- data/lib/rdf/util.rb +1 -0
- data/lib/rdf/util/cache.rb +5 -5
- data/lib/rdf/util/file.rb +12 -9
- data/lib/rdf/util/logger.rb +272 -0
- data/lib/rdf/version.rb +2 -2
- data/lib/rdf/vocab/owl.rb +82 -77
- data/lib/rdf/vocab/rdfs.rb +22 -17
- data/lib/rdf/vocab/xsd.rb +5 -0
- data/lib/rdf/vocabulary.rb +50 -56
- data/lib/rdf/writer.rb +104 -52
- metadata +45 -90
- data/lib/rdf/mixin/inferable.rb +0 -5
- data/lib/rdf/vocab/cc.rb +0 -128
- data/lib/rdf/vocab/cert.rb +0 -245
- data/lib/rdf/vocab/dc.rb +0 -948
- data/lib/rdf/vocab/dc11.rb +0 -167
- data/lib/rdf/vocab/dcat.rb +0 -214
- data/lib/rdf/vocab/doap.rb +0 -337
- data/lib/rdf/vocab/exif.rb +0 -941
- data/lib/rdf/vocab/foaf.rb +0 -614
- data/lib/rdf/vocab/geo.rb +0 -157
- data/lib/rdf/vocab/gr.rb +0 -1501
- data/lib/rdf/vocab/ht.rb +0 -236
- data/lib/rdf/vocab/ical.rb +0 -528
- data/lib/rdf/vocab/ma.rb +0 -513
- data/lib/rdf/vocab/mo.rb +0 -2412
- data/lib/rdf/vocab/og.rb +0 -222
- data/lib/rdf/vocab/ogc.rb +0 -58
- data/lib/rdf/vocab/prov.rb +0 -1550
- data/lib/rdf/vocab/rsa.rb +0 -72
- data/lib/rdf/vocab/rss.rb +0 -66
- data/lib/rdf/vocab/schema.rb +0 -10569
- data/lib/rdf/vocab/sioc.rb +0 -669
- data/lib/rdf/vocab/skos.rb +0 -238
- data/lib/rdf/vocab/skosxl.rb +0 -57
- data/lib/rdf/vocab/v.rb +0 -383
- data/lib/rdf/vocab/vcard.rb +0 -841
- data/lib/rdf/vocab/vmd.rb +0 -383
- data/lib/rdf/vocab/void.rb +0 -186
- data/lib/rdf/vocab/vs.rb +0 -28
- data/lib/rdf/vocab/wdrs.rb +0 -134
- data/lib/rdf/vocab/wot.rb +0 -167
- data/lib/rdf/vocab/xhtml.rb +0 -8
- data/lib/rdf/vocab/xhv.rb +0 -505
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d6b5ce1d8969fb6463efd82a7fe9826589bac799
|
4
|
+
data.tar.gz: e0c0066693ddc81d5089bf63f7502527750d1380
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f866ac2a48e98e154bd786f6e0c30f5298e70c01de47847c660fded022f14ef58f19b0a727e20a53704d0d46f610cae4f53a08b5b2b94dc5f82d85da006e9d0b
|
7
|
+
data.tar.gz: ccede9fff108419d7d0df702df4dd8e8a24bd53be1e0aa0bd1a1986158ff5dcdbfd7bb824eb36cbe1dc0ea41243732bb49f0aec5dbbf869721595911e7f39709
|
data/{README → README.md}
RENAMED
@@ -11,6 +11,8 @@ This is a pure-Ruby library for working with [Resource Description Framework
|
|
11
11
|
|
12
12
|
[![Gem Version](https://badge.fury.io/rb/rdf.png)](http://badge.fury.io/rb/rdf)
|
13
13
|
[![Build Status](https://travis-ci.org/ruby-rdf/rdf.png?branch=master)](http://travis-ci.org/ruby-rdf/rdf)
|
14
|
+
[![Code Climate](https://codeclimate.com/github/ruby-rdf/rdf/badges/gpa.svg)](https://codeclimate.com/github/ruby-rdf/rdf)
|
15
|
+
[![Coverage Status](https://coveralls.io/repos/ruby-rdf/rdf/badge.svg)](https://coveralls.io/r/ruby-rdf/rdf)
|
14
16
|
[![Join the chat at https://gitter.im/ruby-rdf/rdf](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/ruby-rdf/rdf?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
15
17
|
|
16
18
|
## Features
|
@@ -28,8 +30,7 @@ This is a pure-Ruby library for working with [Resource Description Framework
|
|
28
30
|
not modify any of Ruby's core classes or standard library.
|
29
31
|
* Based entirely on Ruby's autoloading, meaning that you can generally make
|
30
32
|
use of any one part of the library without needing to load up the rest.
|
31
|
-
* Compatible with Ruby Ruby
|
32
|
-
* Compatible with older Ruby versions with the help of the [Backports][] gem.
|
33
|
+
* Compatible with Ruby Ruby 2.x, Rubinius and JRuby 1.7+ (in Ruby 2.0 mode).
|
33
34
|
* Performs auto-detection of input to select appropriate Reader class if one
|
34
35
|
cannot be determined from file characteristics.
|
35
36
|
|
@@ -50,12 +51,12 @@ the 1.1 release of RDF.rb:
|
|
50
51
|
* Introduces {RDF::IRI}, as a synonym for {RDF::URI} either {RDF::IRI} or {RDF::URI} can be used interchangeably. Versions of RDF.rb prior to the 1.1 release were already compatible with IRIs. Internationalized Resource Identifiers (see [RFC3987][]) are a super-set of URIs (see [RFC3986][]) which allow for characters other than standard US-ASCII.
|
51
52
|
* {RDF::URI} no longer uses the `Addressable` gem. As URIs typically don't need to be parsed, this provides a substantial performance improvement when enumerating or querying graphs and repositories.
|
52
53
|
* {RDF::List} no longer emits a `rdf:List` type. However, it will now recognize any subjects that are {RDF::Node} instances as being list elements, as long as they have both `rdf:first` and `rdf:rest` predicates.
|
53
|
-
* {RDF::Graph} adding a `
|
54
|
+
* {RDF::Graph} adding a `graph_name` to a graph may only be done when the underlying storage model supports graph_names (the default {RDF::Repository} does). The notion of `graph_name` in RDF.rb is treated equivalently to [Named Graphs](http://www.w3.org/TR/rdf11-concepts/#dfn-named-graph) within an RDF Dataset, and graphs on their own are not named.
|
54
55
|
* {RDF::Graph}, {RDF::Statement} and {RDF::List} now include {RDF::Value}, and not {RDF::Resource}. Made it clear that using {RDF::Graph} does not mean that it may be used within an {RDF::Statement}, for this see {RDF::Term}.
|
55
56
|
* {RDF::Statement} now is stricter about checking that all elements are valid when validating.
|
56
57
|
* {RDF::NTriples::Writer} and {RDF::NQuads::Writer} now default to validate output, only allowing valid statements to be emitted. This may disabled by setting the `:validate` option to `false`.
|
57
58
|
* {RDF::Dataset} is introduced as a class alias of {RDF::Repository}. This allows closer alignment to the RDF concept of [Dataset](http://www.w3.org/TR/rdf11-concepts/#dfn-dataset).
|
58
|
-
* The `
|
59
|
+
* The `graph_name` of a graph within a Dataset or Repository may be either an {RDF::IRI} or {RDF::Node}. Implementations of repositories may restrict this to being only {RDF::IRI}.
|
59
60
|
* There are substantial and somewhat incompatible changes to {RDF::Literal}. In [RDF 1.1][], all literals are typed, including plain literals and language tagged literals. Internally, plain literals are given the `xsd:string` datatype and language tagged literals are given the `rdf:langString` datatype. Creating a plain literal, without a datatype or language, will automatically provide the `xsd:string` datatype; similar for language tagged literals. Note that most serialization formats will remove this datatype. Code which depends on a literal having the `xsd:string` datatype being different from a plain literal (formally, without a datatype) may break. However note that the `#has\_datatype?` will continue to return `false` for plain or language-tagged literals.
|
60
61
|
* {RDF::Query#execute} now accepts a block and returns {RDF::Query::Solutions}. This allows `enumerable.query(query)` to behave like `query.execute(enumerable)` and either return an enumerable or yield each solution.
|
61
62
|
* {RDF::Queryable#query} now returns {RDF::Query::Solutions} instead of an Enumerator if it's argument is an {RDF::Query}.
|
@@ -146,7 +147,7 @@ appropriate writer to use.
|
|
146
147
|
|
147
148
|
RDF::Writer.open("hello.nq", format: :nquads) do |writer|
|
148
149
|
writer << RDF::Repository.new do |repo|
|
149
|
-
repo << RDF::Statement.new(:hello, RDF::RDFS.label, "Hello, world!",
|
150
|
+
repo << RDF::Statement.new(:hello, RDF::RDFS.label, "Hello, world!", graph_name: RDF::URI("http://example/graph_name"))
|
150
151
|
end
|
151
152
|
end
|
152
153
|
|
@@ -154,7 +155,7 @@ A specific sub-type of Writer can also be invoked directly:
|
|
154
155
|
|
155
156
|
require 'rdf/nquads'
|
156
157
|
|
157
|
-
repo = RDF::Repository.new << RDF::Statement.new(:hello, RDF::RDFS.label, "Hello, world!",
|
158
|
+
repo = RDF::Repository.new << RDF::Statement.new(:hello, RDF::RDFS.label, "Hello, world!", graph_name: RDF::URI("http://example/graph_name"))
|
158
159
|
File.open("hello.nq", "w") {|f| f << repo.dump(:nquads)}
|
159
160
|
|
160
161
|
## Reader/Writer convenience methods
|
@@ -298,7 +299,6 @@ from BNode identity (i.e., they each entail the other)
|
|
298
299
|
* {RDF::Countable}
|
299
300
|
* {RDF::Enumerable}
|
300
301
|
* {RDF::Indexable}
|
301
|
-
* {RDF::Inferable}
|
302
302
|
* {RDF::Queryable}
|
303
303
|
* {RDF::Mutable}
|
304
304
|
* {RDF::Durable}
|
@@ -327,44 +327,10 @@ from BNode identity (i.e., they each entail the other)
|
|
327
327
|
* {RDF::RDFV} - RDF Vocabulary (RDFV)
|
328
328
|
* {RDF::XSD} - XML Schema (XSD)
|
329
329
|
|
330
|
-
#### Deprecated Vocabularies
|
331
|
-
|
332
|
-
The following vocabularies will be deprecated in RDF.rb 2.0 and moved to the rdf-vocab gem.
|
333
|
-
|
334
|
-
* {RDF::CC} - Creative Commons (CC)
|
335
|
-
* {RDF::CERT} - W3 Authentication Certificate (CERT)
|
336
|
-
* {RDF::DC} - Dublin Core (DC)
|
337
|
-
* {RDF::DC11} - Dublin Core 1.1 (DC11) _deprecated_
|
338
|
-
* {RDF::DOAP} - Description of a Project (DOAP)
|
339
|
-
* {RDF::EXIF} - Exchangeable Image File Format (EXIF)
|
340
|
-
* {RDF::FOAF} - Friend of a Friend (FOAF)
|
341
|
-
* {RDF::GEO} - WGS84 Geo Positioning (GEO)
|
342
|
-
* {RDF::GR} - GoodRelations (GR)
|
343
|
-
* {RDF::HT} - Hypertext Transfer Protocol (HT)
|
344
|
-
* {RDF::ICAL} - RDF Calendar Workspace (ICAL)
|
345
|
-
* {RDF::MA} - Media Resources (MA)
|
346
|
-
* {RDF::MO} - Music Ontology (MO)
|
347
|
-
* {RDF::OG} - Open Graph protocol (OG)
|
348
|
-
* {RDF::PROV} - Provenance on the web (PROV)
|
349
|
-
* {RDF::RSA} - W3 RSA Keys (RSA)
|
350
|
-
* {RDF::RSS} - RDF Site Summary (RSS)
|
351
|
-
* {RDF::SCHEMA} - Schema.org (SCHEMA)
|
352
|
-
* {RDF::SIOC} - Semantically-Interlinked Online Communities (SIOC)
|
353
|
-
* {RDF::SKOS} - Simple Knowledge Organization System (SKOS)
|
354
|
-
* {RDF::SKOSXL} - SKOS eXtension for Labels (SKOSXL)
|
355
|
-
* {RDF::V} - RDF data vocabulary (V)
|
356
|
-
* {RDF::VCARD} - Ontology for vCards (VCARD)
|
357
|
-
* {RDF::VMD} - Data-Vocabulary.org (VMD)
|
358
|
-
* {RDF::VOID} - Vocabulary of Interlinked Datasets (VOID)
|
359
|
-
* {RDF::VS} - SemWeb Vocab Status ontology (VS)
|
360
|
-
* {RDF::WDRS} - Protocol for Web Description Resources (WDRS)
|
361
|
-
* {RDF::WOT} - Web of Trust (WOT)
|
362
|
-
* {RDF::XHTML} - Extensible HyperText Markup Language (XHTML)
|
363
|
-
* {RDF::XHV} - XHTML Vocabulary (XHV)
|
364
330
|
|
365
331
|
## Dependencies
|
366
332
|
|
367
|
-
* [Ruby](http://ruby-lang.org/) (>=
|
333
|
+
* [Ruby](http://ruby-lang.org/) (>= 2.0)
|
368
334
|
* [LinkHeader][] (>= 0.0.8)
|
369
335
|
* Soft dependency on [RestClient][] (>= 1.7)
|
370
336
|
|
@@ -373,7 +339,7 @@ The following vocabularies will be deprecated in RDF.rb 2.0 and moved to the rdf
|
|
373
339
|
The recommended installation method is via [RubyGems](http://rubygems.org/).
|
374
340
|
To install the latest official release of RDF.rb, do:
|
375
341
|
|
376
|
-
% [sudo] gem install rdf # Ruby
|
342
|
+
% [sudo] gem install rdf # Ruby 2+
|
377
343
|
|
378
344
|
## Download
|
379
345
|
|
@@ -452,7 +418,6 @@ see <http://unlicense.org/> or the accompanying {file:UNLICENSE} file.
|
|
452
418
|
[YARD]: http://yardoc.org/
|
453
419
|
[YARD-GS]: http://rubydoc.info/docs/yard/file/docs/GettingStarted.md
|
454
420
|
[PDD]: http://lists.w3.org/Archives/Public/public-rdf-ruby/2010May/0013.html
|
455
|
-
[Backports]: http://rubygems.org/gems/backports
|
456
421
|
[JSONLD doc]: http://rubydoc.info/github/ruby-rdf/json-ld/frames
|
457
422
|
[LinkedData doc]: http://rubydoc.info/github/datagraph/linkeddata/master/frames
|
458
423
|
[Microdata doc]: http://rubydoc.info/github/ruby-rdf/rdf-microdata/frames
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
2.0.0.beta1
|
data/bin/rdf
CHANGED
@@ -5,7 +5,7 @@ require 'rdf/cli'
|
|
5
5
|
|
6
6
|
options = RDF::CLI.options do
|
7
7
|
self.on('-v', '--verbose', 'Enable verbose output. May be given more than once.') do
|
8
|
-
|
8
|
+
self.options[:logger].level = Logger::INFO
|
9
9
|
end
|
10
10
|
|
11
11
|
self.on('-V', '--version', 'Display the RDF.rb version and exit.') do
|
data/lib/rdf.rb
CHANGED
@@ -7,72 +7,61 @@ require 'rdf/version'
|
|
7
7
|
|
8
8
|
module RDF
|
9
9
|
# RDF mixins
|
10
|
-
autoload :Countable,
|
11
|
-
autoload :Durable,
|
12
|
-
autoload :Enumerable,
|
13
|
-
autoload :Indexable,
|
14
|
-
autoload :
|
15
|
-
autoload :
|
16
|
-
autoload :
|
17
|
-
autoload :
|
18
|
-
autoload :
|
19
|
-
autoload :Writable,
|
10
|
+
autoload :Countable, 'rdf/mixin/countable'
|
11
|
+
autoload :Durable, 'rdf/mixin/durable'
|
12
|
+
autoload :Enumerable, 'rdf/mixin/enumerable'
|
13
|
+
autoload :Indexable, 'rdf/mixin/indexable'
|
14
|
+
autoload :Mutable, 'rdf/mixin/mutable'
|
15
|
+
autoload :Queryable, 'rdf/mixin/queryable'
|
16
|
+
autoload :Readable, 'rdf/mixin/readable'
|
17
|
+
autoload :TypeCheck, 'rdf/mixin/type_check'
|
18
|
+
autoload :Transactable, 'rdf/mixin/transactable'
|
19
|
+
autoload :Writable, 'rdf/mixin/writable'
|
20
20
|
|
21
21
|
# RDF objects
|
22
|
-
autoload :Graph,
|
23
|
-
autoload :IRI,
|
24
|
-
autoload :Literal,
|
25
|
-
autoload :Node,
|
26
|
-
autoload :Resource,
|
27
|
-
autoload :Statement,
|
28
|
-
autoload :URI,
|
29
|
-
autoload :Value,
|
30
|
-
autoload :Term,
|
22
|
+
autoload :Graph, 'rdf/model/graph'
|
23
|
+
autoload :IRI, 'rdf/model/uri'
|
24
|
+
autoload :Literal, 'rdf/model/literal'
|
25
|
+
autoload :Node, 'rdf/model/node'
|
26
|
+
autoload :Resource, 'rdf/model/resource'
|
27
|
+
autoload :Statement, 'rdf/model/statement'
|
28
|
+
autoload :URI, 'rdf/model/uri'
|
29
|
+
autoload :Value, 'rdf/model/value'
|
30
|
+
autoload :Term, 'rdf/model/term'
|
31
31
|
|
32
32
|
# RDF collections
|
33
|
-
autoload :List,
|
33
|
+
autoload :List, 'rdf/model/list'
|
34
34
|
|
35
35
|
# RDF serialization
|
36
|
-
autoload :Format,
|
37
|
-
autoload :Reader,
|
38
|
-
autoload :ReaderError,
|
39
|
-
autoload :Writer,
|
40
|
-
autoload :WriterError,
|
36
|
+
autoload :Format, 'rdf/format'
|
37
|
+
autoload :Reader, 'rdf/reader'
|
38
|
+
autoload :ReaderError, 'rdf/reader'
|
39
|
+
autoload :Writer, 'rdf/writer'
|
40
|
+
autoload :WriterError, 'rdf/writer'
|
41
41
|
|
42
42
|
# RDF serialization formats
|
43
|
-
autoload :NTriples,
|
44
|
-
autoload :NQuads,
|
43
|
+
autoload :NTriples, 'rdf/ntriples'
|
44
|
+
autoload :NQuads, 'rdf/nquads'
|
45
45
|
|
46
46
|
# RDF storage
|
47
|
-
autoload :
|
48
|
-
autoload :
|
49
|
-
autoload :
|
47
|
+
autoload :Changeset, 'rdf/changeset'
|
48
|
+
autoload :Dataset, 'rdf/model/dataset'
|
49
|
+
autoload :Repository, 'rdf/repository'
|
50
|
+
autoload :Transaction, 'rdf/transaction'
|
50
51
|
|
51
52
|
# RDF querying
|
52
|
-
autoload :Query,
|
53
|
+
autoload :Query, 'rdf/query'
|
53
54
|
|
54
55
|
# RDF vocabularies
|
55
|
-
autoload :Vocabulary,
|
56
|
+
autoload :Vocabulary, 'rdf/vocabulary'
|
56
57
|
autoload :StrictVocabulary, 'rdf/vocabulary'
|
57
58
|
VOCABS = Dir.glob(File.join(File.dirname(__FILE__), 'rdf', 'vocab', '*.rb')).map { |f| File.basename(f)[0...-(File.extname(f).size)].to_sym } rescue []
|
58
59
|
|
59
|
-
# Ruby versions < 2.0 are deprecated in RDF.rb 2.0
|
60
|
-
warn %([DEPRECATION] Ruby versions before 2.0 are no longer supported starting with RDF.rb 2.0.) if RUBY_VERSION < "2.0"
|
61
|
-
|
62
60
|
# Use const_missing instead of autoload to load most vocabularies so we can provide deprecation messages
|
63
61
|
def self.const_missing(constant)
|
64
62
|
if VOCABS.include?(constant.to_s.downcase.to_sym)
|
65
|
-
@vocab_fault ||= {}
|
66
|
-
raise "Class not found: RDF::#{constant}" if @vocab_fault[constant.to_s]
|
67
|
-
@vocab_fault[constant.to_s] = true
|
68
|
-
warn %([DEPRECATION] the #{constant} vocabulary will be moved to the rdf-vocab gem
|
69
|
-
for the RDF.rb 2.0 release. Use as RDF::Vocab::#{constant}, or include RDF::Vocab in the RDF module.
|
70
|
-
Called from #{Gem.location_of_caller.join(':')}
|
71
|
-
).gsub(/^\s+/, '') unless [:OWL, :RDFS, :RDFV, :XSD].include?(constant)
|
72
63
|
require "rdf/vocab/#{constant.to_s.downcase}"
|
73
|
-
|
74
|
-
return klass if klass
|
75
|
-
raise "Class not found: RDF::#{constant}"
|
64
|
+
const_get(constant)
|
76
65
|
else
|
77
66
|
super
|
78
67
|
end
|
@@ -131,8 +120,12 @@ module RDF
|
|
131
120
|
#
|
132
121
|
# @param (see RDF::Graph#initialize)
|
133
122
|
# @return [RDF::Graph]
|
134
|
-
def self.Graph(*args, &block)
|
135
|
-
|
123
|
+
def self.Graph(*args, **options, &block)
|
124
|
+
unless args.empty?
|
125
|
+
warn "[DEPRECATION] Graph#initialize now uses keyword arguments. Called from #{Gem.location_of_caller.join(':')}"
|
126
|
+
options[:graph_name] ||= args.first
|
127
|
+
end
|
128
|
+
Graph.new(options, &block)
|
136
129
|
end
|
137
130
|
|
138
131
|
##
|
@@ -172,8 +165,6 @@ module RDF
|
|
172
165
|
# @option options [RDF::Resource] :subject (nil)
|
173
166
|
# @option options [RDF::URI] :predicate (nil)
|
174
167
|
# @option options [RDF::Term] :object (nil)
|
175
|
-
# @option options [RDF::Resource] :context (nil)
|
176
|
-
# Alias for :graph_name, :context is deprecated in RDF.rb.
|
177
168
|
# @option options [RDF::Resource] :graph_name (nil)
|
178
169
|
# Note, a graph_name MUST be an IRI or BNode.
|
179
170
|
# @return [RDF::Statement]
|
@@ -0,0 +1,161 @@
|
|
1
|
+
module RDF
|
2
|
+
##
|
3
|
+
# An RDF changeset that can be applied to an {RDF::Mutable}.
|
4
|
+
#
|
5
|
+
# Changesets consist of a sequence of RDF statements to delete from and a
|
6
|
+
# sequence of RDF statements to insert into a target dataset.
|
7
|
+
#
|
8
|
+
# @example Applying a Changeset with block syntax
|
9
|
+
# graph = RDF::Graph.new
|
10
|
+
# graph << [RDF::URI('s_del'), RDF::URI('p_del'), RDF::URI('o_del')]
|
11
|
+
#
|
12
|
+
# RDF::Changeset.apply(graph) do |c|
|
13
|
+
# c.insert [RDF::URI('s1'), RDF::URI('p1'), RDF::URI('o1')]
|
14
|
+
# c.insert [RDF::URI('s2'), RDF::URI('p2'), RDF::URI('o2')]
|
15
|
+
# c.delete [RDF::URI('s_del'), RDF::URI('p_del'), RDF::URI('o_del')]
|
16
|
+
# end
|
17
|
+
#
|
18
|
+
# @example Defining a changeset for later application to a Mutable
|
19
|
+
# changes = RDF::Changeset.new do |c|
|
20
|
+
# c.insert [RDF::URI('s1'), RDF::URI('p1'), RDF::URI('o1')]
|
21
|
+
# c.insert [RDF::URI('s2'), RDF::URI('p2'), RDF::URI('o2')]
|
22
|
+
# c.delete [RDF::URI('s_del'), RDF::URI('p_del'), RDF::URI('o_del')]
|
23
|
+
# end
|
24
|
+
#
|
25
|
+
# graph = RDF::Graph.new
|
26
|
+
# graph << [RDF::URI('s_del'), RDF::URI('p_del'), RDF::URI('o_del')]
|
27
|
+
#
|
28
|
+
# changes.apply(graph) # or graph.apply_changeset(changes)
|
29
|
+
#
|
30
|
+
# @note When applying a Changeset, deletes are resolved before inserts.
|
31
|
+
#
|
32
|
+
# @since 2.0.0
|
33
|
+
class Changeset
|
34
|
+
include RDF::Mutable
|
35
|
+
|
36
|
+
##
|
37
|
+
# Applies a changeset to the given mutable RDF::Enumerable .
|
38
|
+
#
|
39
|
+
# @param [RDF::Mutable] mutable
|
40
|
+
# @param [Hash{Symbol => Object}] options
|
41
|
+
# @yield [changes]
|
42
|
+
# @yieldparam [RDF::Changeset] changes
|
43
|
+
# @return [void]
|
44
|
+
def self.apply(mutable, options = {}, &block)
|
45
|
+
self.new(&block).apply(mutable, options)
|
46
|
+
end
|
47
|
+
|
48
|
+
##
|
49
|
+
# RDF statements to delete when applied.
|
50
|
+
#
|
51
|
+
# @return [RDF::Enumerable]
|
52
|
+
attr_reader :deletes
|
53
|
+
|
54
|
+
##
|
55
|
+
# RDF statements to insert when applied.
|
56
|
+
#
|
57
|
+
# @return [RDF::Enumerable]
|
58
|
+
attr_reader :inserts
|
59
|
+
|
60
|
+
##
|
61
|
+
# Any additional options for this changeset.
|
62
|
+
#
|
63
|
+
# @return [Hash{Symbol => Object}]
|
64
|
+
attr_reader :options
|
65
|
+
|
66
|
+
##
|
67
|
+
# Initializes this changeset.
|
68
|
+
#
|
69
|
+
# @param [RDF::Enumerable] insert (RDF::Graph.new)
|
70
|
+
# @param [RDF::Enumerable] delete (RDF::Graph.new)
|
71
|
+
# @yield [changes]
|
72
|
+
# @yieldparam [RDF::Changeset] changes
|
73
|
+
def initialize(insert: [], delete: [], &block)
|
74
|
+
@inserts = insert
|
75
|
+
@deletes = delete
|
76
|
+
|
77
|
+
@inserts.extend(RDF::Enumerable) unless @inserts.kind_of?(RDF::Enumerable)
|
78
|
+
@deletes.extend(RDF::Enumerable) unless @deletes.kind_of?(RDF::Enumerable)
|
79
|
+
|
80
|
+
if block_given?
|
81
|
+
case block.arity
|
82
|
+
when 1 then block.call(self)
|
83
|
+
else self.instance_eval(&block)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
##
|
89
|
+
# Returns `false` to indicate that this changeset is append-only.
|
90
|
+
#
|
91
|
+
# Changesets do not support the `RDF::Enumerable` protocol directly.
|
92
|
+
# To enumerate the RDF statements to be inserted or deleted, use the
|
93
|
+
# {RDF::Changeset#inserts} and {RDF::Changeset#deletes} accessors.
|
94
|
+
#
|
95
|
+
# @return [Boolean]
|
96
|
+
# @see RDF::Readable#readable?
|
97
|
+
def readable?
|
98
|
+
false
|
99
|
+
end
|
100
|
+
|
101
|
+
##
|
102
|
+
# Applies this changeset to the given mutable RDF::Enumerable.
|
103
|
+
#
|
104
|
+
# This operation executes as a single write transaction.
|
105
|
+
#
|
106
|
+
# @param [RDF::Mutable] mutable
|
107
|
+
# @param [Hash{Symbol => Object}] options
|
108
|
+
# @return [void]
|
109
|
+
def apply(mutable, options = {})
|
110
|
+
mutable.apply_changeset(self)
|
111
|
+
end
|
112
|
+
|
113
|
+
##
|
114
|
+
# @return [Boolean] `true` iff inserts and deletes are both empty
|
115
|
+
def empty?
|
116
|
+
deletes.empty? && inserts.empty?
|
117
|
+
end
|
118
|
+
|
119
|
+
##
|
120
|
+
# Returns a developer-friendly representation of this changeset.
|
121
|
+
#
|
122
|
+
# @return [String]
|
123
|
+
def inspect
|
124
|
+
sprintf("#<%s:%#0x(deletes: %d, inserts: %d)>", self.class.name,
|
125
|
+
self.__id__, self.deletes.count, self.inserts.count)
|
126
|
+
end
|
127
|
+
|
128
|
+
##
|
129
|
+
# Outputs a developer-friendly representation of this changeset to
|
130
|
+
# `stderr`.
|
131
|
+
#
|
132
|
+
# @return [void]
|
133
|
+
def inspect!
|
134
|
+
$stderr.puts(self.inspect)
|
135
|
+
end
|
136
|
+
|
137
|
+
protected
|
138
|
+
|
139
|
+
##
|
140
|
+
# Appends an RDF statement to the sequence to insert when applied.
|
141
|
+
#
|
142
|
+
# @param [RDF::Statement] statement
|
143
|
+
# @return [void]
|
144
|
+
# @see RDF::Writable#insert_statement
|
145
|
+
def insert_statement(statement)
|
146
|
+
self.inserts << statement
|
147
|
+
end
|
148
|
+
|
149
|
+
##
|
150
|
+
# Appends an RDF statement to the sequence to delete when applied.
|
151
|
+
#
|
152
|
+
# @param [RDF::Statement] statement
|
153
|
+
# @return [void]
|
154
|
+
# @see RDF::Mutable#delete_statement
|
155
|
+
def delete_statement(statement)
|
156
|
+
self.deletes << statement
|
157
|
+
end
|
158
|
+
|
159
|
+
undef_method :load, :update, :clear
|
160
|
+
end # Changeset
|
161
|
+
end # RDF
|
data/lib/rdf/cli.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'rdf'
|
2
2
|
require 'rdf/ntriples'
|
3
3
|
require 'rdf/nquads'
|
4
|
+
require 'logger'
|
4
5
|
require 'optparse'
|
5
6
|
begin
|
6
7
|
gem 'linkeddata'
|
@@ -13,6 +14,11 @@ rescue LoadError
|
|
13
14
|
rescue LoadError
|
14
15
|
end
|
15
16
|
end
|
17
|
+
|
18
|
+
begin
|
19
|
+
require 'json/ld'
|
20
|
+
rescue LoadError
|
21
|
+
end
|
16
22
|
end
|
17
23
|
|
18
24
|
class OptionParser
|
@@ -21,10 +27,87 @@ class OptionParser
|
|
21
27
|
end
|
22
28
|
|
23
29
|
module RDF
|
30
|
+
# Individual formats can modify options by updating {Reader.options} or {Writer.options}. Format-specific commands are taken from {Format.cli_commands} for each loaded format, which returns an array of lambdas taking arguments and options.
|
31
|
+
#
|
32
|
+
# @example Creating Reader-specific options:
|
33
|
+
# class Reader
|
34
|
+
# def self.options
|
35
|
+
# [
|
36
|
+
# RDF::CLI::Option.new(
|
37
|
+
# symbol: :canonicalize,
|
38
|
+
# datatype: TrueClass,
|
39
|
+
# on: ["--canonicalize"],
|
40
|
+
# description: "Canonicalize input/output.") {true},
|
41
|
+
# ...
|
42
|
+
# ]
|
43
|
+
# end
|
44
|
+
#
|
45
|
+
# @example Creating Format-specific commands:
|
46
|
+
# class Format
|
47
|
+
# def self.cli_commands
|
48
|
+
# {
|
49
|
+
# count: ->(argv, opts) do
|
50
|
+
# count = 0
|
51
|
+
# RDF::CLI.parse(argv, opts) do |reader|
|
52
|
+
# reader.each_statement do |statement|
|
53
|
+
# count += 1
|
54
|
+
# end
|
55
|
+
# end
|
56
|
+
# $stdout.puts "Parsed #{count} statements"
|
57
|
+
# end,
|
58
|
+
# }
|
59
|
+
# end
|
60
|
+
#
|
61
|
+
# Format-specific commands should verify that the reader and/or output format are appropriate for the command.
|
24
62
|
class CLI
|
25
63
|
|
64
|
+
# Option description for use within Readers/Writers. See {RDF::Reader.options} and {RDF::Writer.options} for example usage.
|
65
|
+
class Option
|
66
|
+
# Symbol used for this option when calling `Reader.new`
|
67
|
+
# @return [Symbol]
|
68
|
+
attr_reader :symbol
|
69
|
+
|
70
|
+
# Arguments passed to OptionParser#on
|
71
|
+
# @return [Array<String>]
|
72
|
+
attr_reader :on
|
73
|
+
|
74
|
+
# Description of this option (optional)
|
75
|
+
# @return [String]
|
76
|
+
attr_reader :description
|
77
|
+
|
78
|
+
# Argument datatype, which may be enumerated string values
|
79
|
+
# @return [Class, Array<String>]
|
80
|
+
attr_reader :datatype
|
81
|
+
|
82
|
+
# Allows multiple comma-spearated values.
|
83
|
+
# @return [Boolean]
|
84
|
+
attr_reader :multiple
|
85
|
+
|
86
|
+
##
|
87
|
+
# Create a new option with optional callback.
|
88
|
+
#
|
89
|
+
# @param [Symbol] symbol
|
90
|
+
# @param [Array<String>] on
|
91
|
+
# @param [String] description
|
92
|
+
# @param [Class, Array<String>] datatype of value
|
93
|
+
# @param [Boolean] multiple can have multiple comma-separated values
|
94
|
+
# @yield value which may be used within `OptionParser#on`
|
95
|
+
# @yieldparam [Object] value The option value as parsed using `on` argument
|
96
|
+
# @yieldreturn [Object] a possibly modified input value
|
97
|
+
def initialize(symbol: nil, on: nil, description: nil, datatype: String, multiple: false, &block)
|
98
|
+
raise ArgumentError, "symbol is a required argument" unless symbol
|
99
|
+
raise ArgumentError, "on is a required argument" unless on
|
100
|
+
@symbol, @on, @description, @datatype, @multiple, @callback = symbol.to_sym, Array(on), description, datatype, multiple, block
|
101
|
+
end
|
102
|
+
|
103
|
+
def call(arg)
|
104
|
+
@callback ? @callback.call(arg) : arg
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
# @private
|
26
109
|
COMMANDS = {
|
27
|
-
|
110
|
+
count: ->(argv, opts) do
|
28
111
|
start = Time.new
|
29
112
|
count = 0
|
30
113
|
self.parse(argv, opts) do |reader|
|
@@ -35,14 +118,17 @@ module RDF
|
|
35
118
|
secs = Time.new - start
|
36
119
|
$stdout.puts "Parsed #{count} statements with #{@readers.join(', ')} in #{secs} seconds @ #{count/secs} statements/second."
|
37
120
|
end,
|
38
|
-
|
121
|
+
help: ->(argv, opts) do
|
122
|
+
self.usage(self.options)
|
123
|
+
end,
|
124
|
+
lenghts: ->(argv, opts) do
|
39
125
|
self.parse(argv, opts) do |reader|
|
40
126
|
reader.each_statement do |statement|
|
41
127
|
$stdout.puts statement.to_s.size
|
42
128
|
end
|
43
129
|
end
|
44
130
|
end,
|
45
|
-
|
131
|
+
objects: ->(argv, opts) do
|
46
132
|
$stdout.set_encoding(Encoding::UTF_8) if RUBY_PLATFORM == "java"
|
47
133
|
self.parse(argv, opts) do |reader|
|
48
134
|
reader.each_statement do |statement|
|
@@ -50,7 +136,7 @@ module RDF
|
|
50
136
|
end
|
51
137
|
end
|
52
138
|
end,
|
53
|
-
|
139
|
+
predicates: ->(argv, opts) do
|
54
140
|
$stdout.set_encoding(Encoding::UTF_8) if RUBY_PLATFORM == "java"
|
55
141
|
self.parse(argv, opts) do |reader|
|
56
142
|
reader.each_statement do |statement|
|
@@ -58,7 +144,7 @@ module RDF
|
|
58
144
|
end
|
59
145
|
end
|
60
146
|
end,
|
61
|
-
|
147
|
+
serialize: ->(argv, opts) do
|
62
148
|
writer_class = RDF::Writer.for(opts[:output_format]) || RDF::NTriples::Writer
|
63
149
|
out = opts[:output] || $stdout
|
64
150
|
out.set_encoding(Encoding::UTF_8) if out.respond_to?(:set_encoding) && RUBY_PLATFORM == "java"
|
@@ -70,13 +156,26 @@ module RDF
|
|
70
156
|
end
|
71
157
|
end
|
72
158
|
end,
|
73
|
-
|
159
|
+
subjects: ->(argv, opts) do
|
74
160
|
$stdout.set_encoding(Encoding::UTF_8) if RUBY_PLATFORM == "java"
|
75
161
|
self.parse(argv, opts) do |reader|
|
76
162
|
reader.each_statement do |statement|
|
77
163
|
$stdout.puts statement.subject.to_ntriples
|
78
164
|
end
|
79
165
|
end
|
166
|
+
end,
|
167
|
+
validate: ->(argv, opts) do
|
168
|
+
start = Time.new
|
169
|
+
count = 0
|
170
|
+
valid = true
|
171
|
+
self.parse(argv, opts) do |reader|
|
172
|
+
reader.each_statement do |statement|
|
173
|
+
count += 1
|
174
|
+
valid = false if statement.invalid?
|
175
|
+
end
|
176
|
+
end
|
177
|
+
secs = Time.new - start
|
178
|
+
$stdout.puts "Validated #{count} statements with #{@readers.join(', ')} in #{secs} seconds @ #{count/secs} statements/second."
|
80
179
|
end
|
81
180
|
}
|
82
181
|
|
@@ -90,17 +189,36 @@ module RDF
|
|
90
189
|
# @return [OptionParser]
|
91
190
|
def self.options(&block)
|
92
191
|
options = OptionParser.new
|
192
|
+
logger = Logger.new($stderr)
|
193
|
+
logger.level = Logger::ERROR
|
194
|
+
logger.formatter = lambda {|severity, datetime, progname, msg| "#{severity} #{msg}\n"}
|
93
195
|
opts = options.options = {
|
94
|
-
base_uri: nil,
|
95
|
-
canonicalize: false,
|
96
196
|
debug: false,
|
97
197
|
evaluate: nil,
|
98
198
|
format: nil,
|
99
199
|
output: $stdout,
|
100
200
|
output_format: :ntriples,
|
101
|
-
|
201
|
+
logger: logger
|
102
202
|
}
|
103
203
|
|
204
|
+
# Add default Reader and Writer options
|
205
|
+
RDF::Reader.options.each do |cli_opt|
|
206
|
+
next if opts.has_key?(cli_opt.symbol)
|
207
|
+
on_args = cli_opt.on || []
|
208
|
+
on_args << cli_opt.description if cli_opt.description
|
209
|
+
options.on(*on_args) do |arg|
|
210
|
+
opts[cli_opt.symbol] = cli_opt.call(arg)
|
211
|
+
end
|
212
|
+
end
|
213
|
+
RDF::Writer.options.each do |cli_opt|
|
214
|
+
next if opts.has_key?(cli_opt.symbol)
|
215
|
+
on_args = cli_opt.on || []
|
216
|
+
on_args << cli_opt.description if cli_opt.description
|
217
|
+
options.on(*on_args) do |arg|
|
218
|
+
opts[cli_opt.symbol] = cli_opt.call(arg)
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
104
222
|
# Command-specific options
|
105
223
|
if block_given?
|
106
224
|
case block.arity
|
@@ -110,19 +228,28 @@ module RDF
|
|
110
228
|
end
|
111
229
|
options.banner ||= "Usage: #{self.basename} [options] command [args...]"
|
112
230
|
|
113
|
-
options.on('--canonicalize', 'Canonicalize input.') do
|
114
|
-
opts[:canonicalize] = true
|
115
|
-
end
|
116
|
-
|
117
231
|
options.on('-d', '--debug', 'Enable debug output for troubleshooting.') do
|
118
|
-
opts[:
|
232
|
+
opts[:logger].level = Logger::DEBUG
|
119
233
|
end
|
120
234
|
|
121
235
|
options.on("-e", "--evaluate STRING", "Evaluate argument as RDF input, if no files are specified") do |arg|
|
122
236
|
opts[:evaluate] = arg
|
123
237
|
end
|
124
238
|
|
125
|
-
options.on("--input-format FORMAT", "Format of input file, uses heuristic if not specified") do |arg|
|
239
|
+
options.on("--input-format FORMAT", "--format FORMAT", "Format of input file, uses heuristic if not specified") do |arg|
|
240
|
+
unless reader = RDF::Reader.for(arg.downcase.to_sym)
|
241
|
+
self.abort "No reader found for #{arg.downcase.to_sym}. Available readers:\n #{self.formats(reader: true).join("\n ")}"
|
242
|
+
end
|
243
|
+
|
244
|
+
# Add format-specific reader options
|
245
|
+
reader.options.each do |cli_opt|
|
246
|
+
next if opts.has_key?(cli_opt.symbol)
|
247
|
+
on_args = cli_opt.on || []
|
248
|
+
on_args << cli_opt.description if cli_opt.description
|
249
|
+
options.on(*on_args) do |arg|
|
250
|
+
opts[cli_opt.symbol] = cli_opt.call(arg)
|
251
|
+
end
|
252
|
+
end
|
126
253
|
opts[:format] = arg.downcase.to_sym
|
127
254
|
end
|
128
255
|
|
@@ -131,21 +258,24 @@ module RDF
|
|
131
258
|
end
|
132
259
|
|
133
260
|
options.on("--output-format FORMAT", "Format of output file, defaults to NTriples") do |arg|
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
options.on('--uri URI', 'Base URI of input file, defaults to the filename.') do |arg|
|
138
|
-
opts[:base_uri] = arg
|
139
|
-
end
|
261
|
+
unless writer = RDF::Writer.for(arg.downcase.to_sym)
|
262
|
+
self.abort "No writer found for #{arg.downcase.to_sym}. Available writers:\n #{self.formats(writer: true).join("\n ")}"
|
263
|
+
end
|
140
264
|
|
141
|
-
|
142
|
-
|
265
|
+
# Add format-specific writer options
|
266
|
+
writer.options.each do |cli_opt|
|
267
|
+
next if opts.has_key?(cli_opt.symbol)
|
268
|
+
on_args = cli_opt.on || []
|
269
|
+
on_args << cli_opt.description if cli_opt.description
|
270
|
+
options.on(*on_args) do |arg|
|
271
|
+
opts[cli_opt.symbol] = cli_opt.call(arg)
|
272
|
+
end
|
273
|
+
end
|
274
|
+
opts[:output_format] = arg.downcase.to_sym
|
143
275
|
end
|
144
276
|
|
145
277
|
options.on_tail("-h", "--help", "Show this message") do
|
146
|
-
|
147
|
-
$stdout.puts "Available commands:\n\t#{self.commands.join("\n\t")}"
|
148
|
-
exit
|
278
|
+
self.usage(options)
|
149
279
|
end
|
150
280
|
|
151
281
|
begin
|
@@ -158,25 +288,57 @@ module RDF
|
|
158
288
|
end
|
159
289
|
|
160
290
|
##
|
161
|
-
#
|
291
|
+
# Output usage message
|
292
|
+
def self.usage(options)
|
293
|
+
$stdout.puts options
|
294
|
+
$stdout.puts "Note: available commands and options may be different depending on selected --input-format and/or --output-format."
|
295
|
+
$stdout.puts "Available commands:\n\t#{self.commands.join("\n\t")}"
|
296
|
+
$stdout.puts "Available formats:\n\t#{(self.formats).join("\n\t")}"
|
297
|
+
end
|
298
|
+
|
299
|
+
##
|
300
|
+
# @param [#to_sym] command
|
162
301
|
# @param [Array<String>] args
|
163
302
|
# @return [Boolean]
|
164
303
|
def self.exec_command(command, args, options = {})
|
165
|
-
unless
|
166
|
-
abort "
|
304
|
+
unless commands.include?(command.to_s)
|
305
|
+
abort "unknown command `#{command}'"
|
167
306
|
end
|
168
307
|
|
169
|
-
COMMANDS[command].call(args, options)
|
308
|
+
COMMANDS[command.to_sym].call(args, options)
|
309
|
+
rescue ArgumentError => e
|
310
|
+
abort e.message
|
170
311
|
end
|
171
312
|
|
172
313
|
##
|
173
314
|
# @return [Array<String>] list of executable commands
|
174
315
|
def self.commands
|
175
|
-
|
316
|
+
# First, load commands from other formats
|
317
|
+
unless @commands_loaded
|
318
|
+
RDF::Format.each do |format|
|
319
|
+
format.cli_commands.each do |command, lambda|
|
320
|
+
COMMANDS[command] ||= lambda
|
321
|
+
end
|
322
|
+
end
|
323
|
+
@commands_loaded = true
|
324
|
+
end
|
325
|
+
COMMANDS.keys.map(&:to_s).sort
|
326
|
+
end
|
327
|
+
|
328
|
+
##
|
329
|
+
# @return [Array<String>] list of available formats
|
330
|
+
def self.formats(reader: false, writer: false)
|
331
|
+
f = RDF::Format.each.
|
332
|
+
select {|f| (reader ? f.reader : (writer ? f.writer : true))}.
|
333
|
+
inject({}) do |memo, reader|
|
334
|
+
memo.merge(reader.to_sym => reader.name)
|
335
|
+
end
|
336
|
+
sym_len = f.keys.map {|k| k.to_s.length}.max
|
337
|
+
f.map {|s, t| "%*s: %s" % [sym_len, s, t]}
|
176
338
|
end
|
177
339
|
|
178
340
|
##
|
179
|
-
# Parse each file,
|
341
|
+
# Parse each file, $stdin or specified string in `options[:evaluate]`
|
180
342
|
# yielding a reader
|
181
343
|
#
|
182
344
|
# @param [Array<String>] files
|
@@ -186,7 +348,7 @@ module RDF
|
|
186
348
|
def self.parse(files, options = {}, &block)
|
187
349
|
if files.empty?
|
188
350
|
# If files are empty, either use options[:execute]
|
189
|
-
input = options[:evaluate] ? StringIO.new(options[:evaluate]) :
|
351
|
+
input = options[:evaluate] ? StringIO.new(options[:evaluate]) : $stdin
|
190
352
|
input.set_encoding(options.fetch(:encoding, Encoding::UTF_8))
|
191
353
|
RDF::Reader.for(options[:format] || :ntriples).new(input, options) do |reader|
|
192
354
|
yield(reader)
|