json-ld 3.1.5 → 3.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 65b570568511427e573b9ffecdc5eedfee1b708c62e88ffc24dce4ffa8d62c2f
4
- data.tar.gz: a3255398de49dd88c3d4b3beb918857c8939de6eed4cf92c2aa1f61764455b59
3
+ metadata.gz: 2509fe2ee3a0766a3e332d062f11ad05d02bf7a3c00e423dfe4ac8eec23f9746
4
+ data.tar.gz: 277416c70b52a06ec85d89394fe18ccbe9eacb53538a6c65432ed390728b93ca
5
5
  SHA512:
6
- metadata.gz: 6f84d29c4d742ffe07dbdc585f8d51e612b7426dc3a58d21061d959587ebdfff0801bc02d3c7edf11426d03d6b9d500a54bdd172afc34b460bd5957fc0f9e4c5
7
- data.tar.gz: ee8b915d0fb258e909e751c668ea31750b255d5d7e0276123439a149eece298284324fb63a8d13df9b23109f0662dcbcd0db41f56e23e22f745da17f50f7b75b
6
+ metadata.gz: 20db323ff35ccd493d9fbd0b6f73f4c5fc517678363aff6fbf21f114ce33e2e491f4717e87c3ad3f2a19c31beb728c627b00cb7f8bff268575c6655cc29e6ff2
7
+ data.tar.gz: da506865a8f17c2fc304159bfb61411d11c433b656ea58bf1b19371618a2c0f02c08274f8a5a6ca97f1f9087a7d797b9be087314fd0cd41e154fe53721fcb6d8
data/README.md CHANGED
@@ -2,9 +2,10 @@
2
2
 
3
3
  [JSON-LD][] reader/writer for [RDF.rb][RDF.rb] and fully conforming [JSON-LD API][] processor. Additionally this gem implements [JSON-LD Framing][].
4
4
 
5
- [![Gem Version](https://badge.fury.io/rb/json-ld.png)](https://badge.fury.io/rb/json-ld)
6
- [![Build Status](https://secure.travis-ci.org/ruby-rdf/json-ld.png?branch=master)](https://travis-ci.org/ruby-rdf/json-ld)
7
- [![Coverage Status](https://coveralls.io/repos/ruby-rdf/json-ld/badge.svg)](https://coveralls.io/r/ruby-rdf/json-ld)
5
+ [![Gem Version](https://badge.fury.io/rb/json-ld.png)](https://rubygems.org/gems/json-ld)
6
+ [![Build Status](https://secure.travis-ci.org/ruby-rdf/json-ld.png?branch=develop)](https://github.com/ruby-rdf/json-ld/actions?query=workflow%3ACI)
7
+ [![Coverage Status](https://coveralls.io/repos/ruby-rdf/json-ld/badge.svg)](https://coveralls.io/github/ruby-rdf/json-ld)
8
+ [![Gitter chat](https://badges.gitter.im/ruby-rdf.png)](https://gitter.im/gitterHQ/gitter)
8
9
 
9
10
  ## Features
10
11
 
@@ -14,6 +15,7 @@ JSON::LD can now be used to create a _context_ from an RDFS/OWL definition, and
14
15
 
15
16
  * If the [jsonlint][] gem is installed, it will be used when validating an input document.
16
17
  * If available, uses [Nokogiri][] and/or [Nokogumbo][] for parsing HTML, falls back to REXML otherwise.
18
+ * Provisional support for [JSON-LD*][JSON-LD*].
17
19
 
18
20
  [Implementation Report](file.earl.html)
19
21
 
@@ -35,6 +37,59 @@ The order of triples retrieved from the `RDF::Enumerable` dataset determines the
35
37
  ### MultiJson parser
36
38
  The [MultiJson](https://rubygems.org/gems/multi_json) gem is used for parsing JSON; this defaults to the native JSON parser, but will use a more performant parser if one is available. A specific parser can be specified by adding the `:adapter` option to any API call. See [MultiJson](https://rubygems.org/gems/multi_json) for more information.
37
39
 
40
+ ### JSON-LD* (RDFStar)
41
+
42
+ The {JSON::LD::API.toRdf} and {JSON::LD::API.fromRdf} API methods, along with the {JSON::LD::Reader} and {JSON::LD::Writer}, include provisional support for [JSON-LD*][JSON-LD*].
43
+
44
+ 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`.
45
+
46
+ In JSON-LD, with the `rdfstar` option set, the value of `@id`, in addition to an IRI or Blank Node Identifier, can be a JSON-LD node object having exactly one property with an optional `@id`, which may also be an embedded object. (It may also have `@context` and `@index` values).
47
+
48
+ {
49
+ "@id": {
50
+ "@context": {"foaf": "http://xmlns.com/foaf/0.1/"},
51
+ "@index": "ignored",
52
+ "@id": "bob",
53
+ "foaf:age" 23
54
+ },
55
+ "ex:certainty": 0.9
56
+ }
57
+
58
+ **Note: This feature is subject to change or elimination as the standards process progresses.**
59
+
60
+ #### Serializing a Graph containing embedded statements
61
+
62
+ require 'json-ld'
63
+ statement = RDF::Statement(RDF::URI('bob'), RDF::Vocab::FOAF.age, RDF::Literal(23))
64
+ graph = RDF::Graph.new << [statement, RDF::URI("ex:certainty"), RDF::Literal(0.9)]
65
+ graph.dump(:jsonld, validate: false, standard_prefixes: true)
66
+ # => {"@id": {"@id": "bob", "foaf:age" 23}, "ex:certainty": 0.9}
67
+
68
+ Alternatively, using the {JSON::LD::API.fromRdf} method:
69
+
70
+ JSON::LD::API::fromRdf(graph)
71
+ # => {"@id": {"@id": "bob", "foaf:age" 23}, "ex:certainty": 0.9}
72
+
73
+ #### Reading a Graph containing embedded statements
74
+
75
+ By default, {JSON::LD::API.toRdf} (and {JSON::LD::Reader}) will reject a document containing a subject resource.
76
+
77
+ jsonld = %({
78
+ "@id": {
79
+ "@id": "bob", "foaf:age" 23
80
+ },
81
+ "ex:certainty": 0.9
82
+ })
83
+ graph = RDF::Graph.new << JSON::LD::API.toRdf(input)
84
+ # => JSON::LD::JsonLdError::InvalidIdValue
85
+
86
+ {JSON::LD::API.toRdf} (and {JSON::LD::Reader}) support a boolean valued `rdfstar` option; only one statement is asserted, although the reified statement is contained within the graph.
87
+
88
+ graph = RDF::Graph.new do |graph|
89
+ JSON::LD::Reader.new(jsonld, rdfstar: true) {|reader| graph << reader}
90
+ end
91
+ graph.count #=> 1
92
+
38
93
  ## Examples
39
94
 
40
95
  ```ruby
@@ -568,6 +623,7 @@ see <https://unlicense.org/> or the accompanying {file:UNLICENSE} file.
568
623
  [YARD-GS]: https://rubydoc.info/docs/yard/file/docs/GettingStarted.md
569
624
  [PDD]: https://unlicense.org/#unlicensing-contributions
570
625
  [RDF.rb]: https://rubygems.org/gems/rdf
626
+ [JSON-LD*]: https://json-ld.github.io/json-ld-star/
571
627
  [Rack::LinkedData]: https://rubygems.org/gems/rack-linkeddata
572
628
  [Backports]: https://rubygems.org/gems/backports
573
629
  [JSON-LD]: https://www.w3.org/TR/json-ld11/ "JSON-LD 1.1"
data/VERSION CHANGED
@@ -1 +1 @@
1
- 3.1.5
1
+ 3.1.6
@@ -137,6 +137,7 @@ module JSON
137
137
  class InvalidNestValue < JsonLdError; @code = "invalid @nest value"; end
138
138
  class InvalidPrefixValue < JsonLdError; @code = "invalid @prefix value"; end
139
139
  class InvalidPropagateValue < JsonLdError; @code = "invalid @propagate value"; end
140
+ class InvalidEmbeddedNode < JsonLdError; @code = "invalid reified node"; end
140
141
  class InvalidRemoteContext < JsonLdError; @code = "invalid remote context"; end
141
142
  class InvalidReverseProperty < JsonLdError; @code = "invalid reverse property"; end
142
143
  class InvalidReversePropertyMap < JsonLdError; @code = "invalid reverse property map"; end
@@ -89,6 +89,8 @@ module JSON::LD
89
89
  # @option options [String] :processingMode
90
90
  # Processing mode, json-ld-1.0 or json-ld-1.1.
91
91
  # If `processingMode` is not specified, a mode of `json-ld-1.0` or `json-ld-1.1` is set, the context used for `expansion` or `compaction`.
92
+ # @option options [Boolean] rdfstar (false)
93
+ # support parsing JSON-LD* statement resources.
92
94
  # @option options [Boolean] :rename_bnodes (true)
93
95
  # Rename bnodes as part of expansion, or keep them the same.
94
96
  # @option options [Boolean] :unique_bnodes (false)
@@ -273,12 +273,23 @@ module JSON::LD
273
273
  context.expand_iri(v, as_string: true, base: @options[:base], documentRelative: true)
274
274
  end
275
275
  when Hash
276
- raise JsonLdError::InvalidIdValue,
277
- "value of @id must be a string unless framing: #{value.inspect}" unless framing
278
- raise JsonLdError::InvalidTypeValue,
279
- "value of @id must be a an empty object for framing: #{value.inspect}" unless
280
- value.empty?
281
- [{}]
276
+ if framing
277
+ raise JsonLdError::InvalidTypeValue,
278
+ "value of @id must be a an empty object for framing: #{value.inspect}" unless
279
+ value.empty?
280
+ [{}]
281
+ elsif @options[:rdfstar]
282
+ # Result must have just a single statement
283
+ rei_node = expand(value, active_property, context, log_depth: log_depth.to_i + 1)
284
+ statements = to_enum(:item_to_rdf, rei_node)
285
+ raise JsonLdError::InvalidEmbeddedNode,
286
+ "Embedded node with #{statements.size} statements" unless
287
+ statements.count == 1
288
+ rei_node
289
+ else
290
+ raise JsonLdError::InvalidIdValue,
291
+ "value of @id must be a string unless framing: #{value.inspect}" unless framing
292
+ end
282
293
  else
283
294
  raise JsonLdError::InvalidIdValue,
284
295
  "value of @id must be a string or hash if framing: #{value.inspect}"
@@ -165,7 +165,16 @@ module JSON::LD
165
165
  end
166
166
  end
167
167
  end
168
- end
168
+ end,
169
+ options: [
170
+ RDF::CLI::Option.new(
171
+ symbol: :context,
172
+ datatype: RDF::URI,
173
+ control: :url2,
174
+ use: :required,
175
+ on: ["--context CONTEXT"],
176
+ description: "Context to use when compacting.") {|arg| RDF::URI(arg)},
177
+ ]
169
178
  },
170
179
  frame: {
171
180
  description: "Frame JSON-LD or parsed RDF",
@@ -22,7 +22,6 @@ module JSON::LD
22
22
  referenced_once = {}
23
23
 
24
24
  value = nil
25
- ec = @context
26
25
 
27
26
  # Create an entry for compound-literal node detection
28
27
  compound_literal_subjects = {}
@@ -33,7 +32,7 @@ module JSON::LD
33
32
  dataset.each do |statement|
34
33
  #log_debug("statement") { statement.to_nquads.chomp}
35
34
 
36
- name = statement.graph_name ? ec.expand_iri(statement.graph_name, base: @options[:base]).to_s : '@default'
35
+ name = statement.graph_name ? @context.expand_iri(statement.graph_name, base: @options[:base]).to_s : '@default'
37
36
 
38
37
  # Create a graph entry as needed
39
38
  node_map = graph_map[name] ||= {}
@@ -41,30 +40,29 @@ module JSON::LD
41
40
 
42
41
  default_graph[name] ||= {'@id' => name} unless name == '@default'
43
42
 
44
- subject = ec.expand_iri(statement.subject, as_string: true, base: @options[:base])
45
- node = node_map[subject] ||= {'@id' => subject}
43
+ subject = statement.subject.to_s
44
+ node = node_map[subject] ||= resource_representation(statement.subject,useNativeTypes)
46
45
 
47
46
  # If predicate is rdf:datatype, note subject in compound literal subjects map
48
47
  if @options[:rdfDirection] == 'compound-literal' && statement.predicate == RDF.to_uri + 'direction'
49
48
  compound_literal_subjects[name][subject] ||= true
50
49
  end
51
50
 
52
- # If object is an IRI or blank node identifier, and node map does not have an object member, create one and initialize its value to a new JSON object consisting of a single member @id whose value is set to object.
53
- node_map[statement.object.to_s] ||= {'@id' => statement.object.to_s} unless
54
- statement.object.literal?
51
+ # If object is an IRI, blank node identifier, or statement, and node map does not have an object member, create one and initialize its value to a new JSON object consisting of a single member @id whose value is set to object.
52
+ unless statement.object.literal?
53
+ node_map[statement.object.to_s] ||=
54
+ resource_representation(statement.object, useNativeTypes)
55
+ end
55
56
 
56
57
  # If predicate equals rdf:type, and object is an IRI or blank node identifier, append object to the value of the @type member of node. If no such member exists, create one and initialize it to an array whose only item is object. Finally, continue to the next RDF triple.
58
+ # XXX JSON-LD* does not support embedded value of @type
57
59
  if statement.predicate == RDF.type && statement.object.resource? && !useRdfType
58
60
  merge_value(node, '@type', statement.object.to_s)
59
61
  next
60
62
  end
61
63
 
62
64
  # Set value to the result of using the RDF to Object Conversion algorithm, passing object, rdfDirection, and use native types.
63
- value = ec.expand_value(nil,
64
- statement.object,
65
- rdfDirection: @options[:rdfDirection],
66
- useNativeTypes: useNativeTypes,
67
- base: @options[:base])
65
+ value = resource_representation(statement.object, useNativeTypes)
68
66
 
69
67
  merge_value(node, statement.predicate.to_s, value)
70
68
 
@@ -162,5 +160,31 @@ module JSON::LD
162
160
  #log_debug("fromRdf") {result.to_json(JSON_STATE) rescue 'malformed json'}
163
161
  result
164
162
  end
163
+
164
+ private
165
+ def resource_representation(resource, useNativeTypes)
166
+ case resource
167
+ when RDF::Statement
168
+ # Note, if either subject or object are a BNode which is used elsewhere,
169
+ # this might not work will with the BNode accounting from above.
170
+ rep = {'@id' => resource_representation(resource.subject, false)}
171
+ if resource.predicate == RDF.type
172
+ rep['@id'].merge!('@type' => resource.object.to_s)
173
+ else
174
+ rep['@id'].merge!(
175
+ resource.predicate.to_s =>
176
+ as_array(resource_representation(resource.object, useNativeTypes)))
177
+ end
178
+ rep
179
+ when RDF::Literal
180
+ @context.expand_value(nil,
181
+ resource,
182
+ rdfDirection: @options[:rdfDirection],
183
+ useNativeTypes: useNativeTypes,
184
+ base: @options[:base])
185
+ else
186
+ {'@id' => resource.to_s}
187
+ end
188
+ end
165
189
  end
166
190
  end
@@ -16,6 +16,8 @@ module JSON::LD
16
16
  # @return RDF::Resource the subject of this item
17
17
  def item_to_rdf(item, graph_name: nil, &block)
18
18
  # Just return value object as Term
19
+ return unless item
20
+
19
21
  if value?(item)
20
22
  value, datatype = item.fetch('@value'), item.fetch('@type', nil)
21
23
 
@@ -76,11 +78,13 @@ module JSON::LD
76
78
  return parse_list(item['@list'], graph_name: graph_name, &block)
77
79
  end
78
80
 
79
- # Skip if '@id' is nil
80
- subject = if item.has_key?('@id')
81
- item['@id'].nil? ? nil : as_resource(item['@id'])
82
- else
83
- node
81
+ subject = case item['@id']
82
+ when nil then node
83
+ when String then as_resource(item['@id'])
84
+ when Object
85
+ # Embedded statement
86
+ # (No error checking, as this is done in expansion)
87
+ to_enum(:item_to_rdf, item['@id']).to_a.first
84
88
  end
85
89
 
86
90
  #log_debug("item_to_rdf") {"subject: #{subject.to_ntriples rescue 'malformed rdf'}"}
@@ -3376,6 +3376,254 @@ describe JSON::LD::API do
3376
3376
  end
3377
3377
  end
3378
3378
 
3379
+ context "JSON-LD*" do
3380
+ {
3381
+ "node with embedded subject without rdfstar option": {
3382
+ input: %({
3383
+ "@id": {
3384
+ "@id": "ex:rei",
3385
+ "ex:prop": "value"
3386
+ },
3387
+ "ex:prop": "value2"
3388
+ }),
3389
+ exception: JSON::LD::JsonLdError::InvalidIdValue
3390
+ },
3391
+ }.each do |title, params|
3392
+ it(title) {run_expand params}
3393
+ end
3394
+
3395
+ {
3396
+ "node with embedded subject having no @id": {
3397
+ input: %({
3398
+ "@id": {
3399
+ "ex:prop": "value"
3400
+ },
3401
+ "ex:prop": "value2"
3402
+ }),
3403
+ output: %([{
3404
+ "@id": {
3405
+ "ex:prop": [{"@value": "value"}]
3406
+ },
3407
+ "ex:prop": [{"@value": "value2"}]
3408
+ }])
3409
+ },
3410
+ "node with embedded subject having IRI @id": {
3411
+ input: %({
3412
+ "@id": {
3413
+ "@id": "ex:rei",
3414
+ "ex:prop": "value"
3415
+ },
3416
+ "ex:prop": "value2"
3417
+ }),
3418
+ output: %([{
3419
+ "@id": {
3420
+ "@id": "ex:rei",
3421
+ "ex:prop": [{"@value": "value"}]
3422
+ },
3423
+ "ex:prop": [{"@value": "value2"}]
3424
+ }])
3425
+ },
3426
+ "node with embedded subject having BNode @id": {
3427
+ input: %({
3428
+ "@id": {
3429
+ "@id": "_:rei",
3430
+ "ex:prop": "value"
3431
+ },
3432
+ "ex:prop": "value2"
3433
+ }),
3434
+ output: %([{
3435
+ "@id": {
3436
+ "@id": "_:rei",
3437
+ "ex:prop": [{"@value": "value"}]
3438
+ },
3439
+ "ex:prop": [{"@value": "value2"}]
3440
+ }])
3441
+ },
3442
+ "node with embedded subject having a type": {
3443
+ input: %({
3444
+ "@id": {
3445
+ "@id": "ex:rei",
3446
+ "@type": "ex:Type"
3447
+ },
3448
+ "ex:prop": "value2"
3449
+ }),
3450
+ output: %([{
3451
+ "@id": {
3452
+ "@id": "ex:rei",
3453
+ "@type": ["ex:Type"]
3454
+ },
3455
+ "ex:prop": [{"@value": "value2"}]
3456
+ }])
3457
+ },
3458
+ "node with embedded subject having an IRI value": {
3459
+ input: %({
3460
+ "@id": {
3461
+ "@id": "ex:rei",
3462
+ "ex:prop": {"@id": "ex:value"}
3463
+ },
3464
+ "ex:prop": "value2"
3465
+ }),
3466
+ output: %([{
3467
+ "@id": {
3468
+ "@id": "ex:rei",
3469
+ "ex:prop": [{"@id": "ex:value"}]
3470
+ },
3471
+ "ex:prop": [{"@value": "value2"}]
3472
+ }])
3473
+ },
3474
+ "node with embedded subject having an BNode value": {
3475
+ input: %({
3476
+ "@id": {
3477
+ "@id": "ex:rei",
3478
+ "ex:prop": {"@id": "_:value"}
3479
+ },
3480
+ "ex:prop": "value2"
3481
+ }),
3482
+ output: %([{
3483
+ "@id": {
3484
+ "@id": "ex:rei",
3485
+ "ex:prop": [{"@id": "_:value"}]
3486
+ },
3487
+ "ex:prop": [{"@value": "value2"}]
3488
+ }])
3489
+ },
3490
+ "node with recursive embedded subject": {
3491
+ input: %({
3492
+ "@id": {
3493
+ "@id": {
3494
+ "@id": "ex:rei",
3495
+ "ex:prop": "value3"
3496
+ },
3497
+ "ex:prop": "value"
3498
+ },
3499
+ "ex:prop": "value2"
3500
+ }),
3501
+ output: %([{
3502
+ "@id": {
3503
+ "@id": {
3504
+ "@id": "ex:rei",
3505
+ "ex:prop": [{"@value": "value3"}]
3506
+ },
3507
+ "ex:prop": [{"@value": "value"}]
3508
+ },
3509
+ "ex:prop": [{"@value": "value2"}]
3510
+ }])
3511
+ },
3512
+ "illegal node with subject having no property": {
3513
+ input: %({
3514
+ "@id": {
3515
+ "@id": "ex:rei"
3516
+ },
3517
+ "ex:prop": "value3"
3518
+ }),
3519
+ exception: JSON::LD::JsonLdError::InvalidEmbeddedNode
3520
+ },
3521
+ "illegal node with subject having multiple properties": {
3522
+ input: %({
3523
+ "@id": {
3524
+ "@id": "ex:rei",
3525
+ "ex:prop": ["value1", "value2"]
3526
+ },
3527
+ "ex:prop": "value3"
3528
+ }),
3529
+ exception: JSON::LD::JsonLdError::InvalidEmbeddedNode
3530
+ },
3531
+ "illegal node with subject having multiple types": {
3532
+ input: %({
3533
+ "@id": {
3534
+ "@id": "ex:rei",
3535
+ "@type": ["ex:Type1", "ex:Type2"]
3536
+ },
3537
+ "ex:prop": "value3"
3538
+ }),
3539
+ exception: JSON::LD::JsonLdError::InvalidEmbeddedNode
3540
+ },
3541
+ "illegal node with subject having type and property": {
3542
+ input: %({
3543
+ "@id": {
3544
+ "@id": "ex:rei",
3545
+ "@type": "ex:Type",
3546
+ "ex:prop": "value"
3547
+ },
3548
+ "ex:prop": "value2"
3549
+ }),
3550
+ exception: JSON::LD::JsonLdError::InvalidEmbeddedNode
3551
+ },
3552
+ "node with embedded object": {
3553
+ input: %({
3554
+ "@id": "ex:subj",
3555
+ "ex:value": {
3556
+ "@id": {
3557
+ "@id": "ex:rei",
3558
+ "ex:prop": "value"
3559
+ }
3560
+ }
3561
+ }),
3562
+ output: %([{
3563
+ "@id": "ex:subj",
3564
+ "ex:value": [{
3565
+ "@id": {
3566
+ "@id": "ex:rei",
3567
+ "ex:prop": [{"@value": "value"}]
3568
+ }
3569
+ }]
3570
+ }])
3571
+ },
3572
+ "illegal node with embedded object having properties": {
3573
+ input: %({
3574
+ "@id": "ex:subj",
3575
+ "ex:value": {
3576
+ "@id": {
3577
+ "@id": "ex:rei",
3578
+ "ex:prop": "value"
3579
+ },
3580
+ "ex:prop": "value2"
3581
+ }
3582
+ }),
3583
+ output: %([{
3584
+ "@id": "ex:subj",
3585
+ "ex:value": [{
3586
+ "@id": {
3587
+ "@id": "ex:rei",
3588
+ "ex:prop": [{"@value": "value"}]
3589
+ },
3590
+ "ex:prop": [{"@value": "value2"}]
3591
+ }]
3592
+ }])
3593
+ },
3594
+ "node with recursive embedded object": {
3595
+ input: %({
3596
+ "@id": "ex:subj",
3597
+ "ex:value": {
3598
+ "@id": {
3599
+ "@id": {
3600
+ "@id": "ex:rei",
3601
+ "ex:prop": "value3"
3602
+ },
3603
+ "ex:prop": "value"
3604
+ },
3605
+ "ex:prop": "value2"
3606
+ }
3607
+ }),
3608
+ output: %([{
3609
+ "@id": "ex:subj",
3610
+ "ex:value": [{
3611
+ "@id": {
3612
+ "@id": {
3613
+ "@id": "ex:rei",
3614
+ "ex:prop": [{"@value": "value3"}]
3615
+ },
3616
+ "ex:prop":[{"@value": "value"}]
3617
+ },
3618
+ "ex:prop": [{"@value": "value2"}]
3619
+ }]
3620
+ }])
3621
+ },
3622
+ }.each do |title, params|
3623
+ it(title) {run_expand params.merge(rdfstar: true)}
3624
+ end
3625
+ end
3626
+
3379
3627
  begin
3380
3628
  require 'nokogiri'
3381
3629
  rescue LoadError
@@ -766,6 +766,187 @@ describe JSON::LD::API do
766
766
  end
767
767
  end
768
768
 
769
+ context "RDF*" do
770
+ {
771
+ "subject-iii": {
772
+ input: RDF::Statement(
773
+ RDF::Statement(
774
+ RDF::URI('http://example/s1'),
775
+ RDF::URI('http://example/p1'),
776
+ RDF::URI('http://example/o1')),
777
+ RDF::URI('http://example/p'),
778
+ RDF::URI('http://example/o')),
779
+ output: %([{
780
+ "@id": {
781
+ "@id": "http://example/s1",
782
+ "http://example/p1": [{"@id": "http://example/o1"}]
783
+ },
784
+ "http://example/p": [{"@id": "http://example/o"}]
785
+ }])
786
+ },
787
+ "subject-iib": {
788
+ input: RDF::Statement(
789
+ RDF::Statement(
790
+ RDF::URI('http://example/s1'),
791
+ RDF::URI('http://example/p1'),
792
+ RDF::Node.new('o1')),
793
+ RDF::URI('http://example/p'),
794
+ RDF::URI('http://example/o')),
795
+ output: %([{
796
+ "@id": {
797
+ "@id": "http://example/s1",
798
+ "http://example/p1": [{"@id": "_:o1"}]
799
+ },
800
+ "http://example/p": [{"@id": "http://example/o"}]
801
+ }])
802
+ },
803
+ "subject-iil": {
804
+ input: RDF::Statement(
805
+ RDF::Statement(
806
+ RDF::URI('http://example/s1'),
807
+ RDF::URI('http://example/p1'),
808
+ RDF::Literal('o1')),
809
+ RDF::URI('http://example/p'),
810
+ RDF::URI('http://example/o')),
811
+ output: %([{
812
+ "@id": {
813
+ "@id": "http://example/s1",
814
+ "http://example/p1": [{"@value": "o1"}]
815
+ },
816
+ "http://example/p": [{"@id": "http://example/o"}]
817
+ }])
818
+ },
819
+ "subject-bii": {
820
+ input: RDF::Statement(
821
+ RDF::Statement(
822
+ RDF::Node('s1'),
823
+ RDF::URI('http://example/p1'),
824
+ RDF::URI('http://example/o1')),
825
+ RDF::URI('http://example/p'),
826
+ RDF::URI('http://example/o')),
827
+ output: %([{
828
+ "@id": {
829
+ "@id": "_:s1",
830
+ "http://example/p1": [{"@id": "http://example/o1"}]
831
+ },
832
+ "http://example/p": [{"@id": "http://example/o"}]
833
+ }])
834
+ },
835
+ "subject-bib": {
836
+ input: RDF::Statement(
837
+ RDF::Statement(
838
+ RDF::Node('s1'),
839
+ RDF::URI('http://example/p1'),
840
+ RDF::Node.new('o1')),
841
+ RDF::URI('http://example/p'), RDF::URI('http://example/o')),
842
+ output: %([{
843
+ "@id": {
844
+ "@id": "_:s1",
845
+ "http://example/p1": [{"@id": "_:o1"}]
846
+ },
847
+ "http://example/p": [{"@id": "http://example/o"}]
848
+ }])
849
+ },
850
+ "subject-bil": {
851
+ input: RDF::Statement(
852
+ RDF::Statement(
853
+ RDF::Node('s1'),
854
+ RDF::URI('http://example/p1'),
855
+ RDF::Literal('o1')),
856
+ RDF::URI('http://example/p'),
857
+ RDF::URI('http://example/o')),
858
+ output: %([{
859
+ "@id": {
860
+ "@id": "_:s1",
861
+ "http://example/p1": [{"@value": "o1"}]
862
+ },
863
+ "http://example/p": [{"@id": "http://example/o"}]
864
+ }])
865
+ },
866
+ "object-iii": {
867
+ input: RDF::Statement(
868
+ RDF::URI('http://example/s'),
869
+ RDF::URI('http://example/p'),
870
+ RDF::Statement(
871
+ RDF::URI('http://example/s1'),
872
+ RDF::URI('http://example/p1'),
873
+ RDF::URI('http://example/o1'))),
874
+ output: %([{
875
+ "@id": "http://example/s",
876
+ "http://example/p": [{
877
+ "@id": {
878
+ "@id": "http://example/s1",
879
+ "http://example/p1": [{"@id": "http://example/o1"}]
880
+ }
881
+ }]
882
+ }])
883
+ },
884
+ "object-iib": {
885
+ input: RDF::Statement(
886
+ RDF::URI('http://example/s'),
887
+ RDF::URI('http://example/p'),
888
+ RDF::Statement(
889
+ RDF::URI('http://example/s1'),
890
+ RDF::URI('http://example/p1'),
891
+ RDF::Node.new('o1'))),
892
+ output: %([{
893
+ "@id": "http://example/s",
894
+ "http://example/p": [{
895
+ "@id": {
896
+ "@id": "http://example/s1",
897
+ "http://example/p1": [{"@id": "_:o1"}]
898
+ }
899
+ }]
900
+ }])
901
+ },
902
+ "object-iil": {
903
+ input: RDF::Statement(
904
+ RDF::URI('http://example/s'),
905
+ RDF::URI('http://example/p'),
906
+ RDF::Statement(
907
+ RDF::URI('http://example/s1'),
908
+ RDF::URI('http://example/p1'),
909
+ RDF::Literal('o1'))),
910
+ output: %([{
911
+ "@id": "http://example/s",
912
+ "http://example/p": [{
913
+ "@id": {
914
+ "@id": "http://example/s1",
915
+ "http://example/p1": [{"@value": "o1"}]
916
+ }
917
+ }]
918
+ }])
919
+ },
920
+ "recursive-subject": {
921
+ input: RDF::Statement(
922
+ RDF::Statement(
923
+ RDF::Statement(
924
+ RDF::URI('http://example/s2'),
925
+ RDF::URI('http://example/p2'),
926
+ RDF::URI('http://example/o2')),
927
+ RDF::URI('http://example/p1'),
928
+ RDF::URI('http://example/o1')),
929
+ RDF::URI('http://example/p'),
930
+ RDF::URI('http://example/o')),
931
+ output: %([{
932
+ "@id": {
933
+ "@id": {
934
+ "@id": "http://example/s2",
935
+ "http://example/p2": [{"@id": "http://example/o2"}]
936
+ },
937
+ "http://example/p1": [{"@id": "http://example/o1"}]
938
+ },
939
+ "http://example/p": [{"@id": "http://example/o"}]
940
+ }])
941
+ },
942
+ }.each do |name, params|
943
+ it name do
944
+ graph = RDF::Graph.new {|g| g << params[:input]}
945
+ do_fromRdf(params.merge(input: graph, prefixes: {ex: 'http://example/'}))
946
+ end
947
+ end
948
+ end
949
+
769
950
  context "problems" do
770
951
  {
771
952
  "xsd:boolean as value" => {
@@ -9,6 +9,7 @@ describe JSON::LD do
9
9
  m.entries.each do |t|
10
10
  specify "#{t.property('@id')}: #{t.name}#{' (negative test)' unless t.positiveTest?}" do
11
11
  pending "Generalized RDF" if t.options[:produceGeneralizedRdf]
12
+ pending "RDF*" if t.property('@id') == '#te122'
12
13
  if %w(#t0118).include?(t.property('@id'))
13
14
  expect {t.run self}.to write(/Statement .* is invalid/).to(:error)
14
15
  elsif %w(#te075).include?(t.property('@id'))
@@ -1175,6 +1175,212 @@ describe JSON::LD::API do
1175
1175
  end
1176
1176
  end
1177
1177
 
1178
+ context "JSON-LD*" do
1179
+ {
1180
+ "node with embedded subject without rdfstar option": {
1181
+ input: %({
1182
+ "@id": {
1183
+ "@id": "ex:rei",
1184
+ "ex:prop": "value"
1185
+ },
1186
+ "ex:prop": "value2"
1187
+ }),
1188
+ exception: JSON::LD::JsonLdError::InvalidIdValue
1189
+ },
1190
+ }.each do |title, params|
1191
+ it(title) {run_to_rdf params}
1192
+ end
1193
+
1194
+ {
1195
+ "node with embedded subject having no @id": {
1196
+ input: %({
1197
+ "@id": {
1198
+ "ex:prop": "value"
1199
+ },
1200
+ "ex:prop": "value2"
1201
+ }),
1202
+ expected: %(
1203
+ <<_:b0 <ex:prop> "value">> <ex:prop> "value2" .
1204
+ ),
1205
+ },
1206
+ "node with embedded subject having IRI @id": {
1207
+ input: %({
1208
+ "@id": {
1209
+ "@id": "ex:rei",
1210
+ "ex:prop": "value"
1211
+ },
1212
+ "ex:prop": "value2"
1213
+ }),
1214
+ expected: %(
1215
+ <<<ex:rei> <ex:prop> "value">> <ex:prop> "value2" .
1216
+ ),
1217
+ },
1218
+ "node with embedded subject having BNode @id": {
1219
+ input: %({
1220
+ "@id": {
1221
+ "@id": "_:rei",
1222
+ "ex:prop": "value"
1223
+ },
1224
+ "ex:prop": "value2"
1225
+ }),
1226
+ expected: %(
1227
+ <<_:b0 <ex:prop> "value">> <ex:prop> "value2" .
1228
+ ),
1229
+ },
1230
+ "node with embedded subject having a type": {
1231
+ input: %({
1232
+ "@id": {
1233
+ "@id": "ex:rei",
1234
+ "@type": "ex:Type"
1235
+ },
1236
+ "ex:prop": "value2"
1237
+ }),
1238
+ expected: %(
1239
+ <<<ex:rei> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <ex:Type>>> <ex:prop> "value2" .
1240
+ ),
1241
+ },
1242
+ "node with embedded subject having an IRI value": {
1243
+ input: %({
1244
+ "@id": {
1245
+ "@id": "ex:rei",
1246
+ "ex:prop": {"@id": "ex:value"}
1247
+ },
1248
+ "ex:prop": "value2"
1249
+ }),
1250
+ expected: %(
1251
+ <<<ex:rei> <ex:prop> <ex:value>>> <ex:prop> "value2" .
1252
+ ),
1253
+ },
1254
+ "node with embedded subject having an BNode value": {
1255
+ input: %({
1256
+ "@id": {
1257
+ "@id": "ex:rei",
1258
+ "ex:prop": {"@id": "_:value"}
1259
+ },
1260
+ "ex:prop": "value2"
1261
+ }),
1262
+ expected: %(
1263
+ <<<ex:rei> <ex:prop> _:b0>> <ex:prop> "value2" .
1264
+ ),
1265
+ },
1266
+ "node with recursive embedded subject": {
1267
+ input: %({
1268
+ "@id": {
1269
+ "@id": {
1270
+ "@id": "ex:rei",
1271
+ "ex:prop": "value3"
1272
+ },
1273
+ "ex:prop": "value"
1274
+ },
1275
+ "ex:prop": "value2"
1276
+ }),
1277
+ expected: %(
1278
+ <<<<<ex:rei> <ex:prop> "value3">> <ex:prop> "value">> <ex:prop> "value2" .
1279
+ ),
1280
+ },
1281
+ "illegal node with subject having no property": {
1282
+ input: %({
1283
+ "@id": {
1284
+ "@id": "ex:rei"
1285
+ },
1286
+ "ex:prop": "value3"
1287
+ }),
1288
+ exception: JSON::LD::JsonLdError::InvalidEmbeddedNode
1289
+ },
1290
+ "illegal node with subject having multiple properties": {
1291
+ input: %({
1292
+ "@id": {
1293
+ "@id": "ex:rei",
1294
+ "ex:prop": ["value1", "value2"]
1295
+ },
1296
+ "ex:prop": "value3"
1297
+ }),
1298
+ exception: JSON::LD::JsonLdError::InvalidEmbeddedNode
1299
+ },
1300
+ "illegal node with subject having multiple types": {
1301
+ input: %({
1302
+ "@id": {
1303
+ "@id": "ex:rei",
1304
+ "@type": ["ex:Type1", "ex:Type2"]
1305
+ },
1306
+ "ex:prop": "value3"
1307
+ }),
1308
+ exception: JSON::LD::JsonLdError::InvalidEmbeddedNode
1309
+ },
1310
+ "illegal node with subject having type and property": {
1311
+ input: %({
1312
+ "@id": {
1313
+ "@id": "ex:rei",
1314
+ "@type": "ex:Type",
1315
+ "ex:prop": "value"
1316
+ },
1317
+ "ex:prop": "value2"
1318
+ }),
1319
+ exception: JSON::LD::JsonLdError::InvalidEmbeddedNode
1320
+ },
1321
+ "node with embedded object": {
1322
+ input: %({
1323
+ "@id": "ex:subj",
1324
+ "ex:value": {
1325
+ "@id": {
1326
+ "@id": "ex:rei",
1327
+ "ex:prop": "value"
1328
+ }
1329
+ }
1330
+ }),
1331
+ expected: %(
1332
+ <ex:subj> <ex:value> <<<ex:rei> <ex:prop> "value">> .
1333
+ ),
1334
+ },
1335
+ "node with embedded object having properties": {
1336
+ input: %({
1337
+ "@id": "ex:subj",
1338
+ "ex:value": {
1339
+ "@id": {
1340
+ "@id": "ex:rei",
1341
+ "ex:prop": "value"
1342
+ },
1343
+ "ex:prop": "value2"
1344
+ }
1345
+ }),
1346
+ expected: %(
1347
+ <ex:subj> <ex:value> <<<ex:rei> <ex:prop> "value">> .
1348
+ <<<ex:rei> <ex:prop> "value">> <ex:prop> "value2" .
1349
+ ),
1350
+ },
1351
+ "node with recursive embedded object": {
1352
+ input: %({
1353
+ "@id": "ex:subj",
1354
+ "ex:value": {
1355
+ "@id": {
1356
+ "@id": {
1357
+ "@id": "ex:rei",
1358
+ "ex:prop": "value3"
1359
+ },
1360
+ "ex:prop": "value"
1361
+ },
1362
+ "ex:prop": "value2"
1363
+ }
1364
+ }),
1365
+ expected: %(
1366
+ <ex:subj> <ex:value> <<<<<ex:rei> <ex:prop> "value3">> <ex:prop> "value">> .
1367
+ <<<<<ex:rei> <ex:prop> "value3">> <ex:prop> "value">> <ex:prop> "value2" .
1368
+ ),
1369
+ },
1370
+ }.each do |title, params|
1371
+ context(title) do
1372
+ it "Generates statements" do
1373
+ output_graph = RDF::Graph.new {|g| g << RDF::NTriples::Reader.new(params[:expected], rdfstar: true)}
1374
+ run_to_rdf params.merge(rdfstar: true, output: output_graph)
1375
+ end if params[:expected]
1376
+
1377
+ it "Exception" do
1378
+ run_to_rdf params.merge(rdfstar: true)
1379
+ end if params[:exception]
1380
+ end
1381
+ end
1382
+ end
1383
+
1178
1384
  context "exceptions" do
1179
1385
  {
1180
1386
  "Invalid subject" => {
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: json-ld
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.1.5
4
+ version: 3.1.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gregg Kellogg
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-11-15 00:00:00.000000000 Z
11
+ date: 2020-12-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rdf
@@ -426,85 +426,85 @@ required_rubygems_version: !ruby/object:Gem::Requirement
426
426
  - !ruby/object:Gem::Version
427
427
  version: '0'
428
428
  requirements: []
429
- rubygems_version: 3.1.4
429
+ rubygems_version: 3.2.0.rc.2
430
430
  signing_key:
431
431
  specification_version: 4
432
432
  summary: JSON-LD reader/writer for Ruby.
433
433
  test_files:
434
- - spec/spec_helper.rb
435
- - spec/matchers.rb
436
434
  - spec/api_spec.rb
437
- - spec/suite_from_rdf_spec.rb
435
+ - spec/compact_spec.rb
436
+ - spec/conneg_spec.rb
438
437
  - spec/context_spec.rb
438
+ - spec/expand_spec.rb
439
+ - spec/flatten_spec.rb
440
+ - spec/format_spec.rb
441
+ - spec/frame_spec.rb
439
442
  - spec/from_rdf_spec.rb
440
- - spec/suite_helper.rb
443
+ - spec/matchers.rb
441
444
  - spec/reader_spec.rb
442
- - spec/streaming_writer_spec.rb
443
445
  - spec/resource_spec.rb
444
- - spec/suite_to_rdf_spec.rb
445
- - spec/suite_remote_doc_spec.rb
446
- - spec/format_spec.rb
447
- - spec/frame_spec.rb
448
- - spec/to_rdf_spec.rb
449
- - spec/conneg_spec.rb
450
- - spec/support/extensions.rb
451
- - spec/suite_html_spec.rb
452
- - spec/flatten_spec.rb
453
- - spec/suite_frame_spec.rb
446
+ - spec/spec_helper.rb
447
+ - spec/streaming_reader_spec.rb
448
+ - spec/streaming_writer_spec.rb
454
449
  - spec/suite_compact_spec.rb
455
- - spec/expand_spec.rb
456
450
  - spec/suite_expand_spec.rb
457
451
  - spec/suite_flatten_spec.rb
458
- - spec/compact_spec.rb
452
+ - spec/suite_frame_spec.rb
453
+ - spec/suite_from_rdf_spec.rb
454
+ - spec/suite_helper.rb
455
+ - spec/suite_html_spec.rb
459
456
  - spec/suite_http_spec.rb
460
- - spec/streaming_reader_spec.rb
457
+ - spec/suite_remote_doc_spec.rb
458
+ - spec/suite_to_rdf_spec.rb
459
+ - spec/support/extensions.rb
460
+ - spec/to_rdf_spec.rb
461
461
  - spec/writer_spec.rb
462
- - spec/test-files/test-3-compacted.json
463
- - spec/test-files/test-2-rdf.ttl
464
- - spec/test-files/test-4-compacted.json
465
- - spec/test-files/test-5-input.json
466
- - spec/test-files/test-3-rdf.ttl
467
- - spec/test-files/test-5-compacted.json
468
- - spec/test-files/test-9-expanded.json
469
- - spec/test-files/test-8-input.json
470
- - spec/test-files/test-2-compacted.json
471
- - spec/test-files/test-8-compacted.json
472
- - spec/test-files/test-7-expanded.json
473
- - spec/test-files/test-1-rdf.ttl
474
- - spec/test-files/test-7-context.json
475
- - spec/test-files/test-3-expanded.json
476
- - spec/test-files/test-8-rdf.ttl
462
+ - spec/test-files/test-1-compacted.json
463
+ - spec/test-files/test-1-context.json
464
+ - spec/test-files/test-1-expanded.json
465
+ - spec/test-files/test-1-input.json
477
466
  - spec/test-files/test-1-normalized.json
467
+ - spec/test-files/test-1-rdf.ttl
468
+ - spec/test-files/test-2-compacted.json
469
+ - spec/test-files/test-2-context.json
470
+ - spec/test-files/test-2-expanded.json
478
471
  - spec/test-files/test-2-input.json
479
- - spec/test-files/test-7-compacted.json
480
- - spec/test-files/test-1-context.json
481
- - spec/test-files/test-6-context.json
482
- - spec/test-files/test-6-compacted.json
483
- - spec/test-files/test-7-input.json
484
- - spec/test-files/test-1-compacted.json
485
- - spec/test-files/test-4-expanded.json
486
- - spec/test-files/test-9-compacted.json
472
+ - spec/test-files/test-2-normalized.json
473
+ - spec/test-files/test-2-rdf.ttl
474
+ - spec/test-files/test-3-compacted.json
475
+ - spec/test-files/test-3-context.json
476
+ - spec/test-files/test-3-expanded.json
477
+ - spec/test-files/test-3-input.json
478
+ - spec/test-files/test-3-normalized.json
479
+ - spec/test-files/test-3-rdf.ttl
480
+ - spec/test-files/test-4-compacted.json
487
481
  - spec/test-files/test-4-context.json
482
+ - spec/test-files/test-4-expanded.json
488
483
  - spec/test-files/test-4-input.json
489
- - spec/test-files/test-3-context.json
490
- - spec/test-files/test-5-rdf.ttl
491
- - spec/test-files/test-1-expanded.json
492
- - spec/test-files/test-9-input.json
493
- - spec/test-files/test-8-framed.json
484
+ - spec/test-files/test-4-rdf.ttl
485
+ - spec/test-files/test-5-compacted.json
486
+ - spec/test-files/test-5-context.json
494
487
  - spec/test-files/test-5-expanded.json
495
- - spec/test-files/test-3-normalized.json
496
- - spec/test-files/test-2-expanded.json
488
+ - spec/test-files/test-5-input.json
489
+ - spec/test-files/test-5-rdf.ttl
490
+ - spec/test-files/test-6-compacted.json
491
+ - spec/test-files/test-6-context.json
497
492
  - spec/test-files/test-6-expanded.json
498
- - spec/test-files/test-2-context.json
499
- - spec/test-files/test-5-context.json
500
- - spec/test-files/test-1-input.json
501
- - spec/test-files/test-4-rdf.ttl
502
- - spec/test-files/test-8-frame.json
503
493
  - spec/test-files/test-6-input.json
504
- - spec/test-files/test-8-context.json
505
- - spec/test-files/test-8-expanded.json
506
494
  - spec/test-files/test-6-rdf.ttl
495
+ - spec/test-files/test-7-compacted.json
496
+ - spec/test-files/test-7-context.json
497
+ - spec/test-files/test-7-expanded.json
498
+ - spec/test-files/test-7-input.json
507
499
  - spec/test-files/test-7-rdf.ttl
508
- - spec/test-files/test-3-input.json
509
- - spec/test-files/test-2-normalized.json
500
+ - spec/test-files/test-8-compacted.json
501
+ - spec/test-files/test-8-context.json
502
+ - spec/test-files/test-8-expanded.json
503
+ - spec/test-files/test-8-frame.json
504
+ - spec/test-files/test-8-framed.json
505
+ - spec/test-files/test-8-input.json
506
+ - spec/test-files/test-8-rdf.ttl
507
+ - spec/test-files/test-9-compacted.json
510
508
  - spec/test-files/test-9-context.json
509
+ - spec/test-files/test-9-expanded.json
510
+ - spec/test-files/test-9-input.json