Skip to content

Commit

Permalink
Finish 2.1.6
Browse files Browse the repository at this point in the history
  • Loading branch information
gkellogg committed Sep 27, 2017
2 parents 7332ad6 + 7515b7d commit 6e8a32d
Show file tree
Hide file tree
Showing 21 changed files with 208 additions and 135 deletions.
1 change: 1 addition & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ group :development, :test do
gem 'coveralls', require: false, platform: :mri
gem 'psych', platforms: [:mri, :rbx]
gem 'benchmark-ips'
gem 'rake'
end

group :debug do
Expand Down
16 changes: 8 additions & 8 deletions Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,14 @@ file "etc/manifests.nt" do
require 'json/ld'
require 'rdf/ntriples'
graph = RDF::Graph.new do |g|
%w( http://json-ld.org/test-suite/tests/compact-manifest.jsonld
http://json-ld.org/test-suite/tests/error-manifest.jsonld
http://json-ld.org/test-suite/tests/expand-manifest.jsonld
http://json-ld.org/test-suite/tests/flatten-manifest.jsonld
http://json-ld.org/test-suite/tests/frame-manifest.jsonld
http://json-ld.org/test-suite/tests/fromRdf-manifest.jsonld
http://json-ld.org/test-suite/tests/remote-doc-manifest.jsonld
http://json-ld.org/test-suite/tests/toRdf-manifest.jsonld
%w( https://json-ld.org/test-suite/tests/compact-manifest.jsonld
https://json-ld.org/test-suite/tests/error-manifest.jsonld
https://json-ld.org/test-suite/tests/expand-manifest.jsonld
https://json-ld.org/test-suite/tests/flatten-manifest.jsonld
https://json-ld.org/test-suite/tests/frame-manifest.jsonld
https://json-ld.org/test-suite/tests/fromRdf-manifest.jsonld
https://json-ld.org/test-suite/tests/remote-doc-manifest.jsonld
https://json-ld.org/test-suite/tests/toRdf-manifest.jsonld
).each do |man|
puts "load #{man}"
g.load(man, unique_bnodes: true)
Expand Down
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
2.1.5
2.1.6
8 changes: 8 additions & 0 deletions example-files/issue-526.jsonld
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"@context": {
"@vocab" : "http://vocab.getty.edu/",
"a" : "http://vocab.getty.edu/aaaaaaaaaat/"
},
"@id" : "http://vocab.getty.edu/aaaaaaaaaat/5001065997",
"@type": "http://vocab.getty.edu/aaaaaaaaaat/datatype"
}
4 changes: 2 additions & 2 deletions example-files/toRdf-manifest.jsonld
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
{
"@context": "http://json-ld.org/test-suite/context.jsonld",
"@context": "https://json-ld.org/test-suite/context.jsonld",
"@id": "",
"@type": "jld:Manifest",
"rdfs:comment": "JSON-LD to RDF tests generate N-Quads Output",
"name": "toRdf",
"baseIri": "http://json-ld.org/test-suite/tests/",
"baseIri": "https://json-ld.org/test-suite/tests/",
"sequence": [
{
"@type": ["jld:PositiveEvaluationTest", "jld:ToRDFTest"],
Expand Down
3 changes: 1 addition & 2 deletions json-ld.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ Gem::Specification.new do |gem|
gem.license = 'Unlicense'
gem.summary = "JSON-LD reader/writer for Ruby."
gem.description = "JSON::LD parses and serializes JSON-LD into RDF and implements expansion, compaction and framing API interfaces."
gem.rubyforge_project = 'json-ld'

gem.authors = ['Gregg Kellogg']
gem.email = 'public-linked-json@w3.org'
Expand All @@ -27,7 +26,7 @@ Gem::Specification.new do |gem|

gem.required_ruby_version = '>= 2.2.2'
gem.requirements = []
gem.add_runtime_dependency 'rdf', '~> 2.2'
gem.add_runtime_dependency 'rdf', '~> 2.2', '>= 2.2.8'
gem.add_runtime_dependency 'multi_json', '~> 1.12'
gem.add_development_dependency 'linkeddata', '~> 2.2'
gem.add_development_dependency 'jsonlint', '~> 0.2' unless RUBY_ENGINE == "jruby"
Expand Down
5 changes: 3 additions & 2 deletions lib/json/ld.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
$:.unshift(File.expand_path("../ld", __FILE__))
require 'rdf' # @see http://rubygems.org/gems/rdf
require 'multi_json'
require 'set'

module JSON
##
Expand Down Expand Up @@ -41,7 +42,7 @@ module LD
RDF.type.to_s => {"@type" => "@id"}
}.freeze

KEYWORDS = %w(
KEYWORDS = Set.new(%w(
@base
@container
@context
Expand All @@ -62,7 +63,7 @@ module LD
@value
@version
@vocab
).freeze
)).freeze

# Regexp matching an NCName.
NC_REGEXP = Regexp.new(
Expand Down
6 changes: 4 additions & 2 deletions lib/json/ld/api.rb
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ def self.expand(input, options = {}, &block)
end

# 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.
result = result['@graph'] if result.is_a?(Hash) && result.keys == %w(@graph)
result = result['@graph'] if result.is_a?(Hash) && result.length == 1 && result.key?('@graph')

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

default_graph = graph_maps['@default']
graph_maps.keys.kw_sort.reject {|k| k == '@default'}.each do |graph_name|
graph_maps.keys.kw_sort.each do |graph_name|
next if graph_name == '@default'

graph = graph_maps[graph_name]
entry = default_graph[graph_name] ||= {'@id' => graph_name}
nodes = entry['@graph'] ||= []
Expand Down
12 changes: 6 additions & 6 deletions lib/json/ld/compact.rb
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ def compact(element, property: nil)
# @null objects are used in framing
return nil if element.has_key?('@null')

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

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

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

if expanded_value == []
if expanded_value.empty?
item_active_property =
context.compact_iri(expanded_property,
value: expanded_value,
Expand Down Expand Up @@ -181,7 +181,7 @@ def compact(element, property: nil)
end
end

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

# Re-order result keys
result.keys.kw_sort.inject({}) {|map, kk| map[kk] = result[kk]; map}
result.keys.kw_sort.each_with_object({}) {|kk, memo| memo[kk] = result[kk]}
else
# For other types, the compacted value is the element value
#log_debug("compact") {element.class.to_s}
Expand Down
51 changes: 29 additions & 22 deletions lib/json/ld/context.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
# frozen_string_literal: true
require 'json'
require 'bigdecimal'
require 'set'

module JSON::LD
class Context
Expand Down Expand Up @@ -112,7 +113,7 @@ def initialize(term,
def container_mapping=(mapping)
mapping = Array(mapping)
if @as_set = mapping.include?('@set')
mapping -= %w(@set)
mapping.delete('@set')
end
@container_mapping = mapping.first
end
Expand Down Expand Up @@ -554,7 +555,7 @@ def create_term_definition(local_context, term, defined)
end

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

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

Expand All @@ -633,7 +634,7 @@ def create_term_definition(local_context, term, defined)
container = value['@container']
raise JsonLdError::InvalidReverseProperty,
"unknown mapping for '@container' to #{container.inspect} on term #{term.inspect}" unless
container.is_a?(String) && ['@set', '@index'].include?(container)
container.is_a?(String) && (container == '@set' || container == '@index')
definition.container_mapping = check_container(container, local_context, defined, term)
end
definition.reverse_property = true
Expand All @@ -654,7 +655,7 @@ def create_term_definition(local_context, term, defined)
(simple_term || ((processingMode || 'json-ld-1.0') == 'json-ld-1.0'))
elsif term.include?(':')
# 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.
prefix, suffix = term.split(':')
prefix, suffix = term.split(':', 2)
create_term_definition(local_context, prefix, defined) if local_context.has_key?(prefix)

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

# Keep track of predicate ranges
if [RDF::RDFS.range, RDF::SCHEMA.rangeIncludes].include?(statement.predicate)
if [RDF::RDFS.range, RDF::SCHEMA.rangeIncludes].include?(statement.predicate)
(ranges[statement.subject] ||= []) << statement.object
end
end

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

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

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

defined = defined || {} # if we initialized in the keyword arg we would allocate {} at each invokation, even in the 2 (common) early returns above.

# 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.
if local_context && local_context.has_key?(value) && !defined[value]
create_term_definition(local_context, value, defined)
Expand All @@ -1003,7 +1006,7 @@ def expand_iri(value, documentRelative: false, vocab: false, local_context: nil,

# 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.
return RDF::Node.new(namer.get_sym(suffix)) if prefix == '_'
return RDF::URI(value) if suffix[0,2] == '//'
return RDF::URI(value) if suffix.start_with?('//')

# 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.
if local_context && local_context.has_key?(prefix) && !defined[prefix]
Expand Down Expand Up @@ -1138,7 +1141,7 @@ def compact_iri(iri, value: nil, vocab: nil, reverse: false, quiet: false, **opt
tl_value ||= '@null'
preferred_values = []
preferred_values << '@reverse' if tl_value == '@reverse'
if %w(@id @reverse).include?(tl_value) && value.is_a?(Hash) && value.has_key?('@id')
if (tl_value == '@id' || tl_value == '@reverse') && value.is_a?(Hash) && value.has_key?('@id')
t_iri = compact_iri(value['@id'], vocab: true, document_relative: true)
if (r_td = term_definitions[t_iri]) && r_td.id == value['@id']
preferred_values.concat(%w(@vocab @id @none))
Expand Down Expand Up @@ -1204,6 +1207,8 @@ def compact_iri(iri, value: nil, vocab: nil, reverse: false, quiet: false, **opt
end
end

RDF_LITERAL_NATIVE_TYPES = Set.new([RDF::XSD.boolean, RDF::XSD.integer, RDF::XSD.double]).freeze

##
# 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.
#
Expand Down Expand Up @@ -1246,7 +1251,7 @@ def expand_value(property, value, useNativeTypes: false, **options)
when RDF::Literal
#log_debug("Literal") {"datatype: #{value.datatype.inspect}"}
res = {}
if useNativeTypes && [RDF::XSD.boolean, RDF::XSD.integer, RDF::XSD.double].include?(value.datatype)
if useNativeTypes && RDF_LITERAL_NATIVE_TYPES.include?(value.datatype)
res['@value'] = value.object
res['@type'] = uri(coerce(property)) if coerce(property)
else
Expand Down Expand Up @@ -1297,7 +1302,7 @@ def expand_value(property, value, useNativeTypes: false, **options)
def compact_value(property, value, options = {})
#log_debug("compact_value") {"property: #{property.inspect}, value: #{value.inspect}"}

num_members = value.keys.length
num_members = value.length

num_members -= 1 if index?(value) && container(property) == '@index'
if num_members > 2
Expand Down Expand Up @@ -1407,7 +1412,7 @@ def dup
def coerce(property)
# Map property, if it's not an RDF::Value
# @type is always is an IRI
return '@id' if [RDF.type, '@type'].include?(property)
return '@id' if property == RDF.type || property == '@type'
term_definitions[property] && term_definitions[property].type_mapping
end

Expand Down Expand Up @@ -1573,9 +1578,10 @@ def remove_base(iri)
#
# @return [Array<RDF::URI>]
def mappings
term_definitions.inject({}) do |memo, (t,td)|
memo[t] = td ? td.id : nil
memo
{}.tap do |memo|
term_definitions.each_pair do |t,td|
memo[t] = td ? td.id : nil
end
end
end

Expand All @@ -1595,9 +1601,10 @@ def mapping(term)
# @return [Array<String>]
# @deprecated
def languages
term_definitions.inject({}) do |memo, (t,td)|
memo[t] = td.language_mapping
memo
{}.tap do |memo|
term_definitions.each_pair do |t,td|
memo[t] = td.language_mapping
end
end
end

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

val = Array(container)
val -= %w(@set) if has_set = val.include?('@set')
val.delete('@set') if has_set = val.include?('@set')

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

0 comments on commit 6e8a32d

Please sign in to comment.