bebop 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.markdown +111 -0
- data/Rakefile +9 -0
- data/bebop.gemspec +33 -0
- data/examples/filters.rb +60 -0
- data/examples/routes.rb +79 -0
- data/lib/bebop.rb +4 -0
- data/lib/bebop/ext.rb +184 -0
- data/spec/bebop_spec.rb +201 -0
- metadata +91 -0
data/README.markdown
ADDED
@@ -0,0 +1,111 @@
|
|
1
|
+
Bebop
|
2
|
+
=====
|
3
|
+
|
4
|
+
Bebop is small Sinatra/Monk extension for DRY resource based routing. It provides targeted filters, path helpers, nested resources, printable routing information, and familiar action methods like new, show, destroy, update, and index.
|
5
|
+
|
6
|
+
The name comes from its happy partnering with the [Monk](http://monkrb.com) glue framework, as Thelonius Monk is considered to be the father of bebop.
|
7
|
+
|
8
|
+
|
9
|
+
dependencies
|
10
|
+
------------
|
11
|
+
|
12
|
+
* Sinatra
|
13
|
+
* ActiveSupport
|
14
|
+
|
15
|
+
install
|
16
|
+
-------
|
17
|
+
|
18
|
+
Make sure you have gemcutter.org as one of your sources:
|
19
|
+
|
20
|
+
gem sources -a http://gemcutter.org
|
21
|
+
|
22
|
+
Then:
|
23
|
+
|
24
|
+
gem install bebop
|
25
|
+
|
26
|
+
verify
|
27
|
+
------
|
28
|
+
|
29
|
+
Requires rspec version 1.2.9 or higher
|
30
|
+
|
31
|
+
cd /path/to/bebop; spec spec
|
32
|
+
|
33
|
+
sample
|
34
|
+
------
|
35
|
+
|
36
|
+
If you were using an Active Record model Foo:
|
37
|
+
|
38
|
+
require 'bebop'
|
39
|
+
require 'sinatra'
|
40
|
+
require 'foo'
|
41
|
+
|
42
|
+
class MyApp < Sinatra::Base
|
43
|
+
register Bebop
|
44
|
+
|
45
|
+
resource :foos do |foos|
|
46
|
+
|
47
|
+
# GET /foos/:foo_id
|
48
|
+
foos.show do
|
49
|
+
@foo = Foo.find(params[:foo_id])
|
50
|
+
haml :'foos/show'
|
51
|
+
end
|
52
|
+
|
53
|
+
# GET /foos/new
|
54
|
+
foos.new do
|
55
|
+
@foo = Foo.new
|
56
|
+
haml :'foos/new'
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
more detail
|
62
|
+
-----------
|
63
|
+
|
64
|
+
See the examples directory. You can play with each of the examples as follows:
|
65
|
+
|
66
|
+
$ pwd
|
67
|
+
/path/to/bebop
|
68
|
+
$ ruby examples/routes.rb
|
69
|
+
== Sinatra/0.9.4 has taken the stage on 4567 for development with backup from Thin
|
70
|
+
>> Thin web server (v1.2.4 codename Flaming Astroboy)
|
71
|
+
>> Maximum connections set to 1024
|
72
|
+
>> Listening on 0.0.0.0:4567, CTRL+C to stop
|
73
|
+
|
74
|
+
routes
|
75
|
+
------
|
76
|
+
|
77
|
+
Run your sinatra/monk app with the PROUTES env variable set to view the routes created with the resource method
|
78
|
+
|
79
|
+
$ ruby my_app.rb PROUTES=true
|
80
|
+
|
81
|
+
or
|
82
|
+
|
83
|
+
$ thor monk:start PROUTES=true
|
84
|
+
|
85
|
+
NOTE: planning to change the formatting soon, as it currently sucks
|
86
|
+
|
87
|
+
license
|
88
|
+
-------
|
89
|
+
|
90
|
+
(The MIT License)
|
91
|
+
|
92
|
+
Copyright (c) 2010 FIX
|
93
|
+
|
94
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
95
|
+
a copy of this software and associated documentation files (the
|
96
|
+
'Software'), to deal in the Software without restriction, including
|
97
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
98
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
99
|
+
permit persons to whom the Software is furnished to do so, subject to
|
100
|
+
the following conditions:
|
101
|
+
|
102
|
+
The above copyright notice and this permission notice shall be
|
103
|
+
included in all copies or substantial portions of the Software.
|
104
|
+
|
105
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
106
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
107
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
108
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
109
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
110
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
111
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'spec/rake/spectask'
|
3
|
+
|
4
|
+
desc "Run all examples with RCov"
|
5
|
+
Spec::Rake::SpecTask.new('specs_with_rcov') do |t|
|
6
|
+
t.spec_files = FileList['spec/**/*.rb']
|
7
|
+
t.rcov = true
|
8
|
+
t.rcov_opts = ['--exclude spec', '--exclude "gems/*"', '--exclude "bebop.rb"' ]
|
9
|
+
end
|
data/bebop.gemspec
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = 'bebop'
|
3
|
+
s.version = '0.1.0'
|
4
|
+
s.date = '2010-1-10'
|
5
|
+
|
6
|
+
s.summary = s.description = "A small Sinatra/Monk extension for resource routing"
|
7
|
+
|
8
|
+
s.authors = ["John Bender"]
|
9
|
+
s.homepage = 'http://github.com/johnbender/bebop'
|
10
|
+
s.email = 'john.m.bender@gmail.com'
|
11
|
+
|
12
|
+
# = MANIFEST =
|
13
|
+
s.files = %w[
|
14
|
+
README.markdown
|
15
|
+
Rakefile
|
16
|
+
bebop.gemspec
|
17
|
+
examples/filters.rb
|
18
|
+
examples/routes.rb
|
19
|
+
lib/bebop/ext.rb
|
20
|
+
lib/bebop.rb
|
21
|
+
spec/bebop_spec.rb
|
22
|
+
]
|
23
|
+
# = MANIFEST =
|
24
|
+
s.add_dependency 'sinatra', '>= 0.9.4'
|
25
|
+
s.add_dependency 'activesupport', '>= 2.3.5'
|
26
|
+
|
27
|
+
s.add_development_dependency 'rspec', '>=1.2.9'
|
28
|
+
|
29
|
+
s.has_rdoc = false
|
30
|
+
s.require_paths = %w[lib]
|
31
|
+
s.rubyforge_project = 'bebop'
|
32
|
+
s.rubygems_version = '1.3.5'
|
33
|
+
end
|
data/examples/filters.rb
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '..', 'lib', 'bebop')
|
2
|
+
require 'sinatra'
|
3
|
+
|
4
|
+
class MyApp < Sinatra::Base
|
5
|
+
register Bebop
|
6
|
+
|
7
|
+
resource :foos do |foos|
|
8
|
+
# Bebop provides some simple targeting for before and after filters, with the
|
9
|
+
# caveat that they must be defined before the routes they target within the resource block
|
10
|
+
# To have your filter run before all routes under a given resource and its child resources
|
11
|
+
# pass :all as the first parameter
|
12
|
+
#
|
13
|
+
foos.before :all do
|
14
|
+
@all = 'all'
|
15
|
+
end
|
16
|
+
|
17
|
+
# To have your filter run before a specific route, the route must be one of the seven helper
|
18
|
+
# routes (see example/routes.rb) or specify the :identifier parameter
|
19
|
+
#
|
20
|
+
foos.before :new do
|
21
|
+
@new = 'new'
|
22
|
+
end
|
23
|
+
|
24
|
+
foos.new do
|
25
|
+
"#{@all} #{@new}" # => 'all new'
|
26
|
+
end
|
27
|
+
|
28
|
+
# You can target the vanila methods by providing the :identifier hash option
|
29
|
+
#
|
30
|
+
# GET /foos/baz
|
31
|
+
foos.get '/baz', :identifier => :new do
|
32
|
+
@new # => 'new'
|
33
|
+
end
|
34
|
+
|
35
|
+
# You can also specify a before filter for nested routes by using the child resource name
|
36
|
+
#
|
37
|
+
foos.before :bars do
|
38
|
+
@bars = 'some bars'
|
39
|
+
end
|
40
|
+
|
41
|
+
foos.resource :bars do |bars|
|
42
|
+
bars.get '/some_bars' do
|
43
|
+
@bars # => 'some bars'
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
foos.get '/bak' do
|
48
|
+
@bars # => nil
|
49
|
+
end
|
50
|
+
|
51
|
+
# Finally you can specify many different methods in your filters by passing many identifiers
|
52
|
+
#
|
53
|
+
foos.before :bak, :baz do
|
54
|
+
@bak_baz = "bak 'n' baz"
|
55
|
+
end
|
56
|
+
|
57
|
+
foos.get('/something', :identifier => :bak) { @bak_baz }
|
58
|
+
foos.get('/anything', :identifier => :baz) { @bak_baz }
|
59
|
+
end
|
60
|
+
end
|
data/examples/routes.rb
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '..', 'lib', 'bebop')
|
2
|
+
require 'sinatra'
|
3
|
+
|
4
|
+
class MyApp < Sinatra::Base
|
5
|
+
register Bebop
|
6
|
+
|
7
|
+
resource :foos do |foos|
|
8
|
+
|
9
|
+
# Any of the traditional sinatra methods called on the block parameter
|
10
|
+
# will take the first argument (or an empty string) and apply it to
|
11
|
+
# the resource base
|
12
|
+
#
|
13
|
+
# GET /foos/baz
|
14
|
+
foos.get '/baz' do
|
15
|
+
'baz'
|
16
|
+
end
|
17
|
+
|
18
|
+
# There are 7 helper methods for the traditional resource actions. They
|
19
|
+
# are index, new, create, update, edit, destroy, and show. Each is a wrapper
|
20
|
+
# for the corresponding Sinatra method
|
21
|
+
#
|
22
|
+
# GET /foos
|
23
|
+
foos.index {}
|
24
|
+
|
25
|
+
# For actions that require parameters the parameter name is derived from the singularized
|
26
|
+
# name of the resource with '_id' appended.
|
27
|
+
#
|
28
|
+
# GET /foos/:foo_id
|
29
|
+
foos.show {}
|
30
|
+
|
31
|
+
# GET /foos/new
|
32
|
+
foos.new {}
|
33
|
+
|
34
|
+
# POST /foos
|
35
|
+
foos.create {}
|
36
|
+
|
37
|
+
# PUT /foos/:foo_id
|
38
|
+
foos.update {}
|
39
|
+
|
40
|
+
# GET /foos/:foo_id/edit
|
41
|
+
foos.edit {}
|
42
|
+
|
43
|
+
# DELETE /foos/:foo_id
|
44
|
+
foos.destroy {}
|
45
|
+
|
46
|
+
# For each of the helper methods, and any generic method (eg foos.get) that specifies the :identifier
|
47
|
+
# option, bebop will define a relative path helper. See the nested resource below for the nameing of those
|
48
|
+
# methods
|
49
|
+
#
|
50
|
+
# POST /foos/do/redirect
|
51
|
+
foos.get 'do/redirect' do
|
52
|
+
# Redirects to /foos/1
|
53
|
+
redirect foos_show_path(1)
|
54
|
+
end
|
55
|
+
|
56
|
+
# If you want to represent the relationship of your models through nested resources use
|
57
|
+
# the resource method with the block parameter and all new routes will be nested and
|
58
|
+
# parameterized properly
|
59
|
+
#
|
60
|
+
# Prefix all with /foos/:foo_id
|
61
|
+
foos.resource :bars do |bars|
|
62
|
+
|
63
|
+
# GET /foos/:foo_id/bars/:bar_id/edit
|
64
|
+
bars.edit do
|
65
|
+
"foo: #{params[:foo_id]} bar: #{params[:bar_id]}"
|
66
|
+
end
|
67
|
+
|
68
|
+
bars.get '/redirect' do
|
69
|
+
|
70
|
+
# The route helper method naming convention is simple and easy to remember as it follows
|
71
|
+
# the order of nesting for the given route starting with the original parent resource and
|
72
|
+
# ending with the method identifier.
|
73
|
+
#
|
74
|
+
# Redirects to /foos/1/bars/2/edit
|
75
|
+
redirect foos_bars_edit_path(1, 2)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
data/lib/bebop.rb
ADDED
data/lib/bebop/ext.rb
ADDED
@@ -0,0 +1,184 @@
|
|
1
|
+
require 'active_support'
|
2
|
+
|
3
|
+
module Bebop
|
4
|
+
class InvalidPathArgumentError < ArgumentError; end
|
5
|
+
PARAM_REGEX = /:[a-zA-Z0-9_]+/
|
6
|
+
|
7
|
+
def resource(name, &block)
|
8
|
+
resource = ResourceRouter.new
|
9
|
+
resource.resource(name, &block)
|
10
|
+
resource.routes.each do |method, route, options, block, helper|
|
11
|
+
send(method, route, options, &block)
|
12
|
+
define_route_helper(helper, route) if helper
|
13
|
+
end
|
14
|
+
resource.print if ENV['PROUTES']
|
15
|
+
end
|
16
|
+
|
17
|
+
def define_route_helper(helper, route)
|
18
|
+
define_method helper do |*args|
|
19
|
+
unless route.scan(PARAM_REGEX).length == args.length
|
20
|
+
raise InvalidPathArgumentError.new("invalid number of parameters #{args.length} for: #{route}")
|
21
|
+
end
|
22
|
+
|
23
|
+
args.inject(route.dup) do |acc, arg|
|
24
|
+
#handle fixnums and ar objects
|
25
|
+
arg = (arg.kind_of?(Fixnum) ? arg : arg.id)
|
26
|
+
acc.sub!(PARAM_REGEX, arg.to_s)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
|
32
|
+
class ResourceRouter
|
33
|
+
attr_accessor :routes
|
34
|
+
|
35
|
+
def initialize(parent_resources=[], before_all=[], after_all=[])
|
36
|
+
@current_resource = parent_resources.pop
|
37
|
+
@parent_resources = parent_resources
|
38
|
+
@before, @after, @routes = before_all, after_all, []
|
39
|
+
end
|
40
|
+
|
41
|
+
def get(route, options={}, &block)
|
42
|
+
add_route(:get, route, options, block)
|
43
|
+
end
|
44
|
+
|
45
|
+
def put(route, options={}, &block)
|
46
|
+
add_route(:put, route, options, block)
|
47
|
+
end
|
48
|
+
|
49
|
+
def post(route, options={}, &block)
|
50
|
+
add_route(:post, route, options, block)
|
51
|
+
end
|
52
|
+
|
53
|
+
def delete(route, options={}, &block)
|
54
|
+
add_route(:delete, route, options, block)
|
55
|
+
end
|
56
|
+
|
57
|
+
def head(route, options={}, &block)
|
58
|
+
add_route(:head, route, options, block)
|
59
|
+
end
|
60
|
+
|
61
|
+
def new(options={}, &block)
|
62
|
+
get 'new', options.merge(:identifier => :new), &block
|
63
|
+
end
|
64
|
+
|
65
|
+
def create(options={}, &block)
|
66
|
+
post '' , options.merge(:identifier => :create), &block
|
67
|
+
end
|
68
|
+
|
69
|
+
def edit(options={}, &block)
|
70
|
+
get append_token(resource_identifier, 'edit') , options.merge(:identifier => :edit), &block
|
71
|
+
end
|
72
|
+
|
73
|
+
def index(options={}, &block)
|
74
|
+
get '', options.merge(:identifier => :index), &block
|
75
|
+
end
|
76
|
+
|
77
|
+
def show(route=nil, options={}, &block)
|
78
|
+
get append_token(resource_identifier, (route || '').to_s), options.merge(:identifier => route || :show), &block
|
79
|
+
end
|
80
|
+
|
81
|
+
def destroy(options={}, &block)
|
82
|
+
delete resource_identifier, options.merge(:identifier => :destroy), &block
|
83
|
+
end
|
84
|
+
|
85
|
+
def update(options={}, &block)
|
86
|
+
put resource_identifier, options.merge(:identifier => :update), &block
|
87
|
+
end
|
88
|
+
|
89
|
+
def before(*params, &block)
|
90
|
+
add_filter(@before, params, block)
|
91
|
+
end
|
92
|
+
|
93
|
+
def after(*params, &block)
|
94
|
+
add_filter(@after, params, block)
|
95
|
+
end
|
96
|
+
|
97
|
+
def resource(name, &block)
|
98
|
+
before_filters = filters(@before, :all, name)
|
99
|
+
after_filters = filters(@after, :all, name)
|
100
|
+
|
101
|
+
router = self.class.new(all_resources + [name], before_filters, after_filters)
|
102
|
+
yield(router)
|
103
|
+
@routes += router.routes
|
104
|
+
end
|
105
|
+
|
106
|
+
def print
|
107
|
+
#TODO 6! 6! Block parameters, Ah Ah Ah! -> probably need route objects
|
108
|
+
@routes.each do |method, route, options, block, helper, identifier|
|
109
|
+
puts "#{route}"
|
110
|
+
puts " method: #{method.to_s.upcase}"
|
111
|
+
puts " helper: #{helper}" if helper
|
112
|
+
puts " identifier: #{identifier}" if identifier
|
113
|
+
puts
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
private
|
118
|
+
|
119
|
+
def all_resources
|
120
|
+
#in the initial call to resource there is current_resource
|
121
|
+
@current_resource ? @parent_resources + [@current_resource] : @parent_resources
|
122
|
+
end
|
123
|
+
|
124
|
+
def resource_identifier(resource=@current_resource)
|
125
|
+
":#{resource.to_s.singularize}_id"
|
126
|
+
end
|
127
|
+
|
128
|
+
def add_filter(type, params, block)
|
129
|
+
params = [:all] if params.empty?
|
130
|
+
type << {:routes => params, :block => block}
|
131
|
+
end
|
132
|
+
|
133
|
+
def add_route(method, route, options, block)
|
134
|
+
identifier =options[:identifier]
|
135
|
+
route = append_to_path(route)
|
136
|
+
block = add_filters_to_block(block, identifier, method)
|
137
|
+
helper = route_helper(identifier)
|
138
|
+
|
139
|
+
#Sinatra doesn't like the spurious options
|
140
|
+
options.delete(:identifier)
|
141
|
+
|
142
|
+
@routes << [method, route, options, block, helper]
|
143
|
+
end
|
144
|
+
|
145
|
+
def append_to_path(str)
|
146
|
+
append_token(append_token(parent_resource_path, @current_resource), str)
|
147
|
+
end
|
148
|
+
|
149
|
+
def parent_resource_path
|
150
|
+
@parent_resources.inject('') do |acc, x|
|
151
|
+
append_token(append_token(acc, x), resource_identifier(x))
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
def append_token(l, tkn)
|
156
|
+
tkn = tkn.to_s
|
157
|
+
tkn = "/#{tkn}" unless tkn.empty? || tkn =~ /^\//
|
158
|
+
"#{l}#{tkn}"
|
159
|
+
end
|
160
|
+
|
161
|
+
def route_helper(identifier)
|
162
|
+
helper_tokens = (@parent_resources.dup << @current_resource) << identifier
|
163
|
+
"#{helper_tokens.join('_')}_path".to_sym
|
164
|
+
end
|
165
|
+
|
166
|
+
def add_filters_to_block(block, identifier, method)
|
167
|
+
before = filters(@before, identifier, method, :all, @current_resource)
|
168
|
+
after = filters(@after, identifier, method, :all, @current_resource)
|
169
|
+
Proc.new do
|
170
|
+
before.each { |f| instance_eval( &f[:block] ) }
|
171
|
+
result = instance_eval(&block)
|
172
|
+
after.each { |f| instance_eval(&f[:block]) }
|
173
|
+
result
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
def filters(list, *identifiers)
|
178
|
+
list.select do |filter|
|
179
|
+
rs = filter[:routes]
|
180
|
+
!(rs & identifiers).empty?
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
data/spec/bebop_spec.rb
ADDED
@@ -0,0 +1,201 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '..', 'lib', 'bebop')
|
2
|
+
require 'rack/test'
|
3
|
+
require 'sinatra'
|
4
|
+
|
5
|
+
class TestClass < Sinatra::Base
|
6
|
+
register Bebop
|
7
|
+
def self.global
|
8
|
+
@@global
|
9
|
+
end
|
10
|
+
def self.global=(val)
|
11
|
+
@@global = val
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
describe Bebop do
|
16
|
+
include Rack::Test::Methods
|
17
|
+
|
18
|
+
def app
|
19
|
+
@test_app ||= TestClass.new
|
20
|
+
@test_app
|
21
|
+
end
|
22
|
+
|
23
|
+
before :all do
|
24
|
+
app
|
25
|
+
@class = TestClass
|
26
|
+
use_bebop
|
27
|
+
end
|
28
|
+
|
29
|
+
before :each do
|
30
|
+
TestClass.global = nil
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should define route helpers properly for routes specifying an identifier" do
|
34
|
+
@class.instance_methods.should include('foos_bars_index_path')
|
35
|
+
@class.instance_methods.should include('foos_create_path')
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should provide the correct relative url from the route helpers" do
|
39
|
+
@test_app.foos_bars_index_path(1).should == '/foos/1/bars'
|
40
|
+
@test_app.foos_bars_update_path(1,2).should == '/foos/1/bars/2'
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should raise an error when the wrong number of paramters are passed to a route helper" do
|
44
|
+
lambda {@test_app.foos_bars_update_path(1)}.should raise_error(Bebop::InvalidPathArgumentError)
|
45
|
+
end
|
46
|
+
|
47
|
+
it "should define a route with new for the new method" do
|
48
|
+
get '/foos/new'
|
49
|
+
last_response.body.should == "new"
|
50
|
+
end
|
51
|
+
|
52
|
+
it "should define a route with an identifer and append edit for the edit method" do
|
53
|
+
get '/foos/1/edit'
|
54
|
+
last_response.body.should == 'edit 1'
|
55
|
+
end
|
56
|
+
|
57
|
+
it "shoud define a route with an identifer for show and recieve the proper parameters" do
|
58
|
+
get '/foos/1/bars/2'
|
59
|
+
last_response.body.should == 'show 1 2'
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should respond correctly when the route is consulted" do
|
63
|
+
post '/foos'
|
64
|
+
last_response.body.should match(/#{BEFORE_ALL}/)
|
65
|
+
end
|
66
|
+
|
67
|
+
it "should call before and after blocks correctly based on the identifier" do
|
68
|
+
put '/foos/1'
|
69
|
+
last_response.body.should match(/#{BEFORE_UPDATE}/)
|
70
|
+
|
71
|
+
post '/foos'
|
72
|
+
last_response.body.should_not match(/#{BEFORE_UPDATE}/)
|
73
|
+
end
|
74
|
+
|
75
|
+
it "should correctly append any vanilla sinatra method with the resource prefix" do
|
76
|
+
get '/foos/arbitrary'
|
77
|
+
last_response.body.should == 'baz'
|
78
|
+
end
|
79
|
+
|
80
|
+
it "should not call before and after blocks in a nested resource based on the identifer" do
|
81
|
+
put '/foos/1/bars/1'
|
82
|
+
last_response.body.should_not match(/#{BEFORE_UPDATE}/)
|
83
|
+
end
|
84
|
+
|
85
|
+
it "should call before and after all blocks on all resource routes" do
|
86
|
+
put '/foos/1'
|
87
|
+
last_response.body.should match(/#{BEFORE_ALL}/)
|
88
|
+
|
89
|
+
post '/foos'
|
90
|
+
last_response.body.should match(/#{BEFORE_ALL}/)
|
91
|
+
|
92
|
+
get '/foos/1/bars'
|
93
|
+
last_response.body.should match(/#{BEFORE_ALL}/)
|
94
|
+
|
95
|
+
delete '/foos/1/bars/1'
|
96
|
+
last_response.body.should match(/#{BEFORE_ALL}/)
|
97
|
+
|
98
|
+
put '/foos/1/bars/1'
|
99
|
+
last_response.body.should match(/#{BEFORE_ALL}/)
|
100
|
+
end
|
101
|
+
|
102
|
+
it "should call before and after resource blocks only on the nested resource routes" do
|
103
|
+
get '/foos/1/bars'
|
104
|
+
last_response.body.should match(/#{BEFORE_BARS}/)
|
105
|
+
|
106
|
+
delete '/foos/1/bars/1'
|
107
|
+
last_response.body.should match(/#{BEFORE_BARS}/)
|
108
|
+
end
|
109
|
+
|
110
|
+
it "should not call before and after resource blocks on non nested resource blocks" do
|
111
|
+
post '/foos'
|
112
|
+
last_response.body.should_not match(/#{BEFORE_BARS}/)
|
113
|
+
end
|
114
|
+
|
115
|
+
it "should call before and after filters without any identifier specified before all routes" do
|
116
|
+
put '/foos/1'
|
117
|
+
last_response.body.should match(/#{BEFORE_ALL_2}/)
|
118
|
+
|
119
|
+
post '/foos'
|
120
|
+
last_response.body.should match(/#{BEFORE_ALL_2}/)
|
121
|
+
|
122
|
+
get '/foos/1/bars'
|
123
|
+
last_response.body.should match(/#{BEFORE_ALL_2}/)
|
124
|
+
|
125
|
+
delete '/foos/1/bars/1'
|
126
|
+
last_response.body.should match(/#{BEFORE_ALL_2}/)
|
127
|
+
|
128
|
+
put '/foos/1/bars/1'
|
129
|
+
last_response.body.should match(/#{BEFORE_ALL_2}/)
|
130
|
+
end
|
131
|
+
|
132
|
+
it "should call before and after filters that specify multiple identifiers before the proper routes" do
|
133
|
+
post '/foos'
|
134
|
+
TestClass.global.should == AFTER_VALUE
|
135
|
+
|
136
|
+
put '/foos/1'
|
137
|
+
TestClass.global.should == AFTER_VALUE
|
138
|
+
end
|
139
|
+
|
140
|
+
it "should not call before and after filters that specify multiple parameters on anyting else" do
|
141
|
+
get '/foos/new'
|
142
|
+
TestClass.global = nil
|
143
|
+
end
|
144
|
+
|
145
|
+
it "should not prepend previous nested routes on non nested routes that follow" do
|
146
|
+
get '/foos/do/something'
|
147
|
+
last_response.body.should == 'success'
|
148
|
+
end
|
149
|
+
|
150
|
+
it "should produce correct routes for more than 2 levels of nesting"
|
151
|
+
|
152
|
+
BEFORE_BARS = '__before_bars__'
|
153
|
+
BEFORE_UPDATE = '__before_update__'
|
154
|
+
BEFORE_ALL = '__all__'
|
155
|
+
BEFORE_ALL_2 = '__2all__'
|
156
|
+
AFTER_VALUE = '__after__'
|
157
|
+
|
158
|
+
def use_bebop
|
159
|
+
# ENV['PROUTES']='t'
|
160
|
+
@class.resource :foos do |foo|
|
161
|
+
|
162
|
+
foo.before :all do
|
163
|
+
@all = BEFORE_ALL
|
164
|
+
end
|
165
|
+
|
166
|
+
foo.before do
|
167
|
+
@all2 = BEFORE_ALL_2
|
168
|
+
end
|
169
|
+
|
170
|
+
foo.before :update do
|
171
|
+
@update = BEFORE_UPDATE
|
172
|
+
end
|
173
|
+
|
174
|
+
foo.before :bars do
|
175
|
+
@bars = BEFORE_BARS
|
176
|
+
end
|
177
|
+
|
178
|
+
foo.after :create, :update do
|
179
|
+
TestClass.global = AFTER_VALUE
|
180
|
+
end
|
181
|
+
|
182
|
+
foo.get(:arbitrary) { 'baz' }
|
183
|
+
|
184
|
+
foo.create { "#{@all2}#{@all}#{@update}#{@bars}" }
|
185
|
+
foo.update { "#{@all2}#{@all}#{@update}#{@bars}" }
|
186
|
+
|
187
|
+
foo.new { "new" }
|
188
|
+
foo.edit { "edit #{params[:foo_id]}" }
|
189
|
+
|
190
|
+
foo.resource :bars do |bar|
|
191
|
+
bar.index { "#{@all2}#{@all}#{@update}#{@bars}" }
|
192
|
+
bar.update { "#{@all2}#{@all}#{@update}#{@bars}" }
|
193
|
+
bar.destroy { "#{@all2}#{@all}#{@update}#{@bars}" }
|
194
|
+
|
195
|
+
bar.show { "show #{params[:foo_id]} #{params[:bar_id]}" }
|
196
|
+
end
|
197
|
+
|
198
|
+
foo.get('/do/something') { 'success' }
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|
metadata
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: bebop
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- John Bender
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2010-01-10 00:00:00 -08:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: sinatra
|
17
|
+
type: :runtime
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 0.9.4
|
24
|
+
version:
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: activesupport
|
27
|
+
type: :runtime
|
28
|
+
version_requirement:
|
29
|
+
version_requirements: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 2.3.5
|
34
|
+
version:
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: rspec
|
37
|
+
type: :development
|
38
|
+
version_requirement:
|
39
|
+
version_requirements: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: 1.2.9
|
44
|
+
version:
|
45
|
+
description: A small Sinatra/Monk extension for resource routing
|
46
|
+
email: john.m.bender@gmail.com
|
47
|
+
executables: []
|
48
|
+
|
49
|
+
extensions: []
|
50
|
+
|
51
|
+
extra_rdoc_files: []
|
52
|
+
|
53
|
+
files:
|
54
|
+
- README.markdown
|
55
|
+
- Rakefile
|
56
|
+
- bebop.gemspec
|
57
|
+
- examples/filters.rb
|
58
|
+
- examples/routes.rb
|
59
|
+
- lib/bebop/ext.rb
|
60
|
+
- lib/bebop.rb
|
61
|
+
- spec/bebop_spec.rb
|
62
|
+
has_rdoc: true
|
63
|
+
homepage: http://github.com/johnbender/bebop
|
64
|
+
licenses: []
|
65
|
+
|
66
|
+
post_install_message:
|
67
|
+
rdoc_options: []
|
68
|
+
|
69
|
+
require_paths:
|
70
|
+
- lib
|
71
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: "0"
|
76
|
+
version:
|
77
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
78
|
+
requirements:
|
79
|
+
- - ">="
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
version: "0"
|
82
|
+
version:
|
83
|
+
requirements: []
|
84
|
+
|
85
|
+
rubyforge_project: bebop
|
86
|
+
rubygems_version: 1.3.5
|
87
|
+
signing_key:
|
88
|
+
specification_version: 3
|
89
|
+
summary: A small Sinatra/Monk extension for resource routing
|
90
|
+
test_files: []
|
91
|
+
|