def validate(context = Attributor::DEFAULT_ROOT_CONTEXT)
      raise AttributorException, 'validation conflict' if @validating
      @validating = true

      context = [context] if context.is_a? ::String
      keys_with_values = []
      errors = []

      self.class.attributes.each do |sub_attribute_name, sub_attribute|
        sub_context = self.class.generate_subcontext(context, sub_attribute_name)

        value = __send__(sub_attribute_name)
        keys_with_values << sub_attribute_name unless value.nil?

        if value.respond_to?(:validating) # really, it's a thing with sub-attributes
          next if value.validating
        end

        errors.concat sub_attribute.validate(value, sub_context)
      end
      self.class.requirements.each do |req|
        validation_errors = req.validate(keys_with_values, context)
        errors.concat(validation_errors) unless validation_errors.empty?
      end

      errors
    ensure
      @validating = false
    end
def validate(context = Attributor::DEFAULT_ROOT_CONTEXT)
      raise AttributorException, 'validation conflict' if @validating
      @validating = true

      context = [context] if context.is_a? ::String
      keys_with_values = []
      errors = []

      self.class.attributes.each do |sub_attribute_name, sub_attribute|
        sub_context = self.class.generate_subcontext(context, sub_attribute_name)

        value = __send__(sub_attribute_name)
        keys_with_values << sub_attribute_name unless value.nil?

        if value.respond_to?(:validating) # really, it's a thing with sub-attributes
          next if value.validating
        end

        errors.concat sub_attribute.validate(value, sub_context)
      end
      self.class.requirements.each do |req|
        validation_errors = req.validate(keys_with_values, context)
        errors.concat(validation_errors) unless validation_errors.empty?
      end

      errors
    ensure
      @validating = false
    end
TODO: memoize validation results here, but only after rejiggering how we store the context.
       Two calls to validate() with different contexts should return get the same errors,
       but with their respective contexts.