json-ld 3.2.3 → 3.2.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/VERSION +1 -1
- data/lib/json/ld/api.rb +807 -764
- data/lib/json/ld/compact.rb +304 -304
- data/lib/json/ld/conneg.rb +179 -161
- data/lib/json/ld/context.rb +2080 -1945
- data/lib/json/ld/expand.rb +745 -666
- data/lib/json/ld/extensions.rb +14 -13
- data/lib/json/ld/flatten.rb +257 -247
- data/lib/json/ld/format.rb +202 -194
- data/lib/json/ld/frame.rb +525 -502
- data/lib/json/ld/from_rdf.rb +224 -166
- data/lib/json/ld/html/nokogiri.rb +123 -121
- data/lib/json/ld/html/rexml.rb +151 -147
- data/lib/json/ld/reader.rb +107 -100
- data/lib/json/ld/resource.rb +224 -205
- data/lib/json/ld/streaming_reader.rb +574 -507
- data/lib/json/ld/streaming_writer.rb +93 -92
- data/lib/json/ld/to_rdf.rb +171 -167
- data/lib/json/ld/utils.rb +270 -264
- data/lib/json/ld/version.rb +24 -14
- data/lib/json/ld/writer.rb +334 -311
- data/lib/json/ld.rb +103 -96
- metadata +78 -209
- data/spec/api_spec.rb +0 -132
- data/spec/compact_spec.rb +0 -3482
- data/spec/conneg_spec.rb +0 -373
- data/spec/context_spec.rb +0 -2036
- data/spec/expand_spec.rb +0 -4496
- data/spec/flatten_spec.rb +0 -1203
- data/spec/format_spec.rb +0 -115
- data/spec/frame_spec.rb +0 -2498
- data/spec/from_rdf_spec.rb +0 -1005
- data/spec/matchers.rb +0 -20
- data/spec/rdfstar_spec.rb +0 -25
- data/spec/reader_spec.rb +0 -883
- data/spec/resource_spec.rb +0 -76
- data/spec/spec_helper.rb +0 -281
- data/spec/streaming_reader_spec.rb +0 -237
- data/spec/streaming_writer_spec.rb +0 -145
- data/spec/suite_compact_spec.rb +0 -22
- data/spec/suite_expand_spec.rb +0 -36
- data/spec/suite_flatten_spec.rb +0 -34
- data/spec/suite_frame_spec.rb +0 -29
- data/spec/suite_from_rdf_spec.rb +0 -22
- data/spec/suite_helper.rb +0 -411
- data/spec/suite_html_spec.rb +0 -22
- data/spec/suite_http_spec.rb +0 -35
- data/spec/suite_remote_doc_spec.rb +0 -22
- data/spec/suite_to_rdf_spec.rb +0 -30
- data/spec/support/extensions.rb +0 -44
- data/spec/test-files/test-1-compacted.jsonld +0 -10
- data/spec/test-files/test-1-context.jsonld +0 -7
- data/spec/test-files/test-1-expanded.jsonld +0 -5
- data/spec/test-files/test-1-input.jsonld +0 -10
- data/spec/test-files/test-1-rdf.ttl +0 -8
- data/spec/test-files/test-2-compacted.jsonld +0 -20
- data/spec/test-files/test-2-context.jsonld +0 -7
- data/spec/test-files/test-2-expanded.jsonld +0 -16
- data/spec/test-files/test-2-input.jsonld +0 -20
- data/spec/test-files/test-2-rdf.ttl +0 -14
- data/spec/test-files/test-3-compacted.jsonld +0 -11
- data/spec/test-files/test-3-context.jsonld +0 -8
- data/spec/test-files/test-3-expanded.jsonld +0 -10
- data/spec/test-files/test-3-input.jsonld +0 -11
- data/spec/test-files/test-3-rdf.ttl +0 -8
- data/spec/test-files/test-4-compacted.jsonld +0 -10
- data/spec/test-files/test-4-context.jsonld +0 -7
- data/spec/test-files/test-4-expanded.jsonld +0 -6
- data/spec/test-files/test-4-input.jsonld +0 -10
- data/spec/test-files/test-4-rdf.ttl +0 -5
- data/spec/test-files/test-5-compacted.jsonld +0 -13
- data/spec/test-files/test-5-context.jsonld +0 -7
- data/spec/test-files/test-5-expanded.jsonld +0 -9
- data/spec/test-files/test-5-input.jsonld +0 -13
- data/spec/test-files/test-5-rdf.ttl +0 -7
- data/spec/test-files/test-6-compacted.jsonld +0 -10
- data/spec/test-files/test-6-context.jsonld +0 -7
- data/spec/test-files/test-6-expanded.jsonld +0 -10
- data/spec/test-files/test-6-input.jsonld +0 -10
- data/spec/test-files/test-6-rdf.ttl +0 -6
- data/spec/test-files/test-7-compacted.jsonld +0 -23
- data/spec/test-files/test-7-context.jsonld +0 -4
- data/spec/test-files/test-7-expanded.jsonld +0 -20
- data/spec/test-files/test-7-input.jsonld +0 -23
- data/spec/test-files/test-7-rdf.ttl +0 -14
- data/spec/test-files/test-8-compacted.jsonld +0 -34
- data/spec/test-files/test-8-context.jsonld +0 -11
- data/spec/test-files/test-8-expanded.jsonld +0 -24
- data/spec/test-files/test-8-frame.jsonld +0 -18
- data/spec/test-files/test-8-framed.jsonld +0 -25
- data/spec/test-files/test-8-input.jsonld +0 -30
- data/spec/test-files/test-8-rdf.ttl +0 -15
- data/spec/test-files/test-9-compacted.jsonld +0 -20
- data/spec/test-files/test-9-context.jsonld +0 -13
- data/spec/test-files/test-9-expanded.jsonld +0 -14
- data/spec/test-files/test-9-input.jsonld +0 -12
- data/spec/to_rdf_spec.rb +0 -1551
- data/spec/writer_spec.rb +0 -427
data/lib/json/ld/reader.rb
CHANGED
@@ -1,116 +1,123 @@
|
|
1
|
-
#
|
2
|
-
|
3
|
-
module JSON::LD
|
4
|
-
##
|
5
|
-
# A JSON-LD parser in Ruby.
|
6
|
-
#
|
7
|
-
# @see https://www.w3.org/TR/json-ld11-api
|
8
|
-
# @author [Gregg Kellogg](http://greggkellogg.net/)
|
9
|
-
class Reader < RDF::Reader
|
10
|
-
include StreamingReader
|
11
|
-
format Format
|
1
|
+
# frozen_string_literal: true
|
12
2
|
|
3
|
+
module JSON
|
4
|
+
module LD
|
13
5
|
##
|
14
|
-
# JSON-LD
|
15
|
-
# @see https://ruby-rdf.github.io/rdf/RDF/Reader#options-class_method
|
16
|
-
def self.options
|
17
|
-
super + [
|
18
|
-
RDF::CLI::Option.new(
|
19
|
-
symbol: :expandContext,
|
20
|
-
control: :url2,
|
21
|
-
datatype: RDF::URI,
|
22
|
-
on: ["--expand-context CONTEXT"],
|
23
|
-
description: "Context to use when expanding.") {|arg| RDF::URI(arg).absolute? ? RDF::URI(arg) : StringIO.new(File.read(arg))},
|
24
|
-
RDF::CLI::Option.new(
|
25
|
-
symbol: :extractAllScripts,
|
26
|
-
datatype: TrueClass,
|
27
|
-
default: false,
|
28
|
-
control: :checkbox,
|
29
|
-
on: ["--[no-]extract-all-scripts"],
|
30
|
-
description: "If set to true, when extracting JSON-LD script elements from HTML, unless a specific fragment identifier is targeted, extracts all encountered JSON-LD script elements using an array form, if necessary.") {|arg| RDF::URI(arg)},
|
31
|
-
RDF::CLI::Option.new(
|
32
|
-
symbol: :lowercaseLanguage,
|
33
|
-
datatype: TrueClass,
|
34
|
-
control: :checkbox,
|
35
|
-
on: ["--[no-]lowercase-language"],
|
36
|
-
description: "By default, language tags are left as is. To normalize to lowercase, set this option to `true`."),
|
37
|
-
RDF::CLI::Option.new(
|
38
|
-
symbol: :processingMode,
|
39
|
-
datatype: %w(json-ld-1.0 json-ld-1.1),
|
40
|
-
control: :radio,
|
41
|
-
on: ["--processingMode MODE", %w(json-ld-1.0 json-ld-1.1)],
|
42
|
-
description: "Set Processing Mode (json-ld-1.0 or json-ld-1.1)"),
|
43
|
-
RDF::CLI::Option.new(
|
44
|
-
symbol: :rdfDirection,
|
45
|
-
datatype: %w(i18n-datatype compound-literal),
|
46
|
-
default: 'null',
|
47
|
-
control: :select,
|
48
|
-
on: ["--rdf-direction DIR", %w(i18n-datatype compound-literal)],
|
49
|
-
description: "How to serialize literal direction (i18n-datatype compound-literal)") {|arg| RDF::URI(arg)},
|
50
|
-
RDF::CLI::Option.new(
|
51
|
-
symbol: :stream,
|
52
|
-
datatype: TrueClass,
|
53
|
-
control: :checkbox,
|
54
|
-
on: ["--[no-]stream"],
|
55
|
-
description: "Optimize for streaming JSON-LD to RDF.") {|arg| arg},
|
56
|
-
]
|
57
|
-
end
|
58
|
-
|
59
|
-
##
|
60
|
-
# Initializes the JSON-LD reader instance.
|
6
|
+
# A JSON-LD parser in Ruby.
|
61
7
|
#
|
62
|
-
# @
|
63
|
-
# @
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
# @yieldreturn [void] ignored
|
68
|
-
# @raise [RDF::ReaderError] if the JSON document cannot be loaded
|
69
|
-
def initialize(input = $stdin, **options, &block)
|
70
|
-
options[:base_uri] ||= options[:base]
|
71
|
-
options[:rename_bnodes] = false unless options.key?(:rename_bnodes)
|
72
|
-
super do
|
73
|
-
@options[:base] ||= base_uri.to_s if base_uri
|
74
|
-
# Trim non-JSON stuff in script.
|
75
|
-
@doc = if input.respond_to?(:read)
|
76
|
-
input
|
77
|
-
else
|
78
|
-
StringIO.new(input.to_s.sub(%r(\A[^{\[]*)m, '').sub(%r([^}\]]*\Z)m, ''))
|
79
|
-
end
|
8
|
+
# @see https://www.w3.org/TR/json-ld11-api
|
9
|
+
# @author [Gregg Kellogg](http://greggkellogg.net/)
|
10
|
+
class Reader < RDF::Reader
|
11
|
+
include StreamingReader
|
12
|
+
format Format
|
80
13
|
|
81
|
-
|
82
|
-
|
14
|
+
##
|
15
|
+
# JSON-LD Reader options
|
16
|
+
# @see https://ruby-rdf.github.io/rdf/RDF/Reader#options-class_method
|
17
|
+
def self.options
|
18
|
+
super + [
|
19
|
+
RDF::CLI::Option.new(
|
20
|
+
symbol: :expandContext,
|
21
|
+
control: :url2,
|
22
|
+
datatype: RDF::URI,
|
23
|
+
on: ["--expand-context CONTEXT"],
|
24
|
+
description: "Context to use when expanding."
|
25
|
+
) { |arg| RDF::URI(arg).absolute? ? RDF::URI(arg) : StringIO.new(File.read(arg)) },
|
26
|
+
RDF::CLI::Option.new(
|
27
|
+
symbol: :extractAllScripts,
|
28
|
+
datatype: TrueClass,
|
29
|
+
default: false,
|
30
|
+
control: :checkbox,
|
31
|
+
on: ["--[no-]extract-all-scripts"],
|
32
|
+
description: "If set to true, when extracting JSON-LD script elements from HTML, unless a specific fragment identifier is targeted, extracts all encountered JSON-LD script elements using an array form, if necessary."
|
33
|
+
) { |arg| RDF::URI(arg) },
|
34
|
+
RDF::CLI::Option.new(
|
35
|
+
symbol: :lowercaseLanguage,
|
36
|
+
datatype: TrueClass,
|
37
|
+
control: :checkbox,
|
38
|
+
on: ["--[no-]lowercase-language"],
|
39
|
+
description: "By default, language tags are left as is. To normalize to lowercase, set this option to `true`."
|
40
|
+
),
|
41
|
+
RDF::CLI::Option.new(
|
42
|
+
symbol: :processingMode,
|
43
|
+
datatype: %w[json-ld-1.0 json-ld-1.1],
|
44
|
+
control: :radio,
|
45
|
+
on: ["--processingMode MODE", %w[json-ld-1.0 json-ld-1.1]],
|
46
|
+
description: "Set Processing Mode (json-ld-1.0 or json-ld-1.1)"
|
47
|
+
),
|
48
|
+
RDF::CLI::Option.new(
|
49
|
+
symbol: :rdfDirection,
|
50
|
+
datatype: %w[i18n-datatype compound-literal],
|
51
|
+
default: 'null',
|
52
|
+
control: :select,
|
53
|
+
on: ["--rdf-direction DIR", %w[i18n-datatype compound-literal]],
|
54
|
+
description: "How to serialize literal direction (i18n-datatype compound-literal)"
|
55
|
+
) { |arg| RDF::URI(arg) },
|
56
|
+
RDF::CLI::Option.new(
|
57
|
+
symbol: :stream,
|
58
|
+
datatype: TrueClass,
|
59
|
+
control: :checkbox,
|
60
|
+
on: ["--[no-]stream"],
|
61
|
+
description: "Optimize for streaming JSON-LD to RDF."
|
62
|
+
) { |arg| arg }
|
63
|
+
]
|
64
|
+
end
|
65
|
+
|
66
|
+
##
|
67
|
+
# Initializes the JSON-LD reader instance.
|
68
|
+
#
|
69
|
+
# @param [IO, File, String] input
|
70
|
+
# @param [Hash{Symbol => Object}] options
|
71
|
+
# any additional options (see `RDF::Reader#initialize` and {JSON::LD::API.initialize})
|
72
|
+
# @yield [reader] `self`
|
73
|
+
# @yieldparam [RDF::Reader] reader
|
74
|
+
# @yieldreturn [void] ignored
|
75
|
+
# @raise [RDF::ReaderError] if the JSON document cannot be loaded
|
76
|
+
def initialize(input = $stdin, **options, &block)
|
77
|
+
options[:base_uri] ||= options[:base]
|
78
|
+
options[:rename_bnodes] = false unless options.key?(:rename_bnodes)
|
79
|
+
super do
|
80
|
+
@options[:base] ||= base_uri.to_s if base_uri
|
81
|
+
# Trim non-JSON stuff in script.
|
82
|
+
@doc = if input.respond_to?(:read)
|
83
|
+
input
|
84
|
+
else
|
85
|
+
StringIO.new(input.to_s.sub(/\A[^{\[]*/m, '').sub(/[^}\]]*\Z/m, ''))
|
86
|
+
end
|
87
|
+
|
88
|
+
if block
|
89
|
+
case block.arity
|
83
90
|
when 0 then instance_eval(&block)
|
84
|
-
else
|
91
|
+
else yield(self)
|
92
|
+
end
|
85
93
|
end
|
86
94
|
end
|
87
95
|
end
|
88
|
-
end
|
89
96
|
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
97
|
+
##
|
98
|
+
# @private
|
99
|
+
# @see RDF::Reader#each_statement
|
100
|
+
def each_statement(&block)
|
101
|
+
if @options[:stream]
|
102
|
+
stream_statement(&block)
|
103
|
+
else
|
104
|
+
API.toRdf(@doc, **@options, &block)
|
105
|
+
end
|
106
|
+
rescue ::JSON::ParserError, ::JSON::LD::JsonLdError => e
|
107
|
+
log_fatal("Failed to parse input document: #{e.message}", exception: RDF::ReaderError)
|
98
108
|
end
|
99
|
-
rescue ::JSON::ParserError, ::JSON::LD::JsonLdError => e
|
100
|
-
log_fatal("Failed to parse input document: #{e.message}", exception: RDF::ReaderError)
|
101
|
-
end
|
102
109
|
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
+
##
|
111
|
+
# @private
|
112
|
+
# @see RDF::Reader#each_triple
|
113
|
+
def each_triple
|
114
|
+
if block_given?
|
115
|
+
each_statement do |statement|
|
116
|
+
yield(*statement.to_triple)
|
117
|
+
end
|
110
118
|
end
|
119
|
+
enum_for(:each_triple)
|
111
120
|
end
|
112
|
-
enum_for(:each_triple)
|
113
121
|
end
|
114
122
|
end
|
115
123
|
end
|
116
|
-
|
data/lib/json/ld/resource.rb
CHANGED
@@ -1,230 +1,249 @@
|
|
1
|
-
# -*- encoding: utf-8 -*-
|
2
1
|
# frozen_string_literal: true
|
3
|
-
module JSON::LD
|
4
|
-
# Simple Ruby reflector class to provide native
|
5
|
-
# access to JSON-LD objects
|
6
|
-
class Resource
|
7
|
-
include RDF::Enumerable
|
8
|
-
|
9
|
-
# @return [Hash<String => Object] Object representation of resource
|
10
|
-
attr_reader :attributes
|
11
|
-
|
12
|
-
# @return [String] ID of this resource
|
13
|
-
attr_reader :id
|
14
|
-
|
15
|
-
# @return [JSON::LD::Context] Context associated with this resource
|
16
|
-
attr_reader :context
|
17
|
-
|
18
|
-
##
|
19
|
-
# Is this resource clean (i.e., saved to mongo?)
|
20
|
-
#
|
21
|
-
# @return [Boolean]
|
22
|
-
def clean?; @clean; end
|
23
|
-
|
24
|
-
##
|
25
|
-
# Is this resource dirty (i.e., not yet saved to mongo?)
|
26
|
-
#
|
27
|
-
# @return [Boolean]
|
28
|
-
def dirty?; !clean?; end
|
29
|
-
|
30
|
-
##
|
31
|
-
# Has this resource been reconciled against a mongo ID?
|
32
|
-
#
|
33
|
-
# @return [Boolean]
|
34
|
-
def reconciled?; @reconciled; end
|
35
|
-
|
36
|
-
##
|
37
|
-
# Has this resource been resolved so that
|
38
|
-
# all references are to other Resources?
|
39
|
-
#
|
40
|
-
# @return [Boolean]
|
41
|
-
def resolved?; @resolved; end
|
42
|
-
|
43
|
-
##
|
44
|
-
# Anonymous resources have BNode ids or no schema:url
|
45
|
-
#
|
46
|
-
# @return [Boolean]
|
47
|
-
def anonymous?; @anon; end
|
48
|
-
|
49
|
-
##
|
50
|
-
# Is this a stub resource, which has not yet been
|
51
|
-
# synched or created within the DB?
|
52
|
-
def stub?; !!@stub; end
|
53
|
-
|
54
|
-
##
|
55
|
-
# Is this a new resource, which has not yet been
|
56
|
-
# synched or created within the DB?
|
57
|
-
def new?; !!@new; end
|
58
|
-
|
59
|
-
##
|
60
|
-
# A new resource from the parsed graph
|
61
|
-
# @param [Hash{String => Object}] node_definition
|
62
|
-
# @param [Hash{Symbol => Object}] options
|
63
|
-
# @option options [String] :context
|
64
|
-
# Resource context, used for finding
|
65
|
-
# appropriate collection and JSON-LD context.
|
66
|
-
# @option options [Boolean] :clean (false)
|
67
|
-
# @option options [Boolean] :compact (false)
|
68
|
-
# Assume `node_definition` is in expanded form
|
69
|
-
# and compact using `context`.
|
70
|
-
# @option options [Boolean] :reconciled (!new)
|
71
|
-
# node_definition is not based on Mongo IDs
|
72
|
-
# and must be reconciled against Mongo, or merged
|
73
|
-
# into another resource.
|
74
|
-
# @option options [Boolean] :new (true)
|
75
|
-
# This is a new resource, not yet saved to Mongo
|
76
|
-
# @option options [Boolean] :stub (false)
|
77
|
-
# This is a stand-in for another resource that has
|
78
|
-
# not yet been retrieved (or created) from Mongo
|
79
|
-
def initialize(node_definition, **options)
|
80
|
-
@context = options[:context]
|
81
|
-
@clean = options.fetch(:clean, false)
|
82
|
-
@new = options.fetch(:new, true)
|
83
|
-
@reconciled = options.fetch(:reconciled, !@new)
|
84
|
-
@resolved = false
|
85
|
-
@attributes = if options[:compact]
|
86
|
-
JSON::LD::API.compact(node_definition, @context)
|
87
|
-
else
|
88
|
-
node_definition
|
89
|
-
end
|
90
|
-
@id = @attributes['@id']
|
91
|
-
@anon = @id.nil? || @id.to_s.start_with?('_:')
|
92
|
-
end
|
93
2
|
|
94
|
-
|
95
|
-
|
96
|
-
#
|
97
|
-
|
98
|
-
|
99
|
-
|
3
|
+
module JSON
|
4
|
+
module LD
|
5
|
+
# Simple Ruby reflector class to provide native
|
6
|
+
# access to JSON-LD objects
|
7
|
+
class Resource
|
8
|
+
include RDF::Enumerable
|
9
|
+
|
10
|
+
# @return [Hash<String => Object] Object representation of resource
|
11
|
+
attr_reader :attributes
|
12
|
+
|
13
|
+
# @return [String] ID of this resource
|
14
|
+
attr_reader :id
|
15
|
+
|
16
|
+
# @return [JSON::LD::Context] Context associated with this resource
|
17
|
+
attr_reader :context
|
18
|
+
|
19
|
+
##
|
20
|
+
# Is this resource clean (i.e., saved to mongo?)
|
21
|
+
#
|
22
|
+
# @return [Boolean]
|
23
|
+
def clean?
|
24
|
+
@clean
|
25
|
+
end
|
26
|
+
|
27
|
+
##
|
28
|
+
# Is this resource dirty (i.e., not yet saved to mongo?)
|
29
|
+
#
|
30
|
+
# @return [Boolean]
|
31
|
+
def dirty?
|
32
|
+
!clean?
|
33
|
+
end
|
34
|
+
|
35
|
+
##
|
36
|
+
# Has this resource been reconciled against a mongo ID?
|
37
|
+
#
|
38
|
+
# @return [Boolean]
|
39
|
+
def reconciled?
|
40
|
+
@reconciled
|
41
|
+
end
|
42
|
+
|
43
|
+
##
|
44
|
+
# Has this resource been resolved so that
|
45
|
+
# all references are to other Resources?
|
46
|
+
#
|
47
|
+
# @return [Boolean]
|
48
|
+
def resolved?
|
49
|
+
@resolved
|
50
|
+
end
|
51
|
+
|
52
|
+
##
|
53
|
+
# Anonymous resources have BNode ids or no schema:url
|
54
|
+
#
|
55
|
+
# @return [Boolean]
|
56
|
+
def anonymous?
|
57
|
+
@anon
|
58
|
+
end
|
59
|
+
|
60
|
+
##
|
61
|
+
# Is this a stub resource, which has not yet been
|
62
|
+
# synched or created within the DB?
|
63
|
+
def stub?
|
64
|
+
!!@stub
|
65
|
+
end
|
66
|
+
|
67
|
+
##
|
68
|
+
# Is this a new resource, which has not yet been
|
69
|
+
# synched or created within the DB?
|
70
|
+
def new?
|
71
|
+
!!@new
|
72
|
+
end
|
73
|
+
|
74
|
+
##
|
75
|
+
# A new resource from the parsed graph
|
76
|
+
# @param [Hash{String => Object}] node_definition
|
77
|
+
# @param [Hash{Symbol => Object}] options
|
78
|
+
# @option options [String] :context
|
79
|
+
# Resource context, used for finding
|
80
|
+
# appropriate collection and JSON-LD context.
|
81
|
+
# @option options [Boolean] :clean (false)
|
82
|
+
# @option options [Boolean] :compact (false)
|
83
|
+
# Assume `node_definition` is in expanded form
|
84
|
+
# and compact using `context`.
|
85
|
+
# @option options [Boolean] :reconciled (!new)
|
86
|
+
# node_definition is not based on Mongo IDs
|
87
|
+
# and must be reconciled against Mongo, or merged
|
88
|
+
# into another resource.
|
89
|
+
# @option options [Boolean] :new (true)
|
90
|
+
# This is a new resource, not yet saved to Mongo
|
91
|
+
# @option options [Boolean] :stub (false)
|
92
|
+
# This is a stand-in for another resource that has
|
93
|
+
# not yet been retrieved (or created) from Mongo
|
94
|
+
def initialize(node_definition, **options)
|
95
|
+
@context = options[:context]
|
96
|
+
@clean = options.fetch(:clean, false)
|
97
|
+
@new = options.fetch(:new, true)
|
98
|
+
@reconciled = options.fetch(:reconciled, !@new)
|
99
|
+
@resolved = false
|
100
|
+
@attributes = if options[:compact]
|
101
|
+
JSON::LD::API.compact(node_definition, @context)
|
102
|
+
else
|
103
|
+
node_definition
|
104
|
+
end
|
105
|
+
@id = @attributes['@id']
|
106
|
+
@anon = @id.nil? || @id.to_s.start_with?('_:')
|
107
|
+
end
|
108
|
+
|
109
|
+
##
|
110
|
+
# Return a hash of this object, suitable for use by for ETag
|
111
|
+
# @return [Integer]
|
112
|
+
def hash
|
113
|
+
deresolve.hash
|
114
|
+
end
|
100
115
|
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
116
|
+
##
|
117
|
+
# Reverse resolution of resource attributes.
|
118
|
+
# Just returns `attributes` if
|
119
|
+
# resource is unresolved. Otherwise, replaces `Resource`
|
120
|
+
# values with node references.
|
121
|
+
#
|
122
|
+
# Result is expanded and re-compacted to get to normalized
|
123
|
+
# representation.
|
124
|
+
#
|
125
|
+
# @return [Hash] deresolved attribute hash
|
126
|
+
def deresolve
|
127
|
+
node_definition = if resolved?
|
128
|
+
deresolved = [].tap do |memo|
|
129
|
+
attributes.each_pair do |prop, value|
|
130
|
+
memo[prop] = case value
|
131
|
+
when Resource
|
132
|
+
{ 'id' => value.id }
|
133
|
+
when Array
|
134
|
+
value.map do |v|
|
135
|
+
v.is_a?(Resource) ? { 'id' => v.id } : v
|
136
|
+
end
|
137
|
+
else
|
138
|
+
value
|
121
139
|
end
|
122
|
-
else
|
123
|
-
value
|
124
140
|
end
|
125
141
|
end
|
142
|
+
deresolved
|
143
|
+
else
|
144
|
+
attributes
|
126
145
|
end
|
127
|
-
deresolved
|
128
|
-
else
|
129
|
-
attributes
|
130
|
-
end
|
131
146
|
|
132
|
-
|
133
|
-
|
134
|
-
|
147
|
+
compacted = nil
|
148
|
+
JSON::LD::API.expand(node_definition, expandContext: @context) do |expanded|
|
149
|
+
compacted = JSON::LD::API.compact(expanded, @context)
|
150
|
+
end
|
151
|
+
compacted.delete_if { |k, _v| k == '@context' }
|
135
152
|
end
|
136
|
-
compacted.delete_if {|k, v| k == '@context'}
|
137
|
-
end
|
138
153
|
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
154
|
+
##
|
155
|
+
# Serialize to JSON-LD, minus `@context` using
|
156
|
+
# a deresolved version of the attributes
|
157
|
+
#
|
158
|
+
# @param [Hash] options
|
159
|
+
# @return [String] serizlied JSON representation of resource
|
160
|
+
def to_json(**options)
|
161
|
+
deresolve.to_json(**options)
|
162
|
+
end
|
148
163
|
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
164
|
+
##
|
165
|
+
# Enumerate over statements associated with this resource
|
166
|
+
def each(&block)
|
167
|
+
JSON::LD::API.toRdf(attributes, expandContext: context, &block)
|
168
|
+
end
|
154
169
|
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
170
|
+
##
|
171
|
+
# Update node references using the provided map.
|
172
|
+
# This replaces node references with Resources,
|
173
|
+
# either stub or instantiated.
|
174
|
+
#
|
175
|
+
# Node references with ids not in the reference_map
|
176
|
+
# will cause stub resources to be added to the map.
|
177
|
+
#
|
178
|
+
# @param [Hash{String => Resource}] reference_map
|
179
|
+
# @return [Resource] self
|
180
|
+
def resolve(reference_map)
|
181
|
+
return if resolved?
|
182
|
+
|
183
|
+
def update_obj(obj, reference_map)
|
184
|
+
case obj
|
185
|
+
when Array
|
186
|
+
obj.map { |o| update_obj(o, reference_map) }
|
187
|
+
when Hash
|
188
|
+
if node_reference?(obj)
|
189
|
+
reference_map[obj['id']] ||= Resource.new(obj,
|
190
|
+
context: @context_name,
|
191
|
+
clean: false,
|
192
|
+
stub: true)
|
193
|
+
else
|
194
|
+
obj.each_key do |k|
|
195
|
+
obj[k] = update_obj(obj[k], reference_map)
|
196
|
+
end
|
197
|
+
obj
|
181
198
|
end
|
199
|
+
else
|
182
200
|
obj
|
183
201
|
end
|
184
|
-
else
|
185
|
-
obj
|
186
202
|
end
|
187
|
-
end
|
188
203
|
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
204
|
+
# $logger.debug "resolve(0): #{attributes.inspect}"
|
205
|
+
@attributes.each do |k, _v|
|
206
|
+
next if %w[id type].include?(k)
|
207
|
+
|
208
|
+
@attributes[k] = update_obj(@attributes[k], reference_map)
|
209
|
+
end
|
210
|
+
# $logger.debug "resolve(1): #{attributes.inspect}"
|
211
|
+
@resolved = true
|
212
|
+
self
|
193
213
|
end
|
194
|
-
#$logger.debug "resolve(1): #{attributes.inspect}"
|
195
|
-
@resolved = true
|
196
|
-
self
|
197
|
-
end
|
198
214
|
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
215
|
+
##
|
216
|
+
# Override this method to implement save using
|
217
|
+
# an appropriate storage mechanism.
|
218
|
+
#
|
219
|
+
# Save the object to the Mongo collection
|
220
|
+
# use Upsert to create things that don't exist.
|
221
|
+
# First makes sure that the resource is valid.
|
222
|
+
#
|
223
|
+
# @return [Boolean] true or false if resource not saved
|
224
|
+
def save
|
225
|
+
raise NotImplementedError
|
226
|
+
end
|
211
227
|
|
212
|
-
|
213
|
-
|
214
|
-
|
228
|
+
##
|
229
|
+
# Access individual fields, from subject definition
|
230
|
+
def property(prop_name)
|
231
|
+
@attributes.fetch(prop_name, nil)
|
232
|
+
end
|
215
233
|
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
234
|
+
##
|
235
|
+
# Access individual fields, from subject definition
|
236
|
+
def method_missing(method, *_args)
|
237
|
+
property(method.to_s)
|
238
|
+
end
|
221
239
|
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
240
|
+
def inspect
|
241
|
+
"<Resource" +
|
242
|
+
attributes.map do |k, v|
|
243
|
+
"\n #{k}: #{v.inspect}"
|
244
|
+
end.join(" ") +
|
245
|
+
">"
|
246
|
+
end
|
228
247
|
end
|
229
248
|
end
|
230
249
|
end
|