Module: VacuumCleaner::Normalizations::ClassMethods

Defined in:
lib/vacuum_cleaner/normalizations.rb

Instance Method Summary collapse

Instance Method Details

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


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

def normalizes(*attributes, &block)
  metaklass = class << self; self; end
  
  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
    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}=")
              
    rb_src = <<-RUBY
      def #{attribute}=(value)                                                                          #  1.  def name=(value)
        value = send(:'normalize_#{attribute}', value)                                                  #  2.    value = send(:'normalize_name', value)
        return send(#{original_setter.inspect}, value) if respond_to?(#{original_setter.inspect})       #  3.    return send(:'name_wi...=', value) if respond_to?(:'name_wi...=')
        return self[#{attribute.inspect}] = value if respond_to?(:[]=)                                  #  4.    return self[:name] = value if respond_to?(:write_attribute)
        @#{attribute} = value                                                                           #  5.   @name = value
      end                                                                                               #  6.  end
    RUBY
    
    module_eval rb_src, __FILE__, __LINE__
  end
end