json-ld 3.1.10 → 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 (60) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +9 -10
  3. data/VERSION +1 -1
  4. data/lib/json/ld/api.rb +53 -16
  5. data/lib/json/ld/context.rb +8 -8
  6. data/lib/json/ld/expand.rb +2 -2
  7. data/lib/json/ld/flatten.rb +1 -1
  8. data/lib/json/ld/format.rb +2 -1
  9. data/lib/json/ld/reader.rb +2 -2
  10. data/lib/json/ld/streaming_reader.rb +2 -1
  11. data/lib/json/ld/to_rdf.rb +9 -8
  12. data/lib/json/ld/writer.rb +9 -10
  13. data/lib/json/ld.rb +3 -0
  14. data/spec/api_spec.rb +67 -19
  15. data/spec/format_spec.rb +7 -3
  16. data/spec/frame_spec.rb +25 -1
  17. data/spec/reader_spec.rb +14 -14
  18. data/spec/suite_helper.rb +1 -0
  19. data/spec/test-files/{test-1-compacted.json → test-1-compacted.jsonld} +0 -0
  20. data/spec/test-files/{test-1-context.json → test-1-context.jsonld} +0 -0
  21. data/spec/test-files/{test-1-expanded.json → test-1-expanded.jsonld} +0 -0
  22. data/spec/test-files/{test-1-input.json → test-1-input.jsonld} +0 -0
  23. data/spec/test-files/{test-2-compacted.json → test-2-compacted.jsonld} +0 -0
  24. data/spec/test-files/{test-2-context.json → test-2-context.jsonld} +0 -0
  25. data/spec/test-files/{test-2-expanded.json → test-2-expanded.jsonld} +0 -0
  26. data/spec/test-files/{test-2-input.json → test-2-input.jsonld} +0 -0
  27. data/spec/test-files/{test-3-compacted.json → test-3-compacted.jsonld} +0 -0
  28. data/spec/test-files/{test-3-context.json → test-3-context.jsonld} +0 -0
  29. data/spec/test-files/{test-3-expanded.json → test-3-expanded.jsonld} +0 -0
  30. data/spec/test-files/{test-3-input.json → test-3-input.jsonld} +0 -0
  31. data/spec/test-files/{test-4-compacted.json → test-4-compacted.jsonld} +0 -0
  32. data/spec/test-files/{test-4-context.json → test-4-context.jsonld} +0 -0
  33. data/spec/test-files/{test-4-expanded.json → test-4-expanded.jsonld} +0 -0
  34. data/spec/test-files/{test-4-input.json → test-4-input.jsonld} +0 -0
  35. data/spec/test-files/{test-5-compacted.json → test-5-compacted.jsonld} +0 -0
  36. data/spec/test-files/{test-5-context.json → test-5-context.jsonld} +0 -0
  37. data/spec/test-files/{test-5-expanded.json → test-5-expanded.jsonld} +0 -0
  38. data/spec/test-files/{test-5-input.json → test-5-input.jsonld} +0 -0
  39. data/spec/test-files/{test-6-compacted.json → test-6-compacted.jsonld} +0 -0
  40. data/spec/test-files/{test-6-context.json → test-6-context.jsonld} +0 -0
  41. data/spec/test-files/{test-6-expanded.json → test-6-expanded.jsonld} +0 -0
  42. data/spec/test-files/{test-6-input.json → test-6-input.jsonld} +0 -0
  43. data/spec/test-files/{test-7-compacted.json → test-7-compacted.jsonld} +0 -0
  44. data/spec/test-files/{test-7-context.json → test-7-context.jsonld} +0 -0
  45. data/spec/test-files/{test-7-expanded.json → test-7-expanded.jsonld} +0 -0
  46. data/spec/test-files/{test-7-input.json → test-7-input.jsonld} +0 -0
  47. data/spec/test-files/{test-8-compacted.json → test-8-compacted.jsonld} +0 -0
  48. data/spec/test-files/{test-8-context.json → test-8-context.jsonld} +0 -0
  49. data/spec/test-files/{test-8-expanded.json → test-8-expanded.jsonld} +0 -0
  50. data/spec/test-files/{test-8-frame.json → test-8-frame.jsonld} +0 -0
  51. data/spec/test-files/{test-8-framed.json → test-8-framed.jsonld} +0 -0
  52. data/spec/test-files/{test-8-input.json → test-8-input.jsonld} +0 -0
  53. data/spec/test-files/{test-9-compacted.json → test-9-compacted.jsonld} +0 -0
  54. data/spec/test-files/{test-9-context.json → test-9-context.jsonld} +0 -0
  55. data/spec/test-files/{test-9-expanded.json → test-9-expanded.jsonld} +0 -0
  56. data/spec/test-files/{test-9-input.json → test-9-input.jsonld} +0 -0
  57. metadata +110 -111
  58. data/spec/test-files/test-1-normalized.json +0 -8
  59. data/spec/test-files/test-2-normalized.json +0 -32
  60. 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: 0324a9e3b617b6dabe52c3f36c81e4b7fc4b78eaab9450510f45a760933064ba
4
- data.tar.gz: 7cf759dd5940a052969477e50c50bb0dc31d7cac38a5ccc8e1bdc046e3994a43
3
+ metadata.gz: 63c237710b5f32fe8037a11969feaf712a79f68a4d1d568a89ece1a5d1d26ff2
4
+ data.tar.gz: cac81da94266cac30a7e31e5018477ef55e52b6b1701b048214947f266439236
5
5
  SHA512:
6
- metadata.gz: 9d427823af59053d28e4999984f698cde37229fb9a3336a22f06517bcc65fbf80527a535b50dd28eaeca1e5d67e38d0d140dbace8854b9a62944f8ba149ea61c
7
- data.tar.gz: 83ba9860d9b7fe72924c9469a26bd5337a051003396b02fdcf5ae9e4b2bbd13940c37d7b4d95c16b427248fda64fa799551c3dcf5c767436e804ea89fba03b4f
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
 
@@ -72,7 +72,7 @@ In the first case, the embedded node is not asserted, and only appears as the su
72
72
 
73
73
  #### Serializing a Graph containing embedded statements
74
74
 
75
- require 'json-ld'
75
+ require 'json/ld'
76
76
  statement = RDF::Statement(RDF::URI('bob'), RDF::Vocab::FOAF.age, RDF::Literal(23))
77
77
  graph = RDF::Graph.new << [statement, RDF::URI("ex:certainty"), RDF::Literal(0.9)]
78
78
  graph.dump(:jsonld, validate: false, standard_prefixes: true)
@@ -565,7 +565,7 @@ The {JSON::LD::ContentNegotiation#call} method looks for a result which includes
565
565
  See [Rack::LinkedData][] to do the same thing with an RDF Graph or Dataset as the source, rather than Ruby objects.
566
566
 
567
567
  ## Documentation
568
- Full documentation available on [RubyDoc](https://rubydoc.info/gems/json-ld/file/README.md)
568
+ Full documentation available on [RubyDoc](https://ruby-rdf.github.io/json-ld/file/README.md)
569
569
 
570
570
  ## Differences from [JSON-LD API][]
571
571
  The specified JSON-LD API is based on a WebIDL definition implementing [Promises][] intended for use within a browser.
@@ -588,9 +588,9 @@ Note, the API method signatures differed in versions before 1.0, in that they al
588
588
  * {JSON::LD::Writer}
589
589
 
590
590
  ## Dependencies
591
- * [Ruby](https://ruby-lang.org/) (>= 2.4)
592
- * [RDF.rb](https://rubygems.org/gems/rdf) (~> 3.1)
593
- * [JSON](https://rubygems.org/gems/json) (>= 2.2)
591
+ * [Ruby](https://ruby-lang.org/) (>= 2.6)
592
+ * [RDF.rb](https://rubygems.org/gems/rdf) (~> 3.2)
593
+ * [JSON](https://rubygems.org/gems/json) (>= 2.6)
594
594
 
595
595
  ## Installation
596
596
  The recommended installation method is via [RubyGems](https://rubygems.org/).
@@ -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.1.10
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
@@ -5,13 +5,6 @@ require 'bigdecimal'
5
5
  require 'set'
6
6
  require 'rdf/util/cache'
7
7
 
8
- begin
9
- # Attempt to load this to avoid unnecessary context fetches
10
- require 'json-ld-preloaded'
11
- rescue LoadError
12
- # Silently allow this to fail
13
- end
14
-
15
8
  module JSON::LD
16
9
  class Context
17
10
  include Utils
@@ -50,6 +43,13 @@ module JSON::LD
50
43
  end
51
44
  end
52
45
 
46
+ begin
47
+ # Attempt to load this to avoid unnecessary context fetches
48
+ require 'json/ld/preloaded'
49
+ rescue LoadError
50
+ # Silently allow this to fail
51
+ end
52
+
53
53
  # The base.
54
54
  #
55
55
  # @return [RDF::URI] Current base IRI, used for expanding relative IRIs.
@@ -1688,7 +1688,7 @@ module JSON::LD
1688
1688
  ec.default_direction = that.default_direction
1689
1689
  ec.default_language = that.default_language
1690
1690
  ec.previous_context = that.previous_context
1691
- ec.processingMode = that.processingMode if that.instance_variable_get(:@processingModee)
1691
+ ec.processingMode = that.processingMode if that.instance_variable_get(:@processingMode)
1692
1692
  ec.vocab = that.vocab if that.vocab
1693
1693
 
1694
1694
  ec.instance_eval do
@@ -88,7 +88,7 @@ module JSON::LD
88
88
 
89
89
  # If element contains the key @context, set active context to the result of the Context Processing algorithm, passing active context and the value of the @context key as local context.
90
90
  if input.key?('@context')
91
- context = context.parse(input.delete('@context'), base: @options[:base])
91
+ context = context.parse(input['@context'], base: @options[:base])
92
92
  log_debug("expand", depth: log_depth.to_i) {"context: #{context.inspect}"}
93
93
  end
94
94
 
@@ -99,7 +99,7 @@ module JSON::LD
99
99
 
100
100
  # See if keys mapping to @type have terms with a local context
101
101
  type_key = nil
102
- input.keys.sort.
102
+ (input.keys - %w(@context)).sort.
103
103
  select {|k| context.expand_iri(k, vocab: true, base: @options[:base]) == '@type'}.
104
104
  each do |tk|
105
105
 
@@ -202,7 +202,7 @@ module JSON::LD
202
202
  # * Deserialize the key into a map, and re-serialize the value of `@id`.
203
203
  # * If the map contains an entry with that value (after re-canonicalizing, as appropriate), and the associated antry has a item which matches the non-`@id` item from the map, the node is used to create an `@annotation` entry within that value.
204
204
  #
205
- # @param [Hash{String => Hash}] input
205
+ # @param [Hash{String => Hash}] node_map
206
206
  # @return [Hash{String => Hash}]
207
207
  def create_annotations(node_map)
208
208
  node_map.keys.
@@ -23,7 +23,8 @@ module JSON::LD
23
23
  class Format < RDF::Format
24
24
  content_type 'application/ld+json',
25
25
  extension: :jsonld,
26
- alias: 'application/x-ld+json'
26
+ alias: 'application/x-ld+json',
27
+ uri: 'http://www.w3.org/ns/formats/JSON-LD'
27
28
  content_encoding 'utf-8'
28
29
 
29
30
  reader { JSON::LD::Reader }
@@ -12,7 +12,7 @@ module JSON::LD
12
12
 
13
13
  ##
14
14
  # JSON-LD Reader options
15
- # @see http://www.rubydoc.info/github/ruby-rdf/rdf/RDF/Reader#options-class_method
15
+ # @see https://ruby-rdf.github.io/rdf/RDF/Reader#options-class_method
16
16
  def self.options
17
17
  super + [
18
18
  RDF::CLI::Option.new(
@@ -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,10 +11,11 @@ module JSON::LD
11
11
  ##
12
12
  # @param [Hash{String => Object}] item
13
13
  # @param [RDF::Resource] graph_name
14
+ # @param [Boolean] quoted emitted triples are quoted triples.
14
15
  # @yield statement
15
16
  # @yieldparam [RDF::Statement] statement
16
17
  # @return RDF::Resource the subject of this item
17
- def item_to_rdf(item, graph_name: nil, &block)
18
+ def item_to_rdf(item, graph_name: nil, quoted: false, &block)
18
19
  # Just return value object as Term
19
20
  return unless item
20
21
 
@@ -82,9 +83,9 @@ module JSON::LD
82
83
  when nil then node
83
84
  when String then as_resource(item['@id'])
84
85
  when Object
85
- # Embedded statement
86
+ # Embedded/quoted statement
86
87
  # (No error checking, as this is done in expansion)
87
- to_enum(:item_to_rdf, item['@id']).to_a.first
88
+ to_enum(:item_to_rdf, item['@id'], quoted: true).to_a.first
88
89
  end
89
90
 
90
91
  #log_debug("item_to_rdf") {"subject: #{subject.to_ntriples rescue 'malformed rdf'}"}
@@ -95,12 +96,12 @@ module JSON::LD
95
96
  values.each do |v|
96
97
  object = as_resource(v)
97
98
  #log_debug("item_to_rdf") {"type: #{object.to_ntriples rescue 'malformed rdf'}"}
98
- yield RDF::Statement(subject, RDF.type, object, graph_name: graph_name)
99
+ yield RDF::Statement(subject, RDF.type, object, graph_name: graph_name, quoted: quoted)
99
100
  end
100
101
  when '@graph'
101
102
  values = [values].compact unless values.is_a?(Array)
102
103
  values.each do |nd|
103
- item_to_rdf(nd, graph_name: subject, &block)
104
+ item_to_rdf(nd, graph_name: subject, quoted: quoted, &block)
104
105
  end
105
106
  when '@reverse'
106
107
  raise "Huh?" unless values.is_a?(Hash)
@@ -113,7 +114,7 @@ module JSON::LD
113
114
  object = item_to_rdf(v, graph_name: graph_name, &block)
114
115
  #log_debug("item_to_rdf") {"subject: #{object.to_ntriples rescue 'malformed rdf'}"}
115
116
  # yield subject, prediate, and literal to results.
116
- yield RDF::Statement(object, predicate, subject, graph_name: graph_name)
117
+ yield RDF::Statement(object, predicate, subject, graph_name: graph_name, quoted: quoted)
117
118
  end
118
119
  end
119
120
  when '@included'
@@ -136,13 +137,13 @@ module JSON::LD
136
137
  object = parse_list(v['@list'], graph_name: graph_name, &block)
137
138
 
138
139
  # Append a triple composed of subject, prediate, and object to results and add all triples from list_results to results.
139
- yield RDF::Statement(subject, predicate, object, graph_name: graph_name)
140
+ yield RDF::Statement(subject, predicate, object, graph_name: graph_name, quoted: quoted)
140
141
  else
141
142
  # Otherwise, item is a value object or a node definition. Generate object as the result of the Object Converstion algorithm passing item.
142
143
  object = item_to_rdf(v, graph_name: graph_name, &block)
143
144
  #log_debug("item_to_rdf") {"object: #{object.to_ntriples rescue 'malformed rdf'}"}
144
145
  # yield subject, prediate, and literal to results.
145
- yield RDF::Statement(subject, predicate, object, graph_name: graph_name)
146
+ yield RDF::Statement(subject, predicate, object, graph_name: graph_name, quoted: quoted)
146
147
  end
147
148
  end
148
149
  end
@@ -71,7 +71,7 @@ module JSON::LD
71
71
 
72
72
  ##
73
73
  # JSON-LD Writer options
74
- # @see http://www.rubydoc.info/github/ruby-rdf/rdf/RDF/Writer#options-class_method
74
+ # @see https://ruby-rdf.github.io/rdf/RDF/Writer#options-class_method
75
75
  def self.options
76
76
  super + [
77
77
  RDF::CLI::Option.new(
@@ -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)