bebop 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -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
@@ -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
@@ -0,0 +1,4 @@
1
+ libdir = File.dirname(__FILE__)
2
+ $LOAD_PATH.unshift(libdir) unless $LOAD_PATH.include?(libdir)
3
+
4
+ require 'bebop/ext'
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
@@ -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
+