Module: JSON::LD::Expand
Overview
Expand module, used as part of API
Instance Method Summary collapse
-
#expand(input, active_property, context, options = {}) ⇒ Array, Hash
Expand an Array or Object given an active context and performing local context expansion.
Methods included from Utils
#blank_node?, #list?, #subject?, #subject_reference?, #value?
Instance Method Details
#expand(input, active_property, context, options = {}) ⇒ Array, Hash
Expand an Array or Object given an active context and performing local context expansion.
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 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 181 182 183 184 185 186 187 188 189 |
# File 'lib/json/ld/expand.rb', line 15 def (input, active_property, context, = {}) debug("expand") {"input: #{input.inspect}, active_property: #{active_property.inspect}, context: #{context.inspect}"} result = case input when Array # If element is an array, process each item in element recursively using this algorithm, # passing copies of the active context and active property. If the expanded entry is null, drop it. depth do is_list = context.container(active_property) == '@list' value = input.map do |v| # If active property has a @container set to @list, and item is an array, # or the result of expanding any item is an object containing an @list property, # throw an exception as lists of lists are not allowed. raise ProcessingError::ListOfLists, "A list may not contain another list" if v.is_a?(Array) && is_list (v, active_property, context, ) end.flatten.compact if is_list && value.any? {|v| v.is_a?(Hash) && v.has_key?('@list')} raise ProcessingError::ListOfLists, "A list may not contain another list" end value end when Hash # Otherwise, if element is an object # If element has a @context property, update the active context according to the steps outlined # in Context Processing and remove the @context property. if input.has_key?('@context') context = context.parse(input.delete('@context')) debug("expand") {"evaluation context: #{context.inspect}"} end depth do output_object = Hash.ordered # Then, proceed and process each property and value in element as follows: input.each do |key, value| # Remove property from element expand property according to the steps outlined in IRI Expansion property = context.(key, :position => :predicate, :quiet => true) # Set active property to the original un-expanded property if property if not a keyword active_property = key unless key[0,1] == '@' debug("expand property") {"#{active_property.inspect}, expanded: #{property}, value: #{value.inspect}"} # If property does not expand to a keyword or absolute IRI, remove property from element # and continue to the next property from element if property.nil? debug(" => ") {"skip nil key"} next end property = property.to_s = case property when '@id' # If the property is @id the value must be a string. Expand the value according to IRI Expansion. context.(value, :position => :subject, :quiet => true).to_s when '@type' # Otherwise, if the property is @type the value must be a string, an array of strings # or an empty JSON Object. # Expand value or each of it's entries according to IRI Expansion debug("@type") {"value: #{value.inspect}"} case value when Array depth do [value].flatten.map do |v| v = v['@id'] if subject_reference?(v) raise ProcessingError, "Object value must be a string or a subject reference: #{v.inspect}" unless v.is_a?(String) context.(v, .merge(:position => :property, :quiet => true)).to_s end end when Hash # Empty object used for @type wildcard or subject reference if subject_reference?(value) context.(value['@id'], .merge(:position => :property, :quiet => true)).to_s elsif !value.empty? raise ProcessingError, "Object value of @type must be empty or a subject reference: #{value.inspect}" else value end else context.(value, .merge(:position => :property, :quiet => true)).to_s end when '@value', '@language' # Otherwise, if the property is @value or @language the value must not be a JSON object or an array. raise ProcessingError::Lossy, "Value of #{property} must be a string, was #{value.inspect}" if value.is_a?(Hash) || value.is_a?(Array) value when '@list', '@set', '@graph' # Otherwise, if the property is @list, @set, or @graph, expand value recursively # using this algorithm, passing copies of the active context and active property. # If the expanded value is not an array, convert it to an array. value = [value] unless value.is_a?(Array) value = depth { (value, active_property, context, ) } # If property is @list, and any expanded value # is an object containing an @list property, throw an exception, as lists of lists are not supported if property == '@list' && value.any? {|v| v.is_a?(Hash) && v.has_key?('@list')} raise ProcessingError::ListOfLists, "A list may not contain another list" end value else # Otherwise, expand value recursively using this algorithm, passing copies of the active context and active property. depth { (value, active_property, context, ) } end # moved from step 2.2.3 # If expanded value is null and property is not @value, continue with the next property # from element. if property != '@value' && .nil? debug(" => skip nil value") next end # If the expanded value is not null and property is not a keyword # and the active property has a @container set to @list, # convert value to an object with an @list property whose value is set to value # (unless value is already in that form) if && property[0,1] != '@' && context.container(active_property) == '@list' && (!.is_a?(Hash) || !.fetch('@list', false)) debug(" => ") { "convert #{.inspect} to list"} = {'@list' => [].flatten} end # Convert value to array form unless value is null or property is @id, @type, @value, or @language. if !%(@id @language @type @value).include?(property) && !.is_a?(Array) debug(" => make #{.inspect} an array") = [] end if output_object.has_key?(property) # If element already contains a property property, append value to the existing value. output_object[property] += else # Otherwise, create a property property with value as value. output_object[property] = end debug {" => #{.inspect}"} end debug("output object") {output_object.inspect} # If the processed element has an @value property if output_object.has_key?('@value') output_object.delete('@language') if output_object['@language'].to_s.empty? output_object.delete('@type') if output_object['@type'].to_s.empty? if output_object.keys.length > 2 || (%w(@language @type) - output_object.keys).empty? 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 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. output_object['@type'] = [output_object['@type']] end # If element has an @set or @list property, it must be the only property. Set element to the value of @set; # leave @list untouched. if !(%w(@set @list) & output_object.keys).empty? raise ProcessingError, "element must have only @set, @list or @graph" if output_object.keys.length > 1 output_object = output_object.values.first unless output_object.has_key?('@list') end # If element has just a @language property, set element to null. output_object unless output_object.is_a?(Hash) && output_object.keys == %w(@language) end else # Otherwise, unless the value is a number, expand the value according to the Value Expansion rules, passing active property. context.(active_property, input, :position => :object, :depth => @depth) unless input.nil? end debug {" => #{result.inspect}"} result end |