module Nidyx::Parser

Public Instance Methods

parse(schema, options) click to toggle source

@param schema [Hash] JSON Schema @param options [Hash] global application options @return [Hash] a Hash of ModelData objects

# File lib/nidyx/parser.rb, line 19
def parse(schema, options)
  # setup parser
  @class_prefix = options[:class_prefix]
  @options = options
  @schema = schema
  @models = {}

  # run model generation
  generate([], class_name(@class_prefix, nil))
  @models
end

Private Instance Methods

class_name_from_ref(ref) click to toggle source

@param ref [String] reference in json pointer format @return [String] the class name of the object at the location of the ref

# File lib/nidyx/parser.rb, line 175
def class_name_from_ref(ref)
  class_name_from_path(@class_prefix, Nidyx::Pointer.new(ref).path, @schema) if ref
end
generate(path, name) click to toggle source

Generates a Model and adds it to the models array. @param path [Array] the path to an object in the schema @param name [String] raw model name

# File lib/nidyx/parser.rb, line 36
def generate(path, name)
  object = get_object(path)

  type = object[TYPE_KEY]
  if type == OBJECT_TYPE
    generate_object(path, name)

  elsif type == ARRAY_TYPE
    generate_top_level_array(path)

  elsif type.is_a?(Array)
    if type.include?(OBJECT_TYPE)
      raise UnsupportedSchemaError if type.include?(ARRAY_TYPE)
      generate_object(path, name)

    elsif type.include?(ARRAY_TYPE)
      generate_top_leve_array(path)

    else raise UnsupportedSchemaError; end
  else raise UnsupportedSchemaError; end
end
generate_object(path, name) click to toggle source
# File lib/nidyx/parser.rb, line 58
def generate_object(path, name)
  @models[name] = model = Nidyx::Model.new(name)
  required_properties = get_object(path)[REQUIRED_KEY]
  properties_path = path + [PROPERTIES_KEY]

  get_object(properties_path).keys.each do |key|
    optional = is_optional?(key, required_properties)
    property_path = properties_path + [key]
    model.properties << generate_property(key, property_path, model, optional)
  end
end
generate_property(key, path, model, optional) click to toggle source

@param key [String] the key of the property in the JSON Schema @param path [Array] the path to the aforementioned object in the schema @param model [Property] the model that owns the property to be generated @param optional [Boolean] true if the property can be empty or null

# File lib/nidyx/parser.rb, line 78
def generate_property(key, path, model, optional)
  obj = resolve_reference(path)
  class_name = obj[DERIVED_NAME]

  if include_type?(obj, OBJECT_TYPE) && obj[PROPERTIES_KEY]
    model.dependencies << class_name
  elsif include_type?(obj, ARRAY_TYPE)
    obj[COLLECTION_TYPES_KEY] = resolve_array_refs(obj)
    model.dependencies += obj[COLLECTION_TYPES_KEY]
  end

  name = obj[NAME_OVERRIDE_KEY] || key
  property = Nidyx::Property.new(name, class_name, optional, obj)
  property.overriden_name = key if obj[NAME_OVERRIDE_KEY]
  property
end
generate_top_level_array(path) click to toggle source
# File lib/nidyx/parser.rb, line 70
def generate_top_level_array(path)
  resolve_array_refs(get_object(path))
end
get_object(path) click to toggle source

@param path [Array] the path to an object in the global schema @return [Hash] a object containing JSON schema

# File lib/nidyx/parser.rb, line 189
def get_object(path)
  object_at_path(path, @schema)
end
include_type?(obj, type) click to toggle source

@param type_obj [Array, String] the JSON Schema type @param type [String] a string type to test @param true if the string type is a valid type according type object

# File lib/nidyx/parser.rb, line 203
def include_type?(obj, type)
  type_obj = obj[TYPE_KEY]
  type_obj.is_a?(Array) ? type_obj.include?(type) : type_obj == type
end
is_optional?(key, required_keys) click to toggle source

@param key [String] the id of a specific property @param required_keys [Array] an array of the required property keys @return true if the property is optional

# File lib/nidyx/parser.rb, line 196
def is_optional?(key, required_keys)
  !(required_keys && required_keys.include?(key))
end
resolve_array_refs(obj) click to toggle source

Resolves any references buied in the ‘items` property of an array definition. Returns a list of collection types in the array. @param obj [Hash] the array property schema @return [Array] types contained in the array

# File lib/nidyx/parser.rb, line 136
def resolve_array_refs(obj)
  items = obj[ITEMS_KEY]

  case items
  when Array
    return resolve_items_array(items)
  when Hash
    # handle a nested any of key
    any_of = items[ANY_OF_KEY]
    return resolve_items_array(any_of) if any_of.is_a?(Array)

    resolve_reference_string(items[REF_KEY])
    return [class_name_from_ref(items[REF_KEY])].compact
  else
    return []
  end
end
resolve_items_array(items) click to toggle source

@param items [Array] an array of items @return [Array] types contained in the array

# File lib/nidyx/parser.rb, line 156
def resolve_items_array(items)
  types = []
  items.each { |i| types << resolve_single_item(i) }
  types.compact
end
resolve_reference(path, parent = nil) click to toggle source

Given a path, which could be at any part of a reference chain, resolve the immediate schema object. This means:

  • if there is an imediate ref, follow it

  • inherit any schema information from the parent reference chain

(unimplemented)

If we are at the end of a chain, do the following:

  • generate a model for this object if necessary

  • add ‘class_name` to the immediate object when appropriate

  • return the immediate object

@param path [Array] the path to an object in the schema @param parent [Hash, nil] the merged attributes of the parent reference chain @return [Hash] a modified schema object with inherited attributes from it’s parents.

# File lib/nidyx/parser.rb, line 112
def resolve_reference(path, parent = nil)
  obj = get_object(path)
  ref = obj[REF_KEY]

  # TODO: merge parent and obj into obj (destructive)

  # If we find an immediate reference, chase it and pass the immediate
  # object as a parent.
  return resolve_reference_string(ref) if ref

  # If we are dealing with an object, encode it's class name into the
  # schema and generate it's model if necessary.
  if include_type?(obj, OBJECT_TYPE) && obj[PROPERTIES_KEY]
    obj[DERIVED_NAME] = class_name_from_path(@class_prefix, path, @schema)
    generate(path, obj[DERIVED_NAME]) unless @models.has_key?(obj[DERIVED_NAME])
  end

  obj
end
resolve_reference_string(ref) click to toggle source

Resolves a reference as a plain JSON Pointer string. @param ref [String] reference in json pointer format @return [Hash] a modified schema object with inherited attributes from it’s parents.

# File lib/nidyx/parser.rb, line 183
def resolve_reference_string(ref)
  resolve_reference(Nidyx::Pointer.new(ref).path) if ref
end
resolve_single_item(item) click to toggle source

@param item [Hash] a single item return [Array] types for the single item

# File lib/nidyx/parser.rb, line 164
def resolve_single_item(item)
  if item[REF_KEY]
    resolve_reference_string(item[REF_KEY])
    class_name_from_ref(item[REF_KEY])
  elsif item[TYPE_KEY]
    item[TYPE_KEY]
  end
end