json-ld 3.1.10 → 3.2.2

Sign up to get free protection for your applications and to get access to all the features.
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)