Permalink
Browse files

Expand strings and native types to @value form. (json-ld/json-ld.org#115

 resolution).
  • Loading branch information...
1 parent 04bbd60 commit 9e6fb7e06789eda89fc796d243619fe2d38537c9 @gkellogg committed Jun 12, 2012
View
@@ -129,15 +129,10 @@ def self.compact(input, context, callback = nil, options = {})
# 1) Perform the Expansion Algorithm on the JSON-LD input.
# This removes any existing context to allow the given context to be cleanly applied.
- API.new(input, nil, options) do
- expanded = expand(value, nil, self.context)
- debug(".compact") {"expanded input: #{value.to_json(JSON_STATE)}"}
-
- # x) If no context provided, use context from input document
- context ||= value.fetch('@context', nil)
- end
+ expanded = API.expand(input, nil, nil, options)
API.new(expanded, context, options) do
+ debug(".compact") {"expanded input: #{expanded.to_json(JSON_STATE)}"}
result = compact(value, nil)
# xxx) Add the given context to the output
@@ -636,7 +636,7 @@ def expand_value(property, value, options = {})
else
if options[:native]
# Unless there's coercion, to not modify representation
- value.is_a?(RDF::Literal::Boolean) ? value.object : value
+ {"@value" => (value.is_a?(RDF::Literal::Boolean) ? value.object : value)}
else
{"@value" => value.to_s, "@type" => RDF::XSD.boolean.to_s}
end
@@ -648,7 +648,7 @@ def expand_value(property, value, options = {})
when RDF::XSD.integer.to_s, nil
# Unless there's coercion, to not modify representation
if options[:native]
- value.is_a?(RDF::Literal::Integer) ? value.object : value
+ {"@value" => value.is_a?(RDF::Literal::Integer) ? value.object : value}
else
{"@value" => value.to_s, "@type" => RDF::XSD.integer.to_s}
end
@@ -667,7 +667,7 @@ def expand_value(property, value, options = {})
when nil
if options[:native]
# Unless there's coercion, to not modify representation
- value.is_a?(RDF::Literal::Double) ? value.object : value
+ {"@value" => value.is_a?(RDF::Literal::Double) ? value.object : value}
else
{"@value" => RDF::Literal::Double.new(value, :canonicalize => true).to_s, "@type" => RDF::XSD.double.to_s}
end
@@ -696,7 +696,7 @@ def expand_value(property, value, options = {})
{'@id' => expand_iri(value, :position => :object).to_s}
when nil
debug("expand value") {"lang(prop): #{language(property).inspect}, def: #{default_language.inspect}"}
- language(property) ? {"@value" => value.to_s, "@language" => language(property)} : value.to_s
+ language(property) ? {"@value" => value.to_s, "@language" => language(property)} : {"@value" => value.to_s}
else
res = Hash.ordered
res['@value'] = value.to_s
@@ -722,18 +722,19 @@ def expand_value(property, value, options = {})
# @return [Hash] Object representation of value
# @raise [ProcessingError] if the iri cannot be expanded
# @see http://json-ld.org/spec/latest/json-ld-api/#value-compaction
+ # FIXME: revisit the specification version of this.
def compact_value(property, value, options = {})
raise ProcessingError::Lossy, "attempt to compact a non-object value: #{value.inspect}" unless value.is_a?(Hash)
depth(options) do
debug("compact_value") {"property: #{property.inspect}, value: #{value.inspect}, coerce: #{coerce(property).inspect}"}
result = case
- when %w(boolean integer double).any? {|t| expand_iri(value['@type'], :position => :datatype) == RDF::XSD[t]}
- # Compact native type
- debug {" (native)"}
- l = RDF::Literal(value['@value'], :datatype => expand_iri(value['@type'], :position => :datatype))
- l.canonicalize.object
+ #when %w(boolean integer double).any? {|t| expand_iri(value['@type'], :position => :datatype) == RDF::XSD[t]}
+ # # Compact native type
+ # debug {" (native)"}
+ # l = RDF::Literal(value['@value'], :datatype => expand_iri(value['@type'], :position => :datatype))
+ # l.canonicalize.object
when coerce(property) == '@id' && value.has_key?('@id')
# Compact an @id coercion
debug {" (@id & coerce)"}
@@ -751,10 +752,18 @@ def compact_value(property, value, options = {})
# Compact language
debug {" (@language) == #{language(property).inspect}"}
value['@value']
+ when value['@value'] && !value['@value'].is_a?(String)
+ # Compact simple literal to string
+ debug {" (@value not string)"}
+ value['@value']
when value['@value'] && !value['@language'] && !value['@type'] && !coerce(property) && !default_language
# Compact simple literal to string
debug {" (@value && !@language && !@type && !coerce && !language)"}
value['@value']
+ when value['@value'] && !value['@language'] && !value['@type'] && !coerce(property) && !language(property)
+ # Compact simple literal to string
+ debug {" (@value && !@language && !@type && !coerce && language(property).false)"}
+ value['@value']
when value['@type']
# Compact datatype
debug {" (@type)"}
@@ -834,51 +843,47 @@ def bnode(value = nil)
# @param [Object] value
# @return [Integer]
def term_rank(term, value)
- debug("term rank") { "term: #{term.inspect}, value: #{value.inspect}"}
- debug("term rank") { "coerce: #{coerce(term).inspect}, lang: #{languages.fetch(term, nil).inspect}"}
-
- # A term without @language or @type can be used with rank 1 for any value
default_term = !coerce(term) && !languages.has_key?(term)
- debug("term rank") { "default_term: #{default_term.inspect}"}
-
- rank = case value
- when TrueClass, FalseClass
- coerce(term) == RDF::XSD.boolean.to_s ? 3 : (default_term ? 2 : 1)
- when Integer
- coerce(term) == RDF::XSD.integer.to_s ? 3 : (default_term ? 2 : 1)
- when Float
- coerce(term) == RDF::XSD.double.to_s ? 3 : (default_term ? 2 : 1)
- when nil
- # A value of null probably means it's an @id
+ debug("term rank") {
+ "term: #{term.inspect}, " +
+ "value: #{value.inspect}, " +
+ "coerce: #{coerce(term).inspect}, " +
+ "lang: #{languages.fetch(term, nil).inspect}/#{language(term).inspect} " +
+ "default_term: #{default_term.inspect}"
+ }
+
+ # value is null
+ rank = if value.nil?
+ debug("term rank") { "null value: 3"}
3
- when String
- # When compacting a string, the string has no language, so the term can be used if the term has @language null or it is a default term and there is no default language
- debug("term rank") {"string: lang: #{languages.fetch(term, false).inspect}, def: #{default_language.inspect}"}
- !languages.fetch(term, true) || (default_term && !default_language) ? 3 : 0
- when Hash
- if list?(value)
- if value['@list'].empty?
- # If the @list property is an empty array, if term has @container set to @list, term rank is 1, otherwise 0.
- container(term) == '@list' ? 1 : 0
- else
- # Otherwise, return the sum of the term ranks for every entry in the list.
- depth {value['@list'].inject(0) {|memo, v| memo + term_rank(term, v)}}
- end
- elsif subject?(value) || subject_reference?(value)
- coerce(term) == '@id' ? 3 : (default_term ? 1 : 0)
- elsif val_type = value.fetch('@type', nil)
+ elsif list?(value)
+ if value['@list'].empty?
+ # If the @list property is an empty array, if term has @container set to @list, term rank is 1, otherwise 0.
+ container(term) == '@list' ? 1 : 0
+ else
+ # Otherwise, return the sum of the term ranks for every entry in the list.
+ depth {value['@list'].inject(0) {|memo, v| memo + term_rank(term, v)}}
+ end
+ elsif value?(value)
+ val_type = value.fetch('@type', nil)
+ val_lang = value.fetch('@language', nil)
+ debug("term rank") {"@val_type: #{val_type.inspect}, val_lang: #{val_lang.inspect}"}
+ if val_type
coerce(term) == val_type ? 3 : (default_term ? 1 : 0)
- elsif val_lang = value.fetch('@language', nil)
- val_lang == language(term) ? 3 : (default_term ? 1 : 0)
+ elsif !value['@value'].is_a?(String)
+ default_term ? 2 : 1
+ elsif val_lang.nil?
+ debug("val_lang.nil") {"#{language(term).inspect} && #{coerce(term).inspect}"}
+ !language(term) && !coerce(term) ? 3 : 0
else
- default_term ? 3 : 0
+ val_lang == language(term) ? 3 : (default_term ? 1 : 0)
end
- else
- raise ProcessingError, "Unexpected value for term_rank: #{value.inspect}"
+ else # subject definition/reference
+ coerce(term) == '@id' ? 3 : (default_term ? 1 : 0)
end
- # If term has @container @set, and rank is not 0, increase rank by 1.
- rank > 0 && container(term) == '@set' ? rank + 1 : rank
+ debug(" =>") {rank.inspect}
+ rank
end
end
end
@@ -160,10 +160,8 @@ def expand(input, active_property, context, options = {})
raise ProcessingError, "element must not have more than one other property, which can either be @language or @type with a string value." unless value.is_a?(String)
end
- # if @value is the only property or the value of @value equals null, replace element with the value of @value.
- if output_object['@value'].nil? || output_object.keys.length == 1
- return output_object['@value']
- end
+ # if the value of @value equals null, replace element with the value of null.
+ return nil if output_object['@value'].nil?
elsif !output_object.fetch('@type', []).is_a?(Array)
# Otherwise, if element has an @type property and it's value is not in the form of an array,
# convert it to an array.
@@ -39,6 +39,15 @@ def list?(value)
value.is_a?(Hash) && value.keys == %w(@list)
end
+ ##
+ # Is value literal?
+ #
+ # @param [Object] value
+ # @return [Boolean]
+ def value?(value)
+ value.is_a?(Hash) && value.has_key?('@value')
+ end
+
private
# Add debug event to debug array, if specified
View
@@ -7,18 +7,23 @@
context "callbacks" do
describe ".compact" do
+ it "needs to be implemented"
end
describe ".expand" do
+ it "needs to be implemented"
end
describe ".frame" do
+ it "needs to be implemented"
end
describe ".fromRDF" do
+ it "needs to be implemented"
end
describe ".toRDF" do
+ it "needs to be implemented"
end
end
View
@@ -31,6 +31,30 @@
"b" => {"@id" => "http://example.com/c"}
}
},
+ "integer value" => {
+ :input => {
+ "@id" => "http://example.com/a",
+ "http://example.com/b" => {"@value" => 1}
+ },
+ :context => {"b" => "http://example.com/b"},
+ :output => {
+ "@context" => {"b" => "http://example.com/b"},
+ "@id" => "http://example.com/a",
+ "b" => 1
+ }
+ },
+ "boolean value" => {
+ :input => {
+ "@id" => "http://example.com/a",
+ "http://example.com/b" => {"@value" => true}
+ },
+ :context => {"b" => "http://example.com/b"},
+ :output => {
+ "@context" => {"b" => "http://example.com/b"},
+ "@id" => "http://example.com/a",
+ "b" => true
+ }
+ },
"@id" => {
:input => {"@id" => "http://example.org/test#example"},
:context => {},
@@ -74,6 +98,24 @@
"b" => ["c", "d"]
}
},
+ "@list coercion (integer)" => {
+ :input => {
+ "http://example.com/term" => [
+ {"@list" => [1]},
+ ]
+ },
+ :context => {
+ "term4" => {"@id" => "http://example.com/term", "@container" => "@list"},
+ "@language" => "de"
+ },
+ :output => {
+ "@context" => {
+ "term4" => {"@id" => "http://example.com/term", "@container" => "@list"},
+ "@language" => "de"
+ },
+ "term4" => [1],
+ }
+ },
"@set coercion" => {
:input => {
"http://example.com/b" => {"@set" => ["c"]}
@@ -128,6 +170,25 @@
"@type" => "#{RDF::RDFS.Resource}"
},
},
+ "default language" => {
+ :input => {
+ "http://example.com/term" => [
+ "v5",
+ {"@value" => "plain literal"}
+ ]
+ },
+ :context => {
+ "term5" => {"@id" => "http://example.com/term", "@language" => nil},
+ "@language" => "de"
+ },
+ :output => {
+ "@context" => {
+ "term5" => {"@id" => "http://example.com/term", "@language" => nil},
+ "@language" => "de"
+ },
+ "term5" => [ "v5", "plain literal" ]
+ }
+ },
}.each_pair do |title, params|
it title do
jld = JSON::LD::API.compact(params[:input], params[:context], nil, :debug => @debug)
@@ -201,22 +262,22 @@
context "term selection" do
{
- "Uses term with nil language when two terms conflict on language" => {
- :input => [{
- "http://example.com/term" => {"@value" => "v1", "@language" => nil}
- }],
- :context => {
- "term5" => {"@id" => "http://example.com/term","@language" => nil},
- "@language" => "de"
- },
- :output => {
- "@context" => {
- "term5" => {"@id" => "http://example.com/term","@language" => nil},
- "@language" => "de"
- },
- "term5" => "v1",
- }
- },
+ #"Uses term with nil language when two terms conflict on language" => {
+ # :input => [{
+ # "http://example.com/term" => {"@value" => "v1", "@language" => nil}
+ # }],
+ # :context => {
+ # "term5" => {"@id" => "http://example.com/term","@language" => nil},
+ # "@language" => "de"
+ # },
+ # :output => {
+ # "@context" => {
+ # "term5" => {"@id" => "http://example.com/term","@language" => nil},
+ # "@language" => "de"
+ # },
+ # "term5" => "v1",
+ # }
+ #},
"Uses subject alias" => {
:input => [{
"@id" => "http://example.com/id1"
Oops, something went wrong.

0 comments on commit 9e6fb7e

Please sign in to comment.