RubyMoney/money

View on GitHub
lib/money/money/formatting_rules.rb

Summary

Maintainability
A
3 hrs
Test Coverage
# encoding: UTF-8

class Money
  class FormattingRules
    def initialize(currency, *raw_rules)
      @currency = currency

      # support for old format parameters
      @rules = normalize_formatting_rules(raw_rules)

      @rules = default_formatting_rules.merge(@rules) unless @rules[:ignore_defaults]
      @rules = localize_formatting_rules(@rules)
      @rules = translate_formatting_rules(@rules) if @rules[:translate]
      @rules[:format] ||= determine_format_from_formatting_rules(@rules)
      @rules[:delimiter_pattern] ||= delimiter_pattern_rule(@rules)

      warn_about_deprecated_rules(@rules)
    end

    def [](key)
      @rules[key]
    end

    def has_key?(key)
      @rules.has_key? key
    end

    private

    attr_reader :currency

    # Cleans up formatting rules.
    #
    # @param [Hash] rules
    #
    # @return [Hash]
    def normalize_formatting_rules(rules)
      if rules.size == 0
        rules = {}
      elsif rules.size == 1
        rules = rules.pop
        rules = rules.dup if rules.is_a?(Hash)

        if rules.is_a?(Symbol)
          warn '[DEPRECATION] Use Hash when passing rules to Money#format.'
          rules = { rules => true }
        end
      end

      if !rules.include?(:decimal_mark) && rules.include?(:separator)
        rules[:decimal_mark] = rules[:separator]
      end

      if !rules.include?(:thousands_separator) && rules.include?(:delimiter)
        rules[:thousands_separator] = rules[:delimiter]
      end

      rules
    end

    def default_formatting_rules
      Money.default_formatting_rules || {}
    end

    def translate_formatting_rules(rules)
      begin
        rules[:symbol] = I18n.t currency.iso_code, scope: "number.currency.symbol", raise: true
      rescue I18n::MissingTranslationData
        # Do nothing
      end
      rules
    end

    def localize_formatting_rules(rules)
      if currency.iso_code == "JPY" && I18n.locale == :ja && rules[:format] == nil
        rules[:symbol] = "円" unless rules[:symbol] == false
        rules[:format] = '%n%u'
      end
      rules
    end

    def determine_format_from_formatting_rules(rules)
      return currency.format if currency.format && !rules.has_key?(:symbol_position)

      symbol_position = symbol_position_from(rules)

      if symbol_position == :before
        rules.fetch(:symbol_before_without_space, true) ? '%u%n' : '%u %n'
      else
        rules[:symbol_after_without_space] ? '%n%u' : '%n %u'
      end
    end

    def delimiter_pattern_rule(rules)
      if rules[:south_asian_number_formatting]
        # from http://blog.revathskumar.com/2014/11/regex-comma-seperated-indian-currency-format.html
        /(\d+?)(?=(\d\d)+(\d)(?!\d))(\.\d+)?/
      else
        /(\d)(?=(?:\d{3})+(?:[^\d]{1}|$))/
      end
    end

    def symbol_position_from(rules)
      if rules.has_key?(:symbol_position)
        if [:before, :after].include?(rules[:symbol_position])
          return rules[:symbol_position]
        else
          raise ArgumentError, ":symbol_position must be ':before' or ':after'"
        end
      elsif currency.symbol_first?
        :before
      else
        :after
      end
    end

    def warn_about_deprecated_rules(rules)
      if rules.has_key?(:symbol_position)
        position = rules[:symbol_position]
        template = position == :before ? '%u%n' : '%n%u'

        warn "[DEPRECATION] `symbol_position: :#{position}` is deprecated - you can replace it with `format: #{template}`"
      end

      if rules.has_key?(:symbol_before_without_space)
        warn "[DEPRECATION] `symbol_before_without_space:` option is deprecated - you can replace it with `format: '%u%n'`"
      end

      if rules.has_key?(:symbol_after_without_space)
        warn "[DEPRECATION] `symbol_after_without_space:` option is deprecated - you can replace it with `format: '%n%u'`"
      end

      if rules.has_key?(:html)
        warn "[DEPRECATION] `html` is deprecated - use `html_wrap` instead. Please note that `html_wrap` will wrap all parts of currency and if you use `with_currency` option, currency element class changes from `currency` to `money-currency`."
      end

      if rules.has_key?(:html_wrap_symbol)
        warn "[DEPRECATION] `html_wrap_symbol` is deprecated - use `html_wrap` instead. Please note that `html_wrap` will wrap all parts of currency."
      end
    end
  end
end