sinatra-scope 0.1.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.
- data/Gemfile +7 -0
- data/Gemfile.lock +27 -0
- data/lib/sinatra/resource.rb +69 -0
- data/lib/sinatra/scope.rb +65 -0
- data/lib/sinatra/urls.rb +35 -0
- data/test/contest.rb +65 -0
- data/test/helper.rb +83 -0
- data/test/sinatra_resource_test.rb +267 -0
- data/test/sinatra_scope_test.rb +311 -0
- data/test/sinatra_urls_test.rb +35 -0
- metadata +107 -0
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
sinatra-scope (0.0.1)
|
5
|
+
activesupport (~> 3.0.0)
|
6
|
+
i18n (~> 0.5.0)
|
7
|
+
sinatra
|
8
|
+
|
9
|
+
GEM
|
10
|
+
remote: http://rubygems.org/
|
11
|
+
specs:
|
12
|
+
activesupport (3.0.3)
|
13
|
+
i18n (0.5.0)
|
14
|
+
rack (1.2.1)
|
15
|
+
rack-test (0.5.6)
|
16
|
+
rack (>= 1.0)
|
17
|
+
sinatra (1.1.2)
|
18
|
+
rack (~> 1.1)
|
19
|
+
tilt (~> 1.2)
|
20
|
+
tilt (1.2.2)
|
21
|
+
|
22
|
+
PLATFORMS
|
23
|
+
ruby
|
24
|
+
|
25
|
+
DEPENDENCIES
|
26
|
+
rack-test
|
27
|
+
sinatra-scope!
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'sinatra/scope'
|
2
|
+
|
3
|
+
module Sinatra
|
4
|
+
module Resource
|
5
|
+
|
6
|
+
def resource(name, &block)
|
7
|
+
scope name, &block
|
8
|
+
end
|
9
|
+
alias resources resource
|
10
|
+
|
11
|
+
def member(&block)
|
12
|
+
scope ":id", &block
|
13
|
+
end
|
14
|
+
|
15
|
+
def index(&block)
|
16
|
+
get &block
|
17
|
+
end
|
18
|
+
|
19
|
+
def _new(&block)
|
20
|
+
get "/new", &block
|
21
|
+
end
|
22
|
+
|
23
|
+
def create(&block)
|
24
|
+
post &block
|
25
|
+
end
|
26
|
+
|
27
|
+
def show(&block)
|
28
|
+
if block.arity == 0
|
29
|
+
get &block
|
30
|
+
else
|
31
|
+
get { block.call(params[:id]) }
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def edit(&block)
|
36
|
+
if block.arity == 0
|
37
|
+
get "/edit", &block
|
38
|
+
else
|
39
|
+
get("/edit") { block.call(params[:id]) }
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def update(&block)
|
44
|
+
if block.arity == 0
|
45
|
+
put &block
|
46
|
+
else
|
47
|
+
put { block.call(params[:id]) }
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def _delete(&block)
|
52
|
+
if block.arity == 0
|
53
|
+
get "/delete", &block
|
54
|
+
else
|
55
|
+
get("/delete") { block.call(params[:id]) }
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def destroy(&block)
|
60
|
+
if block.arity == 0
|
61
|
+
delete &block
|
62
|
+
else
|
63
|
+
delete { block.call(params[:id]) }
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'active_support/core_ext/string/inflections'
|
2
|
+
require 'active_support/inflections'
|
3
|
+
require 'sinatra/base'
|
4
|
+
|
5
|
+
module Sinatra
|
6
|
+
module Scope
|
7
|
+
|
8
|
+
[:get, :post, :patch, :put, :delete, :head, :options].each do |verb|
|
9
|
+
define_method verb do |path = '', options = {}, &block|
|
10
|
+
super(full_path(path), options, &block)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
[:before, :after].each do |action|
|
15
|
+
define_method action do |path = '', options = {}, &block|
|
16
|
+
super(full_path(path), options, &block)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def scope(path, options = {}, &block)
|
21
|
+
case path
|
22
|
+
when Class
|
23
|
+
path = path.name
|
24
|
+
path = path.demodulize unless options[:full_classname]
|
25
|
+
path = path.underscore.dasherize
|
26
|
+
path = path.pluralize unless options[:singular]
|
27
|
+
else
|
28
|
+
path = path.to_s
|
29
|
+
end
|
30
|
+
|
31
|
+
(@scopes ||= []) << path
|
32
|
+
block.call
|
33
|
+
@scopes.pop
|
34
|
+
end
|
35
|
+
|
36
|
+
def scopes(*paths, &block)
|
37
|
+
@scopes ||= []
|
38
|
+
paths.each do |path|
|
39
|
+
@scopes << path.to_s
|
40
|
+
end
|
41
|
+
block.call
|
42
|
+
paths.each do |path|
|
43
|
+
@scopes.pop
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
protected
|
48
|
+
def full_path(path)
|
49
|
+
case path
|
50
|
+
when String, Symbol
|
51
|
+
("/" + (@scopes || []).join("/") + path.to_s).squeeze("/")
|
52
|
+
when Regexp
|
53
|
+
Regexp.new(Regexp.escape("/" + (@scopes || []).join("/")) + path.source)
|
54
|
+
else
|
55
|
+
path
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def path_name(path)
|
60
|
+
full_path(path).gsub(/^\//, '')
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
data/lib/sinatra/urls.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'sinatra/scope'
|
2
|
+
require 'active_support/core_ext/class/attribute'
|
3
|
+
|
4
|
+
module Sinatra
|
5
|
+
|
6
|
+
class UrlTracker
|
7
|
+
class_attribute :urls
|
8
|
+
self.urls = {}
|
9
|
+
|
10
|
+
def self.add(path, scopes = [], options = {})
|
11
|
+
name = (scopes.join("_") + "_" + path.to_s).gsub(/^_|_$/, "")
|
12
|
+
|
13
|
+
if name =~ /[a-zA-z0-9_\-%]/
|
14
|
+
self.urls[name] = ("/" + scopes.join("/") + "/" + path).squeeze("/")
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
module UrlScope
|
20
|
+
|
21
|
+
def scope(path = '', options = {}, &block)
|
22
|
+
UrlTracker.add(super, @scopes, options)
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
module UrlHelpers
|
28
|
+
|
29
|
+
def url(name, *args)
|
30
|
+
UrlTracker.urls[name.to_s]
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
data/test/contest.rb
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
require "test/unit"
|
2
|
+
|
3
|
+
# Test::Unit loads a default test if the suite is empty, and the only
|
4
|
+
# purpose of that test is to fail. As having empty contexts is a common
|
5
|
+
# practice, we decided to overwrite TestSuite#empty? in order to
|
6
|
+
# allow them. Having a failure when no tests have been defined seems
|
7
|
+
# counter-intuitive.
|
8
|
+
class Test::Unit::TestSuite
|
9
|
+
unless method_defined?(:empty?)
|
10
|
+
def empty?
|
11
|
+
false
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
# We added setup, test and context as class methods, and the instance
|
17
|
+
# method setup now iterates on the setup blocks. Note that all setup
|
18
|
+
# blocks must be defined with the block syntax. Adding a setup instance
|
19
|
+
# method defeats the purpose of this library.
|
20
|
+
class Test::Unit::TestCase
|
21
|
+
def self.setup(&block)
|
22
|
+
setup_blocks << block
|
23
|
+
end
|
24
|
+
|
25
|
+
def setup
|
26
|
+
self.class.setup_blocks.each do |block|
|
27
|
+
instance_eval(&block)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.context(name, &block)
|
32
|
+
subclass = Class.new(self.superclass)
|
33
|
+
subclass.setup_blocks.unshift(*setup_blocks)
|
34
|
+
subclass.class_eval(&block)
|
35
|
+
const_set(context_name(name), subclass)
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.test(name, &block)
|
39
|
+
define_method(test_name(name), &block)
|
40
|
+
end
|
41
|
+
|
42
|
+
class << self
|
43
|
+
alias_method :should, :test
|
44
|
+
alias_method :describe, :context
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def self.setup_blocks
|
50
|
+
@setup_blocks ||= []
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.context_name(name)
|
54
|
+
"Test#{sanitize_name(name).gsub(/(^| )(\w)/) { $2.upcase }}".to_sym
|
55
|
+
end
|
56
|
+
|
57
|
+
def self.test_name(name)
|
58
|
+
"test_#{sanitize_name(name).gsub(/\s+/,'_')}".to_sym
|
59
|
+
end
|
60
|
+
|
61
|
+
def self.sanitize_name(name)
|
62
|
+
name.gsub(/\W+/, ' ').strip
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
data/test/helper.rb
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
ENV['RACK_ENV'] = 'test'
|
2
|
+
|
3
|
+
require 'rack'
|
4
|
+
|
5
|
+
testdir = File.dirname(__FILE__)
|
6
|
+
$LOAD_PATH.unshift testdir unless $LOAD_PATH.include?(testdir)
|
7
|
+
|
8
|
+
libdir = File.dirname(File.dirname(__FILE__)) + '/lib'
|
9
|
+
$LOAD_PATH.unshift libdir unless $LOAD_PATH.include?(libdir)
|
10
|
+
|
11
|
+
require 'contest'
|
12
|
+
require 'rack/test'
|
13
|
+
require 'sinatra/base'
|
14
|
+
require 'sinatra/scope'
|
15
|
+
require 'sinatra/resource'
|
16
|
+
require 'sinatra/urls'
|
17
|
+
|
18
|
+
class Sinatra::Base
|
19
|
+
# Allow assertions in request context
|
20
|
+
include Test::Unit::Assertions
|
21
|
+
end
|
22
|
+
|
23
|
+
# App that includes scope helpers
|
24
|
+
class ScopeApp < Sinatra::Base
|
25
|
+
register Sinatra::Scope
|
26
|
+
register Sinatra::Resource
|
27
|
+
register Sinatra::UrlScope
|
28
|
+
helpers Sinatra::UrlHelpers
|
29
|
+
end
|
30
|
+
|
31
|
+
Sinatra::Base.set :environment, :test
|
32
|
+
|
33
|
+
class Test::Unit::TestCase
|
34
|
+
include Rack::Test::Methods
|
35
|
+
|
36
|
+
class << self
|
37
|
+
alias_method :it, :test
|
38
|
+
end
|
39
|
+
|
40
|
+
alias_method :response, :last_response
|
41
|
+
|
42
|
+
setup do
|
43
|
+
Sinatra::Base.set :environment, :test
|
44
|
+
end
|
45
|
+
|
46
|
+
# Sets up a Sinatra::Base subclass defined with the block
|
47
|
+
# given. Used in setup or individual spec methods to establish
|
48
|
+
# the application.
|
49
|
+
def mock_app(base=ScopeApp, &block)
|
50
|
+
@app = Sinatra.new(base, &block)
|
51
|
+
end
|
52
|
+
|
53
|
+
def app
|
54
|
+
Rack::Lint.new(@app)
|
55
|
+
end
|
56
|
+
|
57
|
+
def body
|
58
|
+
response.body.to_s
|
59
|
+
end
|
60
|
+
|
61
|
+
# Delegate other missing methods to response.
|
62
|
+
def method_missing(name, *args, &block)
|
63
|
+
if response && response.respond_to?(name)
|
64
|
+
response.send(name, *args, &block)
|
65
|
+
else
|
66
|
+
super
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
# Also check response since we delegate there.
|
71
|
+
def respond_to?(symbol, include_private=false)
|
72
|
+
super || (response && response.respond_to?(symbol, include_private))
|
73
|
+
end
|
74
|
+
|
75
|
+
# Do not output warnings for the duration of the block.
|
76
|
+
def silence_warnings
|
77
|
+
$VERBOSE, v = nil, $VERBOSE
|
78
|
+
yield
|
79
|
+
ensure
|
80
|
+
$VERBOSE = v
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
@@ -0,0 +1,267 @@
|
|
1
|
+
require File.expand_path 'helper', File.dirname(__FILE__)
|
2
|
+
|
3
|
+
class ResourceTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
it 'supports the resource method' do
|
6
|
+
mock_app {
|
7
|
+
resource "pages" do
|
8
|
+
get do
|
9
|
+
"Pages are great!"
|
10
|
+
end
|
11
|
+
end
|
12
|
+
}
|
13
|
+
|
14
|
+
get "/pages"
|
15
|
+
assert ok?
|
16
|
+
assert_equal "Pages are great!", body
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'supports the resources method' do
|
20
|
+
mock_app {
|
21
|
+
resources "pages" do
|
22
|
+
get do
|
23
|
+
"Pages are great!"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
}
|
27
|
+
|
28
|
+
get "/pages"
|
29
|
+
assert ok?
|
30
|
+
assert_equal "Pages are great!", body
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'supports the member method' do
|
34
|
+
mock_app {
|
35
|
+
resource "pages" do
|
36
|
+
member do
|
37
|
+
get do
|
38
|
+
"Page id: #{params[:id]}"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
}
|
43
|
+
|
44
|
+
get "/pages/3"
|
45
|
+
assert ok?
|
46
|
+
assert_equal "Page id: 3", body
|
47
|
+
end
|
48
|
+
|
49
|
+
it "supports the index method of a resource" do
|
50
|
+
mock_app do
|
51
|
+
resource "pages" do
|
52
|
+
index do
|
53
|
+
"Hello"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
get "/pages"
|
59
|
+
assert ok?
|
60
|
+
assert_equal "Hello", body
|
61
|
+
end
|
62
|
+
|
63
|
+
it "supports the new (_new) method of a resource" do
|
64
|
+
mock_app do
|
65
|
+
resource "pages" do
|
66
|
+
_new do
|
67
|
+
"New page"
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
get "/pages/new"
|
73
|
+
assert ok?
|
74
|
+
assert_equal "New page", body
|
75
|
+
end
|
76
|
+
|
77
|
+
it "supports the create method of a resource" do
|
78
|
+
mock_app do
|
79
|
+
resource "pages" do
|
80
|
+
create do
|
81
|
+
"Created the page"
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
post "/pages", {}
|
87
|
+
assert ok?
|
88
|
+
assert_equal "Created the page", body
|
89
|
+
end
|
90
|
+
|
91
|
+
it "supports the show method of a resource" do
|
92
|
+
mock_app do
|
93
|
+
resource "pages" do
|
94
|
+
member do
|
95
|
+
show do
|
96
|
+
"Page #{params[:id]}"
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
get "/pages/1"
|
103
|
+
assert ok?
|
104
|
+
assert_equal "Page 1", body
|
105
|
+
end
|
106
|
+
|
107
|
+
it "supports the show method of a resource with the id argument" do
|
108
|
+
mock_app do
|
109
|
+
resource "pages" do
|
110
|
+
member do
|
111
|
+
show do |id|
|
112
|
+
"Page #{id}"
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
get "/pages/1"
|
119
|
+
assert ok?
|
120
|
+
assert_equal "Page 1", body
|
121
|
+
end
|
122
|
+
|
123
|
+
it "supports the edit method of a resource" do
|
124
|
+
mock_app do
|
125
|
+
resource "pages" do
|
126
|
+
member do
|
127
|
+
edit do
|
128
|
+
"Edit page #{params[:id]}"
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
get "/pages/1/edit"
|
135
|
+
assert ok?
|
136
|
+
assert_equal "Edit page 1", body
|
137
|
+
end
|
138
|
+
|
139
|
+
it "supports the edit method of a resource with the id argument" do
|
140
|
+
mock_app do
|
141
|
+
resource "pages" do
|
142
|
+
member do
|
143
|
+
edit do |id|
|
144
|
+
"Edit page #{id}"
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
get "/pages/1/edit"
|
151
|
+
assert ok?
|
152
|
+
assert_equal "Edit page 1", body
|
153
|
+
end
|
154
|
+
|
155
|
+
it "supports the update method of a resource" do
|
156
|
+
mock_app do
|
157
|
+
resource "pages" do
|
158
|
+
member do
|
159
|
+
update do
|
160
|
+
"Updated page #{params[:id]}"
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
put "/pages/1", {}
|
167
|
+
assert ok?
|
168
|
+
assert_equal "Updated page 1", body
|
169
|
+
end
|
170
|
+
|
171
|
+
it "supports the update method of a resource with the id argument" do
|
172
|
+
mock_app do
|
173
|
+
resource "pages" do
|
174
|
+
member do
|
175
|
+
update do |id|
|
176
|
+
"Updated page #{id}"
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
put "/pages/1", {}
|
183
|
+
assert ok?
|
184
|
+
assert_equal "Updated page 1", body
|
185
|
+
end
|
186
|
+
|
187
|
+
it "supports the delete (_delete) method of a resource" do
|
188
|
+
mock_app do
|
189
|
+
resource "pages" do
|
190
|
+
member do
|
191
|
+
_delete do
|
192
|
+
"Page #{params[:id]}"
|
193
|
+
end
|
194
|
+
end
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
get "/pages/1/delete"
|
199
|
+
assert ok?
|
200
|
+
assert_equal "Page 1", body
|
201
|
+
end
|
202
|
+
|
203
|
+
it "supports the delete (_delete) method of a resource with the id argument" do
|
204
|
+
mock_app do
|
205
|
+
resource "pages" do
|
206
|
+
member do
|
207
|
+
_delete do |id|
|
208
|
+
"Page #{id}"
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
get "/pages/1/delete"
|
215
|
+
assert ok?
|
216
|
+
assert_equal "Page 1", body
|
217
|
+
end
|
218
|
+
|
219
|
+
it "supports the destroy method of a resource" do
|
220
|
+
mock_app do
|
221
|
+
resource "pages" do
|
222
|
+
member do
|
223
|
+
destroy do
|
224
|
+
"destroyd page #{params[:id]}"
|
225
|
+
end
|
226
|
+
end
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
delete "/pages/1", {}
|
231
|
+
assert ok?
|
232
|
+
assert_equal "destroyd page 1", body
|
233
|
+
end
|
234
|
+
|
235
|
+
it "supports the destroy method of a resource with the id argument" do
|
236
|
+
mock_app do
|
237
|
+
resource "pages" do
|
238
|
+
member do
|
239
|
+
destroy do |id|
|
240
|
+
"destroyd page #{id}"
|
241
|
+
end
|
242
|
+
end
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
delete "/pages/1", {}
|
247
|
+
assert ok?
|
248
|
+
assert_equal "destroyd page 1", body
|
249
|
+
end
|
250
|
+
|
251
|
+
it 'supports using a class as a resource' do
|
252
|
+
class Page; end
|
253
|
+
|
254
|
+
mock_app {
|
255
|
+
resource Page do
|
256
|
+
_new do
|
257
|
+
"Create a new page?"
|
258
|
+
end
|
259
|
+
end
|
260
|
+
}
|
261
|
+
|
262
|
+
get "/pages/new"
|
263
|
+
assert ok?
|
264
|
+
assert_equal "Create a new page?", body
|
265
|
+
end
|
266
|
+
|
267
|
+
end
|
@@ -0,0 +1,311 @@
|
|
1
|
+
require File.expand_path 'helper', File.dirname(__FILE__)
|
2
|
+
|
3
|
+
class ScopeTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
it "supports the scope method" do
|
6
|
+
mock_app do
|
7
|
+
scope "admin" do
|
8
|
+
get "/login" do
|
9
|
+
"/admin/login works"
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
get "/admin/login"
|
15
|
+
assert ok?
|
16
|
+
assert_equal "/admin/login works", response.body
|
17
|
+
end
|
18
|
+
|
19
|
+
%w[get put patch post delete].each do |verb|
|
20
|
+
it "defines #{verb.upcase} request handlers with #{verb}" do
|
21
|
+
mock_app {
|
22
|
+
send verb, '/hello' do
|
23
|
+
'Hello World'
|
24
|
+
end
|
25
|
+
}
|
26
|
+
|
27
|
+
request = Rack::MockRequest.new(@app)
|
28
|
+
response = request.request(verb.upcase, '/hello', {})
|
29
|
+
assert response.ok?
|
30
|
+
assert_equal 'Hello World', response.body
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
%w[get put post patch delete].each do |verb|
|
35
|
+
it "defines scoped #{verb.upcase} request handlers with #{verb}" do
|
36
|
+
mock_app {
|
37
|
+
scope "something" do
|
38
|
+
send verb, '/hello' do
|
39
|
+
'Hello World'
|
40
|
+
end
|
41
|
+
end
|
42
|
+
}
|
43
|
+
|
44
|
+
request = Rack::MockRequest.new(@app)
|
45
|
+
response = request.request(verb.upcase, '/something/hello', {})
|
46
|
+
assert response.ok?
|
47
|
+
assert_equal 'Hello World', response.body
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
it "defines HEAD request handlers with HEAD" do
|
52
|
+
mock_app {
|
53
|
+
head '/hello' do
|
54
|
+
response['X-Hello'] = 'World!'
|
55
|
+
'remove me'
|
56
|
+
end
|
57
|
+
}
|
58
|
+
|
59
|
+
request = Rack::MockRequest.new(@app)
|
60
|
+
response = request.request('HEAD', '/hello', {})
|
61
|
+
assert response.ok?
|
62
|
+
assert_equal 'World!', response['X-Hello']
|
63
|
+
assert_equal '', response.body
|
64
|
+
end
|
65
|
+
|
66
|
+
it "defines scoped HEAD request handlers with HEAD" do
|
67
|
+
mock_app {
|
68
|
+
scope "something" do
|
69
|
+
head '/hello' do
|
70
|
+
response['X-Hello'] = 'World!'
|
71
|
+
'remove me'
|
72
|
+
end
|
73
|
+
end
|
74
|
+
}
|
75
|
+
|
76
|
+
request = Rack::MockRequest.new(@app)
|
77
|
+
response = request.request('HEAD', '/something/hello', {})
|
78
|
+
assert response.ok?
|
79
|
+
assert_equal 'World!', response['X-Hello']
|
80
|
+
assert_equal '', response.body
|
81
|
+
end
|
82
|
+
|
83
|
+
it "404s when no route satisfies the request" do
|
84
|
+
mock_app {
|
85
|
+
get('/foo') { }
|
86
|
+
}
|
87
|
+
get '/bar'
|
88
|
+
assert_equal 404, status
|
89
|
+
end
|
90
|
+
|
91
|
+
it 'takes multiple definitions of a route' do
|
92
|
+
mock_app {
|
93
|
+
user_agent(/Foo/)
|
94
|
+
get '/foo' do
|
95
|
+
'foo'
|
96
|
+
end
|
97
|
+
|
98
|
+
get '/foo' do
|
99
|
+
'not foo'
|
100
|
+
end
|
101
|
+
}
|
102
|
+
|
103
|
+
get '/foo', {}, 'HTTP_USER_AGENT' => 'Foo'
|
104
|
+
assert ok?
|
105
|
+
assert_equal 'foo', body
|
106
|
+
|
107
|
+
get '/foo'
|
108
|
+
assert ok?
|
109
|
+
assert_equal 'not foo', body
|
110
|
+
end
|
111
|
+
|
112
|
+
it 'takes multiple definitions of a scoped route' do
|
113
|
+
mock_app {
|
114
|
+
scope "something" do
|
115
|
+
user_agent(/Foo/)
|
116
|
+
get '/foo' do
|
117
|
+
'foo'
|
118
|
+
end
|
119
|
+
|
120
|
+
get '/foo' do
|
121
|
+
'not foo'
|
122
|
+
end
|
123
|
+
end
|
124
|
+
}
|
125
|
+
|
126
|
+
get '/something/foo', {}, 'HTTP_USER_AGENT' => 'Foo'
|
127
|
+
assert ok?
|
128
|
+
assert_equal 'foo', body
|
129
|
+
|
130
|
+
get '/something/foo'
|
131
|
+
assert ok?
|
132
|
+
assert_equal 'not foo', body
|
133
|
+
end
|
134
|
+
|
135
|
+
it 'supports regular expressions' do
|
136
|
+
mock_app {
|
137
|
+
get(/^\/foo...\/bar$/) do
|
138
|
+
'Hello World'
|
139
|
+
end
|
140
|
+
}
|
141
|
+
|
142
|
+
get '/foooom/bar'
|
143
|
+
assert ok?
|
144
|
+
assert_equal 'Hello World', body
|
145
|
+
end
|
146
|
+
|
147
|
+
it 'supports regular expressions' do
|
148
|
+
mock_app {
|
149
|
+
scope "something" do
|
150
|
+
get(/\/foo...\/bar$/) do
|
151
|
+
'Hello World'
|
152
|
+
end
|
153
|
+
end
|
154
|
+
}
|
155
|
+
|
156
|
+
get '/something/foooom/bar'
|
157
|
+
assert ok?
|
158
|
+
assert_equal 'Hello World', body
|
159
|
+
end
|
160
|
+
|
161
|
+
it 'raises a TypeError when pattern is not a String or Regexp' do
|
162
|
+
assert_raise(TypeError) {
|
163
|
+
mock_app { get(42){} }
|
164
|
+
}
|
165
|
+
end
|
166
|
+
|
167
|
+
it 'supports helpers' do
|
168
|
+
mock_app {
|
169
|
+
helpers do
|
170
|
+
def foo
|
171
|
+
"bar"
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
get "/foo" do
|
176
|
+
foo
|
177
|
+
end
|
178
|
+
|
179
|
+
scope "something" do
|
180
|
+
get "/foo" do
|
181
|
+
foo
|
182
|
+
end
|
183
|
+
end
|
184
|
+
}
|
185
|
+
|
186
|
+
get '/foo'
|
187
|
+
assert ok?
|
188
|
+
assert_equal 'bar', body
|
189
|
+
end
|
190
|
+
|
191
|
+
it 'supports helpers in scoped urls' do
|
192
|
+
mock_app {
|
193
|
+
helpers do
|
194
|
+
def foo
|
195
|
+
"bar"
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
get "/foo" do
|
200
|
+
foo
|
201
|
+
end
|
202
|
+
|
203
|
+
scope "something" do
|
204
|
+
get "/foo" do
|
205
|
+
foo
|
206
|
+
end
|
207
|
+
end
|
208
|
+
}
|
209
|
+
|
210
|
+
get '/something/foo'
|
211
|
+
assert ok?
|
212
|
+
assert_equal 'bar', body
|
213
|
+
end
|
214
|
+
|
215
|
+
it 'supports helpers inside the scope' do
|
216
|
+
mock_app {
|
217
|
+
scope "something" do
|
218
|
+
helpers do
|
219
|
+
def foo
|
220
|
+
"bar"
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
get "/foo" do
|
225
|
+
foo
|
226
|
+
end
|
227
|
+
end
|
228
|
+
}
|
229
|
+
|
230
|
+
get '/something/foo'
|
231
|
+
assert ok?
|
232
|
+
assert_equal 'bar', body
|
233
|
+
end
|
234
|
+
|
235
|
+
it 'supports using a class as a scope' do
|
236
|
+
class Page; end
|
237
|
+
|
238
|
+
mock_app {
|
239
|
+
scope Page do
|
240
|
+
get "/hello" do
|
241
|
+
"hello back!"
|
242
|
+
end
|
243
|
+
end
|
244
|
+
}
|
245
|
+
|
246
|
+
get "/pages/hello"
|
247
|
+
assert ok?
|
248
|
+
assert_equal 'hello back!', body
|
249
|
+
end
|
250
|
+
|
251
|
+
it 'supports using a class as a scope (singular)' do
|
252
|
+
class Page; end
|
253
|
+
|
254
|
+
mock_app {
|
255
|
+
scope Page, :singular => true do
|
256
|
+
get "/hello" do
|
257
|
+
"hello back!"
|
258
|
+
end
|
259
|
+
end
|
260
|
+
}
|
261
|
+
|
262
|
+
get "/page/hello"
|
263
|
+
assert ok?
|
264
|
+
assert_equal 'hello back!', body
|
265
|
+
end
|
266
|
+
|
267
|
+
it 'supports using a class as a scope (keep full name)' do
|
268
|
+
class Page; end
|
269
|
+
|
270
|
+
mock_app {
|
271
|
+
scope Page, :full_classname => true do
|
272
|
+
get "/hello" do
|
273
|
+
"hello back!"
|
274
|
+
end
|
275
|
+
end
|
276
|
+
}
|
277
|
+
|
278
|
+
get "/scope-test/pages/hello"
|
279
|
+
assert ok?
|
280
|
+
assert_equal 'hello back!', body
|
281
|
+
end
|
282
|
+
|
283
|
+
it "supports scoped before" do
|
284
|
+
mock_app {
|
285
|
+
get("foo") { @text.to_s + "foo" }
|
286
|
+
scope :bar do
|
287
|
+
before { @text = "baz" }
|
288
|
+
get { @text.to_s + "bar" }
|
289
|
+
end
|
290
|
+
}
|
291
|
+
get "/foo"
|
292
|
+
assert ok?
|
293
|
+
assert_equal "foo", body
|
294
|
+
|
295
|
+
get "/bar"
|
296
|
+
assert ok?
|
297
|
+
assert_equal "bazbar", body
|
298
|
+
end
|
299
|
+
|
300
|
+
it "supports multiple scopes at once" do
|
301
|
+
mock_app {
|
302
|
+
scopes :admin, :pages do
|
303
|
+
get { "hello there" }
|
304
|
+
end
|
305
|
+
}
|
306
|
+
get "/admin/pages"
|
307
|
+
assert ok?
|
308
|
+
assert_equal "hello there", body
|
309
|
+
end
|
310
|
+
|
311
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require File.expand_path 'helper', File.dirname(__FILE__)
|
2
|
+
|
3
|
+
class UrlHelperTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
it "supports the url method" do
|
6
|
+
mock_app do
|
7
|
+
scope "admin" do
|
8
|
+
get do
|
9
|
+
"hello #{url(:admin)}"
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
get "/admin"
|
15
|
+
assert ok?
|
16
|
+
assert_equal "hello /admin", body
|
17
|
+
end
|
18
|
+
|
19
|
+
it "supports nested scopes with the url method" do
|
20
|
+
mock_app do
|
21
|
+
scope "admin" do
|
22
|
+
scope "projects" do
|
23
|
+
get do
|
24
|
+
"hello #{url(:admin_projects)}"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
get "/admin/projects"
|
31
|
+
assert ok?
|
32
|
+
assert_equal "hello /admin/projects", body
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
metadata
ADDED
@@ -0,0 +1,107 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: sinatra-scope
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Nathan Herald
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-11-28 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: sinatra
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: activesupport
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ~>
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: 3.0.0
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ~>
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: 3.0.0
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: i18n
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ~>
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 0.5.0
|
54
|
+
type: :runtime
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 0.5.0
|
62
|
+
description: Simple nested routes for Sinatra.
|
63
|
+
email: nathan@myobie.com
|
64
|
+
executables: []
|
65
|
+
extensions: []
|
66
|
+
extra_rdoc_files:
|
67
|
+
- Gemfile
|
68
|
+
- Gemfile.lock
|
69
|
+
files:
|
70
|
+
- lib/sinatra/resource.rb
|
71
|
+
- lib/sinatra/scope.rb
|
72
|
+
- lib/sinatra/urls.rb
|
73
|
+
- test/contest.rb
|
74
|
+
- test/helper.rb
|
75
|
+
- test/sinatra_resource_test.rb
|
76
|
+
- test/sinatra_scope_test.rb
|
77
|
+
- test/sinatra_urls_test.rb
|
78
|
+
- Gemfile
|
79
|
+
- Gemfile.lock
|
80
|
+
homepage: http://github.com/myobie/sinatra-scope
|
81
|
+
licenses: []
|
82
|
+
post_install_message:
|
83
|
+
rdoc_options:
|
84
|
+
- --title
|
85
|
+
- Sinatra::Scope -- Simple nested routes for Sinatra
|
86
|
+
require_paths:
|
87
|
+
- lib
|
88
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ! '>='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0'
|
94
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
95
|
+
none: false
|
96
|
+
requirements:
|
97
|
+
- - ! '>='
|
98
|
+
- !ruby/object:Gem::Version
|
99
|
+
version: '0'
|
100
|
+
requirements:
|
101
|
+
- sinatra
|
102
|
+
rubyforge_project: sinatra-scope
|
103
|
+
rubygems_version: 1.8.23
|
104
|
+
signing_key:
|
105
|
+
specification_version: 3
|
106
|
+
summary: Simple nested routes for Sinatra
|
107
|
+
test_files: []
|