Class: Schemacop::V3::ArrayNode

Inherits:
Node
  • Object
show all
Defined in:
lib/schemacop/v3/array_node.rb

Constant Summary collapse

ATTRIBUTES =
%i[
  min_items
  max_items
  unique_items
].freeze

Instance Attribute Summary collapse

Attributes inherited from Node

#as, #default, #description, #name, #options, #parent, #require_key, #title

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Node

create, #create, #dsl_node, #dsl_scm, #initialize, #require_key?, #required?, resolve_class, #schemas, supports_children, supports_children_options, #used_external_schemas, #validate

Constructor Details

This class inherits a constructor from Schemacop::V3::Node

Instance Attribute Details

#cont_itemObject

Returns the value of attribute cont_item.



22
23
24
# File 'lib/schemacop/v3/array_node.rb', line 22

def cont_item
  @cont_item
end

#itemsObject (readonly)

Returns the value of attribute items.



20
21
22
# File 'lib/schemacop/v3/array_node.rb', line 20

def items
  @items
end

#list_itemObject

Returns the value of attribute list_item.



21
22
23
# File 'lib/schemacop/v3/array_node.rb', line 21

def list_item
  @list_item
end

Class Method Details

.allowed_optionsObject



12
13
14
# File 'lib/schemacop/v3/array_node.rb', line 12

def self.allowed_options
  super + ATTRIBUTES + %i[additional_items reject filter parse_json]
end

.dsl_methodsObject



16
17
18
# 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

Instance Method Details

#_validate(data, result:) ⇒ Object



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
# File 'lib/schemacop/v3/array_node.rb', line 83

def _validate(data, result:)
  super_data = super
  return if super_data.nil?

  # Handle JSON
  super_data = parse_if_json(super_data, result: result, allowed_types: { Array => :array })
  return if super_data.nil?

  # Preprocess
  super_data = preprocess_array(super_data)

  # 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) ⇒ Object



48
49
50
# File 'lib/schemacop/v3/array_node.rb', line 48

def add_child(node)
  @items << node
end

#allowed_typesObject



75
76
77
78
79
80
81
# File 'lib/schemacop/v3/array_node.rb', line 75

def allowed_types
  if options[:parse_json]
    { Array => :array, String => :array }
  else
    { Array => :array }
  end
end

#as_jsonObject



52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
# 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) ⇒ Object



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
# File 'lib/schemacop/v3/array_node.rb', line 151

def cast(value)
  return default unless value

  value = parse_if_json(value, allowed_types: { Array => :array })

  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 preprocess_array(result)
end

#childrenObject



147
148
149
# File 'lib/schemacop/v3/array_node.rb', line 147

def children
  (@items + [@cont_item]).compact
end

#dsl_add(type, **options, &block) ⇒ Object



24
25
26
27
28
29
30
# 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) ⇒ Object



40
41
42
43
44
45
46
# 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) ⇒ Object



32
33
34
35
36
37
38
# 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