json-ld 3.2.1 → 3.2.2

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.
Files changed (55) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +4 -5
  3. data/VERSION +1 -1
  4. data/lib/json/ld/api.rb +53 -16
  5. data/lib/json/ld/reader.rb +1 -1
  6. data/lib/json/ld/streaming_reader.rb +2 -1
  7. data/lib/json/ld/to_rdf.rb +1 -1
  8. data/lib/json/ld/writer.rb +8 -9
  9. data/lib/json/ld.rb +3 -0
  10. data/spec/api_spec.rb +67 -19
  11. data/spec/format_spec.rb +2 -2
  12. data/spec/frame_spec.rb +25 -1
  13. data/spec/suite_helper.rb +1 -0
  14. data/spec/test-files/{test-1-compacted.json → test-1-compacted.jsonld} +0 -0
  15. data/spec/test-files/{test-1-context.json → test-1-context.jsonld} +0 -0
  16. data/spec/test-files/{test-1-expanded.json → test-1-expanded.jsonld} +0 -0
  17. data/spec/test-files/{test-1-input.json → test-1-input.jsonld} +0 -0
  18. data/spec/test-files/{test-2-compacted.json → test-2-compacted.jsonld} +0 -0
  19. data/spec/test-files/{test-2-context.json → test-2-context.jsonld} +0 -0
  20. data/spec/test-files/{test-2-expanded.json → test-2-expanded.jsonld} +0 -0
  21. data/spec/test-files/{test-2-input.json → test-2-input.jsonld} +0 -0
  22. data/spec/test-files/{test-3-compacted.json → test-3-compacted.jsonld} +0 -0
  23. data/spec/test-files/{test-3-context.json → test-3-context.jsonld} +0 -0
  24. data/spec/test-files/{test-3-expanded.json → test-3-expanded.jsonld} +0 -0
  25. data/spec/test-files/{test-3-input.json → test-3-input.jsonld} +0 -0
  26. data/spec/test-files/{test-4-compacted.json → test-4-compacted.jsonld} +0 -0
  27. data/spec/test-files/{test-4-context.json → test-4-context.jsonld} +0 -0
  28. data/spec/test-files/{test-4-expanded.json → test-4-expanded.jsonld} +0 -0
  29. data/spec/test-files/{test-4-input.json → test-4-input.jsonld} +0 -0
  30. data/spec/test-files/{test-5-compacted.json → test-5-compacted.jsonld} +0 -0
  31. data/spec/test-files/{test-5-context.json → test-5-context.jsonld} +0 -0
  32. data/spec/test-files/{test-5-expanded.json → test-5-expanded.jsonld} +0 -0
  33. data/spec/test-files/{test-5-input.json → test-5-input.jsonld} +0 -0
  34. data/spec/test-files/{test-6-compacted.json → test-6-compacted.jsonld} +0 -0
  35. data/spec/test-files/{test-6-context.json → test-6-context.jsonld} +0 -0
  36. data/spec/test-files/{test-6-expanded.json → test-6-expanded.jsonld} +0 -0
  37. data/spec/test-files/{test-6-input.json → test-6-input.jsonld} +0 -0
  38. data/spec/test-files/{test-7-compacted.json → test-7-compacted.jsonld} +0 -0
  39. data/spec/test-files/{test-7-context.json → test-7-context.jsonld} +0 -0
  40. data/spec/test-files/{test-7-expanded.json → test-7-expanded.jsonld} +0 -0
  41. data/spec/test-files/{test-7-input.json → test-7-input.jsonld} +0 -0
  42. data/spec/test-files/{test-8-compacted.json → test-8-compacted.jsonld} +0 -0
  43. data/spec/test-files/{test-8-context.json → test-8-context.jsonld} +0 -0
  44. data/spec/test-files/{test-8-expanded.json → test-8-expanded.jsonld} +0 -0
  45. data/spec/test-files/{test-8-frame.json → test-8-frame.jsonld} +0 -0
  46. data/spec/test-files/{test-8-framed.json → test-8-framed.jsonld} +0 -0
  47. data/spec/test-files/{test-8-input.json → test-8-input.jsonld} +0 -0
  48. data/spec/test-files/{test-9-compacted.json → test-9-compacted.jsonld} +0 -0
  49. data/spec/test-files/{test-9-context.json → test-9-context.jsonld} +0 -0
  50. data/spec/test-files/{test-9-expanded.json → test-9-expanded.jsonld} +0 -0
  51. data/spec/test-files/{test-9-input.json → test-9-input.jsonld} +0 -0
  52. metadata +78 -84
  53. data/spec/test-files/test-1-normalized.json +0 -8
  54. data/spec/test-files/test-2-normalized.json +0 -32
  55. data/spec/test-files/test-3-normalized.json +0 -13
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 54bba5db6d794f8e36e96200fb75cce4377021ea02c008bcc09b76a4a6ff95a2
4
- data.tar.gz: bbd5282a8f1b87d6c44b567a49135f32765f11ada771fffd5e26683481589a19
3
+ metadata.gz: 63c237710b5f32fe8037a11969feaf712a79f68a4d1d568a89ece1a5d1d26ff2
4
+ data.tar.gz: cac81da94266cac30a7e31e5018477ef55e52b6b1701b048214947f266439236
5
5
  SHA512:
6
- metadata.gz: 7f13bf980c40f0aa82965c6cd6ee9fe5f8c63d91b5206974630d5bfd84ebf9318902654e8937644ef79aa02f1447c41cc3c3ea4382998b74b275f80ebff00f93
7
- data.tar.gz: 36a5a219f342d13249f1c6a3971448b9dea645640f5bc55d21278b831c3c619d584ad2dda27cee94793b5bd3954c5a0e54507ea6c99a328a3da7feb19730058a
6
+ metadata.gz: 440da082cc1cbabcd69e8cb3d34858c4fe8fd96b116c0d67651d5ce7338d6e787f9d00451ff1f730d08982f0d8697d097f51d09d033ff7f8e290252006f96c78
7
+ data.tar.gz: 0b877d9d96857964a4913aef1790aa04dc98f83676ec0154c016ad05e7a9dc0a22b1b3bd31ae785cfb4447ac6914291ac56d42f5dc6781fc58c6687ccd4d15cd
data/README.md CHANGED
@@ -32,10 +32,10 @@ This gem also implements an optimized streaming writer used for generating JSON-
32
32
  * Each statement written as a separate node in expanded/flattened form.
33
33
  * `RDF List`s are written as separate nodes using `rdf:first` and `rdf:rest` properties.
34
34
 
35
- The order of triples retrieved from the `RDF::Enumerable` dataset determines the way that JSON-LD node objects are written; for best results, statements should be ordered by _graph name_, _subect_, _predicate_ and _object_.
35
+ The order of triples retrieved from the `RDF::Enumerable` dataset determines the way that JSON-LD node objects are written; for best results, statements should be ordered by _graph name_, _subject_, _predicate_ and _object_.
36
36
 
37
37
  ### MultiJson parser
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.
38
+ The [MultiJson](https://rubygems.org/gems/multi_json) gem is used for parsing and serializing JSON; this defaults to the native JSON parser/serializer, 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. Additionally, a custom serialilzer may be specified by passing the `:serializer` option to {JSON::LD::Writer} or methods of {JSON::LD::API}. See [MultiJson](https://rubygems.org/gems/multi_json) for more information.
39
39
 
40
40
  ### JSON-LD-star (RDFStar)
41
41
 
@@ -624,8 +624,7 @@ To get a local working copy of the development repository, do:
624
624
  which you will be asked to agree to on the first commit to a repo within the organization.
625
625
  Note that the agreement applies to all repos in the [Ruby RDF](https://github.com/ruby-rdf/) organization.
626
626
 
627
- License
628
- -------
627
+ ## License
629
628
 
630
629
  This is free and unencumbered public domain software. For more information,
631
630
  see <https://unlicense.org/> or the accompanying {file:UNLICENSE} file.
@@ -641,7 +640,7 @@ see <https://unlicense.org/> or the accompanying {file:UNLICENSE} file.
641
640
  [Backports]: https://rubygems.org/gems/backports
642
641
  [JSON-LD]: https://www.w3.org/TR/json-ld11/ "JSON-LD 1.1"
643
642
  [JSON-LD API]: https://www.w3.org/TR/json-ld11-api/ "JSON-LD 1.1 Processing Algorithms and API"
644
- [JSON-LD Framing]: https://www.w3.org/TR/json-ld11-framing/ "JSON-LD Framing 1.1"
643
+ [JSON-LD Framing]: https://www.w3.org/TR/json-ld11-framing/ "JSON-LD 1.1 Framing"
645
644
  [Promises]: https://dom.spec.whatwg.org/#promises
646
645
  [jsonlint]: https://rubygems.org/gems/jsonlint
647
646
  [Sinatra]: https://www.sinatrarb.com/
data/VERSION CHANGED
@@ -1 +1 @@
1
- 3.2.1
1
+ 3.2.2
data/lib/json/ld/api.rb CHANGED
@@ -126,7 +126,8 @@ module JSON::LD
126
126
 
127
127
  case remote_doc.document
128
128
  when String
129
- MultiJson.load(remote_doc.document, **options)
129
+ mj_opts = options.keep_if {|k,v| k != :adapter || MUTLI_JSON_ADAPTERS.include?(v)}
130
+ MultiJson.load(remote_doc.document, **mj_opts)
130
131
  else
131
132
  # Already parsed
132
133
  remote_doc.document
@@ -155,6 +156,9 @@ module JSON::LD
155
156
  #
156
157
  # @param [String, #read, Hash, Array] input
157
158
  # The JSON-LD object to copy and perform the expansion upon.
159
+ # @param [Proc] serializer (nil)
160
+ # A Serializer method used for generating the JSON serialization of the result. If absent, the internal Ruby objects are returned, which can be transformed to JSON externally via `#to_json`.
161
+ # See {JSON::LD::API.serializer}.
158
162
  # @param [Hash{Symbol => Object}] options
159
163
  # @option options (see #initialize)
160
164
  # @raise [JsonLdError]
@@ -167,7 +171,7 @@ module JSON::LD
167
171
  # @return [Object, Array<Hash>]
168
172
  # If a block is given, the result of evaluating the block is returned, otherwise, the expanded JSON-LD document
169
173
  # @see https://www.w3.org/TR/json-ld11-api/#expansion-algorithm
170
- def self.expand(input, framing: false, **options, &block)
174
+ def self.expand(input, framing: false, serializer: nil, **options, &block)
171
175
  result = doc_base = nil
172
176
  API.new(input, options[:expandContext], **options) do
173
177
  result = self.expand(self.value, nil, self.context,
@@ -180,6 +184,7 @@ module JSON::LD
180
184
 
181
185
  # Finally, if element is a JSON object, it is wrapped into an array.
182
186
  result = [result].compact unless result.is_a?(Array)
187
+ result = serializer.call(result, **options) if serializer
183
188
 
184
189
  if block_given?
185
190
  case block.arity
@@ -204,6 +209,9 @@ module JSON::LD
204
209
  # The JSON-LD object to copy and perform the compaction upon.
205
210
  # @param [String, #read, Hash, Array, JSON::LD::Context] context
206
211
  # The base context to use when compacting the input.
212
+ # @param [Proc] serializer (nil)
213
+ # A Serializer instance used for generating the JSON serialization of the result. If absent, the internal Ruby objects are returned, which can be transformed to JSON externally via `#to_json`.
214
+ # See {JSON::LD::API.serializer}.
207
215
  # @param [Boolean] expanded (false) Input is already expanded
208
216
  # @param [Hash{Symbol => Object}] options
209
217
  # @option options (see #initialize)
@@ -215,7 +223,7 @@ module JSON::LD
215
223
  # If a block is given, the result of evaluating the block is returned, otherwise, the compacted JSON-LD document
216
224
  # @raise [JsonLdError]
217
225
  # @see https://www.w3.org/TR/json-ld11-api/#compaction-algorithm
218
- def self.compact(input, context, expanded: false, **options)
226
+ def self.compact(input, context, expanded: false, serializer: nil, **options)
219
227
  result = nil
220
228
  options = {compactToRelative: true}.merge(options)
221
229
 
@@ -238,6 +246,7 @@ module JSON::LD
238
246
  end
239
247
  result = ctx.merge(result) unless ctx.fetch('@context', {}).empty?
240
248
  end
249
+ result = serializer.call(result, **options) if serializer
241
250
  block_given? ? yield(result) : result
242
251
  end
243
252
 
@@ -251,6 +260,9 @@ module JSON::LD
251
260
  # @param [String, #read, Hash, Array, JSON::LD::EvaluationContext] context
252
261
  # An optional external context to use additionally to the context embedded in input when expanding the input.
253
262
  # @param [Boolean] expanded (false) Input is already expanded
263
+ # @param [Proc] serializer (nil)
264
+ # A Serializer instance used for generating the JSON serialization of the result. If absent, the internal Ruby objects are returned, which can be transformed to JSON externally via `#to_json`.
265
+ # See {JSON::LD::API.serializer}.
254
266
  # @param [Hash{Symbol => Object}] options
255
267
  # @option options (see #initialize)
256
268
  # @option options [Boolean] :createAnnotations
@@ -262,7 +274,7 @@ module JSON::LD
262
274
  # @return [Object, Hash]
263
275
  # If a block is given, the result of evaluating the block is returned, otherwise, the flattened JSON-LD document
264
276
  # @see https://www.w3.org/TR/json-ld11-api/#framing-algorithm
265
- def self.flatten(input, context, expanded: false, **options)
277
+ def self.flatten(input, context, expanded: false, serializer: nil, **options)
266
278
  flattened = []
267
279
  options = {
268
280
  compactToRelative: true,
@@ -318,6 +330,7 @@ module JSON::LD
318
330
  end
319
331
  end
320
332
 
333
+ flattened = serializer.call(flattened, **options) if serializer
321
334
  block_given? ? yield(flattened) : flattened
322
335
  end
323
336
 
@@ -350,7 +363,7 @@ module JSON::LD
350
363
  # If a block is given, the result of evaluating the block is returned, otherwise, the framed JSON-LD document
351
364
  # @raise [InvalidFrame]
352
365
  # @see https://www.w3.org/TR/json-ld11-api/#framing-algorithm
353
- def self.frame(input, frame, expanded: false, **options)
366
+ def self.frame(input, frame, expanded: false, serializer: nil, **options)
354
367
  result = nil
355
368
  options = {
356
369
  base: (RDF::URI(input) if input.is_a?(String)),
@@ -379,7 +392,8 @@ module JSON::LD
379
392
  requestProfile: 'http://www.w3.org/ns/json-ld#frame',
380
393
  **options)
381
394
  if remote_doc.document.is_a?(String)
382
- MultiJson.load(remote_doc.document)
395
+ mj_opts = options.keep_if {|k,v| k != :adapter || MUTLI_JSON_ADAPTERS.include?(v)}
396
+ MultiJson.load(remote_doc.document, **mj_opts)
383
397
  else
384
398
  remote_doc.document
385
399
  end
@@ -467,6 +481,7 @@ module JSON::LD
467
481
  result
468
482
  end
469
483
 
484
+ result = serializer.call(result, **options) if serializer
470
485
  block_given? ? yield(result) : result
471
486
  end
472
487
 
@@ -528,18 +543,21 @@ module JSON::LD
528
543
  # The resulting `Array` is either returned or yielded, if a block is given.
529
544
  #
530
545
  # @param [RDF::Enumerable] input
546
+ # @param [Boolean] useRdfType (false)
547
+ # If set to `true`, the JSON-LD processor will treat `rdf:type` like a normal property instead of using `@type`.
548
+ # @param [Boolean] useNativeTypes (false) use native representations
549
+ # @param [Proc] serializer (nil)
550
+ # A Serializer instance used for generating the JSON serialization of the result. If absent, the internal Ruby objects are returned, which can be transformed to JSON externally via `#to_json`.
551
+ # See {JSON::LD::API.serializer}.
531
552
  # @param [Hash{Symbol => Object}] options
532
553
  # @option options (see #initialize)
533
- # @option options [Boolean] :useRdfType (false)
534
- # If set to `true`, the JSON-LD processor will treat `rdf:type` like a normal property instead of using `@type`.
535
- # @option options [Boolean] :useNativeTypes (false) use native representations
536
554
  # @yield jsonld
537
555
  # @yieldparam [Hash] jsonld
538
556
  # The JSON-LD document in expanded form
539
557
  # @yieldreturn [Object] returned object
540
558
  # @return [Object, Hash]
541
559
  # If a block is given, the result of evaluating the block is returned, otherwise, the expanded JSON-LD document
542
- def self.fromRdf(input, useRdfType: false, useNativeTypes: false, **options, &block)
560
+ def self.fromRdf(input, useRdfType: false, useNativeTypes: false, serializer: nil, **options, &block)
543
561
  result = nil
544
562
 
545
563
  API.new(nil, nil, **options) do
@@ -548,6 +566,7 @@ module JSON::LD
548
566
  useNativeTypes: useNativeTypes)
549
567
  end
550
568
 
569
+ result = serializer.call(result, **options) if serializer
551
570
  block_given? ? yield(result) : result
552
571
  end
553
572
 
@@ -648,7 +667,8 @@ module JSON::LD
648
667
  end
649
668
  else
650
669
  validate_input(remote_doc.document, url: remote_doc.documentUrl) if validate
651
- MultiJson.load(remote_doc.document, **options)
670
+ mj_opts = options.keep_if {|k,v| k != :adapter || MUTLI_JSON_ADAPTERS.include?(v)}
671
+ MultiJson.load(remote_doc.document, **mj_opts)
652
672
  end
653
673
  end
654
674
 
@@ -682,8 +702,8 @@ module JSON::LD
682
702
  base_uri ||= url.base_uri if url.respond_to?(:base_uri)
683
703
  content_type = options[:content_type]
684
704
  content_type ||= url.content_type if url.respond_to?(:content_type)
685
- context_url = if url.respond_to?(:links) && url.links
686
- (content_type == 'appliaction/json' || content_type.match?(%r(application/(^ld)+json)))
705
+ context_url = if url.respond_to?(:links) && url.links &&
706
+ (content_type == 'application/json' || content_type.match?(%r(application/(^ld)+json)))
687
707
  link = url.links.find_link(LINK_REL_CONTEXT)
688
708
  link.href if link
689
709
  end
@@ -759,7 +779,8 @@ module JSON::LD
759
779
  raise JSON::LD::JsonLdError::LoadingDocumentFailed, "Script tag has type=#{element.attributes['type']}" unless element.attributes['type'].to_s.start_with?('application/ld+json')
760
780
  content = element.inner_html
761
781
  validate_input(content, url: url) if options[:validate]
762
- MultiJson.load(content, **options)
782
+ mj_opts = options.keep_if {|k,v| k != :adapter || MUTLI_JSON_ADAPTERS.include?(v)}
783
+ MultiJson.load(content, **mj_opts)
763
784
  elsif extractAllScripts
764
785
  res = []
765
786
  elements = if profile
@@ -773,7 +794,8 @@ module JSON::LD
773
794
  elements.each do |element|
774
795
  content = element.inner_html
775
796
  validate_input(content, url: url) if options[:validate]
776
- r = MultiJson.load(content, **options)
797
+ mj_opts = options.keep_if {|k,v| k != :adapter || MUTLI_JSON_ADAPTERS.include?(v)}
798
+ r = MultiJson.load(content, **mj_opts)
777
799
  if r.is_a?(Hash)
778
800
  res << r
779
801
  elsif r.is_a?(Array)
@@ -788,12 +810,27 @@ module JSON::LD
788
810
  raise JSON::LD::JsonLdError::LoadingDocumentFailed, "No script tag found" unless element
789
811
  content = element.inner_html
790
812
  validate_input(content, url: url) if options[:validate]
791
- MultiJson.load(content, **options)
813
+ mj_opts = options.keep_if {|k,v| k != :adapter || MUTLI_JSON_ADAPTERS.include?(v)}
814
+ MultiJson.load(content, **mj_opts)
792
815
  end
793
816
  rescue MultiJson::ParseError => e
794
817
  raise JSON::LD::JsonLdError::InvalidScriptElement, e.message
795
818
  end
796
819
 
820
+ ##
821
+ # The default serializer for serialzing Ruby Objects to JSON.
822
+ #
823
+ # Defaults to `MultiJson.dump`
824
+ #
825
+ # @param [Object] object
826
+ # @param [Array<Object>] args
827
+ # other arguments that may be passed for some specific implementation.
828
+ # @param [Hash<Symbol, Object>] options
829
+ # options passed from the invoking context.
830
+ def self.serializer(object, *args, **options)
831
+ MultiJson.dump(object, JSON_STATE)
832
+ end
833
+
797
834
  ##
798
835
  # Validate JSON using JsonLint, if loaded
799
836
  private
@@ -57,7 +57,7 @@ module JSON::LD
57
57
  end
58
58
 
59
59
  ##
60
- # Initializes the RDF/JSON reader instance.
60
+ # Initializes the JSON-LD reader instance.
61
61
  #
62
62
  # @param [IO, File, String] input
63
63
  # @param [Hash{Symbol => Object}] options
@@ -26,7 +26,8 @@ module JSON::LD
26
26
  unique_bnodes, rename_bnodes = @options[:unique_bnodes], @options.fetch(:rename_bnodes, true)
27
27
  # FIXME: document loader doesn't stream
28
28
  @base = RDF::URI(@options[:base] || base_uri)
29
- value = MultiJson.load(@doc, **@options)
29
+ mj_opts = @options.keep_if {|k,v| k != :adapter || MUTLI_JSON_ADAPTERS.include?(v)}
30
+ value = MultiJson.load(@doc, mj_opts)
30
31
  context_ref = @options[:expandContext]
31
32
  #context_ref = @options.fetch(:expandContext, remote_doc.contextUrl)
32
33
  context = Context.parse(context_ref, **@options)
@@ -11,7 +11,7 @@ module JSON::LD
11
11
  ##
12
12
  # @param [Hash{String => Object}] item
13
13
  # @param [RDF::Resource] graph_name
14
- # @param [Boolean] emitted triples are quoted triples.
14
+ # @param [Boolean] quoted emitted triples are quoted triples.
15
15
  # @yield statement
16
16
  # @yieldparam [RDF::Statement] statement
17
17
  # @return RDF::Resource the subject of this item
@@ -186,10 +186,6 @@ module JSON::LD
186
186
  # @return [Boolean]
187
187
  # @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.1
188
188
  def accept?(accept_params)
189
- # Profiles that aren't specific IANA relations represent the URL
190
- # of a context or frame that may be subject to black- or white-listing
191
- profile = accept_params[:profile].to_s.split(/\s+/)
192
-
193
189
  if block_given?
194
190
  yield(accept_params)
195
191
  else
@@ -229,6 +225,8 @@ module JSON::LD
229
225
  # frame to use when serializing.
230
226
  # @option options [Boolean] :unique_bnodes (false)
231
227
  # Use unique bnode identifiers, defaults to using the identifier which the node was originall initialized with (if any).
228
+ # @option options [Proc] serializer (JSON::LD::API.serializer)
229
+ # A Serializer method used for generating the JSON serialization of the result.
232
230
  # @option options [Boolean] :stream (false)
233
231
  # Do not attempt to optimize graph presentation, suitable for streaming large graphs.
234
232
  # @yield [writer] `self`
@@ -239,6 +237,7 @@ module JSON::LD
239
237
  def initialize(output = $stdout, **options, &block)
240
238
  options[:base_uri] ||= options[:base] if options.key?(:base)
241
239
  options[:base] ||= options[:base_uri] if options.key?(:base_uri)
240
+ @serializer = options.fetch(:serializer, JSON::LD::API.method(:serializer))
242
241
  super do
243
242
  @repo = RDF::Repository.new
244
243
 
@@ -300,7 +299,7 @@ module JSON::LD
300
299
  else
301
300
 
302
301
  log_debug("writer") { "serialize #{@repo.count} statements, #{@options.inspect}"}
303
- result = API.fromRdf(@repo, **@options)
302
+ result = API.fromRdf(@repo, **@options.merge(serializer: nil))
304
303
 
305
304
  # Some options may be indicated from accept parameters
306
305
  profile = @options.fetch(:accept_params, {}).fetch(:profile, "").split(' ')
@@ -322,20 +321,20 @@ module JSON::LD
322
321
 
323
322
  # Rename BNodes to uniquify them, if necessary
324
323
  if options[:unique_bnodes]
325
- result = API.flatten(result, context, **@options)
324
+ result = API.flatten(result, context, **@options.merge(serializer: nil))
326
325
  end
327
326
 
328
327
  if frame = @options[:frame]
329
328
  # Perform framing, if given a frame
330
329
  log_debug("writer") { "frame result"}
331
- result = API.frame(result, frame, **@options)
330
+ result = API.frame(result, frame, **@options.merge(serializer: nil))
332
331
  elsif context
333
332
  # Perform compaction, if we have a context
334
333
  log_debug("writer") { "compact result"}
335
- result = API.compact(result, context, **@options)
334
+ result = API.compact(result, context, **@options.merge(serializer: nil))
336
335
  end
337
336
 
338
- @output.write(result.to_json(JSON_STATE))
337
+ @output.write(@serializer.call(result, **@options))
339
338
  end
340
339
 
341
340
  super
data/lib/json/ld.rb CHANGED
@@ -46,6 +46,9 @@ module JSON
46
46
  # Default context when compacting without one being specified
47
47
  DEFAULT_CONTEXT = "http://schema.org"
48
48
 
49
+ # Acceptable MultiJson adapters
50
+ MUTLI_JSON_ADAPTERS = %i(oj json_gem json_pure ok_json yajl nsjsonseerialization)
51
+
49
52
  KEYWORDS = Set.new(%w(
50
53
  @annotation
51
54
  @base
data/spec/api_spec.rb CHANGED
@@ -48,30 +48,78 @@ describe JSON::LD::API do
48
48
  context "with MultiJson adapter #{adapter.inspect}" do
49
49
  Dir.glob(File.expand_path(File.join(File.dirname(__FILE__), 'test-files/*-input.*'))) do |filename|
50
50
  test = File.basename(filename).sub(/-input\..*$/, '')
51
- frame = filename.sub(/-input\..*$/, '-frame.json')
52
- framed = filename.sub(/-input\..*$/, '-framed.json')
53
- compacted = filename.sub(/-input\..*$/, '-compacted.json')
54
- context = filename.sub(/-input\..*$/, '-context.json')
55
- expanded = filename.sub(/-input\..*$/, '-expanded.json')
51
+ frame = filename.sub(/-input\..*$/, '-frame.jsonld')
52
+ framed = filename.sub(/-input\..*$/, '-framed.jsonld')
53
+ compacted = filename.sub(/-input\..*$/, '-compacted.jsonld')
54
+ context = filename.sub(/-input\..*$/, '-context.jsonld')
55
+ expanded = filename.sub(/-input\..*$/, '-expanded.jsonld')
56
56
  ttl = filename.sub(/-input\..*$/, '-rdf.ttl')
57
57
 
58
58
  context test, skip: ("Not supported in JRuby" if RUBY_ENGINE == "jruby" && %w(oj yajl).include?(adapter.to_s)) do
59
- it "expands" do
60
- options = {logger: logger, adapter: adapter}
61
- options[:expandContext] = File.open(context) if context
62
- jld = described_class.expand(File.open(filename), **options)
63
- expect(jld).to produce_jsonld(JSON.load(File.open(expanded)), logger)
64
- end if File.exist?(expanded)
59
+ around do |example|
60
+ @file = File.open(filename)
61
+ case filename
62
+ when /.jsonld$/
63
+ @file.define_singleton_method(:content_type) {'application/ld+json'}
64
+ end
65
+ if context
66
+ @ctx_io = File.open(context)
67
+ case context
68
+ when /.jsonld$/
69
+ @ctx_io.define_singleton_method(:content_type) {'application/ld+json'}
70
+ end
71
+ end
72
+ example.run
73
+ @file.close
74
+ @ctx_io.close if @ctx_io
75
+ end
76
+
77
+ if File.exist?(expanded)
78
+ it "expands" do
79
+ options = {logger: logger, adapter: adapter}
80
+ options[:expandContext] = @ctx_io if context
81
+ jld = described_class.expand(@file, **options)
82
+ expect(jld).to produce_jsonld(JSON.parse(File.read(expanded)), logger)
83
+ end
84
+
85
+ it "expands with serializer" do
86
+ options = {logger: logger, adapter: adapter}
87
+ options[:expandContext] = @ctx_io if context
88
+ jld = described_class.expand(@file, serializer: JSON::LD::API.method(:serializer), **options)
89
+ expect(jld).to be_a(String)
90
+ expect(JSON.load(jld)).to produce_jsonld(JSON.parse(File.read(expanded)), logger)
91
+ end
92
+ end
65
93
 
66
- it "compacts" do
67
- jld = described_class.compact(File.open(filename), File.open(context), adapter: adapter, logger: logger)
68
- expect(jld).to produce_jsonld(JSON.load(File.open(compacted)), logger)
69
- end if File.exist?(compacted) && File.exist?(context)
94
+ if File.exist?(compacted) && File.exist?(context)
95
+ it "compacts" do
96
+ jld = described_class.compact(@file, @ctx_io, adapter: adapter, logger: logger)
97
+ expect(jld).to produce_jsonld(JSON.parse(File.read(compacted)), logger)
98
+ end
99
+
100
+ it "compacts with serializer" do
101
+ jld = described_class.compact(@file, @ctx_io, serializer: JSON::LD::API.method(:serializer), adapter: adapter, logger: logger)
102
+ expect(jld).to be_a(String)
103
+ expect(JSON.load(jld)).to produce_jsonld(JSON.parse(File.read(compacted)), logger)
104
+ end
105
+ end
70
106
 
71
- it "frame" do
72
- jld = described_class.frame(File.open(filename), File.open(frame), adapter: adapter, logger: logger)
73
- expect(jld).to produce_jsonld(JSON.load(File.open(framed)), logger)
74
- end if File.exist?(framed) && File.exist?(frame)
107
+ if File.exist?(framed) && File.exist?(frame)
108
+ it "frames" do
109
+ File.open(frame) do |frame_io|
110
+ jld = described_class.frame(@file, frame_io, adapter: adapter, logger: logger)
111
+ expect(jld).to produce_jsonld(JSON.parse(File.read(framed)), logger)
112
+ end
113
+ end
114
+
115
+ it "frames with serializer" do
116
+ File.open(frame) do |frame_io|
117
+ jld = described_class.frame(@file, frame_io, serializer: JSON::LD::API.method(:serializer), adapter: adapter, logger: logger)
118
+ expect(jld).to be_a(String)
119
+ expect(JSON.load(jld)).to produce_jsonld(JSON.parse(File.read(framed)), logger)
120
+ end
121
+ end
122
+ end
75
123
 
76
124
  it "toRdf" do
77
125
  expect(RDF::Repository.load(filename, format: :jsonld, adapter: adapter, logger: logger)).to be_equivalent_graph(RDF::Repository.load(ttl), logger: logger)
data/spec/format_spec.rb CHANGED
@@ -73,8 +73,8 @@ describe JSON::LD::Format do
73
73
  describe ".cli_commands", skip: Gem.win_platform? do
74
74
  require 'rdf/cli'
75
75
  let(:ttl) {File.expand_path("../test-files/test-1-rdf.ttl", __FILE__)}
76
- let(:json) {File.expand_path("../test-files/test-1-input.json", __FILE__)}
77
- let(:context) {File.expand_path("../test-files/test-1-context.json", __FILE__)}
76
+ let(:json) {File.expand_path("../test-files/test-1-input.jsonld", __FILE__)}
77
+ let(:context) {File.expand_path("../test-files/test-1-context.jsonld", __FILE__)}
78
78
 
79
79
  describe "#expand" do
80
80
  it "expands RDF" do
data/spec/frame_spec.rb CHANGED
@@ -2438,7 +2438,31 @@ describe JSON::LD::API do
2438
2438
  "@id": "ex:entity1"
2439
2439
  }),
2440
2440
  processingMode: "json-ld-1.1"
2441
- }
2441
+ },
2442
+ "don't embed list elements": {
2443
+ frame: %({
2444
+ "@context": {"ex": "http://example.org/"},
2445
+ "ex:embed": {
2446
+ "@list": [{"@embed": "@never"}]
2447
+ }
2448
+ }),
2449
+ input: %({
2450
+ "@context": {"ex": "http://example.org/"},
2451
+ "@id": "ex:Sub1",
2452
+ "ex:embed": {
2453
+ "@list": [{
2454
+ "@id": "ex:Sub2",
2455
+ "ex:prop": "property"
2456
+ }]
2457
+ }
2458
+ }),
2459
+ output: %({
2460
+ "@context": {"ex": "http://example.org/"},
2461
+ "@id": "ex:Sub1",
2462
+ "ex:embed": {"@list": [{"@id": "ex:Sub2"}]}
2463
+ }),
2464
+ processingMode: "json-ld-1.1"
2465
+ },
2442
2466
  }.each do |title, params|
2443
2467
  it title do
2444
2468
  do_frame(params)
data/spec/suite_helper.rb CHANGED
@@ -60,6 +60,7 @@ module RDF::Util
60
60
  document_options[:headers][:content_type] = options[:contentType] if options[:contentType]
61
61
 
62
62
  remote_document = RDF::Util::File::RemoteDocument.new(response.read, **document_options)
63
+ response.close
63
64
  if block_given?
64
65
  return yield remote_document
65
66
  else
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.2.1
4
+ version: 3.2.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gregg Kellogg
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-05-11 00:00:00.000000000 Z
11
+ date: 2022-08-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rdf
@@ -357,55 +357,52 @@ files:
357
357
  - spec/suite_remote_doc_spec.rb
358
358
  - spec/suite_to_rdf_spec.rb
359
359
  - spec/support/extensions.rb
360
- - spec/test-files/test-1-compacted.json
361
- - spec/test-files/test-1-context.json
362
- - spec/test-files/test-1-expanded.json
363
- - spec/test-files/test-1-input.json
364
- - spec/test-files/test-1-normalized.json
360
+ - spec/test-files/test-1-compacted.jsonld
361
+ - spec/test-files/test-1-context.jsonld
362
+ - spec/test-files/test-1-expanded.jsonld
363
+ - spec/test-files/test-1-input.jsonld
365
364
  - spec/test-files/test-1-rdf.ttl
366
- - spec/test-files/test-2-compacted.json
367
- - spec/test-files/test-2-context.json
368
- - spec/test-files/test-2-expanded.json
369
- - spec/test-files/test-2-input.json
370
- - spec/test-files/test-2-normalized.json
365
+ - spec/test-files/test-2-compacted.jsonld
366
+ - spec/test-files/test-2-context.jsonld
367
+ - spec/test-files/test-2-expanded.jsonld
368
+ - spec/test-files/test-2-input.jsonld
371
369
  - spec/test-files/test-2-rdf.ttl
372
- - spec/test-files/test-3-compacted.json
373
- - spec/test-files/test-3-context.json
374
- - spec/test-files/test-3-expanded.json
375
- - spec/test-files/test-3-input.json
376
- - spec/test-files/test-3-normalized.json
370
+ - spec/test-files/test-3-compacted.jsonld
371
+ - spec/test-files/test-3-context.jsonld
372
+ - spec/test-files/test-3-expanded.jsonld
373
+ - spec/test-files/test-3-input.jsonld
377
374
  - spec/test-files/test-3-rdf.ttl
378
- - spec/test-files/test-4-compacted.json
379
- - spec/test-files/test-4-context.json
380
- - spec/test-files/test-4-expanded.json
381
- - spec/test-files/test-4-input.json
375
+ - spec/test-files/test-4-compacted.jsonld
376
+ - spec/test-files/test-4-context.jsonld
377
+ - spec/test-files/test-4-expanded.jsonld
378
+ - spec/test-files/test-4-input.jsonld
382
379
  - spec/test-files/test-4-rdf.ttl
383
- - spec/test-files/test-5-compacted.json
384
- - spec/test-files/test-5-context.json
385
- - spec/test-files/test-5-expanded.json
386
- - spec/test-files/test-5-input.json
380
+ - spec/test-files/test-5-compacted.jsonld
381
+ - spec/test-files/test-5-context.jsonld
382
+ - spec/test-files/test-5-expanded.jsonld
383
+ - spec/test-files/test-5-input.jsonld
387
384
  - spec/test-files/test-5-rdf.ttl
388
- - spec/test-files/test-6-compacted.json
389
- - spec/test-files/test-6-context.json
390
- - spec/test-files/test-6-expanded.json
391
- - spec/test-files/test-6-input.json
385
+ - spec/test-files/test-6-compacted.jsonld
386
+ - spec/test-files/test-6-context.jsonld
387
+ - spec/test-files/test-6-expanded.jsonld
388
+ - spec/test-files/test-6-input.jsonld
392
389
  - spec/test-files/test-6-rdf.ttl
393
- - spec/test-files/test-7-compacted.json
394
- - spec/test-files/test-7-context.json
395
- - spec/test-files/test-7-expanded.json
396
- - spec/test-files/test-7-input.json
390
+ - spec/test-files/test-7-compacted.jsonld
391
+ - spec/test-files/test-7-context.jsonld
392
+ - spec/test-files/test-7-expanded.jsonld
393
+ - spec/test-files/test-7-input.jsonld
397
394
  - spec/test-files/test-7-rdf.ttl
398
- - spec/test-files/test-8-compacted.json
399
- - spec/test-files/test-8-context.json
400
- - spec/test-files/test-8-expanded.json
401
- - spec/test-files/test-8-frame.json
402
- - spec/test-files/test-8-framed.json
403
- - spec/test-files/test-8-input.json
395
+ - spec/test-files/test-8-compacted.jsonld
396
+ - spec/test-files/test-8-context.jsonld
397
+ - spec/test-files/test-8-expanded.jsonld
398
+ - spec/test-files/test-8-frame.jsonld
399
+ - spec/test-files/test-8-framed.jsonld
400
+ - spec/test-files/test-8-input.jsonld
404
401
  - spec/test-files/test-8-rdf.ttl
405
- - spec/test-files/test-9-compacted.json
406
- - spec/test-files/test-9-context.json
407
- - spec/test-files/test-9-expanded.json
408
- - spec/test-files/test-9-input.json
402
+ - spec/test-files/test-9-compacted.jsonld
403
+ - spec/test-files/test-9-context.jsonld
404
+ - spec/test-files/test-9-expanded.jsonld
405
+ - spec/test-files/test-9-input.jsonld
409
406
  - spec/to_rdf_spec.rb
410
407
  - spec/writer_spec.rb
411
408
  homepage: https://github.com/ruby-rdf/json-ld
@@ -466,52 +463,49 @@ test_files:
466
463
  - spec/support/extensions.rb
467
464
  - spec/to_rdf_spec.rb
468
465
  - spec/writer_spec.rb
469
- - spec/test-files/test-1-compacted.json
470
- - spec/test-files/test-1-context.json
471
- - spec/test-files/test-1-expanded.json
472
- - spec/test-files/test-1-input.json
473
- - spec/test-files/test-1-normalized.json
466
+ - spec/test-files/test-1-compacted.jsonld
467
+ - spec/test-files/test-1-context.jsonld
468
+ - spec/test-files/test-1-expanded.jsonld
469
+ - spec/test-files/test-1-input.jsonld
474
470
  - spec/test-files/test-1-rdf.ttl
475
- - spec/test-files/test-2-compacted.json
476
- - spec/test-files/test-2-context.json
477
- - spec/test-files/test-2-expanded.json
478
- - spec/test-files/test-2-input.json
479
- - spec/test-files/test-2-normalized.json
471
+ - spec/test-files/test-2-compacted.jsonld
472
+ - spec/test-files/test-2-context.jsonld
473
+ - spec/test-files/test-2-expanded.jsonld
474
+ - spec/test-files/test-2-input.jsonld
480
475
  - spec/test-files/test-2-rdf.ttl
481
- - spec/test-files/test-3-compacted.json
482
- - spec/test-files/test-3-context.json
483
- - spec/test-files/test-3-expanded.json
484
- - spec/test-files/test-3-input.json
485
- - spec/test-files/test-3-normalized.json
476
+ - spec/test-files/test-3-compacted.jsonld
477
+ - spec/test-files/test-3-context.jsonld
478
+ - spec/test-files/test-3-expanded.jsonld
479
+ - spec/test-files/test-3-input.jsonld
486
480
  - spec/test-files/test-3-rdf.ttl
487
- - spec/test-files/test-4-compacted.json
488
- - spec/test-files/test-4-context.json
489
- - spec/test-files/test-4-expanded.json
490
- - spec/test-files/test-4-input.json
481
+ - spec/test-files/test-4-compacted.jsonld
482
+ - spec/test-files/test-4-context.jsonld
483
+ - spec/test-files/test-4-expanded.jsonld
484
+ - spec/test-files/test-4-input.jsonld
491
485
  - spec/test-files/test-4-rdf.ttl
492
- - spec/test-files/test-5-compacted.json
493
- - spec/test-files/test-5-context.json
494
- - spec/test-files/test-5-expanded.json
495
- - spec/test-files/test-5-input.json
486
+ - spec/test-files/test-5-compacted.jsonld
487
+ - spec/test-files/test-5-context.jsonld
488
+ - spec/test-files/test-5-expanded.jsonld
489
+ - spec/test-files/test-5-input.jsonld
496
490
  - spec/test-files/test-5-rdf.ttl
497
- - spec/test-files/test-6-compacted.json
498
- - spec/test-files/test-6-context.json
499
- - spec/test-files/test-6-expanded.json
500
- - spec/test-files/test-6-input.json
491
+ - spec/test-files/test-6-compacted.jsonld
492
+ - spec/test-files/test-6-context.jsonld
493
+ - spec/test-files/test-6-expanded.jsonld
494
+ - spec/test-files/test-6-input.jsonld
501
495
  - spec/test-files/test-6-rdf.ttl
502
- - spec/test-files/test-7-compacted.json
503
- - spec/test-files/test-7-context.json
504
- - spec/test-files/test-7-expanded.json
505
- - spec/test-files/test-7-input.json
496
+ - spec/test-files/test-7-compacted.jsonld
497
+ - spec/test-files/test-7-context.jsonld
498
+ - spec/test-files/test-7-expanded.jsonld
499
+ - spec/test-files/test-7-input.jsonld
506
500
  - spec/test-files/test-7-rdf.ttl
507
- - spec/test-files/test-8-compacted.json
508
- - spec/test-files/test-8-context.json
509
- - spec/test-files/test-8-expanded.json
510
- - spec/test-files/test-8-frame.json
511
- - spec/test-files/test-8-framed.json
512
- - spec/test-files/test-8-input.json
501
+ - spec/test-files/test-8-compacted.jsonld
502
+ - spec/test-files/test-8-context.jsonld
503
+ - spec/test-files/test-8-expanded.jsonld
504
+ - spec/test-files/test-8-frame.jsonld
505
+ - spec/test-files/test-8-framed.jsonld
506
+ - spec/test-files/test-8-input.jsonld
513
507
  - spec/test-files/test-8-rdf.ttl
514
- - spec/test-files/test-9-compacted.json
515
- - spec/test-files/test-9-context.json
516
- - spec/test-files/test-9-expanded.json
517
- - spec/test-files/test-9-input.json
508
+ - spec/test-files/test-9-compacted.jsonld
509
+ - spec/test-files/test-9-context.jsonld
510
+ - spec/test-files/test-9-expanded.jsonld
511
+ - spec/test-files/test-9-input.jsonld
@@ -1,8 +0,0 @@
1
- [{
2
- "@id": {
3
- "@id": "_:c14n0"
4
- },
5
- "http://xmlns.com/foaf/0.1/avatar": "http://twitter.com/account/profile_image/manusporny",
6
- "http://xmlns.com/foaf/0.1/homepage": "http://manu.sporny.org/",
7
- "http://xmlns.com/foaf/0.1/name": "Manu Sporny"
8
- }]
@@ -1,32 +0,0 @@
1
- [{
2
- "@id": {
3
- "@id": "http://example.org/library"
4
- },
5
- "http://example.org/vocab#contains": {
6
- "@id": "http://example.org/library/the-republic"
7
- },
8
- "http://www.w3.org/1999/02/22-rdf-syntax-ns#type": {
9
- "@id": "http://example.org/vocab#Library"
10
- }
11
- }, {
12
- "@id": {
13
- "@id": "http://example.org/library/the-republic"
14
- },
15
- "http://example.org/vocab#contains": {
16
- "@id": "http://example.org/library/the-republic#introduction"
17
- },
18
- "http://purl.org/dc/elements/1.1/creator": "Plato",
19
- "http://purl.org/dc/elements/1.1/title": "The Republic",
20
- "@type": {
21
- "@id": "http://example.org/vocab#Book"
22
- }
23
- }, {
24
- "@id": {
25
- "@id": "http://example.org/library/the-republic#introduction"
26
- },
27
- "http://purl.org/dc/elements/1.1/description": "An introductory chapter on The Republic.",
28
- "http://purl.org/dc/elements/1.1/title": "The Introduction",
29
- "@type": {
30
- "@id": "http://example.org/vocab#Chapter"
31
- }
32
- }]
@@ -1,13 +0,0 @@
1
- [{
2
- "@id": {
3
- "@id": "_:c14n0"
4
- },
5
- "http://xmlns.com/foaf/0.1/age": {
6
- "@type": "http://www.w3.org/2001/XMLSchema#integer",
7
- "@value": "41"
8
- },
9
- "http://xmlns.com/foaf/0.1/homepage": {
10
- "@id": "http://manu.sporny.org/"
11
- },
12
- "http://xmlns.com/foaf/0.1/name": "Manu Sporny"
13
- }]