roda 2.2.0 → 2.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG +34 -0
- data/Rakefile +22 -46
- data/doc/release_notes/2.3.0.txt +109 -0
- data/lib/roda/plugins/assets.rb +2 -1
- data/lib/roda/plugins/caching.rb +1 -1
- data/lib/roda/plugins/chunked.rb +1 -1
- data/lib/roda/plugins/error_email.rb +1 -1
- data/lib/roda/plugins/head.rb +6 -0
- data/lib/roda/plugins/heartbeat.rb +40 -0
- data/lib/roda/plugins/json.rb +23 -3
- data/lib/roda/plugins/json_parser.rb +72 -0
- data/lib/roda/plugins/mailer.rb +22 -5
- data/lib/roda/plugins/named_templates.rb +2 -2
- data/lib/roda/plugins/path_rewriter.rb +82 -0
- data/lib/roda/plugins/precompile_templates.rb +87 -0
- data/lib/roda/plugins/render.rb +111 -43
- data/lib/roda/plugins/render_each.rb +1 -1
- data/lib/roda/plugins/shared_vars.rb +1 -1
- data/lib/roda/plugins/view_options.rb +28 -3
- data/lib/roda/version.rb +1 -1
- data/spec/composition_spec.rb +3 -3
- data/spec/env_spec.rb +1 -1
- data/spec/freeze_spec.rb +6 -6
- data/spec/integration_spec.rb +16 -15
- data/spec/matchers_spec.rb +110 -110
- data/spec/opts_spec.rb +8 -8
- data/spec/plugin/_erubis_escaping_spec.rb +34 -3
- data/spec/plugin/all_verbs_spec.rb +8 -8
- data/spec/plugin/assets_spec.rb +164 -150
- data/spec/plugin/backtracking_array_spec.rb +18 -18
- data/spec/plugin/caching_spec.rb +70 -70
- data/spec/plugin/chunked_spec.rb +38 -38
- data/spec/plugin/class_level_routing_spec.rb +78 -78
- data/spec/plugin/content_for_spec.rb +2 -2
- data/spec/plugin/cookies_spec.rb +4 -4
- data/spec/plugin/csrf_spec.rb +8 -8
- data/spec/plugin/default_headers_spec.rb +6 -6
- data/spec/plugin/delay_build_spec.rb +7 -6
- data/spec/plugin/delegate_spec.rb +2 -2
- data/spec/plugin/delete_empty_headers_spec.rb +2 -2
- data/spec/plugin/drop_body_spec.rb +6 -6
- data/spec/plugin/empty_root_spec.rb +3 -3
- data/spec/plugin/environments_spec.rb +7 -7
- data/spec/plugin/error_email_spec.rb +23 -23
- data/spec/plugin/error_handler_spec.rb +14 -14
- data/spec/plugin/flash_spec.rb +30 -29
- data/spec/plugin/h_spec.rb +1 -1
- data/spec/plugin/halt_spec.rb +16 -16
- data/spec/plugin/hash_matcher_spec.rb +5 -5
- data/spec/plugin/head_spec.rb +10 -10
- data/spec/plugin/header_matchers_spec.rb +13 -13
- data/spec/plugin/heartbeat_spec.rb +74 -0
- data/spec/plugin/hooks_spec.rb +20 -20
- data/spec/plugin/indifferent_params_spec.rb +1 -1
- data/spec/plugin/json_parser_spec.rb +72 -0
- data/spec/plugin/json_spec.rb +22 -9
- data/spec/plugin/mailer_spec.rb +72 -58
- data/spec/plugin/match_affix_spec.rb +2 -2
- data/spec/plugin/middleware_spec.rb +7 -7
- data/spec/plugin/module_include_spec.rb +4 -4
- data/spec/plugin/multi_route_spec.rb +66 -66
- data/spec/plugin/multi_run_spec.rb +21 -21
- data/spec/plugin/named_templates_spec.rb +6 -6
- data/spec/plugin/not_allowed_spec.rb +17 -17
- data/spec/plugin/not_found_spec.rb +14 -14
- data/spec/plugin/padrino_render_spec.rb +2 -2
- data/spec/plugin/param_matchers_spec.rb +6 -6
- data/spec/plugin/partials_spec.rb +3 -3
- data/spec/plugin/pass_spec.rb +7 -7
- data/spec/plugin/path_matchers_spec.rb +6 -6
- data/spec/plugin/path_rewriter_spec.rb +37 -0
- data/spec/plugin/path_spec.rb +41 -40
- data/spec/plugin/per_thread_caching_spec.rb +6 -6
- data/spec/plugin/precompile_templates_spec.rb +74 -0
- data/spec/plugin/render_each_spec.rb +4 -4
- data/spec/plugin/render_spec.rb +179 -76
- data/spec/plugin/shared_vars_spec.rb +4 -4
- data/spec/plugin/sinatra_helpers_spec.rb +121 -121
- data/spec/plugin/slash_path_empty_spec.rb +10 -10
- data/spec/plugin/static_spec.rb +4 -4
- data/spec/plugin/streaming_spec.rb +11 -11
- data/spec/plugin/symbol_matchers_spec.rb +24 -24
- data/spec/plugin/symbol_views_spec.rb +3 -3
- data/spec/plugin/view_options_spec.rb +10 -10
- data/spec/plugin_spec.rb +2 -2
- data/spec/redirect_spec.rb +10 -10
- data/spec/request_spec.rb +8 -8
- data/spec/response_spec.rb +23 -23
- data/spec/session_spec.rb +4 -4
- data/spec/spec_helper.rb +5 -19
- data/spec/version_spec.rb +4 -4
- data/spec/views/iv.erb +1 -0
- metadata +16 -5
data/lib/roda/plugins/mailer.rb
CHANGED
@@ -87,6 +87,14 @@ class Roda
|
|
87
87
|
# ""
|
88
88
|
# end
|
89
89
|
#
|
90
|
+
# If while preparing the email you figure out you don't want to send an
|
91
|
+
# email, call +no_mail!+:
|
92
|
+
#
|
93
|
+
# r.mail '/welcome/:d' do |id|
|
94
|
+
# no_mail! unless user = User[id]
|
95
|
+
# # ...
|
96
|
+
# end
|
97
|
+
#
|
90
98
|
# By default, the mailer uses text/plain as the Content-Type for emails.
|
91
99
|
# You can override the default by specifying a :content_type option when
|
92
100
|
# loading the plugin:
|
@@ -128,15 +136,19 @@ class Roda
|
|
128
136
|
# calling +deliver+ to send the mail.
|
129
137
|
def mail(path, *args)
|
130
138
|
mail = ::Mail.new
|
131
|
-
|
132
|
-
|
139
|
+
catch(:no_mail) do
|
140
|
+
unless mail.equal?(new(PATH_INFO=>path, SCRIPT_NAME=>EMPTY_STRING, REQUEST_METHOD=>MAIL, RACK_INPUT=>StringIO.new, RODA_MAIL=>mail, RODA_MAIL_ARGS=>args).call(&route_block))
|
141
|
+
raise Error, "route did not return mail instance for #{path.inspect}, #{args.inspect}"
|
142
|
+
end
|
143
|
+
mail
|
133
144
|
end
|
134
|
-
mail
|
135
145
|
end
|
136
146
|
|
137
147
|
# Calls +mail+ and immediately sends the resulting mail.
|
138
148
|
def sendmail(*args)
|
139
|
-
mail(*args)
|
149
|
+
if m = mail(*args)
|
150
|
+
m.deliver
|
151
|
+
end
|
140
152
|
end
|
141
153
|
end
|
142
154
|
|
@@ -149,7 +161,7 @@ class Roda
|
|
149
161
|
def mail(*args)
|
150
162
|
if @env[REQUEST_METHOD] == MAIL
|
151
163
|
if_match(args) do |*vs|
|
152
|
-
yield
|
164
|
+
yield(*(vs + @env[RODA_MAIL_ARGS]))
|
153
165
|
end
|
154
166
|
end
|
155
167
|
end
|
@@ -232,6 +244,11 @@ class Roda
|
|
232
244
|
nil
|
233
245
|
end
|
234
246
|
|
247
|
+
# Signal that no mail should be sent for this request.
|
248
|
+
def no_mail!
|
249
|
+
throw :no_mail
|
250
|
+
end
|
251
|
+
|
235
252
|
private
|
236
253
|
|
237
254
|
# Set the text_part or html_part (depending on the method) in the related email,
|
@@ -79,9 +79,9 @@ class Roda
|
|
79
79
|
def find_template(options)
|
80
80
|
if options[:template] && (template_opts, block = opts[:named_templates][template_name(options)]; block)
|
81
81
|
if template_opts
|
82
|
-
options = template_opts.merge(options)
|
82
|
+
options = Hash[template_opts].merge!(options)
|
83
83
|
else
|
84
|
-
options = options
|
84
|
+
options = Hash[options]
|
85
85
|
end
|
86
86
|
|
87
87
|
options[:inline] = instance_exec(&block)
|
@@ -0,0 +1,82 @@
|
|
1
|
+
class Roda
|
2
|
+
module RodaPlugins
|
3
|
+
# The path_rewriter plugin allows you to rewrite the remaining path
|
4
|
+
# or the path info for requests. This is useful if you want to
|
5
|
+
# transparently treat some paths the same as other paths.
|
6
|
+
#
|
7
|
+
# By default, +rewrite_path+ will rewrite just the remaining path. So
|
8
|
+
# only routing in the current Roda app will be affected. This is useful
|
9
|
+
# if you have other code in your app that uses PATH_INFO and needs to
|
10
|
+
# see the original PATH_INFO (for example, when using relative links).
|
11
|
+
#
|
12
|
+
# rewrite_path '/a', '/b'
|
13
|
+
# # PATH_INFO '/a' => remaining_path '/b'
|
14
|
+
# # PATH_INFO '/a/c' => remaining_path '/b/c'
|
15
|
+
#
|
16
|
+
# In some cases, you may want to override PATH_INFO for the rewritten
|
17
|
+
# paths, such as when you are passing the request to another Rack app.
|
18
|
+
# For those cases, you can use the <tt>:path_info => true</tt> option to
|
19
|
+
# +rewrite_path+.
|
20
|
+
#
|
21
|
+
# rewrite_path '/a', '/b', :path_info => true
|
22
|
+
# # PATH_INFO '/a' => PATH_INFO '/b'
|
23
|
+
# # PATH_INFO '/a/c' => PATH_INFO '/b/c'
|
24
|
+
#
|
25
|
+
# If you pass a string to +rewrite_path+, it will rewrite all paths starting
|
26
|
+
# with that string. You can provide a regexp if you want more complete control,
|
27
|
+
# such as only matching exact paths.
|
28
|
+
#
|
29
|
+
# rewrite_path /\A\/a\z/, '/b'
|
30
|
+
# # PATH_INFO '/a' => remaining_path '/b'
|
31
|
+
# # PATH_INFO '/a/c' => remaining_path '/a/c', no change
|
32
|
+
#
|
33
|
+
# All path rewrites are applied in order, so if a path is rewritten by one rewrite,
|
34
|
+
# it can be rewritten again by a later rewrite. Note that PATH_INFO rewrites are
|
35
|
+
# processed before remaining_path rewrites.
|
36
|
+
module PathRewriter
|
37
|
+
PATH_INFO = 'PATH_INFO'.freeze
|
38
|
+
OPTS={}.freeze
|
39
|
+
|
40
|
+
def self.configure(app)
|
41
|
+
app.instance_exec do
|
42
|
+
app.opts[:remaining_path_rewrites] ||= []
|
43
|
+
app.opts[:path_info_rewrites] ||= []
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
module ClassMethods
|
48
|
+
# Freeze the path rewrite metadata.
|
49
|
+
def freeze
|
50
|
+
opts[:remaining_path_rewrites].freeze
|
51
|
+
opts[:path_info_rewrites].freeze
|
52
|
+
super
|
53
|
+
end
|
54
|
+
|
55
|
+
# Record a path rewrite from path +was+ to path +is+. Options:
|
56
|
+
# :path_info :: Modify PATH_INFO, not just remaining path.
|
57
|
+
def rewrite_path(was, is, opts=OPTS)
|
58
|
+
was = /\A#{Regexp.escape(was)}/ unless was.is_a?(Regexp)
|
59
|
+
array = @opts[opts[:path_info] ? :path_info_rewrites : :remaining_path_rewrites]
|
60
|
+
array << [was, is.dup.freeze].freeze
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
module RequestMethods
|
65
|
+
# Rewrite remaining_path and/or PATH_INFO based on the path rewrites.
|
66
|
+
def initialize(scope, env)
|
67
|
+
path_info = env[PATH_INFO]
|
68
|
+
scope.class.opts[:path_info_rewrites].each do |was, is|
|
69
|
+
path_info.sub!(was, is)
|
70
|
+
end
|
71
|
+
super
|
72
|
+
remaining_path = @remaining_path = @remaining_path.dup
|
73
|
+
scope.class.opts[:remaining_path_rewrites].each do |was, is|
|
74
|
+
remaining_path.sub!(was, is)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
register_plugin(:path_rewriter, PathRewriter)
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
class Roda
|
2
|
+
module RodaPlugins
|
3
|
+
# The precompile_templates plugin adds support for precompiling template code.
|
4
|
+
# This can result in a large memory savings for applications that have large
|
5
|
+
# templates or a large number of small templates if the application uses a
|
6
|
+
# forking webserver. By default, template compilation is lazy, so all the
|
7
|
+
# child processes in a forking webserver will have their own copy of the
|
8
|
+
# compiled template. By using the precompile_templates plugin, you can
|
9
|
+
# precompile the templates in the parent process before forking, and then
|
10
|
+
# all of the child processes can use the same precompiled templates, which
|
11
|
+
# saves memory.
|
12
|
+
#
|
13
|
+
# After loading the plugin, you can call +precompile_templates+ with
|
14
|
+
# the pattern of templates you would like to precompile:
|
15
|
+
#
|
16
|
+
# plugin :precompile_templates
|
17
|
+
# precompile_templates "views/\*\*/*.erb"
|
18
|
+
#
|
19
|
+
# That will precompile all erb template files in the views directory or
|
20
|
+
# any subdirectory.
|
21
|
+
#
|
22
|
+
# If the templates use local variables, you need to specify which local
|
23
|
+
# variables to precompile, which should be an array of symbols:
|
24
|
+
#
|
25
|
+
# precompile_templates 'views/users/_*.erb', :locals=>[:user]
|
26
|
+
#
|
27
|
+
# Note that if you have multiple local variables and are not using a Tilt
|
28
|
+
# version greater than 2.0.1, you should specify the :locals option in the
|
29
|
+
# same order as the keys in the :locals hash you pass to render/view. Since
|
30
|
+
# hashes are not ordered in ruby 1.8, you should not attempt to precompile
|
31
|
+
# templates that use :locals on ruby 1.8 unless you are using a Tilt version
|
32
|
+
# greater than 2.0.1. If you are running the Tilt master branch, you can
|
33
|
+
# force sorting of locals using the +:sort_locals+ option when loading the
|
34
|
+
# plugin.
|
35
|
+
#
|
36
|
+
# You can specify other render options when calling +precompile_templates+,
|
37
|
+
# including +:cache_key+, +:template_class+, and +:template_opts+. If you
|
38
|
+
# are passing any of those options to render/view for the template, you
|
39
|
+
# should pass the same options when precompiling the template.
|
40
|
+
#
|
41
|
+
# To compile inline templates, just pass a single hash containing an :inline
|
42
|
+
# to +precompile_templates+:
|
43
|
+
#
|
44
|
+
# precompile_templates :inline=>some_template_string
|
45
|
+
module PrecompileTemplates
|
46
|
+
OPTS = {}.freeze
|
47
|
+
|
48
|
+
# Load the render plugin as precompile_templates depends on it.
|
49
|
+
# Default to sorting the locals if the Tilt version is greater than 2.0.1.
|
50
|
+
def self.load_dependencies(app, opts=OPTS)
|
51
|
+
app.plugin :render
|
52
|
+
app.opts[:precompile_templates_sort] = opts.fetch(:sort_locals, Tilt::VERSION > '2.0.1')
|
53
|
+
end
|
54
|
+
|
55
|
+
module ClassMethods
|
56
|
+
# Precompile the templates using the given options. See PrecompileTemplates
|
57
|
+
# for details.
|
58
|
+
def precompile_templates(pattern, opts=OPTS)
|
59
|
+
if pattern.is_a?(Hash)
|
60
|
+
opts = pattern.merge(opts)
|
61
|
+
end
|
62
|
+
|
63
|
+
locals = opts[:locals] || []
|
64
|
+
if locals && self.opts[:precompile_templates_sort]
|
65
|
+
locals = locals.sort{|x,y| x.to_s <=> y.to_s}
|
66
|
+
end
|
67
|
+
|
68
|
+
compile_opts = if pattern.is_a?(Hash)
|
69
|
+
[opts]
|
70
|
+
else
|
71
|
+
Dir[pattern].map{|file| opts.merge(:path=>File.expand_path(file))}
|
72
|
+
end
|
73
|
+
|
74
|
+
instance = allocate
|
75
|
+
compile_opts.each do |compile_opt|
|
76
|
+
template = instance.send(:retrieve_template, compile_opt)
|
77
|
+
template.send(:compiled_method, locals)
|
78
|
+
end
|
79
|
+
|
80
|
+
nil
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
register_plugin(:precompile_templates, PrecompileTemplates)
|
86
|
+
end
|
87
|
+
end
|
data/lib/roda/plugins/render.rb
CHANGED
@@ -22,12 +22,15 @@ class Roda
|
|
22
22
|
#
|
23
23
|
# plugin :render, :engine=>'haml', :views=>'admin_views'
|
24
24
|
#
|
25
|
-
#
|
25
|
+
# = Plugin Options
|
26
|
+
#
|
27
|
+
# The following plugin options are supported:
|
26
28
|
#
|
27
29
|
# :cache :: nil/false to not cache templates (useful for development), defaults
|
28
30
|
# to true unless RACK_ENV is development to automatically use the
|
29
31
|
# default template cache.
|
30
|
-
# :engine :: The tilt engine to use for rendering,
|
32
|
+
# :engine :: The tilt engine to use for rendering, also the default file extension for
|
33
|
+
# templates, defaults to 'erb'.
|
31
34
|
# :escape :: Use Roda's Erubis escaping support, which makes <tt><%= %></tt> escape output,
|
32
35
|
# <tt><%== %></tt> not escape output, and handles postfix conditions inside
|
33
36
|
# <tt><%= %></tt> tags.
|
@@ -36,25 +39,32 @@ class Roda
|
|
36
39
|
# :escaper :: Object used for escaping output of <tt><%= %></tt>, when :escape is used,
|
37
40
|
# overriding the default. If given, object should respond to +escape_xml+ with
|
38
41
|
# a single argument and return an output string.
|
39
|
-
# :ext :: The file extension to assume for view files, defaults to the :engine
|
40
|
-
# option.
|
41
42
|
# :layout :: The base name of the layout file, defaults to 'layout'.
|
42
43
|
# :layout_opts :: The options to use when rendering the layout, if different
|
43
44
|
# from the default options.
|
44
|
-
# :template_opts :: The tilt options used when rendering templates
|
45
|
-
#
|
45
|
+
# :template_opts :: The tilt options used when rendering all templates. defaults to:
|
46
|
+
# <tt>{:outvar=>'@_out_buf', :default_encoding=>Encoding.default_external}</tt>.
|
47
|
+
# :engine_opts :: The tilt options to use per template engine. Keys are
|
48
|
+
# engine strings, values are hashes of template options.
|
46
49
|
# :views :: The directory holding the view files, defaults to the 'views' subdirectory of the
|
47
50
|
# application's :root option (the process's working directory by default).
|
48
51
|
#
|
52
|
+
# = Render/View Method Options
|
53
|
+
#
|
49
54
|
# Most of these options can be overridden at runtime by passing options
|
50
55
|
# to the +view+ or +render+ methods:
|
51
56
|
#
|
52
|
-
# view('foo', :
|
57
|
+
# view('foo', :engine=>'html.erb')
|
53
58
|
# render('foo', :views=>'admin_views')
|
54
59
|
#
|
55
|
-
# There are
|
60
|
+
# There are additional options to +view+ and +render+ that are
|
56
61
|
# available at runtime:
|
57
62
|
#
|
63
|
+
# :cache :: Set to false to not cache this template, even when
|
64
|
+
# caching is on by default. Set to true to force caching for
|
65
|
+
# this template, even when the default is to not cache (e.g.
|
66
|
+
# when using the :template_block option).
|
67
|
+
# :cache_key :: Explicitly set the hash key to use when caching.
|
58
68
|
# :content :: Only respected by +view+, provides the content to render
|
59
69
|
# inside the layout, instead of rendering a template to get
|
60
70
|
# the content.
|
@@ -62,13 +72,14 @@ class Roda
|
|
62
72
|
# for template code in a file.
|
63
73
|
# :locals :: Hash of local variables to make available inside the template.
|
64
74
|
# :path :: Use the value given as the full pathname for the file, instead
|
65
|
-
# of using the :views and :
|
75
|
+
# of using the :views and :engine option in combination with the
|
66
76
|
# template name.
|
67
77
|
# :template :: Provides the name of the template to use. This allows you
|
68
78
|
# pass a single options hash to the render/view method, while
|
69
79
|
# still allowing you to specify the template name.
|
70
80
|
# :template_block :: Pass this block when creating the underlying template,
|
71
|
-
# ignored when using :inline.
|
81
|
+
# ignored when using :inline. Disables caching of the
|
82
|
+
# template by default.
|
72
83
|
# :template_class :: Provides the template class to use, inside of using
|
73
84
|
# Tilt or <tt>Tilt[:engine]</tt>.
|
74
85
|
#
|
@@ -80,6 +91,27 @@ class Roda
|
|
80
91
|
# If you pass a hash as the first argument to +view+ or +render+, it should
|
81
92
|
# have either +:template+, +:inline+, +:path+, or +:content+ (for +view+) as
|
82
93
|
# one of the keys.
|
94
|
+
#
|
95
|
+
# = Speeding Up Template Rendering
|
96
|
+
#
|
97
|
+
# By default, determining the cache key to use for the template can be a lot
|
98
|
+
# of work. If you specify the +:cache_key+ option, you can save Roda from
|
99
|
+
# having to do that work, which will make your application faster. However,
|
100
|
+
# if you do this, you need to make sure you choose a correct key.
|
101
|
+
#
|
102
|
+
# If your application uses a unique template per path, in that the same
|
103
|
+
# path never uses more than one template, you can use the +view_options+ plugin
|
104
|
+
# and do:
|
105
|
+
#
|
106
|
+
# set_view_options :cache_key=>r.path_info
|
107
|
+
#
|
108
|
+
# at the top of your route block. You can even do this if you do have paths
|
109
|
+
# that use more than one template, as long as you specify +:cache_key+
|
110
|
+
# specifically when rendering in those paths.
|
111
|
+
#
|
112
|
+
# If you use a single layout in your application, you can also make layout
|
113
|
+
# rendering faster by specifying +:cache_key+ inside the +:layout_opts+
|
114
|
+
# plugin option.
|
83
115
|
module Render
|
84
116
|
OPTS={}.freeze
|
85
117
|
|
@@ -98,12 +130,12 @@ class Roda
|
|
98
130
|
app.opts[:render][:orig_opts] = opts
|
99
131
|
|
100
132
|
opts = app.opts[:render]
|
101
|
-
opts[:engine]
|
102
|
-
opts[:
|
103
|
-
opts[:
|
133
|
+
opts[:engine] = (opts[:engine] || opts[:ext] || "erb").dup.freeze
|
134
|
+
opts[:views] = File.expand_path(opts[:views]||"views", app.opts[:root]).freeze
|
135
|
+
opts[:cache] = app.thread_safe_cache if opts.fetch(:cache, ENV['RACK_ENV'] != 'development')
|
136
|
+
|
104
137
|
opts[:layout_opts] = (opts[:layout_opts] || {}).dup
|
105
138
|
opts[:layout_opts][:_is_layout] = true
|
106
|
-
|
107
139
|
if layout = opts.fetch(:layout, true)
|
108
140
|
opts[:layout] = true unless opts.has_key?(:layout)
|
109
141
|
|
@@ -116,6 +148,7 @@ class Roda
|
|
116
148
|
opts[:layout_opts][:template] = layout
|
117
149
|
end
|
118
150
|
end
|
151
|
+
opts[:layout_opts].freeze
|
119
152
|
|
120
153
|
template_opts = opts[:template_opts] = (opts[:template_opts] || {}).dup
|
121
154
|
template_opts[:outvar] ||= '@_out_buf'
|
@@ -131,9 +164,14 @@ class Roda
|
|
131
164
|
::Erubis::XmlHelper
|
132
165
|
end
|
133
166
|
end
|
134
|
-
|
135
|
-
|
136
|
-
opts[:
|
167
|
+
template_opts.freeze
|
168
|
+
|
169
|
+
engine_opts = opts[:engine_opts] = (opts[:engine_opts] || {}).dup
|
170
|
+
engine_opts.to_a.each do |k,v|
|
171
|
+
engine_opts[k] = v.dup.freeze
|
172
|
+
end
|
173
|
+
engine_opts.freeze
|
174
|
+
|
137
175
|
opts.freeze
|
138
176
|
end
|
139
177
|
|
@@ -157,13 +195,9 @@ class Roda
|
|
157
195
|
module InstanceMethods
|
158
196
|
# Render the given template. See Render for details.
|
159
197
|
def render(template, opts = OPTS, &block)
|
160
|
-
opts =
|
161
|
-
|
162
|
-
|
163
|
-
current_template_opts = opts[:template_opts]
|
164
|
-
template_opts = template_opts.merge(current_template_opts) if current_template_opts
|
165
|
-
opts[:template_class].new(opts[:path], 1, template_opts, &opts[:template_block])
|
166
|
-
end.render(self, (opts[:locals]||OPTS), &block)
|
198
|
+
opts = parse_template_opts(template, opts)
|
199
|
+
merge_render_locals(opts)
|
200
|
+
retrieve_template(opts).render(self, (opts[:locals]||OPTS), &block)
|
167
201
|
end
|
168
202
|
|
169
203
|
# Return the render options for the instance's class. While this
|
@@ -196,8 +230,7 @@ class Roda
|
|
196
230
|
# If caching templates, attempt to retrieve the template from the cache. Otherwise, just yield
|
197
231
|
# to get the template.
|
198
232
|
def cached_template(opts, &block)
|
199
|
-
if cache = render_opts[:cache]
|
200
|
-
key = opts[:key]
|
233
|
+
if (cache = render_opts[:cache]) && (key = opts[:cache_key])
|
201
234
|
unless template = cache[key]
|
202
235
|
template = cache[key] = yield
|
203
236
|
end
|
@@ -210,49 +243,86 @@ class Roda
|
|
210
243
|
# Given the template name and options, set the template class, template path/content,
|
211
244
|
# template block, and locals to use for the render in the passed options.
|
212
245
|
def find_template(opts)
|
246
|
+
render_opts = render_opts()
|
247
|
+
engine_override = opts[:engine] ||= opts[:ext]
|
248
|
+
engine = opts[:engine] ||= render_opts[:engine]
|
213
249
|
if content = opts[:inline]
|
214
250
|
path = opts[:path] = content
|
215
|
-
template_class = opts[:template_class] ||= ::Tilt[
|
251
|
+
template_class = opts[:template_class] ||= ::Tilt[engine]
|
216
252
|
opts[:template_block] = Proc.new{content}
|
217
253
|
else
|
254
|
+
opts[:views] ||= render_opts[:views]
|
218
255
|
path = opts[:path] ||= template_path(opts)
|
219
256
|
template_class = opts[:template_class]
|
220
257
|
opts[:template_class] ||= ::Tilt
|
221
258
|
end
|
222
259
|
|
223
260
|
if render_opts[:cache]
|
224
|
-
|
225
|
-
|
261
|
+
if (cache = opts[:cache]).nil?
|
262
|
+
cache = content || !opts[:template_block]
|
263
|
+
end
|
264
|
+
|
265
|
+
if cache
|
266
|
+
template_block = opts[:template_block] unless content
|
267
|
+
template_opts = opts[:template_opts]
|
226
268
|
|
227
|
-
|
228
|
-
|
269
|
+
opts[:cache_key] ||= if template_class || engine_override || template_opts || template_block
|
270
|
+
[path, template_class, engine_override, template_opts, template_block]
|
271
|
+
else
|
272
|
+
path
|
273
|
+
end
|
229
274
|
else
|
230
|
-
|
275
|
+
opts.delete(:cache_key)
|
231
276
|
end
|
232
|
-
opts[:key] = key
|
233
277
|
end
|
234
278
|
|
279
|
+
opts
|
280
|
+
end
|
281
|
+
|
282
|
+
# Merge any :locals specified in the render_opts into the :locals option given.
|
283
|
+
def merge_render_locals(opts)
|
235
284
|
if !opts[:_is_layout] && (r_locals = render_opts[:locals])
|
236
285
|
opts[:locals] = if locals = opts[:locals]
|
237
|
-
r_locals.merge(locals)
|
286
|
+
Hash[r_locals].merge!(locals)
|
238
287
|
else
|
239
288
|
r_locals
|
240
289
|
end
|
241
290
|
end
|
242
|
-
|
243
|
-
opts
|
244
291
|
end
|
245
292
|
|
246
293
|
# Return a single hash combining the template and opts arguments.
|
247
294
|
def parse_template_opts(template, opts)
|
248
|
-
|
249
|
-
|
295
|
+
opts = Hash[opts]
|
296
|
+
if template.is_a?(Hash)
|
297
|
+
opts.merge!(template)
|
298
|
+
else
|
299
|
+
opts[:template] = template
|
300
|
+
opts
|
301
|
+
end
|
250
302
|
end
|
251
303
|
|
252
304
|
# The default render options to use. These set defaults that can be overridden by
|
253
305
|
# providing a :layout_opts option to the view/render method.
|
254
306
|
def render_layout_opts
|
255
|
-
render_opts[:layout_opts]
|
307
|
+
Hash[render_opts[:layout_opts]]
|
308
|
+
end
|
309
|
+
|
310
|
+
# Retrieve the Tilt::Template object for the given template and opts.
|
311
|
+
def retrieve_template(opts)
|
312
|
+
unless opts[:cache_key] && opts[:cache] != false
|
313
|
+
found_template_opts = opts = find_template(opts)
|
314
|
+
end
|
315
|
+
cached_template(opts) do
|
316
|
+
opts = found_template_opts || find_template(opts)
|
317
|
+
template_opts = render_opts[:template_opts]
|
318
|
+
if engine_opts = render_opts[:engine_opts][opts[:engine]]
|
319
|
+
template_opts = Hash[template_opts].merge!(engine_opts)
|
320
|
+
end
|
321
|
+
if current_template_opts = opts[:template_opts]
|
322
|
+
template_opts = Hash[template_opts].merge!(current_template_opts)
|
323
|
+
end
|
324
|
+
opts[:template_class].new(opts[:path], 1, template_opts, &opts[:template_block])
|
325
|
+
end
|
256
326
|
end
|
257
327
|
|
258
328
|
# The name to use for the template. By default, just converts the :template option to a string.
|
@@ -262,8 +332,7 @@ class Roda
|
|
262
332
|
|
263
333
|
# The template path for the given options.
|
264
334
|
def template_path(opts)
|
265
|
-
|
266
|
-
"#{opts[:views] || render_opts[:views]}/#{template_name(opts)}.#{opts[:ext] || render_opts[:ext] || render_opts[:engine]}"
|
335
|
+
"#{opts[:views]}/#{template_name(opts)}.#{opts[:engine]}"
|
267
336
|
end
|
268
337
|
|
269
338
|
# If a layout should be used, return a hash of options for
|
@@ -274,7 +343,7 @@ class Roda
|
|
274
343
|
layout_opts = render_layout_opts
|
275
344
|
if l_opts = opts[:layout_opts]
|
276
345
|
if (l_locals = l_opts[:locals]) && (layout_locals = layout_opts[:locals])
|
277
|
-
set_locals = layout_locals.merge(l_locals)
|
346
|
+
set_locals = Hash[layout_locals].merge!(l_locals)
|
278
347
|
end
|
279
348
|
layout_opts.merge!(l_opts)
|
280
349
|
if set_locals
|
@@ -294,7 +363,6 @@ class Roda
|
|
294
363
|
layout_opts
|
295
364
|
end
|
296
365
|
end
|
297
|
-
|
298
366
|
end
|
299
367
|
end
|
300
368
|
|