These are some global methods for dealing with URI encoding and decoding in Ruby, such that it behaves exactly like JavaScript.

      # printable ASCII chars (between 32 and 126) without 0..9, A..Z, a..z
      def symbols
        ' !"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~' # symbols.length === 33
      end


      def gsub(input, replace)
        search = Regexp.new(replace.keys.map{|x| "(?:#{Regexp.quote(x)})"}.join('|'))
        input.gsub(search, replace)
      end

      # same as the JavaScript encodeURI
      def encodeURI(value)
        # encodeURI(symbols)  === "%20   ! %22   #   $ %25   &   '   (   )   *   +   , - .   /   :   ; %3C   = %3E   ?   @ %5B %5C %5D %5E _ %60 %7B %7C %7D   ~"
        # CGI.escape(symbols) === "  + %21 %22 %23 %24 %25 %26 %27 %28 %29 %2A %2B %2C - . %2F %3A %3B %3C %3D %3E %3F %40 %5B %5C %5D %5E _ %60 %7B %7C %7D %7E"
        gsub(CGI.escape(value.to_s),
            '+'   => '%20',  '%21' => '!',  '%23' => '#',  '%24' => '$',  '%26' => '&',  '%27' => "'",
            '%28' => '(',    '%29' => ')',  '%2A' => '*',  '%2B' => '+',  '%2C' => ',',  '%2F' => '/',
            '%3A' => ':',    '%3B' => ';',  '%3D' => '=',  '%3F' => '?',  '%40' => '@',  '%7E' => '~'
        )
      end

      # same as the JavaScript encodeURIComponent, also for UTF8 multibyte chars (including gclef)
      def encodeURIComponent(value)
        # encodeURIComponent(symbols) === "%20   ! %22 %23 %24 %25 %26   '   (   )   * %2B %2C - . %2F %3A %3B %3C %3D %3E %3F %40 %5B %5C %5D %5E _ %60 %7B %7C %7D   ~"
        # CGI.escape(symbols)         === "  + %21 %22 %23 %24 %25 %26 %27 %28 %29 %2A %2B %2C - . %2F %3A %3B %3C %3D %3E %3F %40 %5B %5C %5D %5E _ %60 %7B %7C %7D %7E"
        gsub(CGI.escape(value.to_s),
            '+'   => '%20',  '%21' => '!',  '%27' => "'",  '%28' => '(',  '%29' => ')',  '%2A' => '*',
            '%7E' => '~'
        )
      end

      # same as the JavaScript decodeURI
      def decodeURI(value)
        # decodeURI(encodeURI(symbols))     === symbols
        # CGI.unescape(CGI.escape(symbols)) === symbols
        CGI.unescape(gsub(value.to_s,
            '%20' => '+',    '!' => '%21',  '#' => '%23',  '$' => '%24',  '&' => '%26',  "'" => '%27',
            '('   => '%28',  ')' => '%29',  '*' => '%2A',  '+' => '%2B',  ',' => '%2C',  '/' => '%2F',
            ':'   => '%3A',  ';' => '%3B',  '=' => '%3D',  '?' => '%3F',  '@' => '%40',  '~' => '%7E'
        ))
      end

      # same as the JavaScript decodeURIComponent
      def decodeURIComponent(value)
        # decodeURIComponent(encodeURIComponent(symbols)) === symbols
        # CGI.unescape(CGI.escape(symbols))               === symbols
        CGI.unescape(gsub(value.to_s,
            '%20' => '+',    '!' => '%21',  "'" => '%27',  '(' => '%28',  ')' => '%29',  '*' => '%2A',
            '~'   => '%7E'
        ))
      end