# File lib/addressable/uri.rb, line 323
    def self.expand_template(pattern, mapping, processor=nil)

      # FIXME: MUST REFACTOR!!!

      result = pattern.dup

      reserved = Addressable::URI::CharacterClasses::RESERVED
      unreserved = Addressable::URI::CharacterClasses::UNRESERVED
      anything = reserved + unreserved
      operator_expansion =
        /\{-([a-zA-Z]+)\|([#{anything}]+)\|([#{anything}]+)\}/
      variable_expansion = /\{([#{anything}]+?)(=([#{anything}]+))?\}/

      transformed_mapping = mapping.inject({}) do |accu, pair|
        name, value = pair
        unless value.respond_to?(:to_ary) || value.respond_to?(:to_str)
          raise TypeError,
            "Can't convert #{value.class} into String or Array."
        end

        value =
          value.respond_to?(:to_ary) ? value.to_ary : value.to_str
        # Handle unicode normalization
        if value.kind_of?(Array)
          value.map! { |val| Addressable::IDNA.unicode_normalize_kc(val) }
        else
          value = Addressable::IDNA.unicode_normalize_kc(value)
        end

        if processor == nil || !processor.respond_to?(:transform)
          # Handle percent escaping
          if value.kind_of?(Array)
            transformed_value = value.map do |val|
              self.encode_component(
                val, Addressable::URI::CharacterClasses::UNRESERVED)
            end
          else
            transformed_value = self.encode_component(
              value, Addressable::URI::CharacterClasses::UNRESERVED)
          end
        end

        # Process, if we've got a processor
        if processor != nil
          if processor.respond_to?(:validate)
            if !processor.validate(name, value)
              display_value = value.kind_of?(Array) ? value.inspect : value
              raise InvalidTemplateValueError,
                "#{name}=#{display_value} is an invalid template value."
            end
          end
          if processor.respond_to?(:transform)
            transformed_value = processor.transform(name, value)
            if transformed_value.kind_of?(Array)
              transformed_value.map! do |val|
                Addressable::IDNA.unicode_normalize_kc(val)
              end
            else
              transformed_value =
                Addressable::IDNA.unicode_normalize_kc(transformed_value)
            end
          end
        end

        accu[name] = transformed_value
        accu
      end
      result.gsub!(
        /#{operator_expansion}|#{variable_expansion}/
      ) do |capture|
        if capture =~ operator_expansion
          operator, argument, variables, default_mapping =
            parse_template_expansion(capture, transformed_mapping)
          expand_method = "expand_#{operator}_operator"
          if ([expand_method, expand_method.to_sym] & private_methods).empty?
            raise InvalidTemplateOperatorError,
              "Invalid template operator: #{operator}"
          else
            send(expand_method.to_sym, argument, variables, default_mapping)
          end
        else
          varname, _, vardefault = capture.scan(/^\{(.+?)(=(.*))?\}$/)[0]
          transformed_mapping[varname] || vardefault
        end
      end
      return Addressable::URI.parse(result)
    end