padrino-core 0.9.10 → 0.9.11
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.rdoc +2 -2
- data/Rakefile +4 -56
- data/bin/padrino +9 -12
- data/lib/padrino-core.rb +7 -6
- data/lib/padrino-core/application.rb +44 -19
- data/lib/padrino-core/application/mounter.rb +19 -5
- data/lib/padrino-core/application/rendering.rb +123 -101
- data/lib/padrino-core/application/routing.rb +238 -159
- data/lib/padrino-core/cli/adapter.rb +2 -7
- data/lib/padrino-core/cli/base.rb +5 -3
- data/lib/padrino-core/cli/console.rb +0 -1
- data/lib/padrino-core/cli/rake.rb +3 -4
- data/lib/padrino-core/command.rb +27 -0
- data/lib/padrino-core/loader.rb +27 -9
- data/lib/padrino-core/locale/cz.yml +30 -0
- data/lib/padrino-core/locale/de.yml +8 -8
- data/lib/padrino-core/locale/es.yml +30 -0
- data/lib/padrino-core/locale/tr.yml +30 -0
- data/lib/padrino-core/locale/uk.yml +30 -0
- data/lib/padrino-core/reloader.rb +166 -30
- data/lib/padrino-core/router.rb +5 -3
- data/lib/padrino-core/server.rb +10 -4
- data/lib/padrino-core/support_lite.rb +86 -70
- data/lib/padrino-core/version.rb +3 -2
- data/padrino-core.gemspec +17 -120
- data/test/fixtures/apps/complex.rb +2 -2
- data/test/fixtures/apps/simple.rb +11 -2
- data/test/helper.rb +1 -1
- data/test/test_application.rb +25 -8
- data/test/test_mounter.rb +14 -4
- data/test/test_reloader_simple.rb +26 -1
- data/test/test_rendering.rb +53 -8
- data/test/test_router.rb +4 -4
- data/test/test_routing.rb +369 -12
- data/test/test_server.rb +2 -2
- metadata +77 -74
- data/test/fixtures/apps/.components +0 -6
- data/test/fixtures/apps/.gitignore +0 -7
data/README.rdoc
CHANGED
|
@@ -150,7 +150,7 @@ and even configure the respond_to for each route:
|
|
|
150
150
|
|
|
151
151
|
# app/controllers/example.rb
|
|
152
152
|
SimpleApp.controllers :admin do
|
|
153
|
-
get :show, :with => :id, :
|
|
153
|
+
get :show, :with => :id, :provides => :js do
|
|
154
154
|
"Url is /admin/show/#{params[:id]}.#{params[:format]}"
|
|
155
155
|
end
|
|
156
156
|
|
|
@@ -166,7 +166,7 @@ or auto lookup for current locale or content_type
|
|
|
166
166
|
|
|
167
167
|
# app/controllers/example.rb
|
|
168
168
|
SimpleApp.controllers :admin do
|
|
169
|
-
get :show, :with => :id, :
|
|
169
|
+
get :show, :with => :id, :provides => [html, :js] do
|
|
170
170
|
render "admin/show"
|
|
171
171
|
end
|
|
172
172
|
end
|
data/Rakefile
CHANGED
|
@@ -1,57 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
require File.expand_path("../lib/padrino-core/version.rb", __FILE__)
|
|
4
|
-
|
|
5
|
-
begin
|
|
6
|
-
require 'jeweler'
|
|
7
|
-
Jeweler::Tasks.new do |gem|
|
|
8
|
-
gem.name = "padrino-core"
|
|
9
|
-
gem.summary = "The required Padrino core gem"
|
|
10
|
-
gem.description = "The Padrino core gem required for use of this framework"
|
|
11
|
-
gem.email = "padrinorb@gmail.com"
|
|
12
|
-
gem.homepage = "http://github.com/padrino/padrino-framework/tree/master/padrino-core"
|
|
13
|
-
gem.authors = ["Padrino Team", "Nathan Esquenazi", "Davide D'Agostino", "Arthur Chiu"]
|
|
14
|
-
gem.executables = ["padrino"]
|
|
15
|
-
gem.rubyforge_project = 'padrino-core'
|
|
16
|
-
gem.version = Padrino.version
|
|
17
|
-
gem.add_runtime_dependency "sinatra", ">= 1.0.0"
|
|
18
|
-
gem.add_runtime_dependency "i18n", ">= 0.3.2"
|
|
19
|
-
gem.add_runtime_dependency "usher", ">= 0.6.2"
|
|
20
|
-
gem.add_runtime_dependency "thor", ">= 0.13.0"
|
|
21
|
-
gem.add_runtime_dependency "bundler", ">= 0.9.7"
|
|
22
|
-
gem.add_runtime_dependency "activesupport", "= 2.3.5"
|
|
23
|
-
gem.add_development_dependency "shoulda", ">= 2.10.3"
|
|
24
|
-
gem.add_development_dependency "mocha", ">= 0.9.7"
|
|
25
|
-
gem.add_development_dependency "rack-test", ">= 0.5.0"
|
|
26
|
-
gem.add_development_dependency "webrat", ">= 0.5.1"
|
|
27
|
-
gem.add_development_dependency "haml", ">= 2.2.22"
|
|
28
|
-
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
|
29
|
-
end
|
|
30
|
-
Jeweler::GemcutterTasks.new
|
|
31
|
-
Jeweler::RubyforgeTasks.new { |r| r.doc_task = :none }
|
|
32
|
-
rescue LoadError
|
|
33
|
-
puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
require 'rake/testtask'
|
|
37
|
-
Rake::TestTask.new(:test) do |test|
|
|
38
|
-
test.libs << 'test'
|
|
39
|
-
test.pattern = 'test/**/test_*.rb'
|
|
40
|
-
test.verbose = true
|
|
41
|
-
end
|
|
1
|
+
# coding:utf-8
|
|
2
|
+
RAKE_ROOT = __FILE__
|
|
42
3
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
Rcov::RcovTask.new do |rcov|
|
|
46
|
-
rcov.libs << 'test'
|
|
47
|
-
rcov.pattern = 'test/**/test_*.rb'
|
|
48
|
-
rcov.verbose = true
|
|
49
|
-
rcov.rcov_opts << ['--exclude /Gems/1.8/gems/,padrino-admin,padrino-cache,padrino-gen,padrino-helpers,padrino-mailer']
|
|
50
|
-
end
|
|
51
|
-
rescue LoadError
|
|
52
|
-
task :rcov do
|
|
53
|
-
abort "RCov is not available. In order to run rcov, you must: sudo gem install relevance-rcov"
|
|
54
|
-
end
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
task :default => :test
|
|
4
|
+
require 'rubygems'
|
|
5
|
+
require File.expand_path(File.dirname(__FILE__) + '/../gem_rake_helper')
|
data/bin/padrino
CHANGED
|
@@ -1,27 +1,24 @@
|
|
|
1
1
|
#!/usr/bin/env ruby
|
|
2
|
-
require 'rubygems'
|
|
3
2
|
|
|
3
|
+
# We load Padrino libs
|
|
4
4
|
padrino_core_path = File.expand_path('../../lib', __FILE__)
|
|
5
5
|
$:.unshift(padrino_core_path) if File.directory?(padrino_core_path) && !$:.include?(padrino_core_path)
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
$:.unshift(padrino_local_path) if File.directory?(padrino_local_path) && !$:.include?(padrino_local_path)
|
|
9
|
-
|
|
10
|
-
require 'padrino-core/cli/base'
|
|
11
|
-
require 'padrino-core/support_lite'
|
|
12
|
-
|
|
7
|
+
# Build Padrino g as an alias of padrino-gen
|
|
13
8
|
if %w(g gen).include?(ARGV[0])
|
|
14
9
|
ARGV.shift
|
|
15
10
|
begin
|
|
16
11
|
# We try to load the vendored padrino-gen if exist
|
|
17
12
|
padrino_gen_path = File.expand_path('../../../padrino-gen/lib', __FILE__)
|
|
18
13
|
$:.unshift(padrino_gen_path) if File.directory?(padrino_gen_path) && !$:.include?(padrino_gen_path)
|
|
19
|
-
require 'padrino-
|
|
14
|
+
require 'padrino-core/command'
|
|
15
|
+
require 'padrino-gen/command'
|
|
20
16
|
Padrino.bin_gen(ARGV)
|
|
21
17
|
rescue
|
|
22
18
|
puts "<= You need padrino-gen! Run: gem install padrino-gen"
|
|
23
19
|
end
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
Padrino::Cli::Base.start(ARGV)
|
|
20
|
+
else
|
|
21
|
+
# We load our cli
|
|
22
|
+
require 'padrino-core/cli/base'
|
|
23
|
+
Padrino::Cli::Base.start(ARGV)
|
|
24
|
+
end
|
data/lib/padrino-core.rb
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
require 'sinatra/base'
|
|
2
|
-
require 'padrino-core/support_lite'
|
|
2
|
+
require 'padrino-core/support_lite' unless defined?(SupportLite)
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
FileSet.glob_require('padrino-core/application/*.rb', __FILE__)
|
|
5
|
+
FileSet.glob_require('padrino-core/*.rb', __FILE__)
|
|
6
6
|
|
|
7
|
-
# Defines our
|
|
8
|
-
PADRINO_ENV
|
|
7
|
+
# Defines our Constants
|
|
8
|
+
PADRINO_ENV = ENV["PADRINO_ENV"] ||= ENV["RACK_ENV"] ||= "development" unless defined?(PADRINO_ENV)
|
|
9
|
+
PADRINO_ROOT = ENV["PADRINO_ROOT"] ||= File.dirname(Padrino.first_caller) unless defined?(PADRINO_ROOT)
|
|
9
10
|
|
|
10
11
|
module Padrino
|
|
11
12
|
class ApplicationLoadError < RuntimeError #:nodoc:
|
|
@@ -36,7 +37,7 @@ module Padrino
|
|
|
36
37
|
# Returns the resulting rack builder mapping each 'mounted' application
|
|
37
38
|
#
|
|
38
39
|
def application
|
|
39
|
-
raise ApplicationLoadError
|
|
40
|
+
raise ApplicationLoadError, "At least one app must be mounted!" unless self.mounted_apps && self.mounted_apps.any?
|
|
40
41
|
router = Padrino::Router.new
|
|
41
42
|
self.mounted_apps.each { |app| app.map_onto(router) }
|
|
42
43
|
router
|
|
@@ -43,9 +43,16 @@ module Padrino
|
|
|
43
43
|
# MyApp.reload!
|
|
44
44
|
#
|
|
45
45
|
def reload!
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
46
|
+
reset! # Reset sinatra app
|
|
47
|
+
reset_routes! # Remove all existing user-defined application routes
|
|
48
|
+
Padrino.require_dependencies(File.join(self.root, "/models.rb")) # Reload models class
|
|
49
|
+
Padrino.require_dependencies(File.join(self.root, "/models/**/*.rb")) # Reload all models
|
|
50
|
+
Padrino.require_dependencies(self.app_file) # Reload the app file
|
|
51
|
+
register_initializers # Reload our middlewares
|
|
52
|
+
require_load_paths # Reload dependencies
|
|
53
|
+
default_filters! # Reload filters
|
|
54
|
+
default_errors! # Reload our errors
|
|
55
|
+
I18n.reload! if defined?(I18n) # Reload also our translations
|
|
49
56
|
end
|
|
50
57
|
|
|
51
58
|
##
|
|
@@ -60,6 +67,13 @@ module Padrino
|
|
|
60
67
|
default_routes!
|
|
61
68
|
end
|
|
62
69
|
|
|
70
|
+
##
|
|
71
|
+
# Returns the routes of our app
|
|
72
|
+
#
|
|
73
|
+
def routes
|
|
74
|
+
router.routes
|
|
75
|
+
end
|
|
76
|
+
|
|
63
77
|
##
|
|
64
78
|
# Setup the application by registering initializers, load paths and logger
|
|
65
79
|
# Invoked automatically when an application is first instantiated
|
|
@@ -67,25 +81,48 @@ module Padrino
|
|
|
67
81
|
def setup_application!
|
|
68
82
|
return if @_configured
|
|
69
83
|
self.calculate_paths
|
|
70
|
-
self.register_framework_extensions
|
|
71
84
|
self.register_initializers
|
|
72
85
|
self.require_load_paths
|
|
73
86
|
self.disable :logging # We need do that as default because Sinatra use commonlogger.
|
|
74
87
|
self.default_filters!
|
|
75
88
|
self.default_routes!
|
|
76
89
|
self.default_errors!
|
|
77
|
-
I18n
|
|
78
|
-
|
|
90
|
+
if defined?(I18n)
|
|
91
|
+
I18n.load_path += self.locale_path
|
|
92
|
+
I18n.reload!
|
|
93
|
+
end
|
|
79
94
|
@_configured = true
|
|
80
95
|
end
|
|
81
96
|
|
|
97
|
+
##
|
|
98
|
+
# Run the Padrino app as a self-hosted server using
|
|
99
|
+
# Thin, Mongrel or WEBrick (in that order)
|
|
100
|
+
#
|
|
101
|
+
def run!(options={})
|
|
102
|
+
return unless Padrino.load!
|
|
103
|
+
set options
|
|
104
|
+
handler = detect_rack_handler
|
|
105
|
+
handler_name = handler.name.gsub(/.*::/, '')
|
|
106
|
+
puts "=> #{self.name}/#{Padrino.version} has taken the stage #{Padrino.env} on #{port}" unless handler_name =~/cgi/i
|
|
107
|
+
handler.run self, :Host => bind, :Port => port do |server|
|
|
108
|
+
trap(:INT) do
|
|
109
|
+
## Use thins' hard #stop! if available, otherwise just #stop
|
|
110
|
+
server.respond_to?(:stop!) ? server.stop! : server.stop
|
|
111
|
+
puts "<= #{self.name} has ended his set (crowd applauds)" unless handler_name =~/cgi/i
|
|
112
|
+
end
|
|
113
|
+
set :running, true
|
|
114
|
+
end
|
|
115
|
+
rescue Errno::EADDRINUSE => e
|
|
116
|
+
puts "<= Someone is already performing on port #{port}!"
|
|
117
|
+
end
|
|
118
|
+
|
|
82
119
|
protected
|
|
83
120
|
##
|
|
84
121
|
# Defines default settings for Padrino application
|
|
85
122
|
#
|
|
86
123
|
def default_configuration!
|
|
87
124
|
# Overwriting Sinatra defaults
|
|
88
|
-
set :app_file, caller_files.first || $0 # Assume app file is first caller
|
|
125
|
+
set :app_file, File.expand_path(caller_files.first || $0) # Assume app file is first caller
|
|
89
126
|
set :environment, Padrino.env
|
|
90
127
|
set :raise_errors, true if development?
|
|
91
128
|
set :reload, true if development?
|
|
@@ -101,9 +138,6 @@ module Padrino
|
|
|
101
138
|
set :authentication, false
|
|
102
139
|
# Padrino locale
|
|
103
140
|
set :locale_path, Proc.new { Dir[File.join(self.root, "/locale/**/*.{rb,yml}")] }
|
|
104
|
-
# Plugin specific
|
|
105
|
-
set :padrino_mailer, defined?(Padrino::Mailer)
|
|
106
|
-
set :padrino_helpers, defined?(Padrino::Helpers)
|
|
107
141
|
end
|
|
108
142
|
|
|
109
143
|
##
|
|
@@ -162,15 +196,6 @@ module Padrino
|
|
|
162
196
|
use Rack::Flash if flash? && sessions?
|
|
163
197
|
end
|
|
164
198
|
|
|
165
|
-
##
|
|
166
|
-
# Registers all desired padrino extension helpers
|
|
167
|
-
#
|
|
168
|
-
def register_framework_extensions
|
|
169
|
-
register Padrino::Mailer if padrino_mailer?
|
|
170
|
-
register Padrino::Helpers if padrino_helpers?
|
|
171
|
-
register Padrino::Admin::AccessControl if authentication?
|
|
172
|
-
end
|
|
173
|
-
|
|
174
199
|
##
|
|
175
200
|
# Returns the load_paths for the application (relative to the application root)
|
|
176
201
|
#
|
|
@@ -9,12 +9,16 @@ module Padrino
|
|
|
9
9
|
# Mounter.new("blog_app", :app_file => "/path/to/blog/app.rb").to("/blog")
|
|
10
10
|
#
|
|
11
11
|
class Mounter
|
|
12
|
+
class MounterException < RuntimeError #:nodoc:
|
|
13
|
+
end
|
|
14
|
+
|
|
12
15
|
attr_accessor :name, :uri_root, :app_file, :app_class, :app_root, :app_obj, :app_host
|
|
13
16
|
|
|
14
17
|
def initialize(name, options={})
|
|
15
18
|
@name = name.underscore
|
|
16
19
|
@app_class = options[:app_class] || name.classify
|
|
17
20
|
@app_file = options[:app_file] || locate_app_file
|
|
21
|
+
raise MounterException, "Unable to locate app file for #{name}, try with :app_file => /path" unless @app_file
|
|
18
22
|
@app_root = options[:app_root] || File.dirname(@app_file)
|
|
19
23
|
@app_obj = self.app_object
|
|
20
24
|
@uri_root = "/"
|
|
@@ -70,16 +74,26 @@ module Padrino
|
|
|
70
74
|
# Return the class for the app
|
|
71
75
|
#
|
|
72
76
|
def app_object
|
|
73
|
-
|
|
74
|
-
|
|
77
|
+
begin
|
|
78
|
+
app_class.constantize
|
|
79
|
+
rescue
|
|
80
|
+
if app_file
|
|
81
|
+
Padrino.require_dependencies(app_file)
|
|
82
|
+
app_class.constantize
|
|
83
|
+
end
|
|
84
|
+
end
|
|
75
85
|
end
|
|
76
86
|
|
|
77
87
|
##
|
|
78
88
|
# Returns the determined location of the mounted application main file
|
|
79
89
|
#
|
|
80
90
|
def locate_app_file
|
|
81
|
-
|
|
82
|
-
|
|
91
|
+
candidates = []
|
|
92
|
+
candidates << app_object.app_file if app_object.respond_to?(:app_file) && File.exist?(app_object.app_file)
|
|
93
|
+
candidates << Padrino.first_caller if File.identical?(Padrino.first_caller.to_s, Padrino.called_from.to_s)
|
|
94
|
+
candidates << Padrino.mounted_root(name, "app.rb")
|
|
95
|
+
candidates << Padrino.root("app", "app.rb")
|
|
96
|
+
candidates.find { |candidate| File.exist?(candidate) }
|
|
83
97
|
end
|
|
84
98
|
|
|
85
99
|
##
|
|
@@ -126,7 +140,7 @@ module Padrino
|
|
|
126
140
|
def mount_core(*args)
|
|
127
141
|
options = args.extract_options!
|
|
128
142
|
app_class = args.size > 0 ? args.first.to_s.camelize : nil
|
|
129
|
-
options.reverse_merge!(:app_class => app_class
|
|
143
|
+
options.reverse_merge!(:app_class => app_class)
|
|
130
144
|
mount("core", options).to("/")
|
|
131
145
|
end
|
|
132
146
|
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
require 'padrino-core/support_lite' unless defined?(SupportLite)
|
|
2
|
+
|
|
1
3
|
module Padrino
|
|
2
4
|
##
|
|
3
5
|
# Padrino enhances the Sinatra ‘render’ method to have support for automatic template engine detection,
|
|
@@ -17,12 +19,20 @@ module Padrino
|
|
|
17
19
|
/~$/ # This is for Gedit
|
|
18
20
|
]
|
|
19
21
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
22
|
+
##
|
|
23
|
+
# Default rendering options used in the #render-method
|
|
24
|
+
#
|
|
25
|
+
DEFAULT_RENDERING_OPTIONS = { :strict_format => false, :raise_exceptions => true }
|
|
23
26
|
|
|
24
|
-
|
|
25
|
-
|
|
27
|
+
##
|
|
28
|
+
# Main class that register this extension
|
|
29
|
+
#
|
|
30
|
+
class << self
|
|
31
|
+
def registered(app)
|
|
32
|
+
app.send(:include, InstanceMethods)
|
|
33
|
+
app.extend(ClassMethods)
|
|
34
|
+
end
|
|
35
|
+
alias :included :registered
|
|
26
36
|
end
|
|
27
37
|
|
|
28
38
|
module ClassMethods
|
|
@@ -58,6 +68,9 @@ module Padrino
|
|
|
58
68
|
(@_cached_templates ||= {})[render_options] = template_file || []
|
|
59
69
|
end
|
|
60
70
|
|
|
71
|
+
##
|
|
72
|
+
# Retunrs the cached layout path.
|
|
73
|
+
#
|
|
61
74
|
def fetch_layout_path
|
|
62
75
|
layout_name = @layout || :application
|
|
63
76
|
@_cached_layout ||= {}
|
|
@@ -70,107 +83,116 @@ module Padrino
|
|
|
70
83
|
end
|
|
71
84
|
end
|
|
72
85
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
#
|
|
77
|
-
# * Using layout similar to rails
|
|
78
|
-
# * Use render 'path/to/my/template' (without symbols)
|
|
79
|
-
# * Use render 'path/to/my/template' (with engine lookup)
|
|
80
|
-
# * Use render 'path/to/template.haml' (with explicit engine lookup)
|
|
81
|
-
# * Use render 'path/to/template', :layout => false
|
|
82
|
-
# * Use render 'path/to/template', :layout => false, :engine => 'haml'
|
|
83
|
-
# * Use render { :a => 1, :b => 2, :c => 3 } # => return a json string
|
|
84
|
-
#
|
|
85
|
-
def render(engine, data=nil, options={}, locals={}, &block)
|
|
86
|
-
# If engine is a hash then render data converted to json
|
|
87
|
-
return engine.to_json if engine.is_a?(Hash)
|
|
88
|
-
|
|
89
|
-
# Data can actually be a hash of options in certain cases
|
|
90
|
-
options.merge!(data) && data = nil if data.is_a?(Hash)
|
|
91
|
-
|
|
92
|
-
# If an engine is a string then this is a likely a path to be resolved
|
|
93
|
-
data, engine = *resolve_template(engine, options) if data.nil?
|
|
94
|
-
|
|
95
|
-
# Sinatra 1.0 requires an outvar for erb and erubis templates
|
|
96
|
-
options[:outvar] ||= '@_out_buf' if [:erb, :erubis] & [engine]
|
|
97
|
-
|
|
98
|
-
# Resolve layouts similar to in Rails
|
|
99
|
-
if (options[:layout].nil? || options[:layout] == true) && !self.class.templates.has_key?(:layout)
|
|
100
|
-
options[:layout] = resolved_layout || false # We need to force layout false so sinatra don't try to render it
|
|
101
|
-
logger.debug "Resolving layout #{options[:layout]}" if defined?(logger) && options[:layout].present?
|
|
102
|
-
end
|
|
103
|
-
|
|
104
|
-
# Pass arguments to Sinatra render method
|
|
105
|
-
super(engine, data, options.dup, locals, &block)
|
|
86
|
+
module InstanceMethods
|
|
87
|
+
def content_type(type=nil, params={}) #:nodoc:
|
|
88
|
+
type.nil? ? @_content_type : super(type, params)
|
|
106
89
|
end
|
|
107
90
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
91
|
+
private
|
|
92
|
+
##
|
|
93
|
+
# Enhancing Sinatra render functionality for:
|
|
94
|
+
#
|
|
95
|
+
# * Using layout similar to rails
|
|
96
|
+
# * Use render 'path/to/my/template' (without symbols)
|
|
97
|
+
# * Use render 'path/to/my/template' (with engine lookup)
|
|
98
|
+
# * Use render 'path/to/template.haml' (with explicit engine lookup)
|
|
99
|
+
# * Use render 'path/to/template', :layout => false
|
|
100
|
+
# * Use render 'path/to/template', :layout => false, :engine => 'haml'
|
|
101
|
+
# * Use render { :a => 1, :b => 2, :c => 3 } # => return a json string
|
|
102
|
+
#
|
|
103
|
+
def render(engine, data=nil, options={}, locals={}, &block)
|
|
104
|
+
# If engine is a hash then render data converted to json
|
|
105
|
+
return engine.to_json if engine.is_a?(Hash)
|
|
106
|
+
|
|
107
|
+
# Data can actually be a hash of options in certain cases
|
|
108
|
+
options.merge!(data) && data = nil if data.is_a?(Hash)
|
|
109
|
+
|
|
110
|
+
# If an engine is a string then this is a likely a path to be resolved
|
|
111
|
+
data, engine = *resolve_template(engine, options) if data.nil?
|
|
112
|
+
|
|
113
|
+
# Sinatra 1.0 requires an outvar for erb and erubis templates
|
|
114
|
+
options[:outvar] ||= '@_out_buf' if [:erb, :erubis] & [engine]
|
|
115
|
+
|
|
116
|
+
# Resolve layouts similar to in Rails
|
|
117
|
+
if (options[:layout].nil? || options[:layout] == true) && !settings.templates.has_key?(:layout)
|
|
118
|
+
options[:layout] = resolved_layout || false # We need to force layout false so sinatra don't try to render it
|
|
119
|
+
logger.debug "Resolving layout #{options[:layout]}" if defined?(logger) && options[:layout].present?
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
# Pass arguments to Sinatra render method
|
|
123
|
+
super(engine, data, options.dup, locals, &block)
|
|
124
|
+
end
|
|
120
125
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
# # If you request "/foo.js" with I18n.locale == :ru => [:"/path/to/foo.ru.js", :erb]
|
|
133
|
-
# # If you request "/foo" with I18n.locale == :de => [:"/path/to/foo.de.haml", :haml]
|
|
134
|
-
#
|
|
135
|
-
def resolve_template(template_path, options={})
|
|
136
|
-
# Fetch cached template for rendering options
|
|
137
|
-
template_path = "/#{template_path}" unless template_path.to_s[0] == ?/
|
|
138
|
-
rendering_options = [template_path, content_type, locale]
|
|
139
|
-
cached_template = self.class.fetch_template_file(rendering_options)
|
|
140
|
-
return cached_template if cached_template
|
|
141
|
-
|
|
142
|
-
# Resolve view path and options
|
|
143
|
-
options.reverse_merge!(:strict_format => false, :raise_exceptions => true)
|
|
144
|
-
view_path = options.delete(:views) || self.options.views || self.class.views || "./views"
|
|
145
|
-
target_extension = File.extname(template_path)[1..-1] || "none" # retrieves explicit template extension
|
|
146
|
-
template_path = template_path.chomp(".#{target_extension}")
|
|
147
|
-
|
|
148
|
-
# Generate potential template candidates
|
|
149
|
-
templates = Dir[File.join(view_path, template_path) + ".*"].map do |file|
|
|
150
|
-
template_engine = File.extname(file)[1..-1].to_sym # retrieves engine extension
|
|
151
|
-
template_file = file.sub(view_path, '').chomp(".#{template_engine}").to_sym # retrieves template filename
|
|
152
|
-
[template_file, template_engine] unless IGNORE_FILE_PATTERN.any? { |pattern| template_engine.to_s =~ pattern }
|
|
126
|
+
##
|
|
127
|
+
# Returns the located layout to be used for the rendered template (if available)
|
|
128
|
+
#
|
|
129
|
+
# ==== Example
|
|
130
|
+
#
|
|
131
|
+
# resolve_layout(true)
|
|
132
|
+
# => "/layouts/custom"
|
|
133
|
+
#
|
|
134
|
+
def resolved_layout
|
|
135
|
+
located_layout = resolve_template(settings.fetch_layout_path, :strict_format => true, :raise_exceptions => false)
|
|
136
|
+
located_layout ? located_layout[0] : false
|
|
153
137
|
end
|
|
154
138
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
139
|
+
##
|
|
140
|
+
# Returns the template path and engine that match content_type (if present), I18n.locale.
|
|
141
|
+
#
|
|
142
|
+
# === Options
|
|
143
|
+
#
|
|
144
|
+
# :strict_format:: The resolved template must match the content_type of the request (defaults to false)
|
|
145
|
+
# :raise_exceptions:: Raises a +TemplateNotFound+ exception if the template cannot be located.
|
|
146
|
+
#
|
|
147
|
+
# ==== Example
|
|
148
|
+
#
|
|
149
|
+
# get "/foo", :provides => [:html, :js] do; render 'path/to/foo'; end
|
|
150
|
+
# # If you request "/foo.js" with I18n.locale == :ru => [:"/path/to/foo.ru.js", :erb]
|
|
151
|
+
# # If you request "/foo" with I18n.locale == :de => [:"/path/to/foo.de.haml", :haml]
|
|
152
|
+
#
|
|
153
|
+
def resolve_template(template_path, options={})
|
|
154
|
+
# Fetch cached template for rendering options
|
|
155
|
+
template_path = "/#{template_path}" unless template_path.to_s[0] == ?/
|
|
156
|
+
rendering_options = [template_path, content_type, locale]
|
|
157
|
+
cached_template = settings.fetch_template_file(rendering_options)
|
|
158
|
+
return cached_template if cached_template
|
|
159
|
+
|
|
160
|
+
# Resolve view path and options
|
|
161
|
+
options.reverse_merge!(DEFAULT_RENDERING_OPTIONS)
|
|
162
|
+
view_path = options.delete(:views) || settings.views || settings.views || "./views"
|
|
163
|
+
target_extension = File.extname(template_path)[1..-1] || "none" # retrieves explicit template extension
|
|
164
|
+
template_path = template_path.chomp(".#{target_extension}")
|
|
165
|
+
|
|
166
|
+
# Generate potential template candidates
|
|
167
|
+
templates = Dir[File.join(view_path, template_path) + ".*"].map do |file|
|
|
168
|
+
template_engine = File.extname(file)[1..-1].to_sym # retrieves engine extension
|
|
169
|
+
template_file = file.sub(view_path, '').chomp(".#{template_engine}").to_sym # retrieves template filename
|
|
170
|
+
[template_file, template_engine] unless IGNORE_FILE_PATTERN.any? { |pattern| template_engine.to_s =~ pattern }
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
# Check if we have a valid content type
|
|
174
|
+
valid_content_type = [:html, :plain].include?(content_type)
|
|
175
|
+
|
|
176
|
+
# Resolve final template to render
|
|
177
|
+
located_template =
|
|
178
|
+
templates.find { |file, e| file.to_s == "#{template_path}.#{locale}.#{content_type}" } ||
|
|
179
|
+
templates.find { |file, e| file.to_s == "#{template_path}.#{locale}" && valid_content_type } ||
|
|
180
|
+
templates.find { |file, e| File.extname(file.to_s) == ".#{target_extension}" or e.to_s == target_extension.to_s } ||
|
|
181
|
+
templates.find { |file, e| file.to_s == "#{template_path}.#{content_type}" } ||
|
|
182
|
+
templates.find { |file, e| file.to_s == "#{template_path}" && valid_content_type } ||
|
|
183
|
+
templates.any? && !options[:strict_format] && templates.first # If not strict, fall back to the first located template
|
|
184
|
+
|
|
185
|
+
settings.cache_template_file!(located_template, rendering_options) unless settings.reload_templates?
|
|
186
|
+
raise TemplateNotFound, "Template path '#{template_path}' could not be located in '#{view_path}'!" if !located_template && options[:raise_exceptions]
|
|
187
|
+
located_template
|
|
188
|
+
end
|
|
168
189
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
190
|
+
##
|
|
191
|
+
# Return the I18n.locale if I18n is defined
|
|
192
|
+
#
|
|
193
|
+
def locale
|
|
194
|
+
I18n.locale if defined?(I18n)
|
|
195
|
+
end
|
|
196
|
+
end # InstanceMethods
|
|
175
197
|
end # Rendering
|
|
176
198
|
end # Padrino
|