Permalink
Browse files

import sinatra-decompile

  • Loading branch information...
1 parent 4bfeb5d commit 22ada43faa40e0386b2dda9ee3c03b7b151bddc1 @rkh rkh committed Mar 24, 2011
Showing with 114 additions and 0 deletions.
  1. +61 −0 lib/sinatra/decompile.rb
  2. +42 −0 spec/decompile_spec.rb
  3. +11 −0 spec/spec_helper.rb
View
61 lib/sinatra/decompile.rb
@@ -0,0 +1,61 @@
+require 'sinatra/base'
+require 'backports'
+
+module Sinatra
+ ##
+ # Can be used as extension or stand-alone:
+ #
+ # Sinatra::Decompile.decompile(...)
+ module Decompile
+ extend self
+
+ ##
+ # 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 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'
+ def decompile(pattern, keys = nil, *)
+ # Everything in here is basically just the reverse of
+ # Sinatra::Base#compile
+ 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! /^\/\^?|\$?\/$/, ''
+ return pattern if str =~ /^[\.\+]/
+ str.gsub! /\([^\(]*\)/ do |part|
+ case part
+ when '(.*?)'
+ return pattern if keys.shift != 'splat'
+ '*'
+ when '([^\/?#]+)'
+ return pattern if keys.empty?
+ ":" << keys.shift
+ else
+ return pattern
+ end
+ end
+ str.gsub /(.)([\.\+\(\)\/])/ do
+ return pattern if $1 != "\\"
+ $2
+ end
+ end
+ end
+
+ register Decompile
+end
View
42 spec/decompile_spec.rb
@@ -0,0 +1,42 @@
+require 'backports'
+require_relative 'spec_helper'
+
+RSpec::Matchers.define :decompile do |path|
+ match do |app|
+ @compiled, @keys = app.send :compile, path
+ @decompiled = app.decompile(@compiled, @keys)
+ @decompiled.should == path
+ end
+
+ failure_message_for_should do |app|
+ values = [app, @compiled, @keys, path, @decompiled].map(&:inspect)
+ "expected %s to decompile %s with %s to %s, but was %s" % values
+ end
+end
+
+describe Sinatra::Decompile do
+ subject { Sinatra::Application }
+ it { should decompile("") }
+ it { should decompile("/") }
+ it { should decompile("/?") }
+ it { should decompile("/foo") }
+ it { should decompile("/:name") }
+ it { should decompile("/:name?") }
+ it { should decompile("/:foo/:bar") }
+ it { should decompile("/page/:id/edit") }
+ it { should decompile("/hello/*") }
+ it { should decompile("/*/foo/*") }
+ it { should decompile("*") }
+ it { should decompile(":name.:format") }
+ it { should decompile(/./) }
+ it { should decompile(/f(oo)/) }
+ it { should decompile(/ba+r/) }
+
+ it 'just returns strings' do
+ subject.decompile('/foo').should == '/foo'
+ end
+
+ it 'just decompile simple regexps without keys' do
+ subject.decompile(%r{/foo}).should == '/foo'
+ end
+end
View
11 spec/spec_helper.rb
@@ -0,0 +1,11 @@
+require 'forwardable'
+
+module TestHelpers
+end
+
+require 'sinatra/contrib'
+
+RSpec.configure do |config|
+ config.expect_with :rspec, :stdlib
+ config.include Sinatra::TestHelpers
+end

0 comments on commit 22ada43

Please sign in to comment.