%-
def extract_attributes(schema, properties)
attributes = []
_, properties = schema.dereference(properties)
properties.keys.sort.each do |key|
# found a reference to another element:
_, value = schema.dereference(properties[key])
# include top level reference to nested things, when top level is nullable
if value.has_key?('type') && value['type'].include?('null') && (value.has_key?('items') || value.has_key?('properties'))
attributes << build_attribute(schema, key, value)
end
if value.has_key?('anyOf')
descriptions = []
examples = []
anyof = value['anyOf']
anyof.each do |ref|
_, nested_field = schema.dereference(ref)
descriptions << nested_field['description'] if nested_field['description']
examples << nested_field['example'] if nested_field['example']
end
# avoid repetition :}
description = if descriptions.size > 1
descriptions.first.gsub!(/ of (this )?.*/, "")
descriptions[1..-1].map { |d| d.gsub!(/unique /, "") }
[descriptions[0...-1].join(", "), descriptions.last].join(" or ")
else
description = descriptions.last
end
example = [*examples].map { |e| "`#{e.to_json}`" }.join(" or ")
attributes << [key, "string", description, example]
# found a nested object
elsif value['properties']
nested = extract_attributes(schema, value['properties'])
nested.each do |attribute|
attribute[0] = "#{key}:#{attribute[0]}"
end
attributes.concat(nested)
elsif array_with_nested_objects?(value['items'])
if value['items']['properties']
nested = extract_attributes(schema, value['items']['properties'])
nested.each do |attribute|
attribute[0] = "#{key}/#{attribute[0]}"
end
attributes.concat(nested)
end
if value['items']['oneOf']
value['items']['oneOf'].each_with_index do |oneof, index|
ref, oneof_definition = schema.dereference(oneof)
oneof_name = ref ? ref.split('/').last : index
nested = extract_attributes(schema, oneof_definition['properties'])
nested.each do |attribute|
attribute[0] = "#{key}/[#{oneof_name.upcase}].#{attribute[0]}"
end
attributes.concat(nested)
end
end
# just a regular attribute
else
attributes << build_attribute(schema, key, value)
end
end
attributes.map! { |key, type, description, example|
if example.nil? && Prmd::DefaultExamples.key?(type)
example = "`%s`" % Prmd::DefaultExamples[type].to_json
end
[key, type, description, example]
}
return attributes
end
def extract_schemata_refs(schema, properties)
ret = []
properties.each do |_, value|
ref, value = schema.dereference(value)
if value['properties']
refs = extract_schemata_refs(schema, value['properties'])
elsif value['items'] && value['items']['properties']
refs = extract_schemata_refs(schema, value['items']['properties'])
else
refs = [ref]
end
if value.has_key?('type') && value['type'].include?('null') && (value.has_key?('items') || value.has_key?('properties'))
# A nullable object usually isn't a reference to another schema. It's
# either not a reference at all, or it's a reference within the same
# schema. Instead, the definition of the nullable object might contain
# references to specific properties.
#
# If all properties refer to the same schema, we'll use that as the
# reference. This might even overwrite an actual, intra-schema
# reference.
l = refs.map {|v| v && v.split("/")[0..2]}
if l.uniq.size == 1 && l[0] != nil
ref = l[0].join("/")
end
ret << ref
end
ret.concat(refs)
end
ret
end
def build_attribute(schema, key, value)
description = value['description'] || ""
if value['default']
description += "
**default:** `#{value['default'].to_json}`"
end
if value['minimum'] || value['maximum']
description += "
**Range:** `"
if value['minimum']
comparator = value['exclusiveMinimum'] ? "<" : "<="
description += "#{value['minimum'].to_json} #{comparator} "
end
description += "value"
if value['maximum']
comparator = value['exclusiveMaximum'] ? "<" : "<="
description += " #{comparator} #{value['maximum'].to_json}"
end
description += "`"
end
if value['enum']
description += '
**one of:**' + [*value['enum']].map { |e| "`#{e.to_json}`" }.join(" or ")
end
if value['pattern']
description += "
**pattern:** #{value['pattern'].gsub /\|/, '|'}
"
end
if value['minLength'] || value['maxLength']
description += "
**Length:** `"
if value['minLength']
description += "#{value['minLength'].to_json}"
end
unless value['minLength'] == value['maxLength']
if value['maxLength']
unless value['minLength']
description += "0"
end
description += "..#{value['maxLength'].to_json}"
else
description += "..∞"
end
end
description += "`"
end
if value.has_key?('example')
example = if value['example'].is_a?(Hash) && value['example'].has_key?('oneOf')
value['example']['oneOf'].map { |e| "`#{e.to_json}`" }.join(" or ")
else
"`#{value['example'].to_json}`"
end
elsif (value['type'] == ['array'] && value.has_key?('items')) || value.has_key?('enum')
example = "`#{schema.schema_value_example(value).to_json}`"
elsif value['type'].include?('null')
example = "`null`"
end
type = if value['type'].include?('null')
'nullable '
else
''
end
type += (value['format'] || (value['type'] - ['null']).first)
[key, type, description, example]
end
def build_link_path(schema, link)
link['href'].gsub(%r|(\{\([^\)]+\)\})|) do |ref|
ref = ref.gsub('%2F', '/').gsub('%23', '#').gsub(%r|[\{\(\)\}]|, '')
ref_resource = ref.split('#/definitions/').last.split('/').first.gsub('-','_')
identity_key, identity_value = schema.dereference(ref)
if identity_value.has_key?('anyOf')
'{' + ref_resource + '_' + identity_value['anyOf'].map {|r| r['$ref'].split('/').last}.join('_or_') + '}'
else
'{' + ref_resource + '_' + identity_key.split('/').last + '}'
end
end
end
def array_with_nested_objects?(items)
return unless items
items['properties'] || items['oneOf']
end
%>