class Schemacop::V3::ArrayNode

Constants

ATTRIBUTES

Attributes

cont_item[RW]
items[R]
list_item[RW]

Public Class Methods

allowed_options() click to toggle source
Calls superclass method
# File lib/schemacop/v3/array_node.rb, line 12
def self.allowed_options
  super + ATTRIBUTES + %i[additional_items]
end
dsl_methods() click to toggle source
Calls superclass method
# File lib/schemacop/v3/array_node.rb, line 16
def self.dsl_methods
  super + NodeRegistry.dsl_methods(false) + %i[dsl_add dsl_list dsl_cont]
end

Public Instance Methods

_validate(data, result:) click to toggle source
Calls superclass method
# File lib/schemacop/v3/array_node.rb, line 79
def _validate(data, result:)
  super_data = super
  return if super_data.nil?

  # Validate length #
  length = super_data.size

  if options[:min_items] && length < options[:min_items]
    result.error "Array has #{length} items but needs at least #{options[:min_items]}."
  end

  if options[:max_items] && length > options[:max_items]
    result.error "Array has #{length} items but needs at most #{options[:max_items]}."
  end

  if list?
    # Validate list
    super_data.each_with_index do |value, index|
      result.in_path :"[#{index}]" do
        list_item._validate(value, result: result)
      end
    end
  elsif items.any?
    # Validate tuple
    if length == items.size || (options[:additional_items] != false && length >= items.size)
      items.each_with_index do |child_node, index|
        value = super_data[index]

        result.in_path :"[#{index}]" do
          child_node._validate(value, result: result)
        end
      end

      # Validate additional items #
      if options[:additional_items].is_a?(Node)
        (items.size..(length - 1)).each do |index|
          additional_item = super_data[index]
          result.in_path :"[#{index}]" do
            options[:additional_items]._validate(additional_item, result: result)
          end
        end
      end
    else
      result.error "Array has #{length} items but must have exactly #{items.size}."
    end
  end

  if cont_item.present? && super_data.none? { |obj| item_matches?(cont_item, obj) }
    result.error "At least one entry must match schema #{cont_item.as_json.inspect}."
  end

  # Validate uniqueness #
  if options[:unique_items] && super_data.size != super_data.uniq.size
    result.error 'Array has duplicate items.'
  end
end
add_child(node) click to toggle source
# File lib/schemacop/v3/array_node.rb, line 48
def add_child(node)
  @items << node
end
allowed_types() click to toggle source
# File lib/schemacop/v3/array_node.rb, line 75
def allowed_types
  { Array => :array }
end
as_json() click to toggle source
# File lib/schemacop/v3/array_node.rb, line 52
def as_json
  json = { type: :array }

  if cont_item
    json[:contains] = cont_item.as_json
  end

  if list?
    json[:items] = @list_item.as_json
  elsif @items.any?
    json[:items] = @items.map(&:as_json)
    if options[:additional_items] == true
      json[:additionalItems] = true
    elsif options[:additional_items].is_a?(Node)
      json[:additionalItems] = options[:additional_items].as_json
    else
      json[:additionalItems] = false
    end
  end

  return process_json(ATTRIBUTES, json)
end
cast(value) click to toggle source
# File lib/schemacop/v3/array_node.rb, line 140
def cast(value)
  return default unless value

  result = []

  value.each_with_index do |value_item, index|
    if cont_item.present? && item_matches?(cont_item, value_item)
      result << cont_item.cast(value_item)
    elsif list?
      result << list_item.cast(value_item)
    elsif items.any?
      if options[:additional_items] != false && index >= items.size
        if options[:additional_items].is_a?(Node)
          result << options[:additional_items].cast(value_item)
        else
          result << value_item
        end
      else
        item = item_for_data(value_item)
        result << item.cast(value_item)
      end
    else
      result << value_item
    end
  end

  return result
end
children() click to toggle source
# File lib/schemacop/v3/array_node.rb, line 136
def children
  (@items + [@cont_item]).compact
end
dsl_add(type, **options, &block) click to toggle source
# File lib/schemacop/v3/array_node.rb, line 24
def dsl_add(type, **options, &block)
  if @options[:additional_items].is_a?(Node)
    fail Exceptions::InvalidSchemaError, 'You can only use "add" once to specify additional items.'
  end

  @options[:additional_items] = create(type, **options, &block)
end
dsl_cont(type, **options, &block) click to toggle source
# File lib/schemacop/v3/array_node.rb, line 40
def dsl_cont(type, **options, &block)
  if cont_item.is_a?(Node)
    fail Exceptions::InvalidSchemaError, 'You can only use "cont" once.'
  end

  @cont_item = create(type, **options, &block)
end
dsl_list(type, **options, &block) click to toggle source
# File lib/schemacop/v3/array_node.rb, line 32
def dsl_list(type, **options, &block)
  if list_item.is_a?(Node)
    fail Exceptions::InvalidSchemaError, 'You can only use "list" once.'
  end

  @list_item = create(type, **options, &block)
end

Protected Instance Methods

init() click to toggle source
# File lib/schemacop/v3/array_node.rb, line 182
def init
  @items = []
  @cont_item = nil

  if options[:additional_items].nil?
    options[:additional_items] = false
  end
end
item_for_data(data) click to toggle source
# File lib/schemacop/v3/array_node.rb, line 175
def item_for_data(data)
  item = children.find { |c| item_matches?(c, data) }
  return item if item

  fail "Could not find specification for item #{data.inspect}."
end
list?() click to toggle source
# File lib/schemacop/v3/array_node.rb, line 171
def list?
  list_item.present?
end
validate_self() click to toggle source
# File lib/schemacop/v3/array_node.rb, line 191
def validate_self
  if list? && items.any?
    fail 'Can\'t use "list" and normal items.'
  end

  if list? && @options[:additional_items].is_a?(Node)
    fail 'Can\'t use "list" and additional items.'
  end

  unless options[:min_items].nil? || options[:min_items].is_a?(Integer)
    fail 'Option "min_items" must be an "integer"'
  end

  unless options[:max_items].nil? || options[:max_items].is_a?(Integer)
    fail 'Option "max_items" must be an "integer"'
  end

  unless options[:unique_items].nil? || options[:unique_items].is_a?(TrueClass) || options[:unique_items].is_a?(FalseClass)
    fail 'Option "unique_items" must be a "boolean".'
  end

  if options[:min_items] && options[:max_items] && options[:min_items] > options[:max_items]
    fail 'Option "min_items" can\'t be greater than "max_items".'
  end
end