padrino-core 0.5.0 → 0.6.1
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/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
|