padrino-core 0.5.0 → 0.6.1
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +1 -1
- data/README.rdoc +232 -19
- data/Rakefile +1 -0
- data/VERSION +1 -1
- data/bin/padrino +3 -2
- data/lib/padrino-core.rb +2 -0
- data/lib/padrino-core/application.rb +278 -24
- data/lib/padrino-core/cli.rb +102 -0
- data/lib/padrino-core/{tasks → cli}/adapter.rb +1 -2
- data/lib/padrino-core/{tasks → cli}/console.rb +1 -1
- data/lib/padrino-core/cli/rake.rb +25 -0
- data/lib/padrino-core/{tasks → cli}/test.rb +2 -3
- data/lib/padrino-core/images/404.png +0 -0
- data/lib/padrino-core/images/500.png +0 -0
- data/lib/padrino-core/loader.rb +1 -7
- data/lib/padrino-core/logger.rb +7 -3
- data/lib/padrino-core/mounter.rb +2 -0
- data/lib/padrino-core/routing.rb +0 -0
- data/lib/padrino-core/support_lite.rb +1 -1
- data/lib/padrino-core/tasks.rb +11 -82
- data/padrino-core.gemspec +14 -7
- data/test/fixtures/apps/complex.rb +2 -2
- data/test/fixtures/apps/simple.rb +1 -1
- data/test/helper.rb +0 -3
- data/test/test_reloader_complex.rb +1 -0
- data/test/test_reloader_simple.rb +21 -4
- data/test/test_routing.rb +217 -0
- metadata +21 -7
- data/lib/padrino-core/tasks/helpers.rb +0 -20
- data/lib/padrino-core/tasks/rake_tasks.rb +0 -19
data/LICENSE
CHANGED
data/README.rdoc
CHANGED
@@ -1,18 +1,81 @@
|
|
1
1
|
= padrino-core
|
2
2
|
|
3
|
+
Padrino is the godfather of Sinatra.
|
4
|
+
|
5
|
+
== Preface
|
6
|
+
|
7
|
+
Padrino is a ruby framework build upon the {Sinatra Microframework}[http://www.sinatrarb.com].
|
8
|
+
|
9
|
+
Sinatra is a DSL for quickly creating web applications in Ruby with minimal effort.
|
10
|
+
|
11
|
+
The extreme simplicity of this framework is quite refreshing. We have been using Sinatra a great deal
|
12
|
+
for recent projects. First for small and simple json and xml web services and then even
|
13
|
+
for more complex full-featured applications.
|
14
|
+
|
15
|
+
This gem represents an attempt to make it as fun and easy as possible to code increasingly advanced web applications in Sinatra.
|
16
|
+
|
17
|
+
== Introduction
|
18
|
+
|
19
|
+
Many people love Sinatra's simplicity and lightweight but often quickly come to miss a great deal
|
20
|
+
of functionality provided by other web frameworks such as Rails when building non-trivial applications.
|
21
|
+
|
22
|
+
The obvious question in these cases might be "Why not just use rails then?". This can often be a viable option
|
23
|
+
but still Rails is quite a large framework with a 'take it or leave it' attitude.
|
24
|
+
|
25
|
+
Personally, we have come to love the philosophy of Sinatra which acts as a thin layer on top of rack
|
26
|
+
often allowing middleware to do most of the work and pulling in additional complexity only when required.
|
27
|
+
|
28
|
+
Our goal with this framework is to match the essence of Sinatra and at the same time create a standard library
|
29
|
+
of tools, helpers and components that will make Sinatra suitable for more complex applications.
|
30
|
+
|
31
|
+
Here is a small list of what Padrino provides:
|
32
|
+
|
33
|
+
Generators:: for creating new padrino applications i.e.: <tt>padrino-gen app</tt> or <tt>padrino start</tt> on command line
|
34
|
+
MultiApp:: unlike other ruby frameworks Padrino is principally designed for mounting multiple apps at the same time.
|
35
|
+
Routing:: Full url named route, named params, respond_to suppor
|
36
|
+
Tag Helpers:: helpers such as: <tt>tag</tt>, <tt>content_tag</tt>, <tt>input_tag</tt>, ...
|
37
|
+
Asset Helpers:: helpers such as: <tt>link_to</tt>, <tt>image_tag</tt>, <tt>javascript_include_tag</tt>, ...
|
38
|
+
Form Helpers:: with builder support such as: <tt>form_tag</tt>, <tt>form_for</tt>, <tt>field_set_tag</tt>, <tt>text_field</tt>, ...
|
39
|
+
Text Helpers:: useful formatting extensions like: <tt>relative_time_ago</tt>, <tt>js_escape_html</tt>, <tt>sanitize_html</tt>
|
40
|
+
Mailer:: fast, tiny, delivery support for send templating emails (like ActionMailer do)
|
41
|
+
Admin:: an ajax admin that displays your records in sortable grids, tree, windows ... as a desktop app can do.
|
42
|
+
Logging:: Padrino provide a logger that can interact with your orm or any other library
|
43
|
+
Reloading:: With padrino is not necessary like other framework start and restart your server for see changes.
|
44
|
+
I18n:: Padrino has a full support of I18n and can autoset locale.
|
45
|
+
|
46
|
+
Keep in mind, the user will be able to pull in these components seperately and leave out those that are not required
|
47
|
+
or use them altogether for a comprehensive upgrade to Sinatra (a full-stack Padrino application).
|
48
|
+
|
49
|
+
Note that all work has been created to be compatible with haml, erb, and erubis and that this gem is intended to be
|
50
|
+
template-agnostic in providing helpers wherever possible.
|
51
|
+
|
52
|
+
Please help me brainstorm and fork the project if you have any ideas to contribute.
|
53
|
+
|
3
54
|
== Installation
|
4
55
|
|
5
|
-
To install the
|
56
|
+
To install the padrino framework, simply grab the latest version from gemcutter:
|
6
57
|
|
7
58
|
$ sudo gem install padrino --source http://gemcutter.org
|
8
59
|
|
9
60
|
This will install the necessary padrino gems to get you started.
|
10
|
-
Now you are ready to use this gem to enhance your
|
61
|
+
Now you are ready to use this gem to enhance your sinatra projects or to create new Padrino applications.
|
11
62
|
|
12
63
|
== Usage
|
13
64
|
|
14
|
-
|
15
|
-
|
65
|
+
Padrino is a framework which builds on the existing functionality and Sinatra and provides a variety of
|
66
|
+
additional tools and helpers to extend the foundation. This README and Padrino documentation in general will focus
|
67
|
+
on the enhancements to the core Sinatra functionality. To use Padrino, one should be familiar with the basic
|
68
|
+
usage of Sinatra itself. Resources for Sinatra are listed below:
|
69
|
+
|
70
|
+
* {Sinatra Introduction}[http://www.sinatrarb.com/intro.html]
|
71
|
+
* {Sinatra Book}[http://www.sinatrarb.com/book.html]
|
72
|
+
* {Sinatra Github Repo}[http://github.com/sinatra/sinatra]
|
73
|
+
|
74
|
+
Below is a guide to how this gem enhances the Sinatra framework as part of a 'full-stack' padrino application.
|
75
|
+
For information on how to use a specific gem in isolation within an existing Sinatra project, checkout the README for that
|
76
|
+
individual gem or gems.
|
77
|
+
|
78
|
+
== Enhanced Base Application (padrino-core)
|
16
79
|
|
17
80
|
Sinatra has support for classes which can be extended to create an application: <tt>Sinatra::Base</tt> and <tt>Sinatra::Application</tt>
|
18
81
|
These classes can be extended in order to create a Sinatra web application. These classes provide support for all the basic
|
@@ -35,11 +98,170 @@ Let us first take a look at the simplest possible Padrino application:
|
|
35
98
|
Padrino.load!
|
36
99
|
|
37
100
|
class SimpleApp < Padrino::Application
|
38
|
-
get '/ do
|
101
|
+
get '/' do
|
39
102
|
'Hello world'
|
40
103
|
end
|
104
|
+
|
105
|
+
# and for read better we can divide with controllers
|
106
|
+
controller '/admin' do
|
107
|
+
get '/foo' do
|
108
|
+
'Im /admin/foo
|
109
|
+
end
|
110
|
+
end
|
41
111
|
end
|
42
|
-
|
112
|
+
|
113
|
+
=== Controllers
|
114
|
+
|
115
|
+
Suppose we wanted to add additional routes to our Padrino application, and we want to organize the routes
|
116
|
+
within a more structured layout. Simply add a <tt>controllers</tt> or <tt>app/controllers</tt> folder and create a file as such:
|
117
|
+
|
118
|
+
# Simple Example
|
119
|
+
SimpleApp.controllers do
|
120
|
+
get "/test" do
|
121
|
+
"Text to return"
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
== Advanced Routing Support
|
126
|
+
|
127
|
+
Padrino provides support for advanced routing functionality not available within Sinatra. This routing
|
128
|
+
supports named route aliases and easy access to url paths. The benefits of this is that instead of having to
|
129
|
+
hard-code route urls into every area of your application, now we can just define the urls in a
|
130
|
+
single spot and then attach an alias which can be used to refer to the url throughout the application.
|
131
|
+
|
132
|
+
=== Padrino Routing
|
133
|
+
|
134
|
+
Urls mapped here can then be defined within a controller:
|
135
|
+
|
136
|
+
# app/controllers/example.rb
|
137
|
+
SimpleApp.controllers do
|
138
|
+
get :index do
|
139
|
+
...
|
140
|
+
end
|
141
|
+
|
142
|
+
get :account do
|
143
|
+
# access params[:name] and params[:index]
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
and finally referenced anywhere in the application:
|
148
|
+
|
149
|
+
# app/views/example.haml
|
150
|
+
= link_to "Index", url_for(:index)
|
151
|
+
= link_to "Account", url_for(:account, :id => 1, :name => 'first')
|
152
|
+
|
153
|
+
=== Inline Route Alias Definitions
|
154
|
+
|
155
|
+
The routing plugin also supports inline route definitions in which the url and the named alias
|
156
|
+
are defined together within the controller:
|
157
|
+
|
158
|
+
# app/controllers/example.rb
|
159
|
+
SimpleApp.controllers do
|
160
|
+
get :index, :map => '/index' do
|
161
|
+
...
|
162
|
+
end
|
163
|
+
|
164
|
+
get :account, :map => '/the/accounts/:name/and/:id' do
|
165
|
+
# access params[:name] and params[:index]
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
Routes defined inline this way can be accessed and treated the same way as traditional named aliases.
|
170
|
+
|
171
|
+
=== Namespaced Route Aliases
|
172
|
+
|
173
|
+
There is also support for namespaced routes which are organized into a larger grouping:
|
174
|
+
|
175
|
+
# app/controllers/example.rb
|
176
|
+
SimpleApp.controllers :admin do
|
177
|
+
get :show do
|
178
|
+
"Im /admin/show"
|
179
|
+
end
|
180
|
+
|
181
|
+
get :index, :map => "/admin/:id" do
|
182
|
+
"Im /admin/#{params[:id]}"
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
You can then reference the urls using the same url_for method:
|
187
|
+
|
188
|
+
<%= link_to 'admin show page', url_for(:admin_show, :id => 25) %>
|
189
|
+
<%= link_to 'admin index page', url_for(:admin_index, :id => 25) %>
|
190
|
+
|
191
|
+
If you don't want named routes you can
|
192
|
+
|
193
|
+
# app/controllers/example.rb
|
194
|
+
SimpleApp.controllers "/admin" do
|
195
|
+
get "/show" do
|
196
|
+
"Im /admin/show"
|
197
|
+
end
|
198
|
+
|
199
|
+
get "other/:id" do
|
200
|
+
"Im /admin/#{params[:id]}"
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
=== Named Params
|
205
|
+
|
206
|
+
With Padrino you can use named params!! See these examples
|
207
|
+
|
208
|
+
# app/controllers/example.rb
|
209
|
+
SimpleApp.controllers :admin do
|
210
|
+
get :show, :with => :id do
|
211
|
+
"Im /admin/show/#{params[:id]}"
|
212
|
+
end
|
213
|
+
|
214
|
+
get :other, with => [:id, :name] do
|
215
|
+
"Im /admin/#{params[:id]}/#{params[:name]}"
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
You can then reference the urls using the same url_for method:
|
220
|
+
|
221
|
+
<%= link_to 'admin show page', url_for(:admin_show, :id => 25) %>
|
222
|
+
<%= link_to 'admin other page', url_for(:admin_index, :id => 25, :name => :foo) %>
|
223
|
+
|
224
|
+
=== Respond To
|
225
|
+
|
226
|
+
With Padrino you can simply respond to a given format see example:
|
227
|
+
|
228
|
+
# app/controllers/example.rb
|
229
|
+
SimpleApp.controllers :admin do
|
230
|
+
get :show, :with => :id, :respond_to => :js do
|
231
|
+
"Im /admin/show/#{params[:id]}.#{params[:format]}"
|
232
|
+
end
|
233
|
+
|
234
|
+
get :other, with => [:id, :name], respond_to => [:html, :json] do
|
235
|
+
case content_type
|
236
|
+
when :js then ... end
|
237
|
+
when :json then ... end
|
238
|
+
end
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
<%= link_to 'admin show page', url_for(:admin_show, :id => 25, :format => :js) %>
|
243
|
+
<%= link_to 'admin other page', url_for(:admin_index, :id => 25, :name => :foo) %>
|
244
|
+
<%= link_to 'admin other json page', url_for(:admin_index, :id => 25, :name => :foo, :format => :json) %>
|
245
|
+
|
246
|
+
=== Rendering
|
247
|
+
|
248
|
+
Unlike Sinatra Padrino support template auto lookup so:
|
249
|
+
|
250
|
+
# look for 'account/index.{erb,haml,...}
|
251
|
+
render 'account/index'
|
252
|
+
|
253
|
+
=== Layout
|
254
|
+
|
255
|
+
With Padrino you can (like rails do) use for your custom layout, disable it
|
256
|
+
|
257
|
+
class SimpleApp < Padrino::Application
|
258
|
+
|
259
|
+
# Disable layouts
|
260
|
+
disable layout
|
261
|
+
|
262
|
+
# Use the layout located in views/layouts/custom.haml
|
263
|
+
layout :custom
|
264
|
+
|
43
265
|
=== Gemfile Dependency Resolution
|
44
266
|
|
45
267
|
While this is a fully operational Padrino application in itself, let us take a look at Padrino's expanded capabilites. First,
|
@@ -97,18 +319,6 @@ directory following this convention:
|
|
97
319
|
Initializers are automatically required and 'registered' during the application startup process. Note that
|
98
320
|
the name of the module must be the name of the file appended with 'Initializer' (i.e sample.rb => SampleInitializer)
|
99
321
|
|
100
|
-
=== Controllers
|
101
|
-
|
102
|
-
Suppose we wanted to add additional routes to our Padrino application, and we want to organize the routes
|
103
|
-
within a more structured layout. Simply add a <tt>controllers</tt> or <tt>app/controllers</tt> folder and create a file as such:
|
104
|
-
|
105
|
-
# controllers/example.rb
|
106
|
-
SimpleApp.controllers do
|
107
|
-
get "/test" do
|
108
|
-
"Text to return"
|
109
|
-
end
|
110
|
-
end
|
111
|
-
|
112
322
|
=== Application Logging
|
113
323
|
|
114
324
|
Padrino also supports robust logging capabilities. By default, logging information will
|
@@ -200,8 +410,11 @@ The following commands are available:
|
|
200
410
|
# Bootup the Padrino console (irb)
|
201
411
|
$ padrino console
|
202
412
|
|
413
|
+
# Run/List tasks
|
414
|
+
$ padrino rake
|
415
|
+
|
203
416
|
Using these commands can simplify common tasks making development that much smoother.
|
204
417
|
|
205
418
|
== Copyright
|
206
419
|
|
207
|
-
Copyright (c)
|
420
|
+
Copyright (c) 2010 Padrino. See LICENSE for details.
|
data/Rakefile
CHANGED
@@ -13,6 +13,7 @@ begin
|
|
13
13
|
gem.executables = ["padrino"]
|
14
14
|
gem.add_runtime_dependency "sinatra", ">= 0.9.2"
|
15
15
|
gem.add_runtime_dependency "i18n", ">= 0.3.2"
|
16
|
+
gem.add_runtime_dependency "usher", ">= 0.6.2"
|
16
17
|
gem.add_runtime_dependency "thor", ">= 0.11.8"
|
17
18
|
gem.add_development_dependency "haml", ">= 2.2.1"
|
18
19
|
gem.add_runtime_dependency "bundler", ">= 0.5.0"
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.6.1
|
data/bin/padrino
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
%w[rubygems thor].each { |gem| require gem }
|
3
|
-
|
3
|
+
$LOAD_PATH.unshift File.dirname(__FILE__) + "/../lib"
|
4
4
|
|
5
|
+
require "padrino-core/cli"
|
5
6
|
arguments = ARGV.any? ? ARGV : ['-h']
|
6
|
-
Padrino::
|
7
|
+
Padrino::Cli::Base.start(arguments)
|
data/lib/padrino-core.rb
CHANGED
@@ -4,12 +4,47 @@ module Padrino
|
|
4
4
|
# These subclassed applications can be easily mounted into other Padrino applications as well.
|
5
5
|
class Application < Sinatra::Application
|
6
6
|
|
7
|
+
# Return the request format, this is useful when we need to respond to a given content_type like:
|
8
|
+
#
|
9
|
+
# get :index, :respond_to => :any do
|
10
|
+
# case content_type
|
11
|
+
# when :js then ...
|
12
|
+
# when :json then ...
|
13
|
+
# when :html then ...
|
14
|
+
# end
|
15
|
+
# end
|
16
|
+
def content_type(type=nil, params={})
|
17
|
+
type.nil? ? @_content_type : super(type, params)
|
18
|
+
end
|
19
|
+
|
20
|
+
|
21
|
+
# Instance method for url generation like:
|
22
|
+
#
|
23
|
+
# url(:show, :id => 1)
|
24
|
+
# url(:show, :name => :test)
|
25
|
+
# url("/show/:id/:name", :id => 1, :name => foo)
|
26
|
+
#
|
27
|
+
def url(name, *params)
|
28
|
+
self.class.url(name, *params)
|
29
|
+
end
|
30
|
+
alias :url_for :url
|
31
|
+
|
32
|
+
# This is mostly just a helper so request.path_info isn't changed when
|
33
|
+
# serving files from the public directory
|
34
|
+
def static_file?(path)
|
35
|
+
public_dir = File.expand_path(options.public)
|
36
|
+
path = File.expand_path(File.join(public_dir, unescape(path)))
|
37
|
+
path[0, public_dir.length] == public_dir && File.file?(path)
|
38
|
+
end
|
39
|
+
|
7
40
|
class << self
|
8
41
|
def inherited(subclass)
|
9
42
|
CALLERS_TO_IGNORE.concat(PADRINO_IGNORE_CALLERS)
|
10
43
|
subclass.default_configuration!
|
44
|
+
Padrino.require_dependencies(File.join(subclass.root, "/models/**/*.rb"))
|
11
45
|
super # Loading the subclass
|
12
|
-
subclass.
|
46
|
+
subclass.default_filters!
|
47
|
+
subclass.default_routes!
|
13
48
|
end
|
14
49
|
|
15
50
|
# Hooks into when a new instance of the application is created
|
@@ -21,12 +56,67 @@ module Padrino
|
|
21
56
|
super
|
22
57
|
end
|
23
58
|
|
24
|
-
#
|
25
|
-
#
|
26
|
-
|
27
|
-
|
28
|
-
|
59
|
+
# Method for organize in a better way our routes like:
|
60
|
+
#
|
61
|
+
# controller :admin do
|
62
|
+
# get :index do; ...; end
|
63
|
+
# get :show, :with => :id do; ...; end
|
64
|
+
# end
|
65
|
+
#
|
66
|
+
# Now you can call your actions with:
|
67
|
+
#
|
68
|
+
# url(:admin_index) # => "/admin"
|
69
|
+
# url(:admin_show, :id => 1) # "/admin/show/1"
|
70
|
+
#
|
71
|
+
# You can instead using named routes follow the sinatra way like:
|
72
|
+
#
|
73
|
+
# controller "/admin" do
|
74
|
+
# get "/index" do; ...; end
|
75
|
+
# get "/show/:id" do; ...; end
|
76
|
+
# end
|
77
|
+
#
|
78
|
+
# And you can call directly these urls:
|
79
|
+
#
|
80
|
+
# # => "/admin"
|
81
|
+
# # => "/admin/show/1"
|
82
|
+
#
|
83
|
+
def controller(*extensions, &block)
|
84
|
+
if block_given?
|
85
|
+
@_controller, original = extensions, @_controller
|
86
|
+
instance_eval(&block)
|
87
|
+
@_controller = original
|
88
|
+
else
|
89
|
+
include(*extensions) if extensions.any?
|
90
|
+
end
|
91
|
+
end
|
92
|
+
alias :controllers :controller
|
93
|
+
|
94
|
+
# Usher router
|
95
|
+
def router
|
96
|
+
@router ||= Usher.new(:request_methods => [:request_method, :host, :port, :scheme],
|
97
|
+
:ignore_trailing_delimiters => true,
|
98
|
+
:generator => Usher::Util::Generators::URL.new)
|
99
|
+
block_given? ? yield(@router) : @router
|
100
|
+
end
|
101
|
+
alias :urls :router
|
102
|
+
|
103
|
+
# Instance method for url generation like:
|
104
|
+
#
|
105
|
+
# url(:show, :id => 1)
|
106
|
+
# url(:show, :name => :test)
|
107
|
+
# url("/show/:id/:name", :id => 1, :name => foo)
|
108
|
+
#
|
109
|
+
def url(name, *params)
|
110
|
+
params.map! do |param|
|
111
|
+
if param.is_a?(Hash)
|
112
|
+
param[:format] = param[:format].to_s if param.has_key?(:format)
|
113
|
+
param.each { |k,v| param[k] = v.to_param if v.respond_to?(:to_param) }
|
114
|
+
end
|
115
|
+
end
|
116
|
+
url = router.generator.generate(name, *params)
|
117
|
+
uri_root != "/" ? uri_root + url : url
|
29
118
|
end
|
119
|
+
alias :url_for :url
|
30
120
|
|
31
121
|
# With this method we can use layout like rails do or if a block given like sinatra
|
32
122
|
# By default we look in your/app/views/layouts/application.(haml|erb|etc)
|
@@ -50,7 +140,8 @@ module Padrino
|
|
50
140
|
|
51
141
|
# Resets application routes to only routes not defined by the user
|
52
142
|
def reset_routes!
|
53
|
-
|
143
|
+
router.reset!
|
144
|
+
default_routes!
|
54
145
|
end
|
55
146
|
|
56
147
|
# Setup the application by registering initializers, load paths and logger
|
@@ -64,7 +155,6 @@ module Padrino
|
|
64
155
|
self.disable :logging # We need do that as default because Sinatra use commonlogger.
|
65
156
|
I18n.locale = self.locale
|
66
157
|
I18n.load_path += self.translations
|
67
|
-
self.get(""){ redirect("#{options.uri_root}/") } if self.uri_root != "/"
|
68
158
|
@_configured = true
|
69
159
|
end
|
70
160
|
|
@@ -93,6 +183,25 @@ module Padrino
|
|
93
183
|
set :padrino_helpers, defined?(Padrino::Helpers)
|
94
184
|
end
|
95
185
|
|
186
|
+
def default_routes!
|
187
|
+
# images resources
|
188
|
+
get "/__sinatra__/:image.png" do
|
189
|
+
filename = File.dirname(__FILE__) + "/images/#{params[:image]}.png"
|
190
|
+
send_file filename
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
# This filter it's used for know the format of the request, and automatically set the content type.
|
195
|
+
def default_filters!
|
196
|
+
before do
|
197
|
+
unless options.static? && options.public? && (request.get? || request.head?) && static_file?(request.path_info)
|
198
|
+
request.path_info =~ /\.([^\.\/]+)$/
|
199
|
+
@_content_type = ($1 || :html).to_sym
|
200
|
+
content_type(@_content_type) rescue content_type('application/octet-stream')
|
201
|
+
end
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
96
205
|
# Calculates any required paths after app_file and root have been properly configured
|
97
206
|
# Executes as part of the setup_application! method
|
98
207
|
def calculate_paths
|
@@ -111,7 +220,7 @@ module Padrino
|
|
111
220
|
Dir[@initializer_path].each { |file| register_initializer(file) }
|
112
221
|
end
|
113
222
|
|
114
|
-
# Registers all desired padrino extension helpers
|
223
|
+
# Registers all desired padrino extension helpers
|
115
224
|
def register_framework_extensions
|
116
225
|
register Padrino::Mailer if padrino_mailer?
|
117
226
|
register Padrino::Helpers if padrino_helpers?
|
@@ -120,7 +229,7 @@ module Padrino
|
|
120
229
|
|
121
230
|
# Returns the load_paths for the application (relative to the application root)
|
122
231
|
def load_paths
|
123
|
-
@load_paths ||= ["urls.rb", "config/urls.rb", "
|
232
|
+
@load_paths ||= ["urls.rb", "config/urls.rb", "mailers/*.rb", "controllers/**/*.rb", "helpers/*.rb"]
|
124
233
|
end
|
125
234
|
|
126
235
|
# Requires all files within the application load paths
|
@@ -144,15 +253,172 @@ module Padrino
|
|
144
253
|
logger.error "The module '#{file_class}Initializer' (#{file_path}) didn't loaded properly!"
|
145
254
|
logger.error " Initializer error was '#{e.message}'"
|
146
255
|
end
|
147
|
-
|
256
|
+
|
257
|
+
private
|
258
|
+
# Rewrite default because now routes can be:
|
259
|
+
#
|
260
|
+
# get :index # => "/"
|
261
|
+
# get :index, :map => "/" # => "/"
|
262
|
+
# get :show, :map => "/show-me" # => "/show-me"
|
263
|
+
# get "/foo/bar" # => "/show"
|
264
|
+
# get :show, :with => :id # => "/show/:id"
|
265
|
+
# get :show, :with => [:id, :name] # => "/show/:id/:name"
|
266
|
+
# get :list, :respond_to => :js # => "/list.{:format,js)"
|
267
|
+
# get :list, :respond_to => :any # => "/list(.:format)"
|
268
|
+
# get :list, :respond_to => [:js, :json] # => "/list.{!format,js|json}"
|
269
|
+
# gen :list, :respond_to => [:html, :js, :json] # => "/list(.{!format,js|json})"
|
270
|
+
#
|
271
|
+
def route(verb, path, options={}, &block)
|
272
|
+
|
273
|
+
# We dup options so we can build HEAD request correctly
|
274
|
+
options = options.dup
|
275
|
+
|
276
|
+
# We need check if path is a symbol, if that it's a named route
|
277
|
+
map = options.delete(:map)
|
278
|
+
|
279
|
+
if path.kind_of?(Symbol)
|
280
|
+
name = path # The route name
|
281
|
+
path = map || "/#{path}" # The route path
|
282
|
+
end
|
283
|
+
|
284
|
+
if path.kind_of?(String)
|
285
|
+
# Little reformats
|
286
|
+
path.sub!(/\/index$/, "") # If the route end with /index we remove them
|
287
|
+
path = (uri_root == "/" ? "/" : "(/)") if path.blank? # Add a trailing delimiter if empty
|
288
|
+
|
289
|
+
# Now we need to parse our with params
|
290
|
+
if params = options.delete(:with)
|
291
|
+
path += "/" unless path =~ /\/$/
|
292
|
+
path += Array(params).collect(&:inspect).join("/")
|
293
|
+
end
|
294
|
+
|
295
|
+
# Now we need to parse our respond_to
|
296
|
+
if format = options.delete(:respond_to)
|
297
|
+
path += case format
|
298
|
+
when :any then "(.:format)"
|
299
|
+
when Array then
|
300
|
+
formats = format.dup # Prevent changes to HEAD verb
|
301
|
+
container = formats.delete(:html) ? "(%s)" : "%s"
|
302
|
+
match = ".{:format," + formats.collect { |f| "#{f}$" }.join("|") + "}"
|
303
|
+
container % match
|
304
|
+
else ".{:format,#{format}}"
|
305
|
+
end
|
306
|
+
end
|
307
|
+
|
308
|
+
# Build our controller
|
309
|
+
controller = Array(@_controller).collect(&:to_s)
|
310
|
+
|
311
|
+
unless controller.empty?
|
312
|
+
# Now we need to add our controller path only if not mapped directly
|
313
|
+
if map.blank?
|
314
|
+
controller_path = controller.join("/")
|
315
|
+
path = controller_path + path
|
316
|
+
end
|
317
|
+
# Here we build the correct name route
|
318
|
+
if name
|
319
|
+
controller_name = controller.join("_")
|
320
|
+
name = "#{controller_name}_#{name}".to_sym unless controller_name.blank?
|
321
|
+
end
|
322
|
+
end
|
323
|
+
|
324
|
+
# We need to have a path that start with / in some circumstances and that don't end with /
|
325
|
+
if path != "(/)" && path != "/"
|
326
|
+
path = "/" + path if path !~ /^\//
|
327
|
+
path.sub!(/\/$/, '')
|
328
|
+
end
|
329
|
+
end
|
330
|
+
|
331
|
+
# Standard Sinatra requirements
|
332
|
+
options[:conditions] ||= {}
|
333
|
+
options[:conditions][:request_method] = verb
|
334
|
+
options[:conditions][:host] = options.delete(:host) if options.key?(:host)
|
335
|
+
|
336
|
+
# Because of self.options.host
|
337
|
+
host_name(options.delete(:host)) if options.key?(:host)
|
338
|
+
|
339
|
+
# Sinatra defaults
|
340
|
+
define_method "\#{verb} \#{path}", &block
|
341
|
+
unbound_method = instance_method("\#{verb} \#{path}")
|
342
|
+
block =
|
343
|
+
if block.arity != 0
|
344
|
+
lambda { unbound_method.bind(self).call(*@block_params) }
|
345
|
+
else
|
346
|
+
lambda { unbound_method.bind(self).call }
|
347
|
+
end
|
348
|
+
|
349
|
+
invoke_hook(:route_added, verb, path, block)
|
350
|
+
|
351
|
+
route = router.add_route(path, options).to(block)
|
352
|
+
route.name(name) if name
|
353
|
+
route
|
354
|
+
end
|
355
|
+
|
356
|
+
end
|
148
357
|
|
149
358
|
private
|
359
|
+
# TODO: remove this when sinatra 1.0 will be released
|
360
|
+
# Compatibility with sinatra 0.9.4
|
361
|
+
def static!
|
362
|
+
return if (public_dir = options.public).nil?
|
363
|
+
public_dir = File.expand_path(public_dir)
|
364
|
+
|
365
|
+
path = File.expand_path(public_dir + unescape(request.path_info))
|
366
|
+
return if path[0, public_dir.length] != public_dir
|
367
|
+
return unless File.file?(path)
|
368
|
+
|
369
|
+
send_file path, :disposition => nil
|
370
|
+
end
|
371
|
+
|
372
|
+
# Compatibility with usher
|
373
|
+
def route!(base=self.class, pass_block=nil)
|
374
|
+
# TODO: remove this when sinatra 1.0 will be released
|
375
|
+
if Sinatra::VERSION =~ /^0\.9/
|
376
|
+
# enable nested params in Rack < 1.0; allow indifferent access
|
377
|
+
@params = if Rack::Utils.respond_to?(:parse_nested_query)
|
378
|
+
indifferent_params(@request.params)
|
379
|
+
else
|
380
|
+
nested_params(@request.params)
|
381
|
+
end
|
382
|
+
# deliver static files
|
383
|
+
static! if options.static? && (request.get? || request.head?)
|
384
|
+
# perform before filters
|
385
|
+
self.class.filters.each { |block| instance_eval(&block) }
|
386
|
+
end
|
387
|
+
|
388
|
+
# Usher
|
389
|
+
if self.class.router and match = self.class.router.recognize(@request, @request.path_info)
|
390
|
+
@block_params = match.params.map{|p| p.last}
|
391
|
+
@params = @params ? @params.merge(match.params_as_hash) : match.params_as_hash
|
392
|
+
pass_block = catch(:pass) do
|
393
|
+
route_eval(&match.destination)
|
394
|
+
end
|
395
|
+
elsif base.superclass.respond_to?(:routes)
|
396
|
+
route! base.superclass
|
397
|
+
else
|
398
|
+
route_missing
|
399
|
+
end
|
400
|
+
end
|
401
|
+
|
402
|
+
# When we set :auto_locale, true then:
|
403
|
+
#
|
404
|
+
# * if we pass "/:locale/some/foo" we automatically set teh I18n locale to params[:locale]
|
405
|
+
# * if params[:locale] is empty we use the first HTTP_ACCEPT_LANGUAGE
|
406
|
+
def route_eval(&block)
|
407
|
+
if options.auto_locale
|
408
|
+
if params[:locale]
|
409
|
+
I18n.locale = params[:locale].to_sym rescue options.locale
|
410
|
+
end
|
411
|
+
end
|
412
|
+
super
|
413
|
+
end
|
414
|
+
|
150
415
|
# Hijacking the sinatra render for do two thing:
|
151
416
|
#
|
152
417
|
# * Use layout like rails do
|
153
418
|
# * Use render 'path/to/my/template'
|
154
419
|
#
|
155
420
|
def render(engine, data=nil, options={}, locals={}, &block)
|
421
|
+
# TODO: remove these @template_cache.respond_to?(:clear) when sinatra 1.0 will be released
|
156
422
|
@template_cache.clear if Padrino.env != :production && @template_cache && @template_cache.respond_to?(:clear)
|
157
423
|
# If an engine is a string probably is a path so we try to resolve them
|
158
424
|
if data.nil?
|
@@ -178,18 +444,6 @@ module Padrino
|
|
178
444
|
raise "Template path '#{template_path}' could not be located in views!" unless template_file
|
179
445
|
template_engine = File.extname(template_file)[1..-1].to_sym
|
180
446
|
end
|
181
|
-
|
182
|
-
# When we set :auto_locale, true then:
|
183
|
-
#
|
184
|
-
# * if we pass "/:locale/some/foo" we automatically set teh I18n locale to params[:locale]
|
185
|
-
# * if params[:locale] is empty we use the first HTTP_ACCEPT_LANGUAGE
|
186
|
-
def route_eval(&block)
|
187
|
-
if options.auto_locale
|
188
|
-
if params[:locale]
|
189
|
-
I18n.locale = params[:locale].to_sym rescue options.locale
|
190
|
-
end
|
191
|
-
end
|
192
|
-
super
|
193
|
-
end
|
194
447
|
end
|
448
|
+
|
195
449
|
end
|