Module: VacuumCleaner::Normalizations::ClassMethods

Defined in:
lib/vacuum_cleaner/normalizations.rb

Instance Method Summary collapse

Instance Method Details

#normalized_attributesObject

List of already normalized attributes, to keep everything safe when calling normalizes twice for a certain attribute.

When called for the first time checks it’s superclass for any normalized attributes.



22
23
24
25
26
# File 'lib/vacuum_cleaner/normalizations.rb', line 22

def normalized_attributes
  @normalized_attributes ||= [].tap do |ary|
    superclass.normalized_attributes.each { |a| ary << a } if superclass && superclass.respond_to?(:normalized_attributes)
  end
end

#normalizes(*attributes) {|value| ... } ⇒ Object

Enables normalization chain for supplied attributes.

Examples:

Basic usage for plain old ruby objects.

class Doctor
  include VacuumCleaner::Normalizations
  attr_accessor :name      
  normalizes :name
end

Parameters:

  • attributes (Strings, Symbols)

    list of attribute names to normalize, at least one attribute is required

  • options (Hash)

    optional list of normalizers to use, like :downcase => true. To not run the default normalizer (VacuumCleaner::Normalizer#normalize_value) set :default => false

Yields:

  • (value)

    optional block to define some one-time custom normalization logic

  • (instance, attribute, value)

    optional (extended) block with all arguments, like the object and current attribute name. Everything else behaves the same es the single-value yield

Yield Parameters:

  • value

    can be nil, otherwise value as passed through the default normalizer

Yield Returns:

  • should return value as normalized by the block

Raises:

  • (ArgumentError)


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
# File 'lib/vacuum_cleaner/normalizations.rb', line 48

def normalizes(*attributes, &block)
  normalizations = attributes.last.is_a?(Hash) ? attributes.pop : {}
  raise ArgumentError, "You need to supply at least one attribute" if attributes.empty?
  
  normalizers = []
  normalizers << Normalizer.new unless normalizations.delete(:default) === false
  
  normalizations.each do |key, options|
    begin
      normalizers << const_get("#{VacuumCleaner.camelize_value(key)}Normalizer").new(options === true ? {} : options)
    rescue NameError
      raise ArgumentError, "Unknown normalizer: '#{key}'"
    end
  end
  
  attributes.each do |attribute|
    attribute = attribute.to_sym
    
    # guard against calling it twice!
    unless normalized_attributes.include?(attribute)
      send(:define_method, :"normalize_#{attribute}") do |value|
        value = normalizers.inject(value) { |v,n| n.normalize(self, attribute, v) }
        block_given? ? (block.arity == 1 ? yield(value) : yield(self, attribute, value)) : value
      end
      original_setter = "#{attribute}#{VacuumCleaner::WITHOUT_NORMALIZATION_SUFFIX}=".to_sym
      send(:alias_method, original_setter, "#{attribute}=") if instance_methods.include?(RUBY_VERSION =~ /^1.9/ ? :"#{attribute}=" : "#{attribute}=")
              
      class_eval "        def \#{attribute}=(value)                                                                          #  1.  def name=(value)\n          value = send(:'normalize_\#{attribute}', value)                                                  #  2.    value = send(:'normalize_name', value)\n          return send(\#{original_setter.inspect}, value) if respond_to?(\#{original_setter.inspect})       #  3.    return send(:'name_wi...=', value) if respond_to?(:'name_wi...=')\n          return send(:[]=, \#{attribute.inspect}, value) if respond_to?(:[]=)                             #  4.    return send(:[]=, :name, value) if respond_to?(:[]=)\n          @\#{attribute} = value                                                                           #  5.   @name = value\n        end                                                                                               #  6.  end\n      RUBY\n      \n      normalized_attributes << attribute\n    end\n  end\nend\n", __FILE__, __LINE__+1