Class: Errapi::ObjectValidator

Inherits:
Object
  • Object
show all
Includes:
LocationBuilders
Defined in:
lib/errapi/object_validator.rb

Defined Under Namespace

Classes: ContextProxy, RelativeLocation

Instance Method Summary collapse

Methods included from LocationBuilders

#dotted_location, #json_location, #no_location

Constructor Details

#initialize(config, options = {}, &block) ⇒ ObjectValidator

Returns a new instance of ObjectValidator.



8
9
10
11
12
13
# File 'lib/errapi/object_validator.rb', line 8

def initialize config, options = {}, &block
  # TODO: remove these options or if used, pass them to new validators instantiated in #register_validations
  @config = config
  @validations = []
  instance_eval &block if block
end

Instance Method Details

#relative_location(location) ⇒ Object



112
113
114
# File 'lib/errapi/object_validator.rb', line 112

def relative_location location
  RelativeLocation.new location
end

#validate(value, context, options = {}) ⇒ Object



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
# File 'lib/errapi/object_validator.rb', line 29

def validate value, context, options = {}
  # TODO: skip validation by default if previous errors at current location
  # TODO: add support for previous value and skip validation by default if value is unchanged

  return context.valid? unless @validations

  location = if options[:location]
    options[:location]
  elsif options[:location_type]
    builder = "#{options[:location_type]}_location"
    raise "Unknown location type #{options[:location_type].inspect}" unless respond_to? builder
    send builder
  else
    no_location
  end

  source = options[:source]
  context_proxy = ContextProxy.new context, self, location

  @validations.each do |validation_definition|

    each = validation_definition[:each]

    each_values = nil
    each_values_set = nil

    if each
      each_values = extract(value, each[:target], options)[:value]
      each_values_set = each_values.collect{ |v| true } if each_values.kind_of? Array
      each_values = [] unless each_values.kind_of? Array
      each_sources = each_values.collect{ |v| source }
    else
      each_values = [ value ]
      each_values_set = [ options.fetch(:value_set, true) ]
      each_sources = [ source ]
    end

    each_location = each ? location.relative(each[:options][:as] || each[:target]) : location

    each_values.each.with_index do |each_value,i|

      each_index_location = each ? each_location.relative(i) : location
      context_proxy.current_location = each_index_location

      next if validation_definition[:conditions].any?{ |condition| !condition.fulfilled?(each_value, context_proxy) }

      validation_definition[:validations].each do |validation|

        next if validation[:conditions] && validation[:conditions].any?{ |condition| !condition.fulfilled?(each_value, context_proxy) }

        validation_definition[:targets].each do |target|

          target_value_info = extract each_value, target, value_set: each_values_set[i], source: source

          validation_location = target ? each_index_location.relative(validation[:target_alias] || target) : each_index_location
          context_proxy.current_location = validation_location

          error_options = {
            value: target_value_info[:value],
            source: target_value_info[:source],
            value_set: target_value_info[:value_set],
            constraints: validation[:validation_options]
          }

          error_options[:location] = validation_location unless validation_location.kind_of? Errapi::Locations::None

          error_options[:validation] = validation[:validation_name] if validation[:validation_name]

          context_proxy.with_error_options error_options do
            validation_options = { location: validation_location, value_set: target_value_info[:value_set] }
            validation[:validation].validate target_value_info[:value], context_proxy, validation_options
          end
        end
      end
    end
  end

  # TODO: add config option to raise error by default
  raise Errapi::ValidationFailed.new(context) if options[:raise_error] && context.errors?

  context_proxy.valid?
end

#validates(*args, &block) ⇒ Object



15
16
17
# File 'lib/errapi/object_validator.rb', line 15

def validates *args, &block
  register_validations *args, &block
end

#validates_each(*args, &block) ⇒ Object



19
20
21
22
23
24
25
26
27
# File 'lib/errapi/object_validator.rb', line 19

def validates_each *args, &block

  options = args.last.kind_of?(Hash) ? args.pop : {}
  options[:each] = args.shift
  options[:each_options] = options.delete(:each_options) || {}
  args << options

  validates *args, &block
end