Module: Sinatra::Decompile

Extended by:
Decompile
Included in:
Decompile, Namespace::NamespacedMethods
Defined in:
lib/sinatra/decompile.rb

Overview

Sinatra::Decompile

Sinatra::Decompile is an extension that provides a method, conveniently called decompile, that will generate a String pattern for a given route.

Usage

Classic Application

To use the extension in a classic application all you need to do is require it:

require "sinatra"
require "sinatra/decompile"

# Your classic application code goes here...

This will add the decompile method to the application/class scope, but you can also call it as Sinatra::Decompile.decompile.

Modular Application

To use the extension in a modular application you need to require it, and then, tell the application you will use it:

require "sinatra/base"
require "sinatra/decompile"

class MyApp < Sinatra::Base
  register Sinatra::Decompile

  # The rest of your modular application code goes here...
end

This will add the decompile method to the application/class scope. You can choose not to register the extension, but instead of calling decompile, you will need to call Sinatra::Decompile.decompile.

Instance Method Summary collapse

Instance Method Details

#decompile(pattern, keys = nil) ⇒ Object

Regenerates a string pattern for a given route

Example:

class Sinatra::Application
  routes.each do |verb, list|
    puts "#{verb}:"
    list.each do |data|
      puts "\t" << decompile(data)
    end
  end
end

Will return the internal Regexp if it’s unable to reconstruct the pattern, which likely indicates that a Regexp was used in the first place.

You can also use this to check whether you could actually use a string pattern instead of your regexp:

decompile /^/foo$/ # => '/foo'


70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
# File 'lib/sinatra/decompile.rb', line 70

def decompile(pattern, keys = nil, *)
  # Everything in here is basically just the reverse of
  # Sinatra::Base#compile
  #
  # Sinatra 2.0 will come with a mechanism for this, making this obsolete.
  pattern, keys = pattern if pattern.respond_to? :to_ary
  keys, str     = keys.try(:dup), pattern.inspect
  return pattern unless str.start_with? '/' and str.end_with? '/'
  str.gsub! /^\/(\^|\\A)?|(\$|\\z)?\/$/, ''
  str.gsub! encoded(' '), ' '
  return pattern if str =~ /^[\.\+]/
  capture = '((?:[^\.\/?#%]|(?:%[^2].|%[2][^Ee]))+)'
  str.gsub! /\([^\(\)]*\)|\([^\(\)]*\([^\(\)]*\)[^\(\)]*\)|#{Regexp.escape(capture)}/ do |part|
    case part
    when '(.*?)'
      return pattern if keys.shift != 'splat'
      '*'
    when /^\(\?\:(\\*.)\|%[\w\[\]]+\)$/
      $1
    when /^\(\?\:(%\d+)\|([^\)]+|\([^\)]+\))\)$/
      URI.unescape($1)
    when '([^\/?#]+)', capture
      return pattern if keys.empty?
      ":" << keys.shift
    when /^\(\?\:\\?(.)\|/
      char = $1
      return pattern unless encoded(char) == part
      Regexp.escape(char)
    else
      return pattern
    end
  end
  str.gsub /(.)([\.\+\(\)\/])/ do
    return pattern if $1 != "\\"
    $2
  end
end