bebop 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/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
|
+
|