Class: DataMapper::Validations::ContextualValidators

Inherits:
Object
  • Object
show all
Extended by:
Forwardable
Includes:
Enumerable
Defined in:
lib/dm-validations/contextual_validators.rb

Overview

Author:

  • Guy van den Berg

Since:

  • 0.9

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeContextualValidators

Returns a new instance of ContextualValidators.

Since:

  • 0.9



22
23
24
# File 'lib/dm-validations/contextual_validators.rb', line 22

def initialize
  @contexts = {}
end

Instance Attribute Details

#contextsObject (readonly)

Since:

  • 0.9



20
21
22
# File 'lib/dm-validations/contextual_validators.rb', line 20

def contexts
  @contexts
end

Instance Method Details

#clear!Object

Clear all named context validators off of the resource

Since:

  • 0.9



42
43
44
# File 'lib/dm-validations/contextual_validators.rb', line 42

def clear!
  contexts.clear
end

#context(name) ⇒ Array<DataMapper::Validations::GenericValidator>

Return an array of validators for a named context

Parameters:

  • Context (String)

    name for which return validators

Returns:

Since:

  • 0.9



36
37
38
# File 'lib/dm-validations/contextual_validators.rb', line 36

def context(name)
  contexts[name] ||= []
end

#execute(named_context, target) ⇒ Boolean

Execute all validators in the named context against the target. Load together any properties that are designated lazy but are not yet loaded. Optionally only validate dirty properties.

Parameters:

  • named_context (Symbol)

    the context we are validating against

  • target (Object)

    the resource that we are validating

Returns:

  • (Boolean)

    true if all are valid, otherwise false

Since:

  • 0.9



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
# File 'lib/dm-validations/contextual_validators.rb', line 56

def execute(named_context, target)
  target.errors.clear!

  runnable_validators = context(named_context).select{ |validator| validator.execute?(target) }
  validators = runnable_validators.dup

  # By default we start the list with the full set of runnable validators.
  #
  # In the case of a new Resource or regular ruby class instance,
  # everything needs to be validated completely, and no eager-loading
  # logic should apply.
  #
  # In the case of a DM::Resource that isn't new, we optimize:
  #
  #   1. Eager-load all lazy, not-yet-loaded properties that need
  #      validation, all at once.
  #
  #   2. Limit run validators to
  #      - those applied to dirty attributes only,
  #      - those that should always run (presence/absence)
  #      - those that don't reference any real properties (field-less
  #        block validators, validations in virtual attributes)
  if target.kind_of?(DataMapper::Resource) && !target.new?
    attrs       = target.attributes.keys
    dirty_attrs = target.dirty_attributes.keys.map{ |p| p.name }
    validators  = runnable_validators.select{|v|
      !attrs.include?(v.field_name) || dirty_attrs.include?(v.field_name)
    }

    # Load all lazy, not-yet-loaded properties that need validation,
    # all at once.
    fields_to_load = validators.map{|v|
      target.class.properties[v.field_name]
    }.compact.select {|p|
      p.lazy? && !p.loaded?(target)
    }

    target.__send__(:eager_load, fields_to_load)

    # Finally include any validators that should always run or don't
    # reference any real properties (field-less block vaildators).
    validators |= runnable_validators.select do |v|
      [ MethodValidator, PresenceValidator, AbsenceValidator ].any? do |klass|
        v.kind_of?(klass)
      end
    end
  end

  validators.map { |validator| validator.call(target) }.all?
end