rdf 3.2.10 → 3.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +37 -35
- data/VERSION +1 -1
- data/lib/rdf/cli.rb +1 -1
- data/lib/rdf/mixin/enumerable.rb +23 -2
- data/lib/rdf/mixin/queryable.rb +1 -1
- data/lib/rdf/mixin/writable.rb +5 -2
- data/lib/rdf/model/dataset.rb +1 -1
- data/lib/rdf/model/graph.rb +5 -2
- data/lib/rdf/model/list.rb +0 -13
- data/lib/rdf/model/literal/decimal.rb +1 -1
- data/lib/rdf/model/literal.rb +83 -31
- data/lib/rdf/model/statement.rb +14 -1
- data/lib/rdf/model/uri.rb +60 -43
- data/lib/rdf/nquads.rb +0 -1
- data/lib/rdf/ntriples/format.rb +0 -1
- data/lib/rdf/ntriples/reader.rb +15 -14
- data/lib/rdf/ntriples/writer.rb +2 -1
- data/lib/rdf/ntriples.rb +2 -2
- data/lib/rdf/query/solution.rb +1 -1
- data/lib/rdf/reader.rb +7 -5
- data/lib/rdf/repository.rb +4 -2
- data/lib/rdf/util/cache.rb +2 -2
- data/lib/rdf/util/uuid.rb +2 -2
- data/lib/rdf/vocab/rdfv.rb +11 -0
- data/lib/rdf/writer.rb +3 -1
- data/lib/rdf.rb +0 -1
- metadata +28 -21
- data/lib/rdf/extensions.rb +0 -22
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c90d17f92036ca2959a7be98c9cf5322374c0f0a623d4b44782bde2478eb2a65
|
4
|
+
data.tar.gz: ce40842adb100ff6d2ec068cc20b0320a30dab85b5a1a47056823e10fac59302
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4ac4099d5eadff8676d0d692433d1dc3f9875032cf6617f7e0da53a559a53a88afbd6191be491c28204ca5475d007813858beefef2ac4b51f3a13c572b83aecb
|
7
|
+
data.tar.gz: 48688b3f9da835d74fed96bca2f60063da209db8567fb29932d878ab252c85fe0b4f08413ed627bd6cf95ec08ffc6447828c8f353ef897e055bbf5b786204a18
|
data/README.md
CHANGED
@@ -5,7 +5,7 @@ This is a pure-Ruby library for working with [Resource Description Framework
|
|
5
5
|
|
6
6
|
* <https://ruby-rdf.github.io/rdf>
|
7
7
|
|
8
|
-
[![Gem Version](https://badge.fury.io/rb/rdf.
|
8
|
+
[![Gem Version](https://badge.fury.io/rb/rdf.svg)](https://badge.fury.io/rb/rdf)
|
9
9
|
[![Build Status](https://github.com/ruby-rdf/rdf/workflows/CI/badge.svg?branch=develop)](https://github.com/ruby-rdf/rdf/actions?query=workflow%3ACI)
|
10
10
|
[![Coverage Status](https://coveralls.io/repos/ruby-rdf/rdf/badge.svg?branch=develop)](https://coveralls.io/github/ruby-rdf/rdf?branch=develop)
|
11
11
|
[![Gitter chat](https://badges.gitter.im/ruby-rdf/rdf.png)](https://gitter.im/ruby-rdf/rdf)
|
@@ -14,26 +14,28 @@ This is a pure-Ruby library for working with [Resource Description Framework
|
|
14
14
|
|
15
15
|
1. [Features](#features)
|
16
16
|
2. [Differences between RDF 1.0 and RDF 1.1](#differences-between-rdf-1-0-and-rdf-1-1)
|
17
|
-
3. [
|
18
|
-
4. [
|
19
|
-
5. [
|
20
|
-
6. [
|
21
|
-
7. [
|
22
|
-
8. [
|
23
|
-
9. [
|
24
|
-
10. [
|
25
|
-
11. [
|
26
|
-
12. [
|
27
|
-
13. [
|
28
|
-
14. [
|
29
|
-
15. [
|
30
|
-
16. [
|
31
|
-
17. [
|
17
|
+
3. [Differences between RDF 1.1 and RDF 1.2](#differences-between-rdf-1-1-and-rdf-1-2)
|
18
|
+
4. [Tutorials](#tutorials)
|
19
|
+
5. [Command Line](#command-line)
|
20
|
+
6. [Examples](#examples)
|
21
|
+
7. [Reader/Writer convenience methods](#reader/writer-convenience-methods)
|
22
|
+
8. [RDF 1.2](#rdf\_12)
|
23
|
+
9. [Documentation](#documentation)
|
24
|
+
10. [Dependencies](#dependencies)
|
25
|
+
11. [Installation](#installation)
|
26
|
+
12. [Download](#download)
|
27
|
+
13. [Resources](#resources)
|
28
|
+
14. [Mailing List](#mailing-list)
|
29
|
+
15. [Authors](#authors)
|
30
|
+
16. [Contributors](#contributors)
|
31
|
+
17. [Contributing](#contributing)
|
32
|
+
18. [License](#license)
|
32
33
|
|
33
34
|
## Features
|
34
35
|
|
35
36
|
* 100% pure Ruby with minimal dependencies and no bloat.
|
36
37
|
* Fully compatible with [RDF 1.1][] specifications.
|
38
|
+
* Provisional support for [RDF 1.2][] specifications.
|
37
39
|
* 100% free and unencumbered [public domain](https://unlicense.org/) software.
|
38
40
|
* Provides a clean, well-designed RDF object model and related APIs.
|
39
41
|
* Supports parsing and serializing [N-Triples][] and [N-Quads][] out of the box, with more
|
@@ -45,11 +47,10 @@ This is a pure-Ruby library for working with [Resource Description Framework
|
|
45
47
|
not modify any of Ruby's core classes or standard library.
|
46
48
|
* Based entirely on Ruby's autoloading, meaning that you can generally make
|
47
49
|
use of any one part of the library without needing to load up the rest.
|
48
|
-
* Compatible with Ruby Ruby >=
|
49
|
-
* Note, changes in mapping hashes to keyword arguments for Ruby
|
50
|
+
* Compatible with Ruby Ruby >= 3.0, Rubinius and JRuby 9.0+.
|
51
|
+
* Note, changes in mapping hashes to keyword arguments for Ruby 3+ may require that arguments be passed more explicitly, especially when the first argument is a Hash and there are optional keyword arguments. In this case, Hash argument may need to be explicitly included within `{}` and the optional keyword arguments may need to be specified using `**{}` if there are no keyword arguments.
|
50
52
|
* Performs auto-detection of input to select appropriate Reader class if one
|
51
53
|
cannot be determined from file characteristics.
|
52
|
-
* Provisional support for [RDF*][].
|
53
54
|
|
54
55
|
### HTTP requests
|
55
56
|
|
@@ -102,6 +103,10 @@ the 1.1 release of RDF.rb:
|
|
102
103
|
|
103
104
|
Notably, {RDF::Queryable#query} and {RDF::Query#execute} are now completely symmetric; this allows an implementation of {RDF::Queryable} to optimize queries using implementation-specific logic, allowing for substantial performance improvements when executing BGP queries.
|
104
105
|
|
106
|
+
## Differences between RDF 1.1 and RDF 1.2
|
107
|
+
* {RDF::Literal} has an optional `direction` property for directional language-tagged strings.
|
108
|
+
* Removes support for legacy `text/plain` (as an alias for `application/n-triples`) and `text/x-nquads` (as an alias for `application/n-quads`)
|
109
|
+
|
105
110
|
## Tutorials
|
106
111
|
|
107
112
|
* [Getting data from the Semantic Web using Ruby and RDF.rb](https://semanticweb.org/wiki/Getting_data_from_the_Semantic_Web_%28Ruby%29)
|
@@ -260,15 +265,16 @@ A separate [SPARQL][SPARQL doc] gem builds on basic BGP support to provide full
|
|
260
265
|
foaf[:name] #=> RDF::URI("http://xmlns.com/foaf/0.1/name")
|
261
266
|
foaf['mbox'] #=> RDF::URI("http://xmlns.com/foaf/0.1/mbox")
|
262
267
|
|
263
|
-
## RDF
|
268
|
+
## RDF 1.2
|
264
269
|
|
265
|
-
[RDF.rb][] includes provisional support for [RDF
|
270
|
+
[RDF.rb][] includes provisional support for [RDF 1.2][] with an N-Triples/N-Quads syntax for quoted triples in the _subject_ or _object_ position.
|
271
|
+
[RDF.rb][] includes provisional support for [RDF 1.2][] directional language-tagged strings, which are literals of type `rdf:dirLangString` having both a `language` and `direction`.
|
266
272
|
|
267
273
|
Internally, an `RDF::Statement` is treated as another resource, along with `RDF::URI` and `RDF::Node`, which allows an `RDF::Statement` to have a `#subject` or `#object` which is also an `RDF::Statement`.
|
268
274
|
|
269
275
|
**Note: This feature is subject to change or elimination as the standards process progresses.**
|
270
276
|
|
271
|
-
### Serializing a Graph containing
|
277
|
+
### Serializing a Graph containing quoted triples
|
272
278
|
|
273
279
|
require 'rdf/ntriples'
|
274
280
|
statement = RDF::Statement(RDF::URI('bob'), RDF::Vocab::FOAF.age, RDF::Literal(23))
|
@@ -276,7 +282,7 @@ Internally, an `RDF::Statement` is treated as another resource, along with `RDF:
|
|
276
282
|
graph.dump(:ntriples, validate: false)
|
277
283
|
# => '<<<bob> <http://xmlns.com/foaf/0.1/age> "23"^^<http://www.w3.org/2001/XMLSchema#integer>>> <ex:certainty> "0.9"^^<http://www.w3.org/2001/XMLSchema#double> .'
|
278
284
|
|
279
|
-
### Reading a Graph containing
|
285
|
+
### Reading a Graph containing quoted triples
|
280
286
|
|
281
287
|
By default, the N-Triples reader will reject a document containing a subject resource.
|
282
288
|
|
@@ -286,13 +292,6 @@ By default, the N-Triples reader will reject a document containing a subject res
|
|
286
292
|
end
|
287
293
|
# => RDF::ReaderError
|
288
294
|
|
289
|
-
Readers support a boolean valued `rdfstar` option.
|
290
|
-
|
291
|
-
graph = RDF::Graph.new do |graph|
|
292
|
-
RDF::NTriples::Reader.new(nt, rdfstar: true) {|reader| graph << reader}
|
293
|
-
end
|
294
|
-
graph.count #=> 1
|
295
|
-
|
296
295
|
## Documentation
|
297
296
|
|
298
297
|
<https://ruby-rdf.github.io/rdf>
|
@@ -398,8 +397,9 @@ from BNode identity (i.e., they each entail the other)
|
|
398
397
|
|
399
398
|
## Dependencies
|
400
399
|
|
401
|
-
* [Ruby](https://ruby-lang.org/) (>=
|
400
|
+
* [Ruby](https://ruby-lang.org/) (>= 3.0)
|
402
401
|
* [LinkHeader][] (>= 0.0.8)
|
402
|
+
* [bcp47_spec][] ( ~> 0.2)
|
403
403
|
* Soft dependency on [RestClient][] (>= 2.1)
|
404
404
|
|
405
405
|
## Installation
|
@@ -407,7 +407,7 @@ from BNode identity (i.e., they each entail the other)
|
|
407
407
|
The recommended installation method is via [RubyGems](https://rubygems.org/).
|
408
408
|
To install the latest official release of RDF.rb, do:
|
409
409
|
|
410
|
-
% [sudo] gem install rdf # Ruby
|
410
|
+
% [sudo] gem install rdf # Ruby 3+
|
411
411
|
|
412
412
|
## Download
|
413
413
|
|
@@ -481,8 +481,10 @@ This is free and unencumbered public domain software. For more information,
|
|
481
481
|
see <https://unlicense.org/> or the accompanying {file:UNLICENSE} file.
|
482
482
|
|
483
483
|
[RDF]: https://www.w3.org/RDF/
|
484
|
-
[
|
485
|
-
[
|
484
|
+
[LinkHeader]: https://github.com/asplake/link_header
|
485
|
+
[bcp47_spec]: https://github.com/dadah89/bcp47_spec
|
486
|
+
[N-Triples]: https://www.w3.org/TR/rdf-n-triples/
|
487
|
+
[N-Quads]: https://www.w3.org/TR/rdf-n-quads/
|
486
488
|
[YARD]: https://yardoc.org/
|
487
489
|
[YARD-GS]: https://rubydoc.info/docs/yard/file/docs/GettingStarted.md
|
488
490
|
[PDD]: https://unlicense.org/#unlicensing-contributions
|
@@ -496,6 +498,7 @@ see <https://unlicense.org/> or the accompanying {file:UNLICENSE} file.
|
|
496
498
|
[SPARQL doc]: https://ruby-rdf.github.io/sparql
|
497
499
|
[RDF 1.0]: https://www.w3.org/TR/2004/REC-rdf-concepts-20040210/
|
498
500
|
[RDF 1.1]: https://www.w3.org/TR/rdf11-concepts/
|
501
|
+
[RDF 1.2]: https://www.w3.org/TR/rdf12-concepts/
|
499
502
|
[SPARQL 1.1]: https://www.w3.org/TR/sparql11-query/
|
500
503
|
[RDF.rb]: https://ruby-rdf.github.io/
|
501
504
|
[RDF::DO]: https://ruby-rdf.github.io/rdf-do
|
@@ -510,7 +513,6 @@ see <https://unlicense.org/> or the accompanying {file:UNLICENSE} file.
|
|
510
513
|
[RDF::TriX]: https://ruby-rdf.github.io/rdf-trix
|
511
514
|
[RDF::Turtle]: https://ruby-rdf.github.io/rdf-turtle
|
512
515
|
[RDF::Raptor]: https://ruby-rdf.github.io/rdf-raptor
|
513
|
-
[RDF*]: https://w3c.github.io/rdf-star/rdf-star-cg-spec.html
|
514
516
|
[LinkedData]: https://ruby-rdf.github.io/linkeddata
|
515
517
|
[JSON::LD]: https://ruby-rdf.github.io/json-ld
|
516
518
|
[RestClient]: https://rubygems.org/gems/rest-client
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
3.
|
1
|
+
3.3.0
|
data/lib/rdf/cli.rb
CHANGED
@@ -60,7 +60,7 @@ module RDF
|
|
60
60
|
# RDF::CLI::Option.new(
|
61
61
|
# symbol: :canonicalize,
|
62
62
|
# on: ["--canonicalize"],
|
63
|
-
# description: "Canonicalize
|
63
|
+
# description: "Canonicalize URI/literal forms.") {true},
|
64
64
|
# RDF::CLI::Option.new(
|
65
65
|
# symbol: :uri,
|
66
66
|
# on: ["--uri STRING"],
|
data/lib/rdf/mixin/enumerable.rb
CHANGED
@@ -83,7 +83,8 @@ module RDF
|
|
83
83
|
# * `:literal_equality' preserves [term-equality](https://www.w3.org/TR/rdf11-concepts/#dfn-literal-term-equality) for literals. Literals are equal only if their lexical values and datatypes are equal, character by character. Literals may be "inlined" to value-space for efficiency only if `:literal_equality` is `false`.
|
84
84
|
# * `:validity` allows a concrete Enumerable implementation to indicate that it does or does not support valididty checking. By default implementations are assumed to support validity checking.
|
85
85
|
# * `:skolemize` supports [Skolemization](https://www.w3.org/wiki/BnodeSkolemization) of an `Enumerable`. Implementations supporting this feature must implement a `#skolemize` method, taking a base URI used for minting URIs for BNodes as stable identifiers and a `#deskolemize` method, also taking a base URI used for turning URIs having that prefix back into the same BNodes which were originally skolemized.
|
86
|
-
# * `:
|
86
|
+
# * `:quoted_triples` supports RDF 1.2 quoted triples.
|
87
|
+
# * `:base_direction` supports RDF 1.2 directional language-tagged strings.
|
87
88
|
#
|
88
89
|
# @param [Symbol, #to_sym] feature
|
89
90
|
# @return [Boolean]
|
@@ -720,13 +721,33 @@ module RDF
|
|
720
721
|
end
|
721
722
|
alias_method :enum_graphs, :enum_graph
|
722
723
|
|
724
|
+
##
|
725
|
+
# Enumerates each statement using its canonical representation.
|
726
|
+
#
|
727
|
+
# @note This is updated by `RDF::Normalize` to also canonicalize blank nodes.
|
728
|
+
#
|
729
|
+
# @return [RDF::Enumerable]
|
730
|
+
def canonicalize
|
731
|
+
this = self
|
732
|
+
Enumerable::Enumerator.new do |yielder|
|
733
|
+
this.send(:each_statement) {|y| yielder << y.canonicalize}
|
734
|
+
end
|
735
|
+
end
|
736
|
+
|
737
|
+
##
|
738
|
+
# Mutating canonicalization not supported
|
739
|
+
#
|
740
|
+
# @raise NotImplementedError
|
741
|
+
def canonicalize!
|
742
|
+
raise NotImplementedError, "Canonicalizing enumerables not supported"
|
743
|
+
end
|
744
|
+
|
723
745
|
##
|
724
746
|
# Returns all RDF statements in `self` as an array.
|
725
747
|
#
|
726
748
|
# Mixes in `RDF::Enumerable` into the returned object.
|
727
749
|
#
|
728
750
|
# @return [Array]
|
729
|
-
# @since 0.2.0
|
730
751
|
def to_a
|
731
752
|
super.extend(RDF::Enumerable)
|
732
753
|
end
|
data/lib/rdf/mixin/queryable.rb
CHANGED
@@ -140,7 +140,7 @@ module RDF
|
|
140
140
|
# method in order to provide for storage-specific optimized triple
|
141
141
|
# pattern matching.
|
142
142
|
#
|
143
|
-
# ##
|
143
|
+
# ## RDF-star
|
144
144
|
#
|
145
145
|
# Statements may have embedded statements as either a subject or object, recursively.
|
146
146
|
#
|
data/lib/rdf/mixin/writable.rb
CHANGED
@@ -127,8 +127,11 @@ module RDF
|
|
127
127
|
def insert_statements(statements)
|
128
128
|
each = statements.respond_to?(:each_statement) ? :each_statement : :each
|
129
129
|
statements.__send__(each) do |statement|
|
130
|
-
if statement.embedded? && respond_to?(:supports?) && !supports?(:
|
131
|
-
raise ArgumentError, "
|
130
|
+
if statement.embedded? && respond_to?(:supports?) && !supports?(:quoted_triples)
|
131
|
+
raise ArgumentError, "Writable does not support quoted triples"
|
132
|
+
end
|
133
|
+
if statement.object && statement.object.literal? && statement.object.direction? && !supports?(:base_direction)
|
134
|
+
raise ArgumentError, "Writable does not support directional languaged-tagged strings"
|
132
135
|
end
|
133
136
|
insert_statement(statement)
|
134
137
|
end
|
data/lib/rdf/model/dataset.rb
CHANGED
data/lib/rdf/model/graph.rb
CHANGED
@@ -305,8 +305,11 @@ module RDF
|
|
305
305
|
# @private
|
306
306
|
# @see RDF::Mutable#insert
|
307
307
|
def insert_statement(statement)
|
308
|
-
if statement.embedded? && !@data.supports?(:
|
309
|
-
raise ArgumentError, "Graph does not support
|
308
|
+
if statement.embedded? && !@data.supports?(:quoted_triples)
|
309
|
+
raise ArgumentError, "Graph does not support quoted triples"
|
310
|
+
end
|
311
|
+
if statement.object && statement.object.literal? && statement.object.direction? && !@data.supports?(:base_direction)
|
312
|
+
raise ArgumentError, "Graph does not support directional languaged-tagged strings"
|
310
313
|
end
|
311
314
|
statement = statement.dup
|
312
315
|
statement.graph_name = graph_name
|
data/lib/rdf/model/list.rb
CHANGED
@@ -280,19 +280,6 @@ module RDF
|
|
280
280
|
end
|
281
281
|
end
|
282
282
|
|
283
|
-
##
|
284
|
-
# Returns the element at `index`.
|
285
|
-
#
|
286
|
-
# @example
|
287
|
-
# RDF::List[1, 2, 3][0] #=> RDF::Literal(1)
|
288
|
-
#
|
289
|
-
# @param [Integer] index
|
290
|
-
# @return [RDF::Term]
|
291
|
-
# @see http://ruby-doc.org/core-2.2.2/Array.html#method-i-5B-5D
|
292
|
-
def [](index)
|
293
|
-
at(index)
|
294
|
-
end
|
295
|
-
|
296
283
|
##
|
297
284
|
# Element Assignment — Sets the element at `index`, or replaces a subarray from the `start` index for `length` elements, or replaces a subarray specified by the `range` of indices.
|
298
285
|
#
|
@@ -26,7 +26,7 @@ module RDF; class Literal
|
|
26
26
|
when value.is_a?(::Numeric) then BigDecimal(value)
|
27
27
|
else
|
28
28
|
value = value.to_s
|
29
|
-
value += "0" if value.end_with?(".")
|
29
|
+
value += "0" if value.end_with?(".")
|
30
30
|
BigDecimal(value) rescue BigDecimal(0)
|
31
31
|
end
|
32
32
|
end
|
data/lib/rdf/model/literal.rb
CHANGED
@@ -1,4 +1,7 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
require 'bcp47_spec'
|
4
|
+
|
2
5
|
module RDF
|
3
6
|
##
|
4
7
|
# An RDF literal.
|
@@ -9,7 +12,9 @@ module RDF
|
|
9
12
|
#
|
10
13
|
# Specific typed literals may have behavior different from the default implementation. See the following defined sub-classes for specific documentation. Additional sub-classes may be defined, and will interoperate by defining `DATATYPE` and `GRAMMAR` constants, in addition other required overrides of RDF::Literal behavior.
|
11
14
|
#
|
12
|
-
# In RDF 1.1, all literals are typed, including plain literals and language
|
15
|
+
# In RDF 1.1, all literals are typed, including plain literals and language-tagged strings. Internally, plain literals are given the `xsd:string` datatype and language-tagged strings 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 strings. 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 strings.
|
16
|
+
#
|
17
|
+
# RDF 1.2 adds **directional language-tagged strings** which are effectively a subclass of **language-tagged strings** contining an additional **direction** component with value either **ltr** or **rtl** for Left-to-Right or Right-to-Left. This determines the general direction of a string when presented in n a user agent, where it might be in conflict with the inherent direction of the leading Unicode code points. Directional language-tagged strings are given the `rdf:langString` datatype.
|
13
18
|
#
|
14
19
|
# * {RDF::Literal::Boolean}
|
15
20
|
# * {RDF::Literal::Date}
|
@@ -23,16 +28,23 @@ module RDF
|
|
23
28
|
# value = RDF::Literal.new("Hello, world!")
|
24
29
|
# value.plain? #=> true`
|
25
30
|
#
|
26
|
-
# @example Creating a language-tagged
|
31
|
+
# @example Creating a language-tagged string (1)
|
27
32
|
# value = RDF::Literal.new("Hello!", language: :en)
|
28
33
|
# value.language? #=> true
|
29
34
|
# value.language #=> :en
|
30
35
|
#
|
31
|
-
# @example Creating a language-tagged
|
36
|
+
# @example Creating a language-tagged string (2)
|
32
37
|
# RDF::Literal.new("Wazup?", language: :"en-US")
|
33
38
|
# RDF::Literal.new("Hej!", language: :sv)
|
34
39
|
# RDF::Literal.new("¡Hola!", language: :es)
|
35
40
|
#
|
41
|
+
# @example Creating a directional language-tagged string
|
42
|
+
# value = RDF::Literal.new("Hello!", language: :en, direction: :ltr)
|
43
|
+
# value.language? #=> true
|
44
|
+
# value.language #=> :en
|
45
|
+
# value.direction? #=> true
|
46
|
+
# value.direction #=> :ltr
|
47
|
+
#
|
36
48
|
# @example Creating an explicitly datatyped literal
|
37
49
|
# value = RDF::Literal.new("2009-12-31", datatype: RDF::XSD.date)
|
38
50
|
# value.datatype? #=> true
|
@@ -105,8 +117,14 @@ module RDF
|
|
105
117
|
|
106
118
|
##
|
107
119
|
# @private
|
108
|
-
def self.new(value, language: nil, datatype: nil, lexical: nil, validate: false, canonicalize: false, **options)
|
109
|
-
|
120
|
+
def self.new(value, language: nil, datatype: nil, direction: nil, lexical: nil, validate: false, canonicalize: false, **options)
|
121
|
+
if language && direction
|
122
|
+
raise ArgumentError, "datatype with language and direction must be rdf:dirLangString" if (datatype || RDF.dirLangString).to_s != RDF.dirLangString.to_s
|
123
|
+
elsif language
|
124
|
+
raise ArgumentError, "datatype with language must be rdf:langString" if (datatype || RDF.langString).to_s != RDF.langString.to_s
|
125
|
+
else
|
126
|
+
raise ArgumentError, "datatype not compatible with language or direction" if language || direction
|
127
|
+
end
|
110
128
|
|
111
129
|
klass = case
|
112
130
|
when !self.equal?(RDF::Literal)
|
@@ -128,7 +146,7 @@ module RDF
|
|
128
146
|
end
|
129
147
|
end
|
130
148
|
literal = klass.allocate
|
131
|
-
literal.send(:initialize, value, language: language, datatype: datatype, **options)
|
149
|
+
literal.send(:initialize, value, language: language, datatype: datatype, direction: direction, **options)
|
132
150
|
literal.validate! if validate
|
133
151
|
literal.canonicalize! if canonicalize
|
134
152
|
literal
|
@@ -137,18 +155,24 @@ module RDF
|
|
137
155
|
TRUE = RDF::Literal.new(true)
|
138
156
|
FALSE = RDF::Literal.new(false)
|
139
157
|
ZERO = RDF::Literal.new(0)
|
158
|
+
XSD_STRING = RDF::URI("http://www.w3.org/2001/XMLSchema#string")
|
140
159
|
|
141
|
-
# @return [Symbol] The language
|
160
|
+
# @return [Symbol] The language-tag (optional). Implies `datatype` is `rdf:langString`.
|
142
161
|
attr_accessor :language
|
143
162
|
|
163
|
+
# @return [Symbol] The base direction (optional). Implies `datatype` is `rdf:dirLangString`.
|
164
|
+
attr_accessor :direction
|
165
|
+
|
144
166
|
# @return [URI] The XML Schema datatype URI (optional).
|
145
167
|
attr_accessor :datatype
|
146
168
|
|
147
169
|
##
|
148
|
-
# Literals without a datatype are given either xsd:string or rdf:
|
149
|
-
# depending on if there is language
|
170
|
+
# Literals without a datatype are given either `xsd:string`, `rdf:langString`, or `rdf:dirLangString`,
|
171
|
+
# depending on if there is `language` and/or `direction`.
|
150
172
|
#
|
151
173
|
# @param [Object] value
|
174
|
+
# @param [Symbol] direction (nil)
|
175
|
+
# Initial text direction.
|
152
176
|
# @param [Symbol] language (nil)
|
153
177
|
# Language is downcased to ensure proper matching
|
154
178
|
# @param [String] lexical (nil)
|
@@ -163,16 +187,24 @@ module RDF
|
|
163
187
|
# @see http://www.w3.org/TR/rdf11-concepts/#section-Graph-Literal
|
164
188
|
# @see http://www.w3.org/TR/rdf11-concepts/#section-Datatypes
|
165
189
|
# @see #to_s
|
166
|
-
def initialize(value, language: nil, datatype: nil, lexical: nil, validate: false, canonicalize: false, **options)
|
190
|
+
def initialize(value, language: nil, datatype: nil, direction: nil, lexical: nil, validate: false, canonicalize: false, **options)
|
167
191
|
@object = value.freeze
|
168
192
|
@string = lexical if lexical
|
169
193
|
@string = value if !defined?(@string) && value.is_a?(String)
|
170
194
|
@string = @string.encode(Encoding::UTF_8).freeze if instance_variable_defined?(:@string)
|
171
195
|
@object = @string if instance_variable_defined?(:@string) && @object.is_a?(String)
|
172
196
|
@language = language.to_s.downcase.to_sym if language
|
197
|
+
@direction = direction.to_s.downcase.to_sym if direction
|
173
198
|
@datatype = RDF::URI(datatype).freeze if datatype
|
174
199
|
@datatype ||= self.class.const_get(:DATATYPE) if self.class.const_defined?(:DATATYPE)
|
175
|
-
@datatype ||= instance_variable_defined?(:@language) && @language
|
200
|
+
@datatype ||= if instance_variable_defined?(:@language) && @language &&
|
201
|
+
instance_variable_defined?(:@direction) && @direction
|
202
|
+
RDF.dirLangString
|
203
|
+
elsif instance_variable_defined?(:@language) && @language
|
204
|
+
RDF.langString
|
205
|
+
else
|
206
|
+
XSD_STRING
|
207
|
+
end
|
176
208
|
end
|
177
209
|
|
178
210
|
##
|
@@ -202,8 +234,8 @@ module RDF
|
|
202
234
|
#
|
203
235
|
# Compatibility of two arguments is defined as:
|
204
236
|
# * The arguments are simple literals or literals typed as xsd:string
|
205
|
-
# * The arguments are plain literals with identical language
|
206
|
-
# * The first argument is a plain literal with language
|
237
|
+
# * The arguments are plain literals with identical language-tags and directions
|
238
|
+
# * The first argument is a plain literal with language-tag and the second argument is a simple literal or literal typed as xsd:string
|
207
239
|
#
|
208
240
|
# @example
|
209
241
|
# compatible?("abc" "b") #=> true
|
@@ -224,11 +256,11 @@ module RDF
|
|
224
256
|
return false unless other.literal? && plain? && other.plain?
|
225
257
|
|
226
258
|
# * The arguments are simple literals or literals typed as xsd:string
|
227
|
-
# * The arguments are plain literals with identical language
|
228
|
-
# * The first argument is a plain literal with language
|
229
|
-
language? ?
|
230
|
-
(language == other.language || other.datatype ==
|
231
|
-
other.datatype ==
|
259
|
+
# * The arguments are plain literals with identical language-tags
|
260
|
+
# * The first argument is a plain literal with language-tag and the second argument is a simple literal or literal typed as xsd:string
|
261
|
+
language? || direction? ?
|
262
|
+
(language == other.language && direction == other.direction || other.datatype == XSD_STRING) :
|
263
|
+
other.datatype == XSD_STRING
|
232
264
|
end
|
233
265
|
|
234
266
|
##
|
@@ -236,7 +268,7 @@ module RDF
|
|
236
268
|
#
|
237
269
|
# @return [Integer]
|
238
270
|
def hash
|
239
|
-
@hash ||= [to_s, datatype, language].hash
|
271
|
+
@hash ||= [to_s, datatype, language, direction].compact.hash
|
240
272
|
end
|
241
273
|
|
242
274
|
|
@@ -270,6 +302,7 @@ module RDF
|
|
270
302
|
self.value_hash == other.value_hash &&
|
271
303
|
self.value.eql?(other.value) &&
|
272
304
|
self.language.to_s.eql?(other.language.to_s) &&
|
305
|
+
self.direction.to_s.eql?(other.direction.to_s) &&
|
273
306
|
self.datatype.eql?(other.datatype))
|
274
307
|
end
|
275
308
|
|
@@ -290,7 +323,10 @@ module RDF
|
|
290
323
|
case
|
291
324
|
when self.eql?(other)
|
292
325
|
true
|
293
|
-
when self.
|
326
|
+
when self.direction? && self.direction == other.direction
|
327
|
+
# Literals with directions can compare if languages and directions are identical
|
328
|
+
self.value_hash == other.value_hash && self.value == other.value
|
329
|
+
when self.language? && self.language == other.language
|
294
330
|
# Literals with languages can compare if languages are identical
|
295
331
|
self.value_hash == other.value_hash && self.value == other.value
|
296
332
|
when self.simple? && other.simple?
|
@@ -342,14 +378,18 @@ module RDF
|
|
342
378
|
|
343
379
|
##
|
344
380
|
# Returns `true` if this is a plain literal. A plain literal
|
345
|
-
# may have a language, but may not have a datatype. For
|
381
|
+
# may have a language and direction, but may not have a datatype. For
|
346
382
|
# all practical purposes, this includes xsd:string literals
|
347
383
|
# too.
|
348
384
|
#
|
349
385
|
# @return [Boolean] `true` or `false`
|
350
386
|
# @see http://www.w3.org/TR/rdf-concepts/#dfn-plain-literal
|
351
387
|
def plain?
|
352
|
-
[
|
388
|
+
[
|
389
|
+
RDF.langString,
|
390
|
+
RDF.dirLangString,
|
391
|
+
XSD_STRING
|
392
|
+
].include?(datatype)
|
353
393
|
end
|
354
394
|
|
355
395
|
##
|
@@ -359,19 +399,28 @@ module RDF
|
|
359
399
|
# @return [Boolean] `true` or `false`
|
360
400
|
# @see http://www.w3.org/TR/sparql11-query/#simple_literal
|
361
401
|
def simple?
|
362
|
-
datatype ==
|
402
|
+
datatype == XSD_STRING
|
363
403
|
end
|
364
404
|
|
365
405
|
##
|
366
|
-
# Returns `true` if this is a language-tagged
|
406
|
+
# Returns `true` if this is a language-tagged string.
|
367
407
|
#
|
368
408
|
# @return [Boolean] `true` or `false`
|
369
|
-
# @see
|
409
|
+
# @see https://www.w3.org/TR/rdf-concepts/#dfn-language-tagged-string
|
370
410
|
def language?
|
371
|
-
|
411
|
+
[RDF.langString, RDF.dirLangString].include?(datatype)
|
372
412
|
end
|
373
413
|
alias_method :has_language?, :language?
|
374
414
|
|
415
|
+
##
|
416
|
+
# Returns `true` if this is a directional language-tagged string.
|
417
|
+
#
|
418
|
+
# @return [Boolean] `true` or `false`
|
419
|
+
# @see https://www.w3.org/TR/rdf-concepts/#dfn-dir-lang-string
|
420
|
+
def direction?
|
421
|
+
datatype == RDF.dirLangString
|
422
|
+
end
|
423
|
+
|
375
424
|
##
|
376
425
|
# Returns `true` if this is a datatyped literal.
|
377
426
|
#
|
@@ -380,7 +429,7 @@ module RDF
|
|
380
429
|
# @return [Boolean] `true` or `false`
|
381
430
|
# @see http://www.w3.org/TR/rdf-concepts/#dfn-typed-literal
|
382
431
|
def datatype?
|
383
|
-
!plain? && !language?
|
432
|
+
!plain? && !language? && !direction?
|
384
433
|
end
|
385
434
|
alias_method :has_datatype?, :datatype?
|
386
435
|
alias_method :typed?, :datatype?
|
@@ -393,10 +442,13 @@ module RDF
|
|
393
442
|
# @return [Boolean] `true` or `false`
|
394
443
|
# @since 0.2.1
|
395
444
|
def valid?
|
396
|
-
|
445
|
+
BCP47.parse(language.to_s) if language?
|
446
|
+
return false if direction? && !%i{ltr rtl}.include?(direction)
|
397
447
|
return false if datatype? && datatype.invalid?
|
398
448
|
grammar = self.class.const_get(:GRAMMAR) rescue nil
|
399
449
|
grammar.nil? || value.match?(grammar)
|
450
|
+
rescue BCP47::InvalidLanguageTag
|
451
|
+
false
|
400
452
|
end
|
401
453
|
|
402
454
|
##
|
@@ -536,12 +588,12 @@ module RDF
|
|
536
588
|
|
537
589
|
##
|
538
590
|
# @overload #to_str
|
539
|
-
# This method is implemented when the datatype is `xsd:string` or `rdf:
|
591
|
+
# This method is implemented when the datatype is `xsd:string`, `rdf:langString`, or `rdf:dirLangString`
|
540
592
|
# @return [String]
|
541
593
|
def method_missing(name, *args)
|
542
594
|
case name
|
543
595
|
when :to_str
|
544
|
-
return to_s if
|
596
|
+
return to_s if [RDF.langString, RDF.dirLangString, XSD_STRING].include?(@datatype)
|
545
597
|
end
|
546
598
|
super
|
547
599
|
end
|
@@ -549,7 +601,7 @@ module RDF
|
|
549
601
|
def respond_to_missing?(name, include_private = false)
|
550
602
|
case name
|
551
603
|
when :to_str
|
552
|
-
return true if
|
604
|
+
return true if [RDF.langString, RDF.dirLangString, XSD_STRING].include?(@datatype)
|
553
605
|
end
|
554
606
|
super
|
555
607
|
end
|
data/lib/rdf/model/statement.rb
CHANGED
@@ -182,6 +182,7 @@ module RDF
|
|
182
182
|
##
|
183
183
|
# Returns `true` if any element of the statement is, itself, a statement.
|
184
184
|
#
|
185
|
+
# Note: Nomenclature is evolving, alternatives could include `#complex?` and `#nested?`
|
185
186
|
# @return [Boolean]
|
186
187
|
def embedded?
|
187
188
|
subject && subject.statement? || object && object.statement?
|
@@ -410,7 +411,7 @@ module RDF
|
|
410
411
|
end
|
411
412
|
|
412
413
|
##
|
413
|
-
# Canonicalizes each unfrozen term in the statement
|
414
|
+
# Canonicalizes each unfrozen term in the statement.
|
414
415
|
#
|
415
416
|
# @return [RDF::Statement] `self`
|
416
417
|
# @since 1.0.8
|
@@ -436,6 +437,18 @@ module RDF
|
|
436
437
|
nil
|
437
438
|
end
|
438
439
|
|
440
|
+
# New statement with duplicated components (other than blank nodes)
|
441
|
+
#
|
442
|
+
# @return [RDF::Statement]
|
443
|
+
def dup
|
444
|
+
options = Hash[@options]
|
445
|
+
options[:subject] = subject.is_a?(RDF::Node) ? subject : subject.dup
|
446
|
+
options[:predicate] = predicate.dup
|
447
|
+
options[:object] = object.is_a?(RDF::Node) ? object : object.dup
|
448
|
+
options[:graph_name] = graph_name.is_a?(RDF::Node) ? graph_name : graph_name.dup if graph_name
|
449
|
+
RDF::Statement.new(options)
|
450
|
+
end
|
451
|
+
|
439
452
|
##
|
440
453
|
# Returns the terms of this statement as a `Hash`.
|
441
454
|
#
|