lib/phony_rails.rb in phony_rails-0.13.1 vs lib/phony_rails.rb in phony_rails-0.14.0

- old
+ new

@@ -3,10 +3,27 @@ require 'validators/phony_validator' require 'phony_rails/version' require 'yaml' module PhonyRails + def self.default_country_code + @default_country_code ||= nil + end + + def self.default_country_code=(new_code) + @default_country_code = new_code + @default_country_number = nil # Reset default country number, will lookup next time its asked for + end + + def self.default_country_number + @default_country_number ||= default_country_code.present? ? country_number_for(default_country_code) : nil + end + + def self.default_country_number=(new_number) + @default_country_number = new_number + end + def self.country_number_for(country_code) return if country_code.nil? country_codes_hash.fetch(country_code.to_s.upcase, {})['country_code'] end @@ -26,69 +43,101 @@ # http://www.redguava.com.au/2011/06/rails-convert-phone-numbers-to-international-format-for-sms/ def self.normalize_number(number, options = {}) return if number.nil? original_number = number number = number.dup # Just to be sure, we don't want to change the original. + number, ext = extract_extension(number) number.gsub!(/[^\(\)\d\+]/, '') # Strips weird stuff from the number return if number.blank? if _country_number = options[:country_number] || country_number_for(options[:country_code]) options[:add_plus] = true if options[:add_plus].nil? # (Force) add country_number if missing # NOTE: do we need to force adding country code? Otherwise we can share logic with next block if !Phony.plausible?(number) || _country_number != country_code_from_number(number) number = "#{_country_number}#{number}" end - elsif _default_country_number = options[:default_country_number] || country_number_for(options[:default_country_code]) + elsif _default_country_number = extract_default_country_number(options) options[:add_plus] = true if options[:add_plus].nil? - # We try to add the default country number and see if it is a - # correct phone number. See https://github.com/joost/phony_rails/issues/87#issuecomment-89324426 - unless number =~ /\A\+/ # if we don't have a + - if Phony.plausible?("#{_default_country_number}#{number}") || !Phony.plausible?(number) || country_code_from_number(number).nil? - number = "#{_default_country_number}#{number}" - elsif (number =~ /^0[^0]/) && Phony.plausible?("#{_default_country_number}#{number.gsub(/^0/, '')}") - # If the number starts with ONE zero (two might indicate a country code) - # and this is a plausible number for the default_country - # we prefer that one. - number = "#{_default_country_number}#{number.gsub(/^0/, '')}" - end - end - # number = "#{_default_country_number}#{number}" unless Phony.plausible?(number) + number = normalize_number_default_country(number, _default_country_number) end normalized_number = Phony.normalize(number) options[:add_plus] = true if options[:add_plus].nil? && Phony.plausible?(normalized_number) - options[:add_plus] ? "+#{normalized_number}" : normalized_number + normalized_number = options[:add_plus] ? "+#{normalized_number}" : normalized_number + format_extension(normalized_number, ext) rescue original_number # If all goes wrong .. we still return the original input. end + def self.normalize_number_default_country(number, default_country_number) + # We try to add the default country number and see if it is a + # correct phone number. See https://github.com/joost/phony_rails/issues/87#issuecomment-89324426 + unless number =~ /\A\+/ # if we don't have a + + if Phony.plausible?("#{default_country_number}#{number}") || !Phony.plausible?(number) || country_code_from_number(number).nil? + return "#{default_country_number}#{number}" + elsif (number =~ /^0[^0]/) && Phony.plausible?("#{default_country_number}#{number.gsub(/^0/, '')}") + # If the number starts with ONE zero (two might indicate a country code) + # and this is a plausible number for the default_country + # we prefer that one. + return "#{default_country_number}#{number.gsub(/^0/, '')}" + end + end + # number = "#{default_country_number}#{number}" unless Phony.plausible?(number) + # Just return the number unchanged + number + end + + def self.extract_default_country_number(options = {}) + options[:default_country_number] || country_number_for(options[:default_country_code]) || default_country_number + end + def self.country_code_from_number(number) return nil unless Phony.plausible?(number) Phony.split(Phony.normalize(number)).first end # Wrapper for Phony.plausible?. Takes the same options as #normalize_number. # NB: This method calls #normalize_number and passes _options_ directly to that method. def self.plausible_number?(number, options = {}) return false if number.nil? || number.blank? + number = extract_extension(number).first number = normalize_number(number, options) country_number = options[:country_number] || country_number_for(options[:country_code]) || - options[:default_country_number] || country_number_for(options[:default_country_code]) + options[:default_country_number] || country_number_for(options[:default_country_code]) || + default_country_number Phony.plausible? number, cc: country_number rescue false end + COMMON_EXTENSIONS = /[ ]*(ext|ex|x|xt|#|:)+[^0-9]*\(*([-0-9]{1,})\)*#?$/i + + def self.extract_extension(number_and_ext) + return [nil, nil] if number_and_ext.nil? + # :nocov: + if subbed = number_and_ext.sub(COMMON_EXTENSIONS, '') + [subbed, Regexp.last_match(2)] + else + [number_and_ext, nil] + end + # :nocov: + end + + def self.format_extension(number, ext) + ext.present? ? "#{number} x#{ext}" : number + end + module Extension extend ActiveSupport::Concern included do private # This methods sets the attribute to the normalized version. # It also adds the country_code (number), eg. 31 for NL numbers. def set_phony_normalized_numbers(attributes, options = {}) options = options.dup + assign_values_for_phony_symbol_options(options) if respond_to?(:country_code) set_country_as = options[:enforce_record_country] ? :country_code : :default_country_code options[set_country_as] ||= country_code end attributes.each do |attribute| @@ -96,10 +145,17 @@ raise("No attribute #{attribute_name} found on #{self.class.name} (PhonyRails)") unless self.class.attribute_method?(attribute_name) new_value = PhonyRails.normalize_number(send(attribute), options) send("#{attribute_name}=", new_value) if new_value end end + + def assign_values_for_phony_symbol_options(options) + symbol_options = [:country_number, :default_country_number, :country_code, :default_country_code] + symbol_options.each do |option| + options[option] = send(options[option]) if options[option].is_a?(Symbol) + end + end end module ClassMethods # Use this method on the class level like: # phony_normalize :phone_number, :fax_number, :default_country_code => 'NL' @@ -128,13 +184,14 @@ main_options = attributes.last.is_a?(Hash) ? attributes.pop : {} main_options.assert_valid_keys :country_code, :default_country_code attributes.each do |attribute| raise(StandardError, "Instance method normalized_#{attribute} already exists on #{name} (PhonyRails)") if method_defined?(:"normalized_#{attribute}") define_method :"normalized_#{attribute}" do |*args| - options = args.first || {} + options = main_options.merge(args.first || {}) + assign_values_for_phony_symbol_options(options) raise(ArgumentError, "No attribute/method #{attribute} found on #{self.class.name} (PhonyRails)") unless respond_to?(attribute) options[:country_code] ||= country_code if respond_to?(:country_code) - PhonyRails.normalize_number(send(attribute), main_options.merge(options)) + PhonyRails.normalize_number(send(attribute), options) end end end end end