# frozen_string_literal: true module Normalizy module Extension extend ActiveSupport::Concern included do before_validation :apply_normalizy, if: -> { self.class.respond_to? :normalizy } private def apply_normalizy (self.class.normalizy_rules || {}).each do |attribute, rules| rules.each { |rule| normalizy! rule.merge(attribute: attribute) } end end def extract_filter(rule, filters: Normalizy.config.filters) if rule.is_a?(Hash) result = filters[rule.keys.first] || rule.keys.first options = rule.values.first else result = filters[rule] end [result || rule, options || {}] end def extract_value(value, filter, options, block) if filter.respond_to?(:call) if filter.method(:call).arity == -2 filter.call value, options, &block else filter.call value, &block end elsif respond_to?(filter) send filter, value, options, &block elsif value.respond_to?(filter) value.send filter, &block else value end end def normalizy!(attribute:, rules:, options:, block:) return if rules.blank? && block.blank? aliases = Normalizy.config.normalizy_aliases value = nil [rules].flatten.compact.each do |rule| value = original_value(attribute, rule, options) aliased_rules = [aliases.key?(rule) ? aliases[rule] : rule] aliased_rules.flatten.compact.each do |alias_rule| filter, filter_options = extract_filter(alias_rule) value = extract_value(value, filter, filter_options, block) end end return unless value write attribute, value end def original_value(attribute, rule, options) if raw? attribute, rule, options send "#{attribute}_before_type_cast" else send attribute end end def raw?(attribute, rule, options) return false unless respond_to?("#{attribute}_before_type_cast") options[:raw] || Normalizy.config.normalizy_raws.include?(rule) end def write(attribute, value) write_attribute attribute, value rescue ActiveModel::MissingAttributeError send "#{attribute}=", value end end module ClassMethods attr_accessor :normalizy_rules def normalizy(*args, &block) options = args.extract_options! rules = options[:with] || Normalizy.config.default_filters self.normalizy_rules ||= {} args.each do |field| normalizy_rules[field] ||= [] normalizy_rules[field] << { block: block, options: options.except(:with), rules: rules } end end end end end