Skip to content

Commit 6e8a32d

Browse files
committed
Finish 2.1.6
2 parents 7332ad6 + 7515b7d commit 6e8a32d

21 files changed

+208
-135
lines changed

Gemfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ group :development, :test do
2020
gem 'coveralls', require: false, platform: :mri
2121
gem 'psych', platforms: [:mri, :rbx]
2222
gem 'benchmark-ips'
23+
gem 'rake'
2324
end
2425

2526
group :debug do

Rakefile

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -37,14 +37,14 @@ file "etc/manifests.nt" do
3737
require 'json/ld'
3838
require 'rdf/ntriples'
3939
graph = RDF::Graph.new do |g|
40-
%w( http://json-ld.org/test-suite/tests/compact-manifest.jsonld
41-
http://json-ld.org/test-suite/tests/error-manifest.jsonld
42-
http://json-ld.org/test-suite/tests/expand-manifest.jsonld
43-
http://json-ld.org/test-suite/tests/flatten-manifest.jsonld
44-
http://json-ld.org/test-suite/tests/frame-manifest.jsonld
45-
http://json-ld.org/test-suite/tests/fromRdf-manifest.jsonld
46-
http://json-ld.org/test-suite/tests/remote-doc-manifest.jsonld
47-
http://json-ld.org/test-suite/tests/toRdf-manifest.jsonld
40+
%w( https://json-ld.org/test-suite/tests/compact-manifest.jsonld
41+
https://json-ld.org/test-suite/tests/error-manifest.jsonld
42+
https://json-ld.org/test-suite/tests/expand-manifest.jsonld
43+
https://json-ld.org/test-suite/tests/flatten-manifest.jsonld
44+
https://json-ld.org/test-suite/tests/frame-manifest.jsonld
45+
https://json-ld.org/test-suite/tests/fromRdf-manifest.jsonld
46+
https://json-ld.org/test-suite/tests/remote-doc-manifest.jsonld
47+
https://json-ld.org/test-suite/tests/toRdf-manifest.jsonld
4848
).each do |man|
4949
puts "load #{man}"
5050
g.load(man, unique_bnodes: true)

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
2.1.5
1+
2.1.6

example-files/issue-526.jsonld

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"@context": {
3+
"@vocab" : "http://vocab.getty.edu/",
4+
"a" : "http://vocab.getty.edu/aaaaaaaaaat/"
5+
},
6+
"@id" : "http://vocab.getty.edu/aaaaaaaaaat/5001065997",
7+
"@type": "http://vocab.getty.edu/aaaaaaaaaat/datatype"
8+
}

example-files/toRdf-manifest.jsonld

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
{
2-
"@context": "http://json-ld.org/test-suite/context.jsonld",
2+
"@context": "https://json-ld.org/test-suite/context.jsonld",
33
"@id": "",
44
"@type": "jld:Manifest",
55
"rdfs:comment": "JSON-LD to RDF tests generate N-Quads Output",
66
"name": "toRdf",
7-
"baseIri": "http://json-ld.org/test-suite/tests/",
7+
"baseIri": "https://json-ld.org/test-suite/tests/",
88
"sequence": [
99
{
1010
"@type": ["jld:PositiveEvaluationTest", "jld:ToRDFTest"],

json-ld.gemspec

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ Gem::Specification.new do |gem|
1010
gem.license = 'Unlicense'
1111
gem.summary = "JSON-LD reader/writer for Ruby."
1212
gem.description = "JSON::LD parses and serializes JSON-LD into RDF and implements expansion, compaction and framing API interfaces."
13-
gem.rubyforge_project = 'json-ld'
1413

1514
gem.authors = ['Gregg Kellogg']
1615
gem.email = '[email protected]'
@@ -27,7 +26,7 @@ Gem::Specification.new do |gem|
2726

2827
gem.required_ruby_version = '>= 2.2.2'
2928
gem.requirements = []
30-
gem.add_runtime_dependency 'rdf', '~> 2.2'
29+
gem.add_runtime_dependency 'rdf', '~> 2.2', '>= 2.2.8'
3130
gem.add_runtime_dependency 'multi_json', '~> 1.12'
3231
gem.add_development_dependency 'linkeddata', '~> 2.2'
3332
gem.add_development_dependency 'jsonlint', '~> 0.2' unless RUBY_ENGINE == "jruby"

lib/json/ld.rb

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
$:.unshift(File.expand_path("../ld", __FILE__))
44
require 'rdf' # @see http://rubygems.org/gems/rdf
55
require 'multi_json'
6+
require 'set'
67

78
module JSON
89
##
@@ -41,7 +42,7 @@ module LD
4142
RDF.type.to_s => {"@type" => "@id"}
4243
}.freeze
4344

44-
KEYWORDS = %w(
45+
KEYWORDS = Set.new(%w(
4546
@base
4647
@container
4748
@context
@@ -62,7 +63,7 @@ module LD
6263
@value
6364
@version
6465
@vocab
65-
).freeze
66+
)).freeze
6667

6768
# Regexp matching an NCName.
6869
NC_REGEXP = Regexp.new(

lib/json/ld/api.rb

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ def self.expand(input, options = {}, &block)
174174
end
175175

176176
# If, after the algorithm outlined above is run, the resulting element is an JSON object with just a @graph property, element is set to the value of @graph's value.
177-
result = result['@graph'] if result.is_a?(Hash) && result.keys == %w(@graph)
177+
result = result['@graph'] if result.is_a?(Hash) && result.length == 1 && result.key?('@graph')
178178

179179
# Finally, if element is a JSON object, it is wrapped into an array.
180180
result = [result].compact unless result.is_a?(Array)
@@ -277,7 +277,9 @@ def self.flatten(input, context, options = {})
277277
create_node_map(value, graph_maps)
278278

279279
default_graph = graph_maps['@default']
280-
graph_maps.keys.kw_sort.reject {|k| k == '@default'}.each do |graph_name|
280+
graph_maps.keys.kw_sort.each do |graph_name|
281+
next if graph_name == '@default'
282+
281283
graph = graph_maps[graph_name]
282284
entry = default_graph[graph_name] ||= {'@id' => graph_name}
283285
nodes = entry['@graph'] ||= []

lib/json/ld/compact.rb

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ def compact(element, property: nil)
4343
# @null objects are used in framing
4444
return nil if element.has_key?('@null')
4545

46-
if element.keys.any? {|k| %w(@id @value).include?(k)}
46+
if element.key?('@id') || element.key?('@value')
4747
result = context.compact_value(property, element, log_depth: @options[:log_depth])
4848
unless result.is_a?(Hash)
4949
#log_debug("") {"=> scalar result: #{result.inspect}"}
@@ -58,7 +58,7 @@ def compact(element, property: nil)
5858
expanded_value = element[expanded_property]
5959
#log_debug("") {"#{expanded_property}: #{expanded_value.inspect}"}
6060

61-
if %w(@id @type).include?(expanded_property)
61+
if expanded_property == '@id' || expanded_property == '@type'
6262
compacted_value = [expanded_value].flatten.compact.map do |expanded_type|
6363
context.compact_iri(expanded_type, vocab: (expanded_property == '@type'), log_depth: @options[:log_depth])
6464
end
@@ -118,14 +118,14 @@ def compact(element, property: nil)
118118
end
119119

120120
# Otherwise, if expanded property is @index, @value, or @language:
121-
if %w(@index @value @language).include?(expanded_property)
121+
if expanded_property == '@index' || expanded_property == '@value' || expanded_property == '@language'
122122
al = context.compact_iri(expanded_property, vocab: true, quiet: true)
123123
#log_debug(expanded_property) {"#{al} => #{expanded_value.inspect}"}
124124
result[al] = expanded_value
125125
next
126126
end
127127

128-
if expanded_value == []
128+
if expanded_value.empty?
129129
item_active_property =
130130
context.compact_iri(expanded_property,
131131
value: expanded_value,
@@ -181,7 +181,7 @@ def compact(element, property: nil)
181181
end
182182
end
183183

184-
if %w(@language @index @id @type).include?(container)
184+
if container == '@language' || container == '@index' || container == '@id' || container == '@type'
185185
map_object = nest_result[item_active_property] ||= {}
186186
compacted_item = case container
187187
when '@id'
@@ -218,7 +218,7 @@ def compact(element, property: nil)
218218
end
219219

220220
# Re-order result keys
221-
result.keys.kw_sort.inject({}) {|map, kk| map[kk] = result[kk]; map}
221+
result.keys.kw_sort.each_with_object({}) {|kk, memo| memo[kk] = result[kk]}
222222
else
223223
# For other types, the compacted value is the element value
224224
#log_debug("compact") {element.class.to_s}

lib/json/ld/context.rb

Lines changed: 29 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
# frozen_string_literal: true
33
require 'json'
44
require 'bigdecimal'
5+
require 'set'
56

67
module JSON::LD
78
class Context
@@ -112,7 +113,7 @@ def initialize(term,
112113
def container_mapping=(mapping)
113114
mapping = Array(mapping)
114115
if @as_set = mapping.include?('@set')
115-
mapping -= %w(@set)
116+
mapping.delete('@set')
116117
end
117118
@container_mapping = mapping.first
118119
end
@@ -554,7 +555,7 @@ def create_term_definition(local_context, term, defined)
554555
end
555556

556557
# Since keywords cannot be overridden, term must not be a keyword. Otherwise, an invalid value has been detected, which is an error.
557-
if KEYWORDS.include?(term) && !%w(@vocab @language @version).include?(term)
558+
if KEYWORDS.include?(term) && (term != '@vocab' && term != '@language' && term != '@version')
558559
raise JsonLdError::KeywordRedefinition, "term must not be a keyword: #{term.inspect}" if
559560
@options[:validate]
560561
elsif !term_valid?(term) && @options[:validate]
@@ -606,7 +607,7 @@ def create_term_definition(local_context, term, defined)
606607
else
607608
:error
608609
end
609-
unless %w(@id @vocab).include?(type) || type.is_a?(RDF::URI) && type.absolute?
610+
unless (type == '@id' || type == '@vocab') || type.is_a?(RDF::URI) && type.absolute?
610611
raise JsonLdError::InvalidTypeMapping, "unknown mapping for '@type': #{type.inspect} on term #{term.inspect}"
611612
end
612613
#log_debug("") {"type_mapping: #{type.inspect}"}
@@ -615,7 +616,7 @@ def create_term_definition(local_context, term, defined)
615616

616617
if value.has_key?('@reverse')
617618
raise JsonLdError::InvalidReverseProperty, "unexpected key in #{value.inspect} on term #{term.inspect}" if
618-
value.keys.any? {|k| %w(@id @nest).include?(k)}
619+
value.key?('@id') || value.key?('@nest')
619620
raise JsonLdError::InvalidIRIMapping, "expected value of @reverse to be a string: #{value['@reverse'].inspect} on term #{term.inspect}" unless
620621
value['@reverse'].is_a?(String)
621622

@@ -633,7 +634,7 @@ def create_term_definition(local_context, term, defined)
633634
container = value['@container']
634635
raise JsonLdError::InvalidReverseProperty,
635636
"unknown mapping for '@container' to #{container.inspect} on term #{term.inspect}" unless
636-
container.is_a?(String) && ['@set', '@index'].include?(container)
637+
container.is_a?(String) && (container == '@set' || container == '@index')
637638
definition.container_mapping = check_container(container, local_context, defined, term)
638639
end
639640
definition.reverse_property = true
@@ -654,7 +655,7 @@ def create_term_definition(local_context, term, defined)
654655
(simple_term || ((processingMode || 'json-ld-1.0') == 'json-ld-1.0'))
655656
elsif term.include?(':')
656657
# If term is a compact IRI with a prefix that is a key in local context then a dependency has been found. Use this algorithm recursively passing active context, local context, the prefix as term, and defined.
657-
prefix, suffix = term.split(':')
658+
prefix, suffix = term.split(':', 2)
658659
create_term_definition(local_context, prefix, defined) if local_context.has_key?(prefix)
659660

660661
definition.id = if td = term_definitions[prefix]
@@ -791,15 +792,15 @@ def from_vocabulary(graph)
791792
(statements[statement.subject] ||= []) << statement
792793

793794
# Keep track of predicate ranges
794-
if [RDF::RDFS.range, RDF::SCHEMA.rangeIncludes].include?(statement.predicate)
795+
if [RDF::RDFS.range, RDF::SCHEMA.rangeIncludes].include?(statement.predicate)
795796
(ranges[statement.subject] ||= []) << statement.object
796797
end
797798
end
798799

799800
# Add term definitions for each class and property not in vocab, and
800801
# for those properties having an object range
801802
statements.each do |subject, values|
802-
types = values.select {|v| v.predicate == RDF.type}.map(&:object)
803+
types = values.each_with_object([]) { |v, memo| memo << v.object if v.predicate == RDF.type }
803804
is_property = types.any? {|t| t.to_s.include?("Property")}
804805

805806
term = subject.to_s.split(/[\/\#]/).last
@@ -886,7 +887,7 @@ def container(term)
886887
# @param [Term, #to_s] term in unexpanded form
887888
# @return [Boolean]
888889
def as_array?(term)
889-
return true if %w(@graph @list).include?(term)
890+
return true if term == '@graph' || term == '@list'
890891
term = find_definition(term)
891892
term && (term.as_set || term.container_mapping == '@list')
892893
end
@@ -979,12 +980,14 @@ def reverse_term(term)
979980
# IRI or String, if it's a keyword
980981
# @raise [JSON::LD::JsonLdError::InvalidIRIMapping] if the value cannot be expanded
981982
# @see http://json-ld.org/spec/latest/json-ld-api/#iri-expansion
982-
def expand_iri(value, documentRelative: false, vocab: false, local_context: nil, defined: {}, quiet: false, **options)
983+
def expand_iri(value, documentRelative: false, vocab: false, local_context: nil, defined: nil, quiet: false, **options)
983984
return value unless value.is_a?(String)
984985

985986
return value if KEYWORDS.include?(value)
986987
#log_debug("expand_iri") {"value: #{value.inspect}"} unless quiet
987988

989+
defined = defined || {} # if we initialized in the keyword arg we would allocate {} at each invokation, even in the 2 (common) early returns above.
990+
988991
# If local context is not null, it contains a key that equals value, and the value associated with the key that equals value in defined is not true, then invoke the Create Term Definition subalgorithm, passing active context, local context, value as term, and defined. This will ensure that a term definition is created for value in active context during Context Processing.
989992
if local_context && local_context.has_key?(value) && !defined[value]
990993
create_term_definition(local_context, value, defined)
@@ -1003,7 +1006,7 @@ def expand_iri(value, documentRelative: false, vocab: false, local_context: nil,
10031006

10041007
# If prefix is underscore (_) or suffix begins with double-forward-slash (//), return value as it is already an absolute IRI or a blank node identifier.
10051008
return RDF::Node.new(namer.get_sym(suffix)) if prefix == '_'
1006-
return RDF::URI(value) if suffix[0,2] == '//'
1009+
return RDF::URI(value) if suffix.start_with?('//')
10071010

10081011
# If local context is not null, it contains a key that equals prefix, and the value associated with the key that equals prefix in defined is not true, invoke the Create Term Definition algorithm, passing active context, local context, prefix as term, and defined. This will ensure that a term definition is created for prefix in active context during Context Processing.
10091012
if local_context && local_context.has_key?(prefix) && !defined[prefix]
@@ -1138,7 +1141,7 @@ def compact_iri(iri, value: nil, vocab: nil, reverse: false, quiet: false, **opt
11381141
tl_value ||= '@null'
11391142
preferred_values = []
11401143
preferred_values << '@reverse' if tl_value == '@reverse'
1141-
if %w(@id @reverse).include?(tl_value) && value.is_a?(Hash) && value.has_key?('@id')
1144+
if (tl_value == '@id' || tl_value == '@reverse') && value.is_a?(Hash) && value.has_key?('@id')
11421145
t_iri = compact_iri(value['@id'], vocab: true, document_relative: true)
11431146
if (r_td = term_definitions[t_iri]) && r_td.id == value['@id']
11441147
preferred_values.concat(%w(@vocab @id @none))
@@ -1204,6 +1207,8 @@ def compact_iri(iri, value: nil, vocab: nil, reverse: false, quiet: false, **opt
12041207
end
12051208
end
12061209

1210+
RDF_LITERAL_NATIVE_TYPES = Set.new([RDF::XSD.boolean, RDF::XSD.integer, RDF::XSD.double]).freeze
1211+
12071212
##
12081213
# If active property has a type mapping in the active context set to @id or @vocab, a JSON object with a single member @id whose value is the result of using the IRI Expansion algorithm on value is returned.
12091214
#
@@ -1246,7 +1251,7 @@ def expand_value(property, value, useNativeTypes: false, **options)
12461251
when RDF::Literal
12471252
#log_debug("Literal") {"datatype: #{value.datatype.inspect}"}
12481253
res = {}
1249-
if useNativeTypes && [RDF::XSD.boolean, RDF::XSD.integer, RDF::XSD.double].include?(value.datatype)
1254+
if useNativeTypes && RDF_LITERAL_NATIVE_TYPES.include?(value.datatype)
12501255
res['@value'] = value.object
12511256
res['@type'] = uri(coerce(property)) if coerce(property)
12521257
else
@@ -1297,7 +1302,7 @@ def expand_value(property, value, useNativeTypes: false, **options)
12971302
def compact_value(property, value, options = {})
12981303
#log_debug("compact_value") {"property: #{property.inspect}, value: #{value.inspect}"}
12991304

1300-
num_members = value.keys.length
1305+
num_members = value.length
13011306

13021307
num_members -= 1 if index?(value) && container(property) == '@index'
13031308
if num_members > 2
@@ -1407,7 +1412,7 @@ def dup
14071412
def coerce(property)
14081413
# Map property, if it's not an RDF::Value
14091414
# @type is always is an IRI
1410-
return '@id' if [RDF.type, '@type'].include?(property)
1415+
return '@id' if property == RDF.type || property == '@type'
14111416
term_definitions[property] && term_definitions[property].type_mapping
14121417
end
14131418

@@ -1573,9 +1578,10 @@ def remove_base(iri)
15731578
#
15741579
# @return [Array<RDF::URI>]
15751580
def mappings
1576-
term_definitions.inject({}) do |memo, (t,td)|
1577-
memo[t] = td ? td.id : nil
1578-
memo
1581+
{}.tap do |memo|
1582+
term_definitions.each_pair do |t,td|
1583+
memo[t] = td ? td.id : nil
1584+
end
15791585
end
15801586
end
15811587

@@ -1595,9 +1601,10 @@ def mapping(term)
15951601
# @return [Array<String>]
15961602
# @deprecated
15971603
def languages
1598-
term_definitions.inject({}) do |memo, (t,td)|
1599-
memo[t] = td.language_mapping
1600-
memo
1604+
{}.tap do |memo|
1605+
term_definitions.each_pair do |t,td|
1606+
memo[t] = td.language_mapping
1607+
end
16011608
end
16021609
end
16031610

@@ -1610,7 +1617,7 @@ def check_container(container, local_context, defined, term)
16101617
end
16111618

16121619
val = Array(container)
1613-
val -= %w(@set) if has_set = val.include?('@set')
1620+
val.delete('@set') if has_set = val.include?('@set')
16141621

16151622
raise JsonLdError::InvalidContainerMapping,
16161623
"'@container' has more than one value other than @set" if val.length > 1

0 commit comments

Comments
 (0)