json-ld 3.2.0 → 3.2.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +6 -7
  3. data/VERSION +1 -1
  4. data/lib/json/ld/api.rb +55 -16
  5. data/lib/json/ld/context.rb +7 -7
  6. data/lib/json/ld/expand.rb +2 -2
  7. data/lib/json/ld/format.rb +83 -116
  8. data/lib/json/ld/reader.rb +2 -2
  9. data/lib/json/ld/streaming_reader.rb +2 -1
  10. data/lib/json/ld/to_rdf.rb +9 -8
  11. data/lib/json/ld/writer.rb +9 -10
  12. data/lib/json/ld.rb +3 -0
  13. data/spec/api_spec.rb +67 -19
  14. data/spec/format_spec.rb +7 -3
  15. data/spec/frame_spec.rb +25 -1
  16. data/spec/reader_spec.rb +14 -14
  17. data/spec/suite_helper.rb +1 -0
  18. data/spec/test-files/{test-1-compacted.json → test-1-compacted.jsonld} +0 -0
  19. data/spec/test-files/{test-1-context.json → test-1-context.jsonld} +0 -0
  20. data/spec/test-files/{test-1-expanded.json → test-1-expanded.jsonld} +0 -0
  21. data/spec/test-files/{test-1-input.json → test-1-input.jsonld} +0 -0
  22. data/spec/test-files/{test-2-compacted.json → test-2-compacted.jsonld} +0 -0
  23. data/spec/test-files/{test-2-context.json → test-2-context.jsonld} +0 -0
  24. data/spec/test-files/{test-2-expanded.json → test-2-expanded.jsonld} +0 -0
  25. data/spec/test-files/{test-2-input.json → test-2-input.jsonld} +0 -0
  26. data/spec/test-files/{test-3-compacted.json → test-3-compacted.jsonld} +0 -0
  27. data/spec/test-files/{test-3-context.json → test-3-context.jsonld} +0 -0
  28. data/spec/test-files/{test-3-expanded.json → test-3-expanded.jsonld} +0 -0
  29. data/spec/test-files/{test-3-input.json → test-3-input.jsonld} +0 -0
  30. data/spec/test-files/{test-4-compacted.json → test-4-compacted.jsonld} +0 -0
  31. data/spec/test-files/{test-4-context.json → test-4-context.jsonld} +0 -0
  32. data/spec/test-files/{test-4-expanded.json → test-4-expanded.jsonld} +0 -0
  33. data/spec/test-files/{test-4-input.json → test-4-input.jsonld} +0 -0
  34. data/spec/test-files/{test-5-compacted.json → test-5-compacted.jsonld} +0 -0
  35. data/spec/test-files/{test-5-context.json → test-5-context.jsonld} +0 -0
  36. data/spec/test-files/{test-5-expanded.json → test-5-expanded.jsonld} +0 -0
  37. data/spec/test-files/{test-5-input.json → test-5-input.jsonld} +0 -0
  38. data/spec/test-files/{test-6-compacted.json → test-6-compacted.jsonld} +0 -0
  39. data/spec/test-files/{test-6-context.json → test-6-context.jsonld} +0 -0
  40. data/spec/test-files/{test-6-expanded.json → test-6-expanded.jsonld} +0 -0
  41. data/spec/test-files/{test-6-input.json → test-6-input.jsonld} +0 -0
  42. data/spec/test-files/{test-7-compacted.json → test-7-compacted.jsonld} +0 -0
  43. data/spec/test-files/{test-7-context.json → test-7-context.jsonld} +0 -0
  44. data/spec/test-files/{test-7-expanded.json → test-7-expanded.jsonld} +0 -0
  45. data/spec/test-files/{test-7-input.json → test-7-input.jsonld} +0 -0
  46. data/spec/test-files/{test-8-compacted.json → test-8-compacted.jsonld} +0 -0
  47. data/spec/test-files/{test-8-context.json → test-8-context.jsonld} +0 -0
  48. data/spec/test-files/{test-8-expanded.json → test-8-expanded.jsonld} +0 -0
  49. data/spec/test-files/{test-8-frame.json → test-8-frame.jsonld} +0 -0
  50. data/spec/test-files/{test-8-framed.json → test-8-framed.jsonld} +0 -0
  51. data/spec/test-files/{test-8-input.json → test-8-input.jsonld} +0 -0
  52. data/spec/test-files/{test-9-compacted.json → test-9-compacted.jsonld} +0 -0
  53. data/spec/test-files/{test-9-context.json → test-9-context.jsonld} +0 -0
  54. data/spec/test-files/{test-9-expanded.json → test-9-expanded.jsonld} +0 -0
  55. data/spec/test-files/{test-9-input.json → test-9-input.jsonld} +0 -0
  56. metadata +94 -89
  57. data/spec/test-files/test-1-normalized.json +0 -8
  58. data/spec/test-files/test-2-normalized.json +0 -32
  59. 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: e157972b224a8cbe834defdf32656a0b9f090357760fab179076e728427d1639
4
- data.tar.gz: a63cd584853e5a830c85a427d30711bc84999e958949c81bc7d236df20f14ee6
3
+ metadata.gz: ff11a49b52d7ca0faf6deaac7324f08530747b53ec857ebe007c027a1bf412b4
4
+ data.tar.gz: b0a808fc12be08ecaa47f399c0f20ff26120cc36820bf45d6c434ad1f31f53e3
5
5
  SHA512:
6
- metadata.gz: 77a85aa85eea6844e1adb9107fe0b2d5a4ad82b877456adcdbbc56031f884da21cc992169232c326f255491d8aa6f607aacbeaeb386578fe8a1ac374cc795ff5
7
- data.tar.gz: 2f8353dca7bb6ea9bed3ed7fbea3e0bf883bdec9a3687d3b084f936ae0171a21df1d55bda8cf44fc0ae6d6682d5235234792901fb2fc7ffed327d2956fec289f
6
+ metadata.gz: c3e17fbb3280f393ece72136d09182d1032982ca116d49577f03dc72ca35ebc8193495054a1944e525acdad8ae67ce6cb341f6859c5e97a7d2497ca047d7ee40
7
+ data.tar.gz: eef60e136ca7d86ac66cd0b74d5b01862b4f5c7039352c7d6e678b73ab783bf7bbf2f397f7fd928421bc52e332389cab1432e69175d6fa0d260dfcf7a315a66a
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.
@@ -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.0
1
+ 3.2.3
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,29 @@ 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
+ # @option options [Object] :serializer_opts (JSON_STATE)
831
+ def self.serializer(object, *args, **options)
832
+ serializer_opts = options.fetch(:serializer_opts, JSON_STATE)
833
+ MultiJson.dump(object, serializer_opts)
834
+ end
835
+
797
836
  ##
798
837
  # Validate JSON using JsonLint, if loaded
799
838
  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.
@@ -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
 
@@ -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 }
@@ -44,8 +45,80 @@ module JSON::LD
44
45
  !sample.include?("http://www.w3.org/ns/csvw")
45
46
  end
46
47
 
48
+ # Specify how to execute CLI commands for each supported format.
49
+ # Derived formats (e.g., YAML-LD) define their own entrypoints.
50
+ LD_FORMATS = {
51
+ jsonld: {
52
+ expand: ->(input, **options) {
53
+ JSON::LD::API.expand(input,
54
+ serializer: JSON::LD::API.method(:serializer),
55
+ **options)
56
+ },
57
+ compact: ->(input, **options) {
58
+ JSON::LD::API.compact(input,
59
+ options[:context],
60
+ serializer: JSON::LD::API.method(:serializer),
61
+ **options)
62
+ },
63
+ flatten: ->(input, **options) {
64
+ JSON::LD::API.flatten(input,
65
+ options[:context],
66
+ serializer: JSON::LD::API.method(:serializer),
67
+ **options)
68
+ },
69
+ frame: ->(input, **options) {
70
+ JSON::LD::API.frame(input,
71
+ options[:frame],
72
+ serializer: JSON::LD::API.method(:serializer),
73
+ **options)
74
+ },
75
+ }
76
+ }
77
+
78
+ # Execute the body of a CLI command, generic for each different API method based on definitions on {LD_FORMATS}.
79
+ #
80
+ # Expands the input, or transforms from an RDF format based on the `:format` option, and then executes the appropriate command based on `:output_format` and does appropriate output serialization.
81
+ # @private
82
+ def self.cli_exec(command, files, output: $stdin, **options)
83
+ output.set_encoding(Encoding::UTF_8) if output.respond_to?(:set_encoding) && RUBY_PLATFORM == "java"
84
+ options[:base] ||= options[:base_uri]
85
+
86
+ # Parse using input format, serialize using output format
87
+ in_fmt = LD_FORMATS[options.fetch(:format, :jsonld)]
88
+ out_fmt = LD_FORMATS[options.fetch(:output_format, :jsonld)]
89
+
90
+ if in_fmt
91
+ # Input is a JSON-LD based source (or derived)
92
+ if files.empty?
93
+ # If files are empty, either use options[:evaluate] or STDIN
94
+ input = options[:evaluate] ? StringIO.new(options[:evaluate]) : STDIN
95
+ input.set_encoding(options.fetch(:encoding, Encoding::UTF_8))
96
+ expanded = in_fmt[:expand].call(input, serializer: nil, **options)
97
+ output.puts out_fmt[command].call(expanded, expanded: true, **options)
98
+ else
99
+ files.each do |file|
100
+ expanded = in_fmt[:expand].call(file, serializer: nil, **options)
101
+ output.puts out_fmt[command].call(expanded, expanded: true, **options)
102
+ end
103
+ end
104
+ else
105
+ # Turn RDF into JSON-LD first
106
+ RDF::CLI.parse(files, **options) do |reader|
107
+ JSON::LD::API.fromRdf(reader, serializer: nil, **options) do |expanded|
108
+ output.puts out_fmt[command].call(expanded, expanded: true, **options)
109
+ end
110
+ end
111
+ end
112
+ end
113
+
47
114
  ##
48
- # Hash of CLI commands appropriate for this format
115
+ # Hash of CLI commands appropriate for this format:
116
+ #
117
+ # * `expand` => {JSON::LD::API.expand}
118
+ # * `compact` => {JSON::LD::API.compact}
119
+ # * `flatten` => {JSON::LD::API.flatten}
120
+ # * `frame` => {JSON::LD::API.frame}
121
+ #
49
122
  # @return [Hash{Symbol => Hash}]
50
123
  def self.cli_commands
51
124
  {
@@ -53,73 +126,21 @@ module JSON::LD
53
126
  description: "Expand JSON-LD or parsed RDF",
54
127
  parse: false,
55
128
  help: "expand [--context <context-file>] files ...",
56
- filter: {output_format: :jsonld}, # Only shows output format set
129
+ filter: {output_format: LD_FORMATS.keys}, # Only shows output format set
57
130
  lambda: ->(files, **options) do
58
- out = options[:output] || $stdout
59
- out.set_encoding(Encoding::UTF_8) if RUBY_PLATFORM == "java"
60
131
  options = options.merge(expandContext: options.delete(:context)) if options.key?(:context)
61
- options[:base] ||= options[:base_uri]
62
- if options[:format] == :jsonld
63
- if files.empty?
64
- # If files are empty, either use options[:evaluate] or STDIN
65
- input = options[:evaluate] ? StringIO.new(options[:evaluate]) : STDIN
66
- input.set_encoding(options.fetch(:encoding, Encoding::UTF_8))
67
- JSON::LD::API.expand(input, validate: false, **options) do |expanded|
68
- out.puts expanded.to_json(JSON::LD::JSON_STATE)
69
- end
70
- else
71
- files.each do |file|
72
- JSON::LD::API.expand(file, validate: false, **options) do |expanded|
73
- out.puts expanded.to_json(JSON::LD::JSON_STATE)
74
- end
75
- end
76
- end
77
- else
78
- # Turn RDF into JSON-LD first
79
- RDF::CLI.parse(files, **options) do |reader|
80
- JSON::LD::API.fromRdf(reader) do |expanded|
81
- out.puts expanded.to_json(JSON::LD::JSON_STATE)
82
- end
83
- end
84
- end
132
+ cli_exec(:expand, files, **options)
85
133
  end,
86
134
  option_use: {context: :removed}
87
135
  },
88
136
  compact: {
89
137
  description: "Compact JSON-LD or parsed RDF",
90
138
  parse: false,
91
- filter: {output_format: :jsonld}, # Only shows output format set
139
+ filter: {output_format: LD_FORMATS.keys}, # Only shows output format set
92
140
  help: "compact --context <context-file> files ...",
93
141
  lambda: ->(files, **options) do
94
142
  raise ArgumentError, "Compacting requires a context" unless options[:context]
95
- out = options[:output] || $stdout
96
- out.set_encoding(Encoding::UTF_8) if RUBY_PLATFORM == "java"
97
- options[:base] ||= options[:base_uri]
98
- if options[:format] == :jsonld
99
- if files.empty?
100
- # If files are empty, either use options[:evaluate] or STDIN
101
- input = options[:evaluate] ? StringIO.new(options[:evaluate]) : STDIN
102
- input.set_encoding(options.fetch(:encoding, Encoding::UTF_8))
103
- JSON::LD::API.compact(input, options[:context], **options) do |compacted|
104
- out.puts compacted.to_json(JSON::LD::JSON_STATE)
105
- end
106
- else
107
- files.each do |file|
108
- JSON::LD::API.compact(file, options[:context], **options) do |compacted|
109
- out.puts compacted.to_json(JSON::LD::JSON_STATE)
110
- end
111
- end
112
- end
113
- else
114
- # Turn RDF into JSON-LD first
115
- RDF::CLI.parse(files, **options) do |reader|
116
- JSON::LD::API.fromRdf(reader) do |expanded|
117
- JSON::LD::API.compact(expanded, options[:context], **options) do |compacted|
118
- out.puts compacted.to_json(JSON::LD::JSON_STATE)
119
- end
120
- end
121
- end
122
- end
143
+ cli_exec(:compact, files, **options)
123
144
  end,
124
145
  options: [
125
146
  RDF::CLI::Option.new(
@@ -135,36 +156,9 @@ module JSON::LD
135
156
  description: "Flatten JSON-LD or parsed RDF",
136
157
  parse: false,
137
158
  help: "flatten [--context <context-file>] files ...",
138
- filter: {output_format: :jsonld}, # Only shows output format set
159
+ filter: {output_format: LD_FORMATS.keys}, # Only shows output format set
139
160
  lambda: ->(files, **options) do
140
- out = options[:output] || $stdout
141
- out.set_encoding(Encoding::UTF_8) if RUBY_PLATFORM == "java"
142
- options[:base] ||= options[:base_uri]
143
- if options[:format] == :jsonld
144
- if files.empty?
145
- # If files are empty, either use options[:evaluate] or STDIN
146
- input = options[:evaluate] ? StringIO.new(options[:evaluate]) : STDIN
147
- input.set_encoding(options.fetch(:encoding, Encoding::UTF_8))
148
- JSON::LD::API.flatten(input, options[:context], **options) do |flattened|
149
- out.puts flattened.to_json(JSON::LD::JSON_STATE)
150
- end
151
- else
152
- files.each do |file|
153
- JSON::LD::API.flatten(file, options[:context], **options) do |flattened|
154
- out.puts flattened.to_json(JSON::LD::JSON_STATE)
155
- end
156
- end
157
- end
158
- else
159
- # Turn RDF into JSON-LD first
160
- RDF::CLI.parse(files, **options) do |reader|
161
- JSON::LD::API.fromRdf(reader) do |expanded|
162
- JSON::LD::API.flatten(expanded, options[:context], **options) do |flattened|
163
- out.puts flattened.to_json(JSON::LD::JSON_STATE)
164
- end
165
- end
166
- end
167
- end
161
+ cli_exec(:compact, files, **options)
168
162
  end,
169
163
  options: [
170
164
  RDF::CLI::Option.new(
@@ -187,37 +181,10 @@ module JSON::LD
187
181
  description: "Frame JSON-LD or parsed RDF",
188
182
  parse: false,
189
183
  help: "frame --frame <frame-file> files ...",
190
- filter: {output_format: :jsonld}, # Only shows output format set
184
+ filter: {output_format: LD_FORMATS.keys}, # Only shows output format set
191
185
  lambda: ->(files, **options) do
192
186
  raise ArgumentError, "Framing requires a frame" unless options[:frame]
193
- out = options[:output] || $stdout
194
- out.set_encoding(Encoding::UTF_8) if RUBY_PLATFORM == "java"
195
- options[:base] ||= options[:base_uri]
196
- if options[:format] == :jsonld
197
- if files.empty?
198
- # If files are empty, either use options[:evaluate] or STDIN
199
- input = options[:evaluate] ? StringIO.new(options[:evaluate]) : STDIN
200
- input.set_encoding(options.fetch(:encoding, Encoding::UTF_8))
201
- JSON::LD::API.frame(input, options[:frame], **options) do |framed|
202
- out.puts framed.to_json(JSON::LD::JSON_STATE)
203
- end
204
- else
205
- files.each do |file|
206
- JSON::LD::API.frame(file, options[:frame], **options) do |framed|
207
- out.puts framed.to_json(JSON::LD::JSON_STATE)
208
- end
209
- end
210
- end
211
- else
212
- # Turn RDF into JSON-LD first
213
- RDF::CLI.parse(files, **options) do |reader|
214
- JSON::LD::API.fromRdf(reader) do |expanded|
215
- JSON::LD::API.frame(expanded, options[:frame], **options) do |framed|
216
- out.puts framed.to_json(JSON::LD::JSON_STATE)
217
- end
218
- end
219
- end
220
- end
187
+ cli_exec(:compact, files, **options)
221
188
  end,
222
189
  option_use: {context: :removed},
223
190
  options: [
@@ -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)