pendragon 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.travis.yml +13 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +64 -0
- data/README.md +159 -0
- data/Rakefile +19 -0
- data/config.ru +9 -0
- data/lib/pendragon.rb +36 -0
- data/lib/pendragon/compile_helpers.rb +41 -0
- data/lib/pendragon/configuration.rb +25 -0
- data/lib/pendragon/error_handler.rb +43 -0
- data/lib/pendragon/matcher.rb +78 -0
- data/lib/pendragon/padrino.rb +15 -0
- data/lib/pendragon/padrino/ext/class_methods.rb +306 -0
- data/lib/pendragon/padrino/ext/instance_methods.rb +63 -0
- data/lib/pendragon/padrino/route.rb +50 -0
- data/lib/pendragon/padrino/router.rb +45 -0
- data/lib/pendragon/route.rb +60 -0
- data/lib/pendragon/router.rb +188 -0
- data/lib/pendragon/version.rb +4 -0
- data/pendragon.gemspec +20 -0
- data/test/compile_helper.rb +5 -0
- data/test/helper.rb +87 -0
- data/test/padrino_test.rb +1942 -0
- data/test/pendragon_test.rb +139 -0
- metadata +168 -0
@@ -0,0 +1,60 @@
|
|
1
|
+
module Pendragon
|
2
|
+
class Route
|
3
|
+
|
4
|
+
##
|
5
|
+
# The accessors are useful to access from Pendragon::Router
|
6
|
+
attr_accessor :block, :capture, :router, :options, :verb, :order
|
7
|
+
|
8
|
+
##
|
9
|
+
# For compile option
|
10
|
+
attr_accessor :index
|
11
|
+
|
12
|
+
##
|
13
|
+
# Constructs a new instance of Pendragon::Route
|
14
|
+
def initialize(path, verb, options = {}, &block)
|
15
|
+
@block = block if block_given?
|
16
|
+
@path, @verb, @options = path, verb, options
|
17
|
+
@capture = {}
|
18
|
+
@order = 0
|
19
|
+
end
|
20
|
+
|
21
|
+
def matcher
|
22
|
+
@matcher ||= Matcher.new(@path, :capture => @capture,
|
23
|
+
:default_values => options[:default_values])
|
24
|
+
end
|
25
|
+
|
26
|
+
def arity
|
27
|
+
block.arity
|
28
|
+
end
|
29
|
+
|
30
|
+
def call(*args)
|
31
|
+
@block.call(*args)
|
32
|
+
end
|
33
|
+
|
34
|
+
def match(pattern)
|
35
|
+
matcher.match(pattern)
|
36
|
+
end
|
37
|
+
|
38
|
+
def name
|
39
|
+
@options[:name]
|
40
|
+
end
|
41
|
+
|
42
|
+
def name=(value)
|
43
|
+
warn "[DEPRECATION] 'name=' is depreacted. Please use 'options[:name]=' instead"
|
44
|
+
@options[:name] = value
|
45
|
+
end
|
46
|
+
|
47
|
+
def to(&block)
|
48
|
+
@block = block if block_given?
|
49
|
+
@order = router.current
|
50
|
+
router.increment_order!
|
51
|
+
end
|
52
|
+
|
53
|
+
def path(*args)
|
54
|
+
return @path if args.empty?
|
55
|
+
params = args[0]
|
56
|
+
params.delete(:captures)
|
57
|
+
matcher.expand(params) if matcher.mustermann?
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,188 @@
|
|
1
|
+
require 'pendragon/route'
|
2
|
+
require 'pendragon/matcher'
|
3
|
+
require 'pendragon/error_handler'
|
4
|
+
require 'pendragon/compile_helpers'
|
5
|
+
require 'pendragon/configuration'
|
6
|
+
require 'rack'
|
7
|
+
|
8
|
+
module Pendragon
|
9
|
+
class Router
|
10
|
+
|
11
|
+
# The accessors are useful to access from Pendragon::Route
|
12
|
+
attr_accessor :current, :routes
|
13
|
+
|
14
|
+
# Constructs a new instance of Pendragon::Router
|
15
|
+
# Possible to pass the block
|
16
|
+
#
|
17
|
+
# @example with a block
|
18
|
+
# app = Pendragon::Router.new do
|
19
|
+
# get("/"){ "hello!" }
|
20
|
+
# post("/"){ "hello post!" }
|
21
|
+
# end
|
22
|
+
#
|
23
|
+
# @example with base style
|
24
|
+
# app = Pendragon::Router.new
|
25
|
+
# app.get("/"){ "hello!" }
|
26
|
+
# app.post("/"){ "hello post!" }
|
27
|
+
def initialize(&block)
|
28
|
+
reset!
|
29
|
+
instance_eval(&block) if block_given?
|
30
|
+
end
|
31
|
+
|
32
|
+
# Finds the routes if request method is valid
|
33
|
+
# @return the Rack style response
|
34
|
+
def call(env)
|
35
|
+
request = Rack::Request.new(env)
|
36
|
+
raise BadRequest unless valid_verb?(request.request_method)
|
37
|
+
prepare! unless prepared?
|
38
|
+
route, params = recognize(request).first
|
39
|
+
body = route.arity != 0 ? route.call(params) : route.call
|
40
|
+
[200, {'Content-Type' => 'text/html;charset=utf-8'}, Array(body)]
|
41
|
+
rescue BadRequest, NotFound, MethodNotAllowed
|
42
|
+
$!.call
|
43
|
+
end
|
44
|
+
|
45
|
+
# Provides some methods intuitive than #add
|
46
|
+
# Basic usage is the same as #add
|
47
|
+
# @see Pendragon::Router#add
|
48
|
+
def get(path, options = {}, &block); add :get, path, options, &block end
|
49
|
+
def post(path, options = {}, &block); add :post, path, options, &block end
|
50
|
+
def delete(path, options = {}, &block); add :delete, path, options, &block end
|
51
|
+
def put(path, options = {}, &block); add :put, path, options, &block end
|
52
|
+
def head(path, options = {}, &block); add :head, path, options, &block end
|
53
|
+
|
54
|
+
# Adds a new route to router
|
55
|
+
# @return [Pendragon::Route]
|
56
|
+
def add(verb, path, options = {}, &block)
|
57
|
+
routes << (route = Route.new(path, verb, options, &block))
|
58
|
+
route.router = self
|
59
|
+
route
|
60
|
+
end
|
61
|
+
|
62
|
+
# Resets the router's instance variables
|
63
|
+
def reset!
|
64
|
+
@routes = []
|
65
|
+
@current = 0
|
66
|
+
@prepared = nil
|
67
|
+
end
|
68
|
+
|
69
|
+
# Prepares the router for route's priority
|
70
|
+
# This method is executed only once in the initial load
|
71
|
+
def prepare!
|
72
|
+
@prepared = true
|
73
|
+
@routes.sort_by!(&:order) unless current.zero?
|
74
|
+
if Pendragon.configuration.enable_compiler?
|
75
|
+
class << self
|
76
|
+
include CompileHelpers
|
77
|
+
alias_method :old_recognize, :recognize
|
78
|
+
alias_method :recognize, :recognize_by_compiling_regexp
|
79
|
+
end
|
80
|
+
compile!
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
# @return [Boolean] the router is already prepared?
|
85
|
+
def prepared?
|
86
|
+
!!@prepared
|
87
|
+
end
|
88
|
+
|
89
|
+
# Increments for the integrity of priorities
|
90
|
+
def increment_order!
|
91
|
+
@current += 1
|
92
|
+
end
|
93
|
+
|
94
|
+
# Recognizes the route by request
|
95
|
+
# @param request [Rack::Request]
|
96
|
+
# @return [Array]
|
97
|
+
def recognize(request)
|
98
|
+
path_info, verb, request_params = parse_request(request)
|
99
|
+
scan(path_info, verb) do |route|
|
100
|
+
params, match_data = {}, route.match(path_info)
|
101
|
+
if match_data.names.empty?
|
102
|
+
params[:captures] = match_data.captures
|
103
|
+
else
|
104
|
+
params.merge!(match_data.names.inject({}){|result, name|
|
105
|
+
result[name.to_sym] = match_data[name] ? Rack::Utils.unescape(match_data[name]) : nil
|
106
|
+
result
|
107
|
+
}).merge!(request_params){|key, self_val, new_val| self_val || new_val }
|
108
|
+
end
|
109
|
+
[route, params]
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
# Recognizes a given path
|
114
|
+
# @param path_info [String]
|
115
|
+
# @return [Array]
|
116
|
+
def recognize_path(path_info)
|
117
|
+
route, params = recognize(Rack::MockRequest.env_for(path_info)).first
|
118
|
+
[route.options[:name], params]
|
119
|
+
end
|
120
|
+
|
121
|
+
# Returns a expanded path matched with the conditions as arguments
|
122
|
+
# @return [String, Regexp]
|
123
|
+
# @example
|
124
|
+
# router = Pendragon.new
|
125
|
+
# index = router.get("/:id", :name => :index){}
|
126
|
+
# router.path(:index, :id => 1) #=> "/1"
|
127
|
+
# router.path(:index, :id => 2, :foo => "bar") #=> "/1?foo=bar"
|
128
|
+
def path(name, *args)
|
129
|
+
params = args.delete_at(args.last.is_a?(Hash) ? -1 : 0) || {}
|
130
|
+
saved_args = args.dup
|
131
|
+
@routes.each do |route|
|
132
|
+
next unless route.options[:name] == name
|
133
|
+
matcher = route.matcher
|
134
|
+
if !args.empty? and matcher.mustermann?
|
135
|
+
matcher_names = matcher.names
|
136
|
+
params_for_expand = Hash[matcher_names.map{|matcher_name|
|
137
|
+
[matcher_name.to_sym, (params[matcher_name.to_sym] || args.shift)]}]
|
138
|
+
params_for_expand.merge!(Hash[params.select{|k, v| !matcher_names.include?(name.to_sym) }])
|
139
|
+
args = saved_args.dup
|
140
|
+
else
|
141
|
+
params_for_expand = params.dup
|
142
|
+
end
|
143
|
+
return matcher.mustermann? ? matcher.expand(params_for_expand) : route.path
|
144
|
+
end
|
145
|
+
raise InvalidRouteException
|
146
|
+
end
|
147
|
+
|
148
|
+
private
|
149
|
+
|
150
|
+
# @!visibility private
|
151
|
+
def valid_verb?(verb)
|
152
|
+
Pendragon::HTTP_VERBS.include?(verb.downcase.to_sym)
|
153
|
+
end
|
154
|
+
|
155
|
+
# @!visibility private
|
156
|
+
def scan(pattern, verb)
|
157
|
+
raise NotFound if (selected_routes = routes.select{|route| route.match(pattern) }).empty?
|
158
|
+
|
159
|
+
result = selected_routes.map do |route|
|
160
|
+
next unless verb == route.verb
|
161
|
+
yield route
|
162
|
+
end.compact
|
163
|
+
|
164
|
+
if result.empty?
|
165
|
+
raise MethodNotAllowed.new(selected_routes.map(&:verb))
|
166
|
+
else
|
167
|
+
result
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
# @!visibility private
|
172
|
+
def parse_request(request)
|
173
|
+
if request.is_a?(Hash)
|
174
|
+
[request['PATH_INFO'], request['REQUEST_METHOD'].downcase.to_sym, {}]
|
175
|
+
else
|
176
|
+
[request.path_info, request.request_method.downcase.to_sym, parse_request_params(request.params)]
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
# @!visibility private
|
181
|
+
def parse_request_params(params)
|
182
|
+
params.inject({}) do |result, entry|
|
183
|
+
result[entry[0].to_sym] = entry[1]
|
184
|
+
result
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
data/pendragon.gemspec
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require File.expand_path("../lib/pendragon/version", __FILE__)
|
2
|
+
|
3
|
+
Gem::Specification.new "pendragon", Pendragon::VERSION do |s|
|
4
|
+
s.description = "Provides an HTTP router for use in Rack and Padrino."
|
5
|
+
s.summary = s.description
|
6
|
+
s.authors = ["namusyaka"]
|
7
|
+
s.email = "namusyaka@gmail.com"
|
8
|
+
s.homepage = "https://github.com/namusyaka/pendragon"
|
9
|
+
s.files = `git ls-files`.split("\n") - %w(.gitignore)
|
10
|
+
s.test_files = s.files.select { |path| path =~ /^test\/.*_test\.rb/ }
|
11
|
+
s.license = "MIT"
|
12
|
+
|
13
|
+
s.add_dependency "rack", ">= 1.3.0"
|
14
|
+
s.add_dependency "mustermann", "= 0.2.0"
|
15
|
+
s.add_development_dependency "rake", ">= 0.8.7"
|
16
|
+
s.add_development_dependency "rack-test", ">= 0.5.0"
|
17
|
+
s.add_development_dependency "mocha", ">= 0.10.0"
|
18
|
+
s.add_development_dependency "haml"
|
19
|
+
s.add_development_dependency "padrino-core", "= 0.12.0.rc3"
|
20
|
+
end
|
data/test/helper.rb
ADDED
@@ -0,0 +1,87 @@
|
|
1
|
+
require 'bundler/setup'
|
2
|
+
ENV['PADRINO_ENV'] = 'test'
|
3
|
+
PADRINO_ROOT = File.dirname(__FILE__) unless defined?(PADRINO_ROOT)
|
4
|
+
require File.expand_path('../../lib/pendragon', __FILE__)
|
5
|
+
|
6
|
+
require 'minitest/unit'
|
7
|
+
require 'minitest/autorun'
|
8
|
+
require 'minitest/spec'
|
9
|
+
require 'mocha/setup'
|
10
|
+
require 'padrino-core'
|
11
|
+
require 'rack'
|
12
|
+
require 'rack/test'
|
13
|
+
|
14
|
+
begin
|
15
|
+
require 'ruby-debug'
|
16
|
+
rescue LoadError; end
|
17
|
+
|
18
|
+
class Sinatra::Base
|
19
|
+
include MiniTest::Assertions
|
20
|
+
end
|
21
|
+
|
22
|
+
class MiniTest::Spec
|
23
|
+
include Rack::Test::Methods
|
24
|
+
|
25
|
+
def pendragon
|
26
|
+
@app = Pendragon.new
|
27
|
+
end
|
28
|
+
|
29
|
+
def enable_compiler?
|
30
|
+
Pendragon.configuration.enable_compiler?
|
31
|
+
end
|
32
|
+
|
33
|
+
def mock_app(base = nil, &block)
|
34
|
+
@app = Sinatra.new(base || ::Padrino::Application, &block)
|
35
|
+
end
|
36
|
+
|
37
|
+
def app
|
38
|
+
Rack::Lint.new(@app)
|
39
|
+
end
|
40
|
+
|
41
|
+
def method_missing(name, *args, &block)
|
42
|
+
if response && response.respond_to?(name)
|
43
|
+
response.send(name, *args, &block)
|
44
|
+
else
|
45
|
+
super(name, *args, &block)
|
46
|
+
end
|
47
|
+
rescue Rack::Test::Error # no response yet
|
48
|
+
super(name, *args, &block)
|
49
|
+
end
|
50
|
+
alias response last_response
|
51
|
+
|
52
|
+
class << self
|
53
|
+
alias :setup :before unless defined?(Rails)
|
54
|
+
alias :teardown :after unless defined?(Rails)
|
55
|
+
alias :should :it
|
56
|
+
alias :context :describe
|
57
|
+
def should_eventually(desc)
|
58
|
+
it("should eventually #{desc}") { skip("Should eventually #{desc}") }
|
59
|
+
end
|
60
|
+
end
|
61
|
+
alias :assert_no_match :refute_match
|
62
|
+
alias :assert_not_nil :refute_nil
|
63
|
+
alias :assert_not_equal :refute_equal
|
64
|
+
end
|
65
|
+
|
66
|
+
|
67
|
+
class ColoredIO
|
68
|
+
def initialize(io)
|
69
|
+
@io = io
|
70
|
+
end
|
71
|
+
|
72
|
+
def print(o)
|
73
|
+
case o
|
74
|
+
when "." then @io.send(:print, o.colorize(:green))
|
75
|
+
when "E" then @io.send(:print, o.colorize(:red))
|
76
|
+
when "F" then @io.send(:print, o.colorize(:yellow))
|
77
|
+
when "S" then @io.send(:print, o.colorize(:magenta))
|
78
|
+
else @io.send(:print, o)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def puts(*o)
|
83
|
+
super
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
MiniTest::Unit.output = ColoredIO.new($stdout)
|
@@ -0,0 +1,1942 @@
|
|
1
|
+
require File.expand_path('../../lib/pendragon/padrino', __FILE__)
|
2
|
+
$:.unshift(File.dirname(__FILE__))
|
3
|
+
require 'helper'
|
4
|
+
|
5
|
+
class FooError < RuntimeError; end
|
6
|
+
|
7
|
+
describe "Pendragon::Padrino" do
|
8
|
+
setup do
|
9
|
+
Padrino::Application.send(:register, Padrino::Rendering)
|
10
|
+
Padrino::Application.send(:register, Pendragon::Padrino)
|
11
|
+
Padrino::Rendering::DEFAULT_RENDERING_OPTIONS[:strict_format] = false
|
12
|
+
end
|
13
|
+
|
14
|
+
should "serve static files with simple cache control" do
|
15
|
+
mock_app do
|
16
|
+
set :static_cache_control, :public
|
17
|
+
set :public_folder, File.dirname(__FILE__)
|
18
|
+
end
|
19
|
+
get "/#{File.basename(__FILE__)}"
|
20
|
+
assert headers.has_key?('Cache-Control')
|
21
|
+
assert_equal headers['Cache-Control'], 'public'
|
22
|
+
end # static simple
|
23
|
+
|
24
|
+
should "serve static files with cache control and max_age" do
|
25
|
+
mock_app do
|
26
|
+
set :static_cache_control, [:public, :must_revalidate, {:max_age => 300}]
|
27
|
+
set :public_folder, File.dirname(__FILE__)
|
28
|
+
end
|
29
|
+
get "/#{File.basename(__FILE__)}"
|
30
|
+
assert headers.has_key?('Cache-Control')
|
31
|
+
assert_equal headers['Cache-Control'], 'public, must-revalidate, max-age=300'
|
32
|
+
end # static max_age
|
33
|
+
|
34
|
+
should 'ignore trailing delimiters for basic route' do
|
35
|
+
mock_app do
|
36
|
+
get("/foo"){ "okey" }
|
37
|
+
get(:test) { "tester" }
|
38
|
+
end
|
39
|
+
get "/foo"
|
40
|
+
assert_equal "okey", body
|
41
|
+
get "/foo/"
|
42
|
+
assert_equal "okey", body
|
43
|
+
get "/test"
|
44
|
+
assert_equal "tester", body
|
45
|
+
get "/test/"
|
46
|
+
assert_equal "tester", body
|
47
|
+
end
|
48
|
+
|
49
|
+
should 'fail with unrecognized route exception when not found' do
|
50
|
+
mock_app do
|
51
|
+
get(:index){ "okey" }
|
52
|
+
end
|
53
|
+
get @app.url_for(:index)
|
54
|
+
assert_equal "okey", body
|
55
|
+
assert_raises(Padrino::Routing::UnrecognizedException) {
|
56
|
+
get @app.url_for(:fake)
|
57
|
+
}
|
58
|
+
end
|
59
|
+
|
60
|
+
should 'accept regexp routes' do
|
61
|
+
mock_app do
|
62
|
+
get(%r./fob|/baz.) { "regexp" }
|
63
|
+
get("/foo") { "str" }
|
64
|
+
get %r./([0-9]+)/. do |num|
|
65
|
+
"Your lucky number: #{num} #{params[:captures].first}"
|
66
|
+
end
|
67
|
+
get %r./page/([0-9]+)|/. do |num|
|
68
|
+
"My lucky number: #{num} #{params[:captures].first}"
|
69
|
+
end
|
70
|
+
end
|
71
|
+
get "/foo"
|
72
|
+
assert_equal "str", body
|
73
|
+
get "/fob"
|
74
|
+
assert_equal "regexp", body
|
75
|
+
get "/baz"
|
76
|
+
assert_equal "regexp", body
|
77
|
+
get "/321/"
|
78
|
+
assert_equal "Your lucky number: 321 321", body
|
79
|
+
get "/page/99"
|
80
|
+
assert_equal "My lucky number: 99 99", body
|
81
|
+
end
|
82
|
+
|
83
|
+
should 'accept regexp routes with generate with :generate_with' do
|
84
|
+
mock_app do
|
85
|
+
get(%r{/fob|/baz}, :name => :foo, :generate_with => '/fob') { "regexp" }
|
86
|
+
end
|
87
|
+
assert_equal "/fob", @app.url(:foo)
|
88
|
+
end
|
89
|
+
|
90
|
+
should "parse routes with question marks" do
|
91
|
+
mock_app do
|
92
|
+
get("/foo/?"){ "okey" }
|
93
|
+
post('/unauthenticated/?') { "no access" }
|
94
|
+
end
|
95
|
+
get "/foo"
|
96
|
+
assert_equal "okey", body
|
97
|
+
get "/foo/"
|
98
|
+
assert_equal "okey", body
|
99
|
+
post "/unauthenticated"
|
100
|
+
assert_equal "no access", body
|
101
|
+
post "/unauthenticated/"
|
102
|
+
assert_equal "no access", body
|
103
|
+
end
|
104
|
+
|
105
|
+
should 'parse routes that are encoded' do
|
106
|
+
mock_app do
|
107
|
+
get('/щч') { 'success!' }
|
108
|
+
end
|
109
|
+
get(URI.escape('/щч'))
|
110
|
+
assert_equal 'success!', body
|
111
|
+
end
|
112
|
+
|
113
|
+
should 'parse routes that include encoded slash' do
|
114
|
+
mock_app do
|
115
|
+
get('/:drive_alias/:path', :path => /.*/){
|
116
|
+
"Show #{params[:drive_alias]} and #{params[:path]}"
|
117
|
+
}
|
118
|
+
end
|
119
|
+
get("/drive%2Ffoo/some/path")
|
120
|
+
assert_equal "Show drive/foo and some/path", body
|
121
|
+
end
|
122
|
+
|
123
|
+
should 'parse route that contains encoded param.' do
|
124
|
+
mock_app do
|
125
|
+
get('/foo/:name'){ params[:name] }
|
126
|
+
end
|
127
|
+
get(URI.escape('/foo/あいうえお'))
|
128
|
+
assert_equal 'あいうえお', body
|
129
|
+
end
|
130
|
+
|
131
|
+
should 'encode params using UTF-8' do
|
132
|
+
mock_app do
|
133
|
+
get('/:foo') { params[:foo].encoding.name }
|
134
|
+
end
|
135
|
+
get '/bar'
|
136
|
+
assert_equal 'UTF-8', body
|
137
|
+
end
|
138
|
+
|
139
|
+
should 'match correctly similar paths' do
|
140
|
+
mock_app do
|
141
|
+
get("/my/:foo_id"){ params[:foo_id] }
|
142
|
+
get("/my/:bar_id/bar"){ params[:bar_id] }
|
143
|
+
end
|
144
|
+
get "/my/1"
|
145
|
+
assert_equal "1", body
|
146
|
+
get "/my/2/bar"
|
147
|
+
assert_equal "2", body
|
148
|
+
end
|
149
|
+
|
150
|
+
should "match user agents" do
|
151
|
+
skip if enable_compiler?
|
152
|
+
app = mock_app do
|
153
|
+
get("/main", :agent => /IE/){ "hello IE" }
|
154
|
+
get("/main"){ "hello" }
|
155
|
+
end
|
156
|
+
get "/main"
|
157
|
+
assert_equal "hello", body
|
158
|
+
get "/main", {}, {'HTTP_USER_AGENT' => 'This is IE'}
|
159
|
+
assert_equal "hello IE", body
|
160
|
+
end
|
161
|
+
|
162
|
+
should "use regex for parts of a route" do
|
163
|
+
app = mock_app do
|
164
|
+
get("/main/:id", :id => /\d+/){ "hello #{params[:id]}" }
|
165
|
+
end
|
166
|
+
get "/main/123"
|
167
|
+
assert_equal "hello 123", body
|
168
|
+
get "/main/asd"
|
169
|
+
assert_equal 404, status
|
170
|
+
end
|
171
|
+
|
172
|
+
should "parse params when use regex for parts of a route" do
|
173
|
+
mock_app do
|
174
|
+
post :index, :with => [:foo, :bar], :bar => /.+/ do
|
175
|
+
"show #{params[:foo]}"
|
176
|
+
end
|
177
|
+
|
178
|
+
get :index, :map => '/mystuff/:a_id/boing/:boing_id' do
|
179
|
+
"show #{params[:a_id]} and #{params[:boing_id]}"
|
180
|
+
end
|
181
|
+
end
|
182
|
+
get "/mystuff/5/boing/2"
|
183
|
+
assert_equal "show 5 and 2", body
|
184
|
+
end
|
185
|
+
|
186
|
+
should "not generate overlapping head urls" do
|
187
|
+
app = mock_app do
|
188
|
+
get("/main"){ "hello" }
|
189
|
+
post("/main"){ "hello" }
|
190
|
+
end
|
191
|
+
assert_equal 3, app.routes.size, "should generate GET, HEAD and PUT"
|
192
|
+
assert_equal "GET", app.routes[0].request_methods.first
|
193
|
+
assert_equal "HEAD", app.routes[1].request_methods.first
|
194
|
+
assert_equal "POST", app.routes[2].request_methods.first
|
195
|
+
end
|
196
|
+
|
197
|
+
should 'generate basic urls' do
|
198
|
+
mock_app do
|
199
|
+
get(:foo){ "/foo" }
|
200
|
+
get(:foo, :with => :id){ |id| "/foo/#{id}" }
|
201
|
+
get([:foo, :id]){ |id| "/foo/#{id}" }
|
202
|
+
get(:hash, :with => :id){ url(:hash, :id => 1) }
|
203
|
+
get([:hash, :id]){ url(:hash, :id => 1) }
|
204
|
+
get(:array, :with => :id){ url(:array, 23) }
|
205
|
+
get([:array, :id]){ url(:array, 23) }
|
206
|
+
get(:hash_with_extra, :with => :id){ url(:hash_with_extra, :id => 1, :query => 'string') }
|
207
|
+
get([:hash_with_extra, :id]){ url(:hash_with_extra, :id => 1, :query => 'string') }
|
208
|
+
get(:array_with_extra, :with => :id){ url(:array_with_extra, 23, :query => 'string') }
|
209
|
+
get([:array_with_extra, :id]){ url(:array_with_extra, 23, :query => 'string') }
|
210
|
+
get("/old-bar/:id"){ params[:id] }
|
211
|
+
post(:mix, :map => "/mix-bar/:id"){ params[:id] }
|
212
|
+
get(:mix, :map => "/mix-bar/:id"){ params[:id] }
|
213
|
+
end
|
214
|
+
get "/foo"
|
215
|
+
assert_equal "/foo", body
|
216
|
+
get "/foo/123"
|
217
|
+
assert_equal "/foo/123", body
|
218
|
+
get "/hash/2"
|
219
|
+
assert_equal "/hash/1", body
|
220
|
+
get "/array/23"
|
221
|
+
assert_equal "/array/23", body
|
222
|
+
get "/hash_with_extra/1"
|
223
|
+
assert_equal "/hash_with_extra/1?query=string", body
|
224
|
+
get "/array_with_extra/23"
|
225
|
+
assert_equal "/array_with_extra/23?query=string", body
|
226
|
+
get "/old-bar/3"
|
227
|
+
assert_equal "3", body
|
228
|
+
post "/mix-bar/4"
|
229
|
+
assert_equal "4", body
|
230
|
+
get "/mix-bar/4"
|
231
|
+
assert_equal "4", body
|
232
|
+
end
|
233
|
+
|
234
|
+
should 'generate url with format' do
|
235
|
+
mock_app do
|
236
|
+
get(:a, :provides => :any){ url(:a, :format => :json) }
|
237
|
+
get(:b, :provides => :js){ url(:b, :format => :js) }
|
238
|
+
get(:c, :provides => [:js, :json]){ url(:c, :format => :json) }
|
239
|
+
get(:d, :provides => [:html, :js]){ url(:d, :format => :js, :foo => :bar) }
|
240
|
+
end
|
241
|
+
get "/a.js"
|
242
|
+
assert_equal "/a.json", body
|
243
|
+
get "/b.js"
|
244
|
+
assert_equal "/b.js", body
|
245
|
+
get "/b.ru"
|
246
|
+
assert_equal 404, status
|
247
|
+
get "/c.js"
|
248
|
+
assert_equal "/c.json", body
|
249
|
+
get "/c.json"
|
250
|
+
assert_equal "/c.json", body
|
251
|
+
get "/c.ru"
|
252
|
+
assert_equal 404, status
|
253
|
+
get "/d"
|
254
|
+
assert_equal "/d.js?foo=bar", body
|
255
|
+
get "/d.js"
|
256
|
+
assert_equal "/d.js?foo=bar", body
|
257
|
+
get "/e.xml"
|
258
|
+
assert_equal 404, status
|
259
|
+
end
|
260
|
+
|
261
|
+
should 'generate absolute urls' do
|
262
|
+
mock_app do
|
263
|
+
get(:hash, :with => :id){ absolute_url(:hash, :id => 1) }
|
264
|
+
end
|
265
|
+
get "/hash/2"
|
266
|
+
assert_equal "http://example.org/hash/1", body
|
267
|
+
get "https://example.org/hash/2"
|
268
|
+
assert_equal "https://example.org/hash/1", body
|
269
|
+
end
|
270
|
+
|
271
|
+
should 'generate proper absolute urls for mounted apps' do
|
272
|
+
class Test < Padrino::Application
|
273
|
+
get :foo do
|
274
|
+
absolute_url(:foo, :id => 1)
|
275
|
+
end
|
276
|
+
end
|
277
|
+
Padrino.mount("Test").to("/test")
|
278
|
+
@app = Padrino.application
|
279
|
+
get('/test/foo')
|
280
|
+
assert_equal 'http://example.org/test/foo?id=1', body
|
281
|
+
end
|
282
|
+
|
283
|
+
should 'allow regex url with format' do
|
284
|
+
mock_app do
|
285
|
+
get(/.*/, :provides => :any) { "regexp" }
|
286
|
+
end
|
287
|
+
get "/anything"
|
288
|
+
assert_equal "regexp", body
|
289
|
+
end
|
290
|
+
|
291
|
+
should 'use padrino url method' do
|
292
|
+
mock_app do
|
293
|
+
end
|
294
|
+
|
295
|
+
assert_equal @app.method(:url).owner, Pendragon::Padrino::ClassMethods
|
296
|
+
end
|
297
|
+
|
298
|
+
should 'work correctly with sinatra redirects' do
|
299
|
+
mock_app do
|
300
|
+
get(:index) { redirect url(:index) }
|
301
|
+
get(:google) { redirect "http://google.com" }
|
302
|
+
get("/foo") { redirect "/bar" }
|
303
|
+
get("/bar") { "Bar" }
|
304
|
+
end
|
305
|
+
|
306
|
+
get "/"
|
307
|
+
assert_equal "http://example.org/", headers['Location']
|
308
|
+
get "/google"
|
309
|
+
assert_equal "http://google.com", headers['Location']
|
310
|
+
get "/foo"
|
311
|
+
assert_equal "http://example.org/bar", headers['Location']
|
312
|
+
end
|
313
|
+
|
314
|
+
should "return 406 on Accept-Headers it does not provide" do
|
315
|
+
mock_app do
|
316
|
+
get(:a, :provides => [:html, :js]){ content_type }
|
317
|
+
end
|
318
|
+
|
319
|
+
get "/a", {}, {"HTTP_ACCEPT" => "application/yaml"}
|
320
|
+
assert_equal 406, status
|
321
|
+
end
|
322
|
+
|
323
|
+
should "return 406 on file extensions it does not provide and flag is set" do
|
324
|
+
mock_app do
|
325
|
+
enable :treat_format_as_accept
|
326
|
+
get(:a, :provides => [:html, :js]){ content_type }
|
327
|
+
end
|
328
|
+
|
329
|
+
get "/a.xml", {}, {}
|
330
|
+
assert_equal 406, status
|
331
|
+
end
|
332
|
+
|
333
|
+
should "return 404 on file extensions it does not provide and flag is not set" do
|
334
|
+
mock_app do
|
335
|
+
get(:a, :provides => [:html, :js]){ content_type }
|
336
|
+
end
|
337
|
+
|
338
|
+
get "/a.xml", {}, {}
|
339
|
+
assert_equal 404, status
|
340
|
+
end
|
341
|
+
|
342
|
+
should "not set content_type to :html if Accept */* and html not in provides" do
|
343
|
+
mock_app do
|
344
|
+
get("/foo", :provides => [:json, :xml]) { content_type.to_s }
|
345
|
+
end
|
346
|
+
|
347
|
+
get '/foo', {}, { 'HTTP_ACCEPT' => '*/*;q=0.5' }
|
348
|
+
assert_equal 'json', body
|
349
|
+
end
|
350
|
+
|
351
|
+
should "set content_type to :json if Accept contains */*" do
|
352
|
+
mock_app do
|
353
|
+
get("/foo", :provides => [:json]) { content_type.to_s }
|
354
|
+
end
|
355
|
+
|
356
|
+
get '/foo', {}, { 'HTTP_ACCEPT' => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8' }
|
357
|
+
assert_equal 'json', body
|
358
|
+
end
|
359
|
+
|
360
|
+
should 'set and get content_type' do
|
361
|
+
mock_app do
|
362
|
+
get("/foo"){ content_type(:json); content_type.to_s }
|
363
|
+
end
|
364
|
+
get "/foo"
|
365
|
+
assert_equal 'application/json', content_type
|
366
|
+
assert_equal 'json', body
|
367
|
+
end
|
368
|
+
|
369
|
+
should "send the appropriate number of params" do
|
370
|
+
mock_app do
|
371
|
+
get('/id/:user_id', :provides => [:json]) { |user_id, format| user_id}
|
372
|
+
end
|
373
|
+
get '/id/5.json'
|
374
|
+
assert_equal '5', body
|
375
|
+
end
|
376
|
+
|
377
|
+
should "allow .'s in param values" do
|
378
|
+
#skip
|
379
|
+
mock_app do
|
380
|
+
get('/id/:email', :provides => [:json]) { |email, format| [email, format] * '/' }
|
381
|
+
end
|
382
|
+
get '/id/foo@bar.com.json'
|
383
|
+
assert_equal 'foo@bar.com/json', body
|
384
|
+
end
|
385
|
+
|
386
|
+
should "set correct content_type for Accept not equal to */* even if */* also provided" do
|
387
|
+
mock_app do
|
388
|
+
get("/foo", :provides => [:html, :js, :xml]) { content_type.to_s }
|
389
|
+
end
|
390
|
+
|
391
|
+
get '/foo', {}, { 'HTTP_ACCEPT' => 'application/javascript, */*;q=0.5' }
|
392
|
+
assert_equal 'js', body
|
393
|
+
end
|
394
|
+
|
395
|
+
should "return the first content type in provides if accept header is empty" do
|
396
|
+
mock_app do
|
397
|
+
get(:a, :provides => [:js]){ content_type.to_s }
|
398
|
+
end
|
399
|
+
|
400
|
+
get "/a", {}, {}
|
401
|
+
assert_equal "js", body
|
402
|
+
end
|
403
|
+
|
404
|
+
should "not default to HTML if HTML is not provided and no type is given" do
|
405
|
+
mock_app do
|
406
|
+
get(:a, :provides => [:js]){ content_type }
|
407
|
+
end
|
408
|
+
|
409
|
+
get "/a", {}, {}
|
410
|
+
assert_equal "application/javascript;charset=utf-8", content_type
|
411
|
+
end
|
412
|
+
|
413
|
+
should "not match routes if url_format and http_accept is provided but not included" do
|
414
|
+
mock_app do
|
415
|
+
get(:a, :provides => [:js, :html]){ content_type }
|
416
|
+
end
|
417
|
+
|
418
|
+
get "/a.xml", {}, {"HTTP_ACCEPT" => "text/html"}
|
419
|
+
assert_equal 404, status
|
420
|
+
end
|
421
|
+
|
422
|
+
should "generate routes for format simple" do
|
423
|
+
mock_app do
|
424
|
+
get(:foo, :provides => [:html, :rss]) { render :haml, "Test" }
|
425
|
+
end
|
426
|
+
get "/foo"
|
427
|
+
assert_equal "Test\n", body
|
428
|
+
get "/foo.rss"
|
429
|
+
assert_equal "Test\n", body
|
430
|
+
end
|
431
|
+
|
432
|
+
should "should inject the controller name into the request" do
|
433
|
+
mock_app do
|
434
|
+
controller :posts do
|
435
|
+
get(:index) { request.controller }
|
436
|
+
controller :mini do
|
437
|
+
get(:index) { request.controller }
|
438
|
+
end
|
439
|
+
end
|
440
|
+
end
|
441
|
+
get "/posts"
|
442
|
+
assert_equal "posts", body
|
443
|
+
get "/mini"
|
444
|
+
assert_equal "mini", body
|
445
|
+
end
|
446
|
+
|
447
|
+
should "should inject the action name into the request" do
|
448
|
+
mock_app do
|
449
|
+
controller :posts do
|
450
|
+
get('/omnomnom(/:id)?') { request.action.inspect }
|
451
|
+
controller :mini do
|
452
|
+
get([:a, :b, :c]) { request.action.inspect }
|
453
|
+
end
|
454
|
+
end
|
455
|
+
end
|
456
|
+
get "/posts/omnomnom"
|
457
|
+
assert_equal "\"/omnomnom(/:id)?\"", body
|
458
|
+
get "/mini/a/b/c"
|
459
|
+
assert_equal ":a", body
|
460
|
+
end
|
461
|
+
|
462
|
+
should "support not_found" do
|
463
|
+
mock_app do
|
464
|
+
not_found { 'whatever' }
|
465
|
+
|
466
|
+
get :index, :map => "/" do
|
467
|
+
'index'
|
468
|
+
end
|
469
|
+
end
|
470
|
+
get '/wrong'
|
471
|
+
assert_equal 404, status
|
472
|
+
assert_equal 'whatever', body
|
473
|
+
get '/'
|
474
|
+
assert_equal 'index', body
|
475
|
+
assert_equal 200, status
|
476
|
+
end
|
477
|
+
|
478
|
+
should "should inject the route into the request" do
|
479
|
+
mock_app do
|
480
|
+
controller :posts do
|
481
|
+
get(:index) { request.route_obj.name.to_s }
|
482
|
+
end
|
483
|
+
end
|
484
|
+
get "/posts"
|
485
|
+
assert_equal "posts index", body
|
486
|
+
end
|
487
|
+
|
488
|
+
should "preserve the format if you set it manually" do
|
489
|
+
mock_app do
|
490
|
+
before do
|
491
|
+
params[:format] = "json"
|
492
|
+
end
|
493
|
+
|
494
|
+
get "test", :provides => [:html, :json] do
|
495
|
+
content_type.inspect
|
496
|
+
end
|
497
|
+
end
|
498
|
+
get "/test"
|
499
|
+
assert_equal ":json", body
|
500
|
+
get "/test.html"
|
501
|
+
assert_equal ":json", body
|
502
|
+
get "/test.php"
|
503
|
+
assert_equal ":json", body
|
504
|
+
end
|
505
|
+
|
506
|
+
should "correctly accept '.' in the route" do
|
507
|
+
mock_app do
|
508
|
+
get "test.php", :provides => [:html, :json] do
|
509
|
+
content_type.inspect
|
510
|
+
end
|
511
|
+
end
|
512
|
+
get "/test.php"
|
513
|
+
assert_equal ":html", body
|
514
|
+
get "/test.php.json"
|
515
|
+
assert_equal ":json", body
|
516
|
+
end
|
517
|
+
|
518
|
+
should "correctly accept priority of format" do
|
519
|
+
mock_app do
|
520
|
+
get "test.php", :provides => [:html, :json, :xml] do
|
521
|
+
content_type.inspect
|
522
|
+
end
|
523
|
+
end
|
524
|
+
|
525
|
+
get "/test.php"
|
526
|
+
assert_equal ":html", body
|
527
|
+
get "/test.php", {}, { 'HTTP_ACCEPT' => 'application/xml' }
|
528
|
+
assert_equal ":xml", body
|
529
|
+
get "/test.php?format=json", { 'HTTP_ACCEPT' => 'application/xml' }
|
530
|
+
assert_equal ":json", body
|
531
|
+
get "/test.php.json?format=html", { 'HTTP_ACCEPT' => 'application/xml' }
|
532
|
+
assert_equal ":json", body
|
533
|
+
end
|
534
|
+
|
535
|
+
should "generate routes for format with controller" do
|
536
|
+
mock_app do
|
537
|
+
controller :posts do
|
538
|
+
get(:index, :provides => [:html, :rss, :atom, :js]) { render :haml, "Index.#{content_type}" }
|
539
|
+
get(:show, :with => :id, :provides => [:html, :rss, :atom]) { render :haml, "Show.#{content_type}" }
|
540
|
+
end
|
541
|
+
end
|
542
|
+
get "/posts"
|
543
|
+
assert_equal "Index.html\n", body
|
544
|
+
get "/posts.rss"
|
545
|
+
assert_equal "Index.rss\n", body
|
546
|
+
get "/posts.atom"
|
547
|
+
assert_equal "Index.atom\n", body
|
548
|
+
get "/posts.js"
|
549
|
+
assert_equal "Index.js\n", body
|
550
|
+
get "/posts/show/5"
|
551
|
+
assert_equal "Show.html\n", body
|
552
|
+
get "/posts/show/5.rss"
|
553
|
+
assert_equal "Show.rss\n", body
|
554
|
+
get "/posts/show/10.atom"
|
555
|
+
assert_equal "Show.atom\n", body
|
556
|
+
end
|
557
|
+
|
558
|
+
should 'map routes' do
|
559
|
+
mock_app do
|
560
|
+
get(:bar){ "bar" }
|
561
|
+
end
|
562
|
+
get "/bar"
|
563
|
+
assert_equal "bar", body
|
564
|
+
assert_equal "/bar", @app.url(:bar)
|
565
|
+
end
|
566
|
+
|
567
|
+
should 'remove index from path' do
|
568
|
+
mock_app do
|
569
|
+
get(:index){ "index" }
|
570
|
+
get("/accounts/index"){ "accounts" }
|
571
|
+
end
|
572
|
+
get "/"
|
573
|
+
assert_equal "index", body
|
574
|
+
assert_equal "/", @app.url(:index)
|
575
|
+
get "/accounts/index"
|
576
|
+
assert_equal "accounts", body
|
577
|
+
end
|
578
|
+
|
579
|
+
should 'remove index from path with params' do
|
580
|
+
mock_app do
|
581
|
+
get(:index, :with => :name){ "index with #{params[:name]}" }
|
582
|
+
end
|
583
|
+
get "/bobby"
|
584
|
+
assert_equal "index with bobby", body
|
585
|
+
assert_equal "/john", @app.url(:index, :name => "john")
|
586
|
+
end
|
587
|
+
|
588
|
+
should 'parse named params' do
|
589
|
+
mock_app do
|
590
|
+
get(:print, :with => :id){ "Im #{params[:id]}" }
|
591
|
+
end
|
592
|
+
get "/print/9"
|
593
|
+
assert_equal "Im 9", body
|
594
|
+
assert_equal "/print/9", @app.url(:print, :id => 9)
|
595
|
+
end
|
596
|
+
|
597
|
+
should '405 on wrong request_method' do
|
598
|
+
skip if enable_compiler?
|
599
|
+
mock_app do
|
600
|
+
post('/bar'){ "bar" }
|
601
|
+
end
|
602
|
+
get "/bar"
|
603
|
+
assert_equal 405, status
|
604
|
+
end
|
605
|
+
|
606
|
+
should 'respond to' do
|
607
|
+
mock_app do
|
608
|
+
get(:a, :provides => :js){ "js" }
|
609
|
+
get(:b, :provides => :any){ "any" }
|
610
|
+
get(:c, :provides => [:js, :json]){ "js,json" }
|
611
|
+
get(:d, :provides => [:html, :js]){ "html,js"}
|
612
|
+
end
|
613
|
+
get "/a"
|
614
|
+
assert_equal 200, status
|
615
|
+
assert_equal "js", body
|
616
|
+
get "/a.js"
|
617
|
+
assert_equal "js", body
|
618
|
+
get "/b"
|
619
|
+
assert_equal "any", body
|
620
|
+
# TODO randomly fails in minitest :(
|
621
|
+
# assert_raises(RuntimeError) { get "/b.foo" }
|
622
|
+
get "/c"
|
623
|
+
assert_equal 200, status
|
624
|
+
assert_equal "js,json", body
|
625
|
+
get "/c.js"
|
626
|
+
assert_equal "js,json", body
|
627
|
+
get "/c.json"
|
628
|
+
assert_equal "js,json", body
|
629
|
+
get "/d"
|
630
|
+
assert_equal "html,js", body
|
631
|
+
get "/d.js"
|
632
|
+
assert_equal "html,js", body
|
633
|
+
end
|
634
|
+
|
635
|
+
should 'respond_to and set content_type' do
|
636
|
+
Rack::Mime::MIME_TYPES['.foo'] = 'application/foo'
|
637
|
+
mock_app do
|
638
|
+
get :a, :provides => :any do
|
639
|
+
case content_type
|
640
|
+
when :js then "js"
|
641
|
+
when :json then "json"
|
642
|
+
when :foo then "foo"
|
643
|
+
when :html then "html"
|
644
|
+
end
|
645
|
+
end
|
646
|
+
end
|
647
|
+
get "/a.js"
|
648
|
+
assert_equal "js", body
|
649
|
+
assert_equal 'application/javascript;charset=utf-8', response["Content-Type"]
|
650
|
+
get "/a.json"
|
651
|
+
assert_equal "json", body
|
652
|
+
assert_equal 'application/json;charset=utf-8', response["Content-Type"]
|
653
|
+
get "/a.foo"
|
654
|
+
assert_equal "foo", body
|
655
|
+
assert_equal 'application/foo;charset=utf-8', response["Content-Type"]
|
656
|
+
get "/a"
|
657
|
+
assert_equal "html", body
|
658
|
+
assert_equal 'text/html;charset=utf-8', response["Content-Type"]
|
659
|
+
end
|
660
|
+
|
661
|
+
should 'use controllers' do
|
662
|
+
mock_app do
|
663
|
+
controller "/admin" do
|
664
|
+
get("/"){ "index" }
|
665
|
+
get("/show/:id"){ "show #{params[:id]}" }
|
666
|
+
end
|
667
|
+
end
|
668
|
+
get "/admin"
|
669
|
+
assert_equal "index", body
|
670
|
+
get "/admin/show/1"
|
671
|
+
assert_equal "show 1", body
|
672
|
+
end
|
673
|
+
|
674
|
+
should 'use named controllers' do
|
675
|
+
mock_app do
|
676
|
+
controller :admin do
|
677
|
+
get(:index, :with => :id){ params[:id] }
|
678
|
+
get(:show, :with => :id){ "show #{params[:id]}" }
|
679
|
+
end
|
680
|
+
controllers :foo, :bar do
|
681
|
+
get(:index){ "foo_bar_index" }
|
682
|
+
end
|
683
|
+
end
|
684
|
+
get "/admin/1"
|
685
|
+
assert_equal "1", body
|
686
|
+
get "/admin/show/1"
|
687
|
+
assert_equal "show 1", body
|
688
|
+
assert_equal "/admin/1", @app.url(:admin, :index, :id => 1)
|
689
|
+
assert_equal "/admin/show/1", @app.url(:admin, :show, :id => 1)
|
690
|
+
get "/foo/bar"
|
691
|
+
assert_equal "foo_bar_index", body
|
692
|
+
end
|
693
|
+
|
694
|
+
should 'use map and with' do
|
695
|
+
mock_app do
|
696
|
+
get :index, :map => '/bugs', :with => :id do
|
697
|
+
params[:id]
|
698
|
+
end
|
699
|
+
end
|
700
|
+
get '/bugs/4'
|
701
|
+
assert_equal '4', body
|
702
|
+
assert_equal "/bugs/4", @app.url(:index, :id => 4)
|
703
|
+
end
|
704
|
+
|
705
|
+
should "ignore trailing delimiters within a named controller" do
|
706
|
+
mock_app do
|
707
|
+
controller :posts do
|
708
|
+
get(:index, :provides => [:html, :js]){ "index" }
|
709
|
+
get(:new) { "new" }
|
710
|
+
get(:show, :with => :id){ "show #{params[:id]}" }
|
711
|
+
end
|
712
|
+
end
|
713
|
+
get "/posts"
|
714
|
+
assert_equal "index", body
|
715
|
+
get "/posts/"
|
716
|
+
assert_equal "index", body
|
717
|
+
get "/posts.js"
|
718
|
+
assert_equal "index", body
|
719
|
+
get "/posts.js/"
|
720
|
+
assert_equal "index", body
|
721
|
+
get "/posts/new"
|
722
|
+
assert_equal "new", body
|
723
|
+
get "/posts/new/"
|
724
|
+
assert_equal "new", body
|
725
|
+
end
|
726
|
+
|
727
|
+
should "ignore trailing delimiters within a named controller for unnamed actions" do
|
728
|
+
mock_app do
|
729
|
+
controller :accounts do
|
730
|
+
get("/") { "account_index" }
|
731
|
+
get("/new") { "new" }
|
732
|
+
end
|
733
|
+
controller :votes do
|
734
|
+
get("/") { "vote_index" }
|
735
|
+
end
|
736
|
+
end
|
737
|
+
get "/accounts"
|
738
|
+
assert_equal "account_index", body
|
739
|
+
get "/accounts/"
|
740
|
+
assert_equal "account_index", body
|
741
|
+
get "/accounts/new"
|
742
|
+
assert_equal "new", body
|
743
|
+
get "/accounts/new/"
|
744
|
+
assert_equal "new", body
|
745
|
+
get "/votes"
|
746
|
+
assert_equal "vote_index", body
|
747
|
+
get "/votes/"
|
748
|
+
assert_equal "vote_index", body
|
749
|
+
end
|
750
|
+
|
751
|
+
should 'use named controllers with array routes' do
|
752
|
+
mock_app do
|
753
|
+
controller :admin do
|
754
|
+
get(:index){ "index" }
|
755
|
+
get(:show, :with => :id){ "show #{params[:id]}" }
|
756
|
+
end
|
757
|
+
controllers :foo, :bar do
|
758
|
+
get(:index){ "foo_bar_index" }
|
759
|
+
end
|
760
|
+
end
|
761
|
+
get "/admin"
|
762
|
+
assert_equal "index", body
|
763
|
+
get "/admin/show/1"
|
764
|
+
assert_equal "show 1", body
|
765
|
+
assert_equal "/admin", @app.url(:admin, :index)
|
766
|
+
assert_equal "/admin/show/1", @app.url(:admin, :show, :id => 1)
|
767
|
+
get "/foo/bar"
|
768
|
+
assert_equal "foo_bar_index", body
|
769
|
+
end
|
770
|
+
|
771
|
+
should "support a reindex action and remove index inside controller" do
|
772
|
+
mock_app do
|
773
|
+
controller :posts do
|
774
|
+
get(:index){ "index" }
|
775
|
+
get(:reindex){ "reindex" }
|
776
|
+
end
|
777
|
+
end
|
778
|
+
get "/posts"
|
779
|
+
assert_equal "index", body
|
780
|
+
get "/posts/reindex"
|
781
|
+
assert_equal "/posts/reindex", @app.url(:posts, :reindex)
|
782
|
+
assert_equal "reindex", body
|
783
|
+
end
|
784
|
+
|
785
|
+
should 'use uri_root' do
|
786
|
+
mock_app do
|
787
|
+
get(:foo){ "foo" }
|
788
|
+
end
|
789
|
+
@app.uri_root = '/'
|
790
|
+
assert_equal "/foo", @app.url(:foo)
|
791
|
+
@app.uri_root = '/testing'
|
792
|
+
assert_equal "/testing/foo", @app.url(:foo)
|
793
|
+
@app.uri_root = '/testing/'
|
794
|
+
assert_equal "/testing/foo", @app.url(:foo)
|
795
|
+
@app.uri_root = 'testing/bar///'
|
796
|
+
assert_equal "/testing/bar/foo", @app.url(:foo)
|
797
|
+
end
|
798
|
+
|
799
|
+
should 'use uri_root with controllers' do
|
800
|
+
mock_app do
|
801
|
+
controller :foo do
|
802
|
+
get(:bar){ "bar" }
|
803
|
+
end
|
804
|
+
end
|
805
|
+
@app.uri_root = '/testing'
|
806
|
+
assert_equal "/testing/foo/bar", @app.url(:foo, :bar)
|
807
|
+
end
|
808
|
+
|
809
|
+
should 'use RACK_BASE_URI' do
|
810
|
+
mock_app do
|
811
|
+
get(:foo){ "foo" }
|
812
|
+
end
|
813
|
+
# Wish there was a side-effect free way to test this...
|
814
|
+
ENV['RACK_BASE_URI'] = '/'
|
815
|
+
assert_equal "/foo", @app.url(:foo)
|
816
|
+
ENV['RACK_BASE_URI'] = '/testing'
|
817
|
+
assert_equal "/testing/foo", @app.url(:foo)
|
818
|
+
ENV['RACK_BASE_URI'] = nil
|
819
|
+
end
|
820
|
+
|
821
|
+
should 'reset routes' do
|
822
|
+
mock_app do
|
823
|
+
get("/"){ "foo" }
|
824
|
+
reset_router!
|
825
|
+
end
|
826
|
+
get "/"
|
827
|
+
assert_equal 404, status
|
828
|
+
end
|
829
|
+
|
830
|
+
should "match params and format" do
|
831
|
+
app = mock_app do
|
832
|
+
get '/:id', :provides => [:json, :html] do |id, _|
|
833
|
+
id
|
834
|
+
end
|
835
|
+
|
836
|
+
get 'format/:id', :provides => [:json, :html] do |id, format|
|
837
|
+
format
|
838
|
+
end
|
839
|
+
end
|
840
|
+
|
841
|
+
get '/123.html'
|
842
|
+
assert_equal '123', body
|
843
|
+
|
844
|
+
get 'format/123.html'
|
845
|
+
assert_equal 'html', body
|
846
|
+
end
|
847
|
+
|
848
|
+
|
849
|
+
should 'respect priorities' do
|
850
|
+
skip if enable_compiler?
|
851
|
+
route_order = []
|
852
|
+
mock_app do
|
853
|
+
get(:index, :priority => :normal) { route_order << :normal; pass }
|
854
|
+
get(:index, :priority => :low) { route_order << :low; "hello" }
|
855
|
+
get(:index, :priority => :high) { route_order << :high; pass }
|
856
|
+
end
|
857
|
+
get '/'
|
858
|
+
assert_equal [:high, :normal, :low], route_order
|
859
|
+
assert_equal "hello", body
|
860
|
+
end
|
861
|
+
|
862
|
+
should 'catch all after controllers' do
|
863
|
+
mock_app do
|
864
|
+
get(:index, :with => :slug, :priority => :low) { "catch all" }
|
865
|
+
controllers :contact do
|
866
|
+
get(:index) { "contact"}
|
867
|
+
end
|
868
|
+
end
|
869
|
+
get "/contact"
|
870
|
+
assert_equal "contact", body
|
871
|
+
get "/foo"
|
872
|
+
assert_equal "catch all", body
|
873
|
+
end
|
874
|
+
|
875
|
+
should 'allow optionals' do
|
876
|
+
mock_app do
|
877
|
+
get(:show, :map => "/stories/:type(/:category)?") do
|
878
|
+
"#{params[:type]}/#{params[:category]}"
|
879
|
+
end
|
880
|
+
end
|
881
|
+
get "/stories/foo"
|
882
|
+
assert_equal "foo/", body
|
883
|
+
get "/stories/foo/bar"
|
884
|
+
assert_equal "foo/bar", body
|
885
|
+
end
|
886
|
+
|
887
|
+
should 'apply maps' do
|
888
|
+
mock_app do
|
889
|
+
controllers :admin do
|
890
|
+
get(:index, :map => "/"){ "index" }
|
891
|
+
get(:show, :with => :id, :map => "/show"){ "show #{params[:id]}" }
|
892
|
+
get(:edit, :map => "/edit/:id/product"){ "edit #{params[:id]}" }
|
893
|
+
get(:wacky, :map => "/wacky-:id-:product_id"){ "wacky #{params[:id]}-#{params[:product_id]}" }
|
894
|
+
end
|
895
|
+
end
|
896
|
+
get "/"
|
897
|
+
assert_equal "index", body
|
898
|
+
get @app.url(:admin, :index)
|
899
|
+
assert_equal "index", body
|
900
|
+
get "/show/1"
|
901
|
+
assert_equal "show 1", body
|
902
|
+
get "/edit/1/product"
|
903
|
+
assert_equal "edit 1", body
|
904
|
+
get "/wacky-1-2"
|
905
|
+
assert_equal "wacky 1-2", body
|
906
|
+
end
|
907
|
+
|
908
|
+
should 'apply maps when given path is kind of hash' do
|
909
|
+
mock_app do
|
910
|
+
controllers :admin do
|
911
|
+
get(:foobar, "/foo/bar"){ "foobar" }
|
912
|
+
end
|
913
|
+
end
|
914
|
+
get "/foo/bar"
|
915
|
+
assert_equal "foobar", body
|
916
|
+
end
|
917
|
+
|
918
|
+
should "apply parent to route" do
|
919
|
+
mock_app do
|
920
|
+
controllers :project do
|
921
|
+
get(:index, :parent => :user) { "index #{params[:user_id]}" }
|
922
|
+
get(:index, :parent => [:user, :section]) { "index #{params[:user_id]} #{params[:section_id]}" }
|
923
|
+
get(:edit, :with => :id, :parent => :user) { "edit #{params[:id]} #{params[:user_id]}"}
|
924
|
+
get(:show, :with => :id, :parent => [:user, :product]) { "show #{params[:id]} #{params[:user_id]} #{params[:product_id]}"}
|
925
|
+
end
|
926
|
+
end
|
927
|
+
get "/user/1/project"
|
928
|
+
assert_equal "index 1", body
|
929
|
+
get "/user/1/section/3/project"
|
930
|
+
assert_equal "index 1 3", body
|
931
|
+
get "/user/1/project/edit/2"
|
932
|
+
assert_equal "edit 2 1", body
|
933
|
+
get "/user/1/product/2/project/show/3"
|
934
|
+
assert_equal "show 3 1 2", body
|
935
|
+
end
|
936
|
+
|
937
|
+
should "respect parent precedence: controllers parents go before route parents" do
|
938
|
+
mock_app do
|
939
|
+
controllers :project do
|
940
|
+
get(:index, :parent => :user) { "index #{params[:user_id]}" }
|
941
|
+
end
|
942
|
+
|
943
|
+
controllers :bar, :parent => :foo do
|
944
|
+
get(:index) { "index on foo #{params[:foo_id]} @ bar" }
|
945
|
+
get(:index, :parent => :baz) { "index on foo #{params[:foo_id]} @ baz #{params[:baz_id]} @ bar" }
|
946
|
+
end
|
947
|
+
end
|
948
|
+
|
949
|
+
get "/user/1/project"
|
950
|
+
assert_equal "index 1", body
|
951
|
+
get "/foo/1/bar"
|
952
|
+
assert_equal "index on foo 1 @ bar", body
|
953
|
+
get "/foo/1/baz/2/bar"
|
954
|
+
assert_equal "index on foo 1 @ baz 2 @ bar", body
|
955
|
+
end
|
956
|
+
|
957
|
+
should "keep a reference to the parent on the route" do
|
958
|
+
mock_app do
|
959
|
+
controllers :project do
|
960
|
+
get(:index, :parent => :user) { "index #{params[:user_id]}" }
|
961
|
+
get(:index, :parent => [:user, :section]) { "index #{params[:user_id]} #{params[:section_id]}" }
|
962
|
+
get(:edit, :with => :id, :parent => :user) { "edit #{params[:id]} #{params[:user_id]}"}
|
963
|
+
get(:show, :with => :id, :parent => [:user, :product]) { "show #{params[:id]} #{params[:user_id]} #{params[:product_id]}"}
|
964
|
+
end
|
965
|
+
|
966
|
+
controllers :bar, :parent => :foo do
|
967
|
+
get(:index) { "index on foo/bar" }
|
968
|
+
get(:index, :parent => :baz) { "index on foo/baz/bar" }
|
969
|
+
end
|
970
|
+
end
|
971
|
+
|
972
|
+
# get "/user/1/project"
|
973
|
+
assert_equal :user, @app.routes[0].parent
|
974
|
+
# get "/user/1/section/3/project"
|
975
|
+
assert_equal [:user, :section], @app.routes[2].parent
|
976
|
+
# get "/user/1/project/edit/2"
|
977
|
+
assert_equal :user, @app.routes[4].parent
|
978
|
+
# get "/user/1/product/2/project/show/3"
|
979
|
+
assert_equal [:user, :product], @app.routes[6].parent
|
980
|
+
# get "/foo/1/bar"
|
981
|
+
assert_equal :foo, @app.routes[8].parent
|
982
|
+
# get "/foo/1/baz/2/bar"
|
983
|
+
assert_equal [:foo, :baz], @app.routes[10].parent
|
984
|
+
end
|
985
|
+
|
986
|
+
should "apply parent to controller" do
|
987
|
+
mock_app do
|
988
|
+
controller :project, :parent => :user do
|
989
|
+
get(:index) { "index #{params[:user_id]}"}
|
990
|
+
get(:edit, :with => :id, :parent => :user) { "edit #{params[:id]} #{params[:user_id]}"}
|
991
|
+
get(:show, :with => :id, :parent => :product) { "show #{params[:id]} #{params[:user_id]} #{params[:product_id]}"}
|
992
|
+
end
|
993
|
+
end
|
994
|
+
|
995
|
+
user_project_url = "/user/1/project"
|
996
|
+
get user_project_url
|
997
|
+
assert_equal "index 1", body
|
998
|
+
assert_equal user_project_url, @app.url(:project, :index, :user_id => 1)
|
999
|
+
|
1000
|
+
user_project_edit_url = "/user/1/project/edit/2"
|
1001
|
+
get user_project_edit_url
|
1002
|
+
assert_equal "edit 2 1", body
|
1003
|
+
assert_equal user_project_edit_url, @app.url(:project, :edit, :user_id => 1, :id => 2)
|
1004
|
+
|
1005
|
+
user_product_project_url = "/user/1/product/2/project/show/3"
|
1006
|
+
get user_product_project_url
|
1007
|
+
assert_equal "show 3 1 2", body
|
1008
|
+
assert_equal user_product_project_url, @app.url(:project, :show, :user_id => 1, :product_id => 2, :id => 3)
|
1009
|
+
end
|
1010
|
+
|
1011
|
+
should "apply parent with shallowing to controller" do
|
1012
|
+
mock_app do
|
1013
|
+
controller :project do
|
1014
|
+
parent :user
|
1015
|
+
parent :shop, :optional => true
|
1016
|
+
get(:index) { "index #{params[:user_id]} #{params[:shop_id]}" }
|
1017
|
+
get(:edit, :with => :id) { "edit #{params[:id]} #{params[:user_id]} #{params[:shop_id]}" }
|
1018
|
+
get(:show, :with => :id, :parent => :product) { "show #{params[:id]} #{params[:user_id]} #{params[:product_id]} #{params[:shop_id]}" }
|
1019
|
+
end
|
1020
|
+
end
|
1021
|
+
|
1022
|
+
assert_equal "/user/1/project", @app.url(:project, :index, :user_id => 1, :shop_id => nil)
|
1023
|
+
assert_equal "/user/1/shop/23/project", @app.url(:project, :index, :user_id => 1, :shop_id => 23)
|
1024
|
+
|
1025
|
+
user_project_url = "/user/1/project"
|
1026
|
+
get user_project_url
|
1027
|
+
assert_equal "index 1 ", body
|
1028
|
+
assert_equal user_project_url, @app.url(:project, :index, :user_id => 1)
|
1029
|
+
|
1030
|
+
user_project_edit_url = "/user/1/project/edit/2"
|
1031
|
+
get user_project_edit_url
|
1032
|
+
assert_equal "edit 2 1 ", body
|
1033
|
+
assert_equal user_project_edit_url, @app.url(:project, :edit, :user_id => 1, :id => 2)
|
1034
|
+
|
1035
|
+
user_product_project_url = "/user/1/product/2/project/show/3"
|
1036
|
+
get user_product_project_url
|
1037
|
+
assert_equal "show 3 1 2 ", body
|
1038
|
+
assert_equal user_product_project_url, @app.url(:project, :show, :user_id => 1, :product_id => 2, :id => 3)
|
1039
|
+
|
1040
|
+
user_project_url = "/user/1/shop/1/project"
|
1041
|
+
get user_project_url
|
1042
|
+
assert_equal "index 1 1", body
|
1043
|
+
assert_equal user_project_url, @app.url(:project, :index, :user_id => 1, :shop_id => 1)
|
1044
|
+
|
1045
|
+
user_project_edit_url = "/user/1/shop/1/project/edit/2"
|
1046
|
+
get user_project_edit_url
|
1047
|
+
assert_equal "edit 2 1 1", body
|
1048
|
+
assert_equal user_project_edit_url, @app.url(:project, :edit, :user_id => 1, :id => 2, :shop_id => 1)
|
1049
|
+
|
1050
|
+
user_product_project_url = "/user/1/shop/1/product/2/project/show/3"
|
1051
|
+
get user_product_project_url
|
1052
|
+
assert_equal "show 3 1 2 1", body
|
1053
|
+
assert_equal user_product_project_url, @app.url(:project, :show, :user_id => 1, :product_id => 2, :id => 3, :shop_id => 1)
|
1054
|
+
end
|
1055
|
+
|
1056
|
+
should "respect map in parents with shallowing" do
|
1057
|
+
mock_app do
|
1058
|
+
controller :project do
|
1059
|
+
parent :shop, :map => "/foo/bar"
|
1060
|
+
get(:index) { "index #{params[:shop_id]}" }
|
1061
|
+
end
|
1062
|
+
end
|
1063
|
+
|
1064
|
+
shop_project_url = "/foo/bar/1/project"
|
1065
|
+
get shop_project_url
|
1066
|
+
assert_equal "index 1", body
|
1067
|
+
assert_equal shop_project_url, @app.url(:project, :index, :shop_id => 1)
|
1068
|
+
end
|
1069
|
+
|
1070
|
+
should "use default values" do
|
1071
|
+
mock_app do
|
1072
|
+
controller :lang => :it do
|
1073
|
+
get(:index, :map => "/:lang") { "lang is #{params[:lang]}" }
|
1074
|
+
end
|
1075
|
+
# This is only for be sure that default values
|
1076
|
+
# work only for the given controller
|
1077
|
+
get(:foo, :map => "/foo") {}
|
1078
|
+
end
|
1079
|
+
assert_equal "/it", @app.url(:index)
|
1080
|
+
assert_equal "/foo", @app.url(:foo)
|
1081
|
+
get "/en"
|
1082
|
+
assert_equal "lang is en", body
|
1083
|
+
end
|
1084
|
+
|
1085
|
+
should "transitions to the next matching route on pass" do
|
1086
|
+
skip if enable_compiler?
|
1087
|
+
mock_app do
|
1088
|
+
get '/:foo' do
|
1089
|
+
pass
|
1090
|
+
'Hello Foo'
|
1091
|
+
end
|
1092
|
+
get '/:bar' do
|
1093
|
+
'Hello World'
|
1094
|
+
end
|
1095
|
+
end
|
1096
|
+
|
1097
|
+
get '/za'
|
1098
|
+
assert_equal 'Hello World', body
|
1099
|
+
end
|
1100
|
+
|
1101
|
+
should "filters by accept header" do
|
1102
|
+
mock_app do
|
1103
|
+
get '/foo', :provides => [:xml, :js] do
|
1104
|
+
request.env['HTTP_ACCEPT']
|
1105
|
+
end
|
1106
|
+
end
|
1107
|
+
|
1108
|
+
get '/foo', {}, { 'HTTP_ACCEPT' => 'application/xml' }
|
1109
|
+
assert ok?
|
1110
|
+
assert_equal 'application/xml', body
|
1111
|
+
assert_equal 'application/xml;charset=utf-8', response.headers['Content-Type']
|
1112
|
+
|
1113
|
+
get '/foo.xml'
|
1114
|
+
assert ok?
|
1115
|
+
assert_equal 'application/xml;charset=utf-8', response.headers['Content-Type']
|
1116
|
+
|
1117
|
+
get '/foo', {}, { 'HTTP_ACCEPT' => 'application/javascript' }
|
1118
|
+
assert ok?
|
1119
|
+
assert_equal 'application/javascript', body
|
1120
|
+
assert_equal 'application/javascript;charset=utf-8', response.headers['Content-Type']
|
1121
|
+
|
1122
|
+
get '/foo.js'
|
1123
|
+
assert ok?
|
1124
|
+
assert_equal 'application/javascript;charset=utf-8', response.headers['Content-Type']
|
1125
|
+
|
1126
|
+
get '/foo', {}, { "HTTP_ACCEPT" => 'text/html' }
|
1127
|
+
assert_equal 406, status
|
1128
|
+
end
|
1129
|
+
|
1130
|
+
should "does not allow global provides" do
|
1131
|
+
mock_app do
|
1132
|
+
provides :xml
|
1133
|
+
|
1134
|
+
get("/foo"){ "Foo in #{content_type.inspect}" }
|
1135
|
+
get("/bar"){ "Bar in #{content_type.inspect}" }
|
1136
|
+
end
|
1137
|
+
|
1138
|
+
get '/foo', {}, { 'HTTP_ACCEPT' => 'application/xml' }
|
1139
|
+
assert_equal 'Foo in :xml', body
|
1140
|
+
get '/foo'
|
1141
|
+
assert_equal 'Foo in :xml', body
|
1142
|
+
|
1143
|
+
get '/bar', {}, { 'HTTP_ACCEPT' => 'application/xml' }
|
1144
|
+
assert_equal 'Bar in nil', body
|
1145
|
+
end
|
1146
|
+
|
1147
|
+
should "does not allow global provides in controller" do
|
1148
|
+
mock_app do
|
1149
|
+
controller :base do
|
1150
|
+
provides :xml
|
1151
|
+
|
1152
|
+
get(:foo, "/foo"){ "Foo in #{content_type.inspect}" }
|
1153
|
+
get(:bar, "/bar"){ "Bar in #{content_type.inspect}" }
|
1154
|
+
end
|
1155
|
+
end
|
1156
|
+
|
1157
|
+
get '/foo', {}, { 'HTTP_ACCEPT' => 'application/xml' }
|
1158
|
+
assert_equal 'Foo in :xml', body
|
1159
|
+
get '/foo'
|
1160
|
+
assert_equal 'Foo in :xml', body
|
1161
|
+
|
1162
|
+
get '/bar', {}, { 'HTTP_ACCEPT' => 'application/xml' }
|
1163
|
+
assert_equal 'Bar in nil', body
|
1164
|
+
end
|
1165
|
+
|
1166
|
+
should "map non named routes in controllers" do
|
1167
|
+
mock_app do
|
1168
|
+
controller :base do
|
1169
|
+
get("/foo") { "ok" }
|
1170
|
+
get("/bar") { "ok" }
|
1171
|
+
end
|
1172
|
+
end
|
1173
|
+
|
1174
|
+
get "/base/foo"
|
1175
|
+
assert ok?
|
1176
|
+
get "/base/bar"
|
1177
|
+
assert ok?
|
1178
|
+
end
|
1179
|
+
|
1180
|
+
should "set content_type to :html for both empty Accept as well as Accept text/html" do
|
1181
|
+
mock_app do
|
1182
|
+
provides :html
|
1183
|
+
|
1184
|
+
get("/foo"){ content_type.to_s }
|
1185
|
+
end
|
1186
|
+
|
1187
|
+
get '/foo', {}, {}
|
1188
|
+
assert_equal 'html', body
|
1189
|
+
|
1190
|
+
get '/foo', {}, { 'HTTP_ACCEPT' => 'text/html' }
|
1191
|
+
assert_equal 'html', body
|
1192
|
+
end
|
1193
|
+
|
1194
|
+
should "set content_type to :html if Accept */*" do
|
1195
|
+
mock_app do
|
1196
|
+
get("/foo", :provides => [:html, :js]) { content_type.to_s }
|
1197
|
+
end
|
1198
|
+
get '/foo', {}, {}
|
1199
|
+
assert_equal 'html', body
|
1200
|
+
|
1201
|
+
get '/foo', {}, { 'HTTP_ACCEPT' => '*/*;q=0.5' }
|
1202
|
+
assert_equal 'html', body
|
1203
|
+
end
|
1204
|
+
|
1205
|
+
should "set content_type to :js if Accept includes both application/javascript and */*;q=0.5" do
|
1206
|
+
mock_app do
|
1207
|
+
get("/foo", :provides => [:html, :js]) { content_type.to_s }
|
1208
|
+
end
|
1209
|
+
get '/foo', {}, { 'HTTP_ACCEPT' => 'application/javascript, */*;q=0.5' }
|
1210
|
+
assert_equal 'js', body
|
1211
|
+
end
|
1212
|
+
|
1213
|
+
should "set content_type to :html if Accept */* and provides of :any" do
|
1214
|
+
mock_app do
|
1215
|
+
get("/foo", :provides => :any) { content_type.to_s }
|
1216
|
+
end
|
1217
|
+
|
1218
|
+
get '/foo', {}, { 'HTTP_ACCEPT' => '*/*' }
|
1219
|
+
assert_equal 'html', body
|
1220
|
+
end
|
1221
|
+
|
1222
|
+
should "set content_type to :js if Accept includes both application/javascript, */*;q=0.5 and provides of :any" do
|
1223
|
+
mock_app do
|
1224
|
+
get("/foo", :provides => :any) { content_type.to_s }
|
1225
|
+
end
|
1226
|
+
|
1227
|
+
get '/foo', {}, { 'HTTP_ACCEPT' => 'application/javascript, */*;q=0.5' }
|
1228
|
+
assert_equal 'js', body
|
1229
|
+
end
|
1230
|
+
|
1231
|
+
should 'allows custom route-conditions to be set via route options and halt' do
|
1232
|
+
protector = Module.new do
|
1233
|
+
def protect(*args)
|
1234
|
+
condition {
|
1235
|
+
unless authorize(params["user"], params["password"])
|
1236
|
+
halt 403, "go away"
|
1237
|
+
end
|
1238
|
+
}
|
1239
|
+
end
|
1240
|
+
end
|
1241
|
+
|
1242
|
+
mock_app do
|
1243
|
+
register protector
|
1244
|
+
|
1245
|
+
helpers do
|
1246
|
+
def authorize(username, password)
|
1247
|
+
username == "foo" && password == "bar"
|
1248
|
+
end
|
1249
|
+
end
|
1250
|
+
|
1251
|
+
get "/", :protect => true do
|
1252
|
+
"hey"
|
1253
|
+
end
|
1254
|
+
end
|
1255
|
+
|
1256
|
+
get "/"
|
1257
|
+
assert forbidden?
|
1258
|
+
assert_equal "go away", body
|
1259
|
+
|
1260
|
+
get "/", :user => "foo", :password => "bar"
|
1261
|
+
assert ok?
|
1262
|
+
assert_equal "hey", body
|
1263
|
+
end
|
1264
|
+
|
1265
|
+
should 'allows custom route-conditions to be set via route options using two routes' do
|
1266
|
+
skip if enable_compiler?
|
1267
|
+
protector = Module.new do
|
1268
|
+
def protect(*args)
|
1269
|
+
condition { authorize(params["user"], params["password"]) }
|
1270
|
+
end
|
1271
|
+
end
|
1272
|
+
|
1273
|
+
mock_app do
|
1274
|
+
register protector
|
1275
|
+
|
1276
|
+
helpers do
|
1277
|
+
def authorize(username, password)
|
1278
|
+
username == "foo" && password == "bar"
|
1279
|
+
end
|
1280
|
+
end
|
1281
|
+
|
1282
|
+
get "/", :protect => true do
|
1283
|
+
"hey"
|
1284
|
+
end
|
1285
|
+
|
1286
|
+
get "/" do
|
1287
|
+
"go away"
|
1288
|
+
end
|
1289
|
+
end
|
1290
|
+
|
1291
|
+
get "/"
|
1292
|
+
assert_equal "go away", body
|
1293
|
+
|
1294
|
+
get "/", :user => "foo", :password => "bar"
|
1295
|
+
assert ok?
|
1296
|
+
assert_equal "hey", body
|
1297
|
+
end
|
1298
|
+
|
1299
|
+
should "allow concise routing" do
|
1300
|
+
mock_app do
|
1301
|
+
get :index, ":id" do
|
1302
|
+
params[:id]
|
1303
|
+
end
|
1304
|
+
|
1305
|
+
get :map, "route/:id" do
|
1306
|
+
params[:id]
|
1307
|
+
end
|
1308
|
+
end
|
1309
|
+
|
1310
|
+
get "/123"
|
1311
|
+
assert_equal "123", body
|
1312
|
+
|
1313
|
+
get "/route/123"
|
1314
|
+
assert_equal "123", body
|
1315
|
+
end
|
1316
|
+
|
1317
|
+
should "support halting with 404 and message" do
|
1318
|
+
mock_app do
|
1319
|
+
controller do
|
1320
|
+
get :index do
|
1321
|
+
halt 404, "not found"
|
1322
|
+
end
|
1323
|
+
end
|
1324
|
+
end
|
1325
|
+
|
1326
|
+
get "/"
|
1327
|
+
assert_equal 404, status
|
1328
|
+
assert_equal "not found", body
|
1329
|
+
end
|
1330
|
+
|
1331
|
+
should "allow passing & halting in before filters" do
|
1332
|
+
skip if enable_compiler?
|
1333
|
+
mock_app do
|
1334
|
+
controller do
|
1335
|
+
before { env['QUERY_STRING'] == 'secret' or pass }
|
1336
|
+
get :index do
|
1337
|
+
"secret index"
|
1338
|
+
end
|
1339
|
+
end
|
1340
|
+
|
1341
|
+
controller do
|
1342
|
+
before { env['QUERY_STRING'] == 'halt' and halt 401, 'go away!' }
|
1343
|
+
get :index do
|
1344
|
+
"index"
|
1345
|
+
end
|
1346
|
+
end
|
1347
|
+
end
|
1348
|
+
|
1349
|
+
get "/?secret"
|
1350
|
+
assert_equal "secret index", body
|
1351
|
+
|
1352
|
+
get "/?halt"
|
1353
|
+
assert_equal "go away!", body
|
1354
|
+
assert_equal 401, status
|
1355
|
+
|
1356
|
+
get "/"
|
1357
|
+
assert_equal "index", body
|
1358
|
+
end
|
1359
|
+
|
1360
|
+
should 'scope filters in the given controller' do
|
1361
|
+
mock_app do
|
1362
|
+
before { @global = 'global' }
|
1363
|
+
after { @global = nil }
|
1364
|
+
|
1365
|
+
controller :foo do
|
1366
|
+
before { @foo = :foo }
|
1367
|
+
after { @foo = nil }
|
1368
|
+
get("/") { [@foo, @bar, @global].compact.join(" ") }
|
1369
|
+
end
|
1370
|
+
|
1371
|
+
get("/") { [@foo, @bar, @global].compact.join(" ") }
|
1372
|
+
|
1373
|
+
controller :bar do
|
1374
|
+
before { @bar = :bar }
|
1375
|
+
after { @bar = nil }
|
1376
|
+
get("/") { [@foo, @bar, @global].compact.join(" ") }
|
1377
|
+
end
|
1378
|
+
end
|
1379
|
+
|
1380
|
+
get "/bar"
|
1381
|
+
assert_equal "bar global", body
|
1382
|
+
|
1383
|
+
get "/foo"
|
1384
|
+
assert_equal "foo global", body
|
1385
|
+
|
1386
|
+
get "/"
|
1387
|
+
assert_equal "global", body
|
1388
|
+
end
|
1389
|
+
|
1390
|
+
should 'works with optionals params' do
|
1391
|
+
mock_app do
|
1392
|
+
get("/foo(/:bar)?") { params[:bar] }
|
1393
|
+
end
|
1394
|
+
|
1395
|
+
get "/foo/bar"
|
1396
|
+
assert_equal "bar", body
|
1397
|
+
|
1398
|
+
get "/foo"
|
1399
|
+
assert_equal "", body
|
1400
|
+
end
|
1401
|
+
|
1402
|
+
should 'work with multiple dashed params' do
|
1403
|
+
mock_app do
|
1404
|
+
get "/route/:foo/:bar/:baz", :provides => :html do
|
1405
|
+
"#{params[:foo]};#{params[:bar]};#{params[:baz]}"
|
1406
|
+
end
|
1407
|
+
end
|
1408
|
+
|
1409
|
+
get "/route/foo/bar/baz"
|
1410
|
+
assert_equal 'foo;bar;baz', body
|
1411
|
+
|
1412
|
+
get "/route/foo/bar-whatever/baz"
|
1413
|
+
assert_equal 'foo;bar-whatever;baz', body
|
1414
|
+
end
|
1415
|
+
|
1416
|
+
should 'work with arbitrary params' do
|
1417
|
+
mock_app do
|
1418
|
+
get(:testing) { params[:foo] }
|
1419
|
+
end
|
1420
|
+
|
1421
|
+
url = @app.url(:testing, :foo => 'bar')
|
1422
|
+
assert_equal "/testing?foo=bar", url
|
1423
|
+
get url
|
1424
|
+
assert_equal "bar", body
|
1425
|
+
end
|
1426
|
+
|
1427
|
+
should 'ignore nil params' do
|
1428
|
+
mock_app do
|
1429
|
+
get(:testing, :provides => [:html, :json]) do
|
1430
|
+
end
|
1431
|
+
end
|
1432
|
+
assert_equal '/testing.html', @app.url(:testing, :format => :html)
|
1433
|
+
assert_equal '/testing', @app.url(:testing, :format => nil)
|
1434
|
+
end
|
1435
|
+
|
1436
|
+
should 'be able to access params in a before filter' do
|
1437
|
+
username_from_before_filter = nil
|
1438
|
+
|
1439
|
+
mock_app do
|
1440
|
+
before do
|
1441
|
+
username_from_before_filter = params[:username]
|
1442
|
+
end
|
1443
|
+
|
1444
|
+
get :users, :with => :username do
|
1445
|
+
end
|
1446
|
+
end
|
1447
|
+
get '/users/josh'
|
1448
|
+
assert_equal 'josh', username_from_before_filter
|
1449
|
+
end
|
1450
|
+
|
1451
|
+
should "be able to access params normally when a before filter is specified" do
|
1452
|
+
mock_app do
|
1453
|
+
before { }
|
1454
|
+
get :index do
|
1455
|
+
params.inspect
|
1456
|
+
end
|
1457
|
+
end
|
1458
|
+
get '/?test=what'
|
1459
|
+
assert_equal '{"test"=>"what"}', body
|
1460
|
+
end
|
1461
|
+
|
1462
|
+
should 'work with controller and arbitrary params' do
|
1463
|
+
mock_app do
|
1464
|
+
get(:testing) { params[:foo] }
|
1465
|
+
controller :test1 do
|
1466
|
+
get(:url1) { params[:foo] }
|
1467
|
+
get(:url2, :provides => [:html, :json]) { params[:foo] }
|
1468
|
+
end
|
1469
|
+
end
|
1470
|
+
|
1471
|
+
url = @app.url(:test1, :url1, :foo => 'bar1')
|
1472
|
+
assert_equal "/test1/url1?foo=bar1", url
|
1473
|
+
get url
|
1474
|
+
assert_equal "bar1", body
|
1475
|
+
|
1476
|
+
url = @app.url(:test1, :url2, :foo => 'bar2')
|
1477
|
+
assert_equal "/test1/url2?foo=bar2", url
|
1478
|
+
get url
|
1479
|
+
assert_equal "bar2", body
|
1480
|
+
end
|
1481
|
+
|
1482
|
+
should "parse two routes with the same path but different http verbs" do
|
1483
|
+
mock_app do
|
1484
|
+
get(:index) { "This is the get index" }
|
1485
|
+
post(:index) { "This is the post index" }
|
1486
|
+
end
|
1487
|
+
get "/"
|
1488
|
+
assert_equal "This is the get index", body
|
1489
|
+
post "/"
|
1490
|
+
assert_equal "This is the post index", body
|
1491
|
+
end
|
1492
|
+
|
1493
|
+
should "use optionals params" do
|
1494
|
+
mock_app do
|
1495
|
+
get(:index, :map => "/:foo(/:bar)?") { "#{params[:foo]}-#{params[:bar]}" }
|
1496
|
+
end
|
1497
|
+
get "/foo"
|
1498
|
+
assert_equal "foo-", body
|
1499
|
+
get "/foo/bar"
|
1500
|
+
assert_equal "foo-bar", body
|
1501
|
+
end
|
1502
|
+
|
1503
|
+
should "parse two routes with the same path but different http verbs and provides" do
|
1504
|
+
mock_app do
|
1505
|
+
get(:index, :provides => [:html, :json]) { "This is the get index.#{content_type}" }
|
1506
|
+
post(:index, :provides => [:html, :json]) { "This is the post index.#{content_type}" }
|
1507
|
+
end
|
1508
|
+
get "/"
|
1509
|
+
assert_equal "This is the get index.html", body
|
1510
|
+
post "/"
|
1511
|
+
assert_equal "This is the post index.html", body
|
1512
|
+
get "/.json"
|
1513
|
+
assert_equal "This is the get index.json", body
|
1514
|
+
get "/.js"
|
1515
|
+
assert_equal 404, status
|
1516
|
+
post "/.json"
|
1517
|
+
assert_equal "This is the post index.json", body
|
1518
|
+
post "/.js"
|
1519
|
+
assert_equal 404, status
|
1520
|
+
end
|
1521
|
+
|
1522
|
+
should "allow controller level mapping" do
|
1523
|
+
mock_app do
|
1524
|
+
controller :map => "controller-:id" do
|
1525
|
+
get(:url3) { "#{params[:id]}" }
|
1526
|
+
get(:url4, :map => 'test-:id2') { "#{params[:id]}, #{params[:id2]}" }
|
1527
|
+
end
|
1528
|
+
end
|
1529
|
+
|
1530
|
+
url = @app.url(:url3, :id => 1)
|
1531
|
+
assert_equal "/controller-1/url3", url
|
1532
|
+
get url
|
1533
|
+
assert_equal "1", body
|
1534
|
+
|
1535
|
+
url = @app.url(:url4, 1, 2)
|
1536
|
+
assert_equal "/controller-1/test-2", url
|
1537
|
+
get url
|
1538
|
+
assert_equal "1, 2", body
|
1539
|
+
end
|
1540
|
+
|
1541
|
+
should "replace name of named controller with mapping path" do
|
1542
|
+
mock_app do
|
1543
|
+
controller :ugly, :map => "/pretty/:id" do
|
1544
|
+
get(:url3) { "#{params[:id]}" }
|
1545
|
+
get(:url4, :map => 'test-:id2') { "#{params[:id]}, #{params[:id2]}" }
|
1546
|
+
end
|
1547
|
+
controller :voldemort, :map => "" do
|
1548
|
+
get(:url5) { "okay" }
|
1549
|
+
end
|
1550
|
+
end
|
1551
|
+
|
1552
|
+
url = @app.url(:ugly, :url3, :id => 1)
|
1553
|
+
assert_equal "/pretty/1/url3", url
|
1554
|
+
get url
|
1555
|
+
assert_equal "1", body
|
1556
|
+
|
1557
|
+
url = @app.url(:ugly, :url4, 3, 5)
|
1558
|
+
assert_equal "/pretty/3/test-5", url
|
1559
|
+
get url
|
1560
|
+
assert_equal "3, 5", body
|
1561
|
+
|
1562
|
+
url = @app.url(:voldemort, :url5)
|
1563
|
+
assert_equal "/url5", url
|
1564
|
+
get url
|
1565
|
+
assert_equal 'okay', body
|
1566
|
+
end
|
1567
|
+
|
1568
|
+
should 'use absolute and relative maps' do
|
1569
|
+
mock_app do
|
1570
|
+
controller :one do
|
1571
|
+
parent :three
|
1572
|
+
get :index, :map => 'one' do; end
|
1573
|
+
get :index2, :map => '/one' do; end
|
1574
|
+
end
|
1575
|
+
|
1576
|
+
controller :two, :map => 'two' do
|
1577
|
+
parent :three
|
1578
|
+
get :index, :map => 'two' do; end
|
1579
|
+
get :index2, :map => '/two', :with => :id do; end
|
1580
|
+
end
|
1581
|
+
end
|
1582
|
+
assert_equal "/three/three_id/one", @app.url(:one, :index, 'three_id')
|
1583
|
+
assert_equal "/one", @app.url(:one, :index2)
|
1584
|
+
assert_equal "/two/three/three_id/two", @app.url(:two, :index, 'three_id')
|
1585
|
+
assert_equal "/two/four_id", @app.url(:two, :index2, 'four_id')
|
1586
|
+
end
|
1587
|
+
|
1588
|
+
should "work with params and parent options" do
|
1589
|
+
mock_app do
|
1590
|
+
controller :test2, :parent => :parent1, :parent1_id => 1 do
|
1591
|
+
get(:url3) { params[:foo] }
|
1592
|
+
get(:url4, :with => :with1) { params[:foo] }
|
1593
|
+
get(:url5, :with => :with2, :provides => [:html]) { params[:foo] }
|
1594
|
+
end
|
1595
|
+
end
|
1596
|
+
|
1597
|
+
url = @app.url(:test2, :url3, :foo => 'bar3')
|
1598
|
+
assert_equal "/parent1/1/test2/url3?foo=bar3", url
|
1599
|
+
get url
|
1600
|
+
assert_equal "bar3", body
|
1601
|
+
|
1602
|
+
url = @app.url(:test2, :url4, :with1 => 'awith1', :foo => 'bar4')
|
1603
|
+
assert_equal "/parent1/1/test2/url4/awith1?foo=bar4", url
|
1604
|
+
get url
|
1605
|
+
assert_equal "bar4", body
|
1606
|
+
|
1607
|
+
url = @app.url(:test2, :url5, :with2 => 'awith1', :foo => 'bar5')
|
1608
|
+
assert_equal "/parent1/1/test2/url5/awith1?foo=bar5", url
|
1609
|
+
get url
|
1610
|
+
assert_equal "bar5", body
|
1611
|
+
end
|
1612
|
+
|
1613
|
+
should "parse params without explicit provides for every matching route" do
|
1614
|
+
mock_app do
|
1615
|
+
get(:index, :map => "/foos/:bar") { "get bar = #{params[:bar]}" }
|
1616
|
+
post :create, :map => "/foos/:bar", :provides => [:html, :js] do
|
1617
|
+
"post bar = #{params[:bar]}"
|
1618
|
+
end
|
1619
|
+
end
|
1620
|
+
|
1621
|
+
get "/foos/hello"
|
1622
|
+
assert_equal "get bar = hello", body
|
1623
|
+
post "/foos/hello"
|
1624
|
+
assert_equal "post bar = hello", body
|
1625
|
+
post "/foos/hello.js"
|
1626
|
+
assert_equal "post bar = hello", body
|
1627
|
+
end
|
1628
|
+
|
1629
|
+
should "properly route to first foo with two similar routes" do
|
1630
|
+
mock_app do
|
1631
|
+
controllers do
|
1632
|
+
get('/foo/') { "this is foo" }
|
1633
|
+
get(:show, :map => "/foo/:bar/:id") { "/foo/#{params[:bar]}/#{params[:id]}" }
|
1634
|
+
end
|
1635
|
+
end
|
1636
|
+
get "/foo"
|
1637
|
+
assert_equal "this is foo", body
|
1638
|
+
get "/foo/"
|
1639
|
+
assert_equal "this is foo", body
|
1640
|
+
get '/foo/5/10'
|
1641
|
+
assert_equal "/foo/5/10", body
|
1642
|
+
end
|
1643
|
+
|
1644
|
+
should "index routes should be optional when nested" do
|
1645
|
+
mock_app do
|
1646
|
+
controller '/users', :provides => [:json] do
|
1647
|
+
get '/' do
|
1648
|
+
"foo"
|
1649
|
+
end
|
1650
|
+
end
|
1651
|
+
end
|
1652
|
+
get "/users.json"
|
1653
|
+
assert_equal "foo", body
|
1654
|
+
end
|
1655
|
+
|
1656
|
+
should "use provides as conditional" do
|
1657
|
+
mock_app do
|
1658
|
+
provides :json
|
1659
|
+
get "/" do
|
1660
|
+
"foo"
|
1661
|
+
end
|
1662
|
+
end
|
1663
|
+
get "/.json"
|
1664
|
+
assert_equal "foo", body
|
1665
|
+
end
|
1666
|
+
|
1667
|
+
should_eventually "reset provides for routes that didn't use it" do
|
1668
|
+
mock_app do
|
1669
|
+
get('/foo', :provides => :js){}
|
1670
|
+
get('/bar'){}
|
1671
|
+
end
|
1672
|
+
get '/foo'
|
1673
|
+
assert ok?
|
1674
|
+
get '/foo.js'
|
1675
|
+
assert ok?
|
1676
|
+
get '/bar'
|
1677
|
+
assert ok?
|
1678
|
+
get '/bar.js'
|
1679
|
+
assert_equal 404, status
|
1680
|
+
end
|
1681
|
+
|
1682
|
+
should "pass controller conditions to each route" do
|
1683
|
+
counter = 0
|
1684
|
+
|
1685
|
+
mock_app do
|
1686
|
+
self.class.send(:define_method, :increment!) do |*args|
|
1687
|
+
condition { counter += 1 }
|
1688
|
+
end
|
1689
|
+
|
1690
|
+
controller :posts, :conditions => {:increment! => true} do
|
1691
|
+
get("/foo") { "foo" }
|
1692
|
+
get("/bar") { "bar" }
|
1693
|
+
end
|
1694
|
+
|
1695
|
+
end
|
1696
|
+
|
1697
|
+
get "/posts/foo"
|
1698
|
+
get "/posts/bar"
|
1699
|
+
assert_equal 2, counter
|
1700
|
+
end
|
1701
|
+
|
1702
|
+
should "allow controller conditions to be overridden" do
|
1703
|
+
counter = 0
|
1704
|
+
|
1705
|
+
mock_app do
|
1706
|
+
self.class.send(:define_method, :increment!) do |increment|
|
1707
|
+
condition { counter += 1 } if increment
|
1708
|
+
end
|
1709
|
+
|
1710
|
+
controller :posts, :conditions => {:increment! => true} do
|
1711
|
+
get("/foo") { "foo" }
|
1712
|
+
get("/bar", :increment! => false) { "bar" }
|
1713
|
+
end
|
1714
|
+
|
1715
|
+
end
|
1716
|
+
|
1717
|
+
get "/posts/foo"
|
1718
|
+
get "/posts/bar"
|
1719
|
+
assert_equal 1, counter
|
1720
|
+
end
|
1721
|
+
|
1722
|
+
should "parse params with class level provides" do
|
1723
|
+
mock_app do
|
1724
|
+
controllers :posts, :provides => [:html, :js] do
|
1725
|
+
post(:create, :map => "/foo/:bar/:baz/:id") {
|
1726
|
+
"POST CREATE #{params[:bar]} - #{params[:baz]} - #{params[:id]}"
|
1727
|
+
}
|
1728
|
+
end
|
1729
|
+
controllers :topics, :provides => [:js, :html] do
|
1730
|
+
get(:show, :map => "/foo/:bar/:baz/:id") { render "topics/show" }
|
1731
|
+
post(:create, :map => "/foo/:bar/:baz") { "TOPICS CREATE #{params[:bar]} - #{params[:baz]}" }
|
1732
|
+
end
|
1733
|
+
end
|
1734
|
+
post "/foo/bar/baz.js"
|
1735
|
+
assert_equal "TOPICS CREATE bar - baz", body, "should parse params with explicit .js"
|
1736
|
+
post @app.url(:topics, :create, :format => :js, :bar => 'bar', :baz => 'baz')
|
1737
|
+
assert_equal "TOPICS CREATE bar - baz", body, "should parse params from generated url"
|
1738
|
+
post "/foo/bar/baz/5.js"
|
1739
|
+
assert_equal "POST CREATE bar - baz - 5", body
|
1740
|
+
post @app.url(:posts, :create, :format => :js, :bar => 'bar', :baz => 'baz', :id => 5)
|
1741
|
+
assert_equal "POST CREATE bar - baz - 5", body
|
1742
|
+
end
|
1743
|
+
|
1744
|
+
should "parse params properly with inline provides" do
|
1745
|
+
mock_app do
|
1746
|
+
controllers :posts do
|
1747
|
+
post(:create, :map => "/foo/:bar/:baz/:id", :provides => [:html, :js]) {
|
1748
|
+
"POST CREATE #{params[:bar]} - #{params[:baz]} - #{params[:id]}"
|
1749
|
+
}
|
1750
|
+
end
|
1751
|
+
controllers :topics do
|
1752
|
+
get(:show, :map => "/foo/:bar/:baz/:id", :provides => [:html, :js]) { render "topics/show" }
|
1753
|
+
post(:create, :map => "/foo/:bar/:baz", :provides => [:html, :js]) { "TOPICS CREATE #{params[:bar]} - #{params[:baz]}" }
|
1754
|
+
end
|
1755
|
+
end
|
1756
|
+
post @app.url(:topics, :create, :format => :js, :bar => 'bar', :baz => 'baz')
|
1757
|
+
assert_equal "TOPICS CREATE bar - baz", body, "should properly post to topics create action"
|
1758
|
+
post @app.url(:posts, :create, :format => :js, :bar => 'bar', :baz => 'baz', :id => 5)
|
1759
|
+
assert_equal "POST CREATE bar - baz - 5", body, "should properly post to create action"
|
1760
|
+
end
|
1761
|
+
|
1762
|
+
should "have overideable format" do
|
1763
|
+
::Rack::Mime::MIME_TYPES[".other"] = "text/html"
|
1764
|
+
mock_app do
|
1765
|
+
before do
|
1766
|
+
params[:format] ||= :other
|
1767
|
+
end
|
1768
|
+
get("/format_test", :provides => [:html, :other]){ content_type.to_s }
|
1769
|
+
end
|
1770
|
+
get "/format_test"
|
1771
|
+
assert_equal "other", body
|
1772
|
+
::Rack::Mime::MIME_TYPES.delete('.other')
|
1773
|
+
end
|
1774
|
+
|
1775
|
+
should 'invokes handlers registered with ::error when raised' do
|
1776
|
+
mock_app do
|
1777
|
+
set :raise_errors, false
|
1778
|
+
error(FooError) { 'Foo!' }
|
1779
|
+
get '/' do
|
1780
|
+
raise FooError
|
1781
|
+
end
|
1782
|
+
end
|
1783
|
+
get '/'
|
1784
|
+
assert_equal 500, status
|
1785
|
+
assert_equal 'Foo!', body
|
1786
|
+
end
|
1787
|
+
|
1788
|
+
should 'have MethodOverride middleware' do
|
1789
|
+
mock_app do
|
1790
|
+
put('/') { 'okay' }
|
1791
|
+
end
|
1792
|
+
assert @app.method_override?
|
1793
|
+
post '/', {'_method'=>'PUT'}, {}
|
1794
|
+
assert_equal 200, status
|
1795
|
+
assert_equal 'okay', body
|
1796
|
+
end
|
1797
|
+
|
1798
|
+
should 'return value from params' do
|
1799
|
+
mock_app do
|
1800
|
+
get("/foo/:bar"){ raise "'bar' should be a string" unless params[:bar].kind_of? String}
|
1801
|
+
end
|
1802
|
+
get "/foo/50"
|
1803
|
+
assert ok?
|
1804
|
+
end
|
1805
|
+
|
1806
|
+
should 'have MethodOverride middleware with more options' do
|
1807
|
+
mock_app do
|
1808
|
+
put('/hi', :provides => [:json]) { 'hi' }
|
1809
|
+
end
|
1810
|
+
post '/hi', {'_method'=>'PUT'}
|
1811
|
+
assert_equal 200, status
|
1812
|
+
assert_equal 'hi', body
|
1813
|
+
post '/hi.json', {'_method'=>'PUT'}
|
1814
|
+
assert_equal 200, status
|
1815
|
+
assert_equal 'hi', body
|
1816
|
+
unless enable_compiler?
|
1817
|
+
post '/hi.json'
|
1818
|
+
assert_equal 405, status
|
1819
|
+
end
|
1820
|
+
end
|
1821
|
+
|
1822
|
+
should 'parse nested params' do
|
1823
|
+
mock_app do
|
1824
|
+
get(:index) { "%s %s" % [params[:account][:name], params[:account][:surname]] }
|
1825
|
+
end
|
1826
|
+
get "/?account[name]=foo&account[surname]=bar"
|
1827
|
+
assert_equal 'foo bar', body
|
1828
|
+
get @app.url(:index, "account[name]" => "foo", "account[surname]" => "bar")
|
1829
|
+
assert_equal 'foo bar', body
|
1830
|
+
end
|
1831
|
+
|
1832
|
+
should 'render sinatra NotFound page' do
|
1833
|
+
mock_app { set :environment, :development }
|
1834
|
+
get "/"
|
1835
|
+
assert_equal 404, status
|
1836
|
+
assert_match %r{(Sinatra doesn’t know this ditty.|<h1>Not Found</h1>)}, body
|
1837
|
+
end
|
1838
|
+
|
1839
|
+
should 'render a custom NotFound page' do
|
1840
|
+
mock_app do
|
1841
|
+
error(Sinatra::NotFound) { "not found" }
|
1842
|
+
end
|
1843
|
+
get "/"
|
1844
|
+
assert_equal 404, status
|
1845
|
+
assert_match(/not found/, body)
|
1846
|
+
end
|
1847
|
+
|
1848
|
+
should 'render a custom 404 page using not_found' do
|
1849
|
+
mock_app do
|
1850
|
+
not_found { "custom 404 not found" }
|
1851
|
+
end
|
1852
|
+
get "/"
|
1853
|
+
assert_equal 404, status
|
1854
|
+
assert_equal "custom 404 not found", body
|
1855
|
+
end
|
1856
|
+
|
1857
|
+
should 'render a custom error page using error method' do
|
1858
|
+
skip
|
1859
|
+
mock_app do
|
1860
|
+
error(404) { "custom 404 error" }
|
1861
|
+
end
|
1862
|
+
get "/"
|
1863
|
+
assert_equal 404, status
|
1864
|
+
assert_equal "custom 404 error", body
|
1865
|
+
end
|
1866
|
+
|
1867
|
+
should 'render a custom 403 page' do
|
1868
|
+
mock_app do
|
1869
|
+
error(403) { "custom 403 not found" }
|
1870
|
+
get("/") { status 403 }
|
1871
|
+
end
|
1872
|
+
get "/"
|
1873
|
+
assert_equal 403, status
|
1874
|
+
assert_equal "custom 403 not found", body
|
1875
|
+
end
|
1876
|
+
|
1877
|
+
should 'recognize paths' do
|
1878
|
+
mock_app do
|
1879
|
+
controller :foo do
|
1880
|
+
get(:bar, :map => "/my/:id/custom-route") { }
|
1881
|
+
end
|
1882
|
+
get(:simple, :map => "/simple/:id") { }
|
1883
|
+
get(:with_format, :with => :id, :provides => :js) { }
|
1884
|
+
end
|
1885
|
+
assert_equal [:"foo bar", { :id => "fantastic" }], @app.recognize_path(@app.url(:foo, :bar, :id => :fantastic))
|
1886
|
+
assert_equal [:"foo bar", { :id => "18" }], @app.recognize_path(@app.url(:foo, :bar, :id => 18))
|
1887
|
+
assert_equal [:simple, { :id => "bar" }], @app.recognize_path(@app.url(:simple, :id => "bar"))
|
1888
|
+
assert_equal [:simple, { :id => "true" }], @app.recognize_path(@app.url(:simple, :id => true))
|
1889
|
+
assert_equal [:simple, { :id => "9" }], @app.recognize_path(@app.url(:simple, :id => 9))
|
1890
|
+
assert_equal [:with_format, { :id => "bar", :format => "js" }], @app.recognize_path(@app.url(:with_format, :id => "bar", :format => :js))
|
1891
|
+
assert_equal [:with_format, { :id => "true", :format => "js" }], @app.recognize_path(@app.url(:with_format, :id => true, :format => "js"))
|
1892
|
+
assert_equal [:with_format, { :id => "9", :format => "js" }], @app.recognize_path(@app.url(:with_format, :id => 9, :format => :js))
|
1893
|
+
end
|
1894
|
+
|
1895
|
+
should 'have current_path' do
|
1896
|
+
mock_app do
|
1897
|
+
controller :foo do
|
1898
|
+
get(:index) { current_path }
|
1899
|
+
get :bar, :map => "/paginate/:page" do
|
1900
|
+
current_path
|
1901
|
+
end
|
1902
|
+
get(:after) { current_path }
|
1903
|
+
end
|
1904
|
+
end
|
1905
|
+
get "/paginate/10"
|
1906
|
+
assert_equal "/paginate/10", body
|
1907
|
+
get "/foo/after"
|
1908
|
+
assert_equal "/foo/after", body
|
1909
|
+
get "/foo"
|
1910
|
+
assert_equal "/foo", body
|
1911
|
+
end
|
1912
|
+
|
1913
|
+
should 'accept :map and :parent' do
|
1914
|
+
mock_app do
|
1915
|
+
controller :posts do
|
1916
|
+
get :show, :parent => :users, :map => "posts/:id" do
|
1917
|
+
"#{params[:user_id]}-#{params[:id]}"
|
1918
|
+
end
|
1919
|
+
end
|
1920
|
+
end
|
1921
|
+
get '/users/123/posts/321'
|
1922
|
+
assert_equal "123-321", body
|
1923
|
+
end
|
1924
|
+
|
1925
|
+
should 'change params in current_path' do
|
1926
|
+
mock_app do
|
1927
|
+
get :index, :map => "/paginate/:page" do
|
1928
|
+
current_path(:page => 66)
|
1929
|
+
end
|
1930
|
+
end
|
1931
|
+
get @app.url(:index, :page => 10)
|
1932
|
+
assert_equal "/paginate/66", body
|
1933
|
+
end
|
1934
|
+
|
1935
|
+
should 'not route get :users, :with => :id to /users//' do
|
1936
|
+
mock_app do
|
1937
|
+
get(:users, :with => :id) { 'boo' }
|
1938
|
+
end
|
1939
|
+
get '/users//'
|
1940
|
+
assert_equal 404, status
|
1941
|
+
end
|
1942
|
+
end
|