actionpack 3.0.0.beta → 3.0.0.beta2
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of actionpack might be problematic. Click here for more details.
- data/CHANGELOG +291 -260
- data/lib/abstract_controller.rb +5 -2
- data/lib/abstract_controller/assigns.rb +21 -0
- data/lib/abstract_controller/base.rb +13 -5
- data/lib/abstract_controller/collector.rb +2 -0
- data/lib/abstract_controller/helpers.rb +4 -14
- data/lib/abstract_controller/layouts.rb +50 -99
- data/lib/abstract_controller/logger.rb +2 -2
- data/lib/abstract_controller/rendering.rb +105 -173
- data/lib/abstract_controller/view_paths.rb +69 -0
- data/lib/action_controller.rb +1 -2
- data/lib/action_controller/base.rb +10 -32
- data/lib/action_controller/caching.rb +19 -18
- data/lib/action_controller/caching/actions.rb +17 -11
- data/lib/action_controller/caching/fragments.rb +5 -17
- data/lib/action_controller/caching/pages.rb +24 -24
- data/lib/action_controller/caching/sweeping.rb +1 -3
- data/lib/action_controller/deprecated.rb +0 -2
- data/lib/action_controller/deprecated/base.rb +143 -0
- data/lib/action_controller/metal.rb +29 -26
- data/lib/action_controller/metal/compatibility.rb +18 -87
- data/lib/action_controller/metal/cookies.rb +0 -1
- data/lib/action_controller/metal/head.rb +1 -0
- data/lib/action_controller/metal/helpers.rb +2 -2
- data/lib/action_controller/metal/hide_actions.rb +4 -6
- data/lib/action_controller/metal/http_authentication.rb +18 -33
- data/lib/action_controller/metal/implicit_render.rb +21 -0
- data/lib/action_controller/metal/instrumentation.rb +1 -1
- data/lib/action_controller/metal/mime_responds.rb +2 -1
- data/lib/action_controller/metal/rack_delegation.rb +3 -8
- data/lib/action_controller/metal/redirecting.rb +2 -1
- data/lib/action_controller/metal/renderers.rb +4 -2
- data/lib/action_controller/metal/rendering.rb +31 -44
- data/lib/action_controller/metal/request_forgery_protection.rb +41 -4
- data/lib/action_controller/metal/responder.rb +2 -0
- data/lib/action_controller/metal/session_management.rb +0 -36
- data/lib/action_controller/metal/streaming.rb +20 -47
- data/lib/action_controller/metal/testing.rb +0 -1
- data/lib/action_controller/metal/url_for.rb +11 -148
- data/lib/action_controller/middleware.rb +2 -1
- data/lib/action_controller/polymorphic_routes.rb +1 -2
- data/lib/action_controller/railtie.rb +63 -10
- data/lib/action_controller/railties/{subscriber.rb → log_subscriber.rb} +5 -12
- data/lib/action_controller/railties/url_helpers.rb +14 -0
- data/lib/action_controller/record_identifier.rb +20 -1
- data/lib/action_controller/test_case.rb +123 -12
- data/lib/action_dispatch.rb +1 -0
- data/lib/action_dispatch/http/cache.rb +20 -3
- data/lib/action_dispatch/http/filter_parameters.rb +40 -25
- data/lib/action_dispatch/http/mime_negotiation.rb +6 -17
- data/lib/action_dispatch/http/mime_type.rb +2 -7
- data/lib/action_dispatch/http/request.rb +12 -33
- data/lib/action_dispatch/http/response.rb +35 -15
- data/lib/action_dispatch/http/upload.rb +2 -0
- data/lib/action_dispatch/http/url.rb +5 -32
- data/lib/action_dispatch/middleware/callbacks.rb +1 -1
- data/lib/action_dispatch/middleware/cookies.rb +4 -3
- data/lib/action_dispatch/middleware/params_parser.rb +4 -3
- data/lib/action_dispatch/middleware/remote_ip.rb +51 -0
- data/lib/action_dispatch/middleware/session/abstract_store.rb +1 -0
- data/lib/action_dispatch/middleware/session/cookie_store.rb +6 -8
- data/lib/action_dispatch/middleware/show_exceptions.rb +0 -14
- data/lib/action_dispatch/middleware/stack.rb +6 -2
- data/lib/action_dispatch/railtie.rb +3 -1
- data/lib/action_dispatch/routing.rb +2 -0
- data/lib/action_dispatch/routing/deprecated_mapper.rb +35 -7
- data/lib/action_dispatch/routing/mapper.rb +134 -48
- data/lib/action_dispatch/routing/route.rb +2 -2
- data/lib/action_dispatch/routing/route_set.rb +217 -158
- data/lib/action_dispatch/routing/url_for.rb +139 -0
- data/lib/action_dispatch/testing/assertions/response.rb +14 -61
- data/lib/action_dispatch/testing/assertions/routing.rb +25 -14
- data/lib/action_dispatch/testing/integration.rb +32 -50
- data/lib/action_dispatch/testing/performance_test.rb +3 -1
- data/lib/action_dispatch/testing/test_process.rb +2 -0
- data/lib/action_dispatch/testing/test_request.rb +2 -0
- data/lib/action_pack/version.rb +4 -3
- data/lib/action_view.rb +11 -6
- data/lib/action_view/base.rb +33 -121
- data/lib/action_view/context.rb +0 -2
- data/lib/action_view/helpers.rb +26 -23
- data/lib/action_view/helpers/active_model_helper.rb +28 -18
- data/lib/action_view/helpers/asset_tag_helper.rb +109 -54
- data/lib/action_view/helpers/atom_feed_helper.rb +2 -2
- data/lib/action_view/helpers/cache_helper.rb +22 -1
- data/lib/action_view/helpers/capture_helper.rb +22 -22
- data/lib/action_view/helpers/date_helper.rb +6 -5
- data/lib/action_view/helpers/form_helper.rb +78 -63
- data/lib/action_view/helpers/form_options_helper.rb +6 -4
- data/lib/action_view/helpers/form_tag_helper.rb +26 -15
- data/lib/action_view/helpers/javascript_helper.rb +90 -10
- data/lib/action_view/helpers/number_helper.rb +315 -118
- data/lib/action_view/helpers/prototype_helper.rb +19 -46
- data/lib/action_view/helpers/record_tag_helper.rb +4 -4
- data/lib/action_view/helpers/tag_helper.rb +7 -24
- data/lib/action_view/helpers/text_helper.rb +8 -7
- data/lib/action_view/helpers/translation_helper.rb +7 -5
- data/lib/action_view/helpers/url_helper.rb +19 -16
- data/lib/action_view/locale/en.yml +45 -6
- data/lib/action_view/lookup_context.rb +190 -0
- data/lib/action_view/paths.rb +22 -63
- data/lib/action_view/railtie.rb +14 -4
- data/lib/action_view/railties/{subscriber.rb → log_subscriber.rb} +1 -1
- data/lib/action_view/render/layouts.rb +73 -0
- data/lib/action_view/render/partials.rb +15 -41
- data/lib/action_view/render/rendering.rb +27 -78
- data/lib/action_view/template.rb +20 -24
- data/lib/action_view/template/error.rb +22 -2
- data/lib/action_view/template/handlers/erb.rb +33 -9
- data/lib/action_view/template/handlers/rjs.rb +1 -2
- data/lib/action_view/template/resolver.rb +46 -104
- data/lib/action_view/template/text.rb +5 -12
- data/lib/action_view/test_case.rb +14 -23
- metadata +83 -40
- data/lib/abstract_controller/compatibility.rb +0 -18
- data/lib/abstract_controller/localized_cache.rb +0 -49
- data/lib/action_controller/metal/configuration.rb +0 -28
- data/lib/action_controller/url_rewriter.rb +0 -76
@@ -12,30 +12,17 @@ module ActionView
|
|
12
12
|
#
|
13
13
|
# If no options hash is passed or :update specified, the default is to render a partial and use the second parameter
|
14
14
|
# as the locals hash.
|
15
|
-
def render(options = {}, locals = {}, &block)
|
15
|
+
def render(options = {}, locals = {}, &block)
|
16
16
|
case options
|
17
17
|
when Hash
|
18
|
-
layout = options[:layout]
|
19
|
-
options[:locals] ||= {}
|
20
|
-
|
21
18
|
if block_given?
|
22
|
-
|
19
|
+
_render_partial(options.merge(:partial => options[:layout]), &block)
|
23
20
|
elsif options.key?(:partial)
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
elsif options[:inline]
|
30
|
-
handler = Template.handler_class_for_extension(options[:type] || "erb")
|
31
|
-
Template.new(options[:inline], "inline template", handler, {})
|
32
|
-
elsif options[:text]
|
33
|
-
Template::Text.new(options[:text])
|
34
|
-
end
|
35
|
-
|
36
|
-
if template
|
37
|
-
layout = find(layout, {:formats => formats}) if layout
|
38
|
-
_render_template(template, layout, :locals => options[:locals])
|
21
|
+
_render_partial(options)
|
22
|
+
else
|
23
|
+
template = _determine_template(options)
|
24
|
+
lookup_context.freeze_formats(template.formats, true)
|
25
|
+
_render_template(template, options[:layout], options)
|
39
26
|
end
|
40
27
|
when :update
|
41
28
|
update_page(&block)
|
@@ -44,74 +31,36 @@ module ActionView
|
|
44
31
|
end
|
45
32
|
end
|
46
33
|
|
47
|
-
#
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
# <html><% yield %></html>
|
61
|
-
#
|
62
|
-
# In this case, instead of the default block, which would return content_for(:layout),
|
63
|
-
# this method returns the block that was passed in to render layout, and the response
|
64
|
-
# would be <html>Content</html>.
|
65
|
-
#
|
66
|
-
# Finally, the block can take block arguments, which can be passed in by yield.
|
67
|
-
#
|
68
|
-
# ==== Example
|
69
|
-
#
|
70
|
-
# # The template
|
71
|
-
# <% render :layout => "my_layout" do |customer| %>Hello <%= customer.name %><% end %>
|
72
|
-
#
|
73
|
-
# # The layout
|
74
|
-
# <html><% yield Struct.new(:name).new("David") %></html>
|
75
|
-
#
|
76
|
-
# In this case, the layout would receive the block passed into <tt>render :layout</tt>,
|
77
|
-
# and the Struct specified in the layout would be passed into the block. The result
|
78
|
-
# would be <html>Hello David</html>.
|
79
|
-
def _layout_for(name = nil, &block)
|
80
|
-
return @_content_for[name || :layout] if !block_given? || name
|
81
|
-
capture(&block)
|
82
|
-
end
|
83
|
-
|
84
|
-
# This is the API to render a ViewContext's template from a controller.
|
85
|
-
#
|
86
|
-
# Internal Options:
|
87
|
-
# _template:: The Template object to render
|
88
|
-
# _layout:: The layout, if any, to wrap the Template in
|
89
|
-
def render_template(options)
|
90
|
-
_evaluate_assigns_and_ivars
|
91
|
-
template, layout = options.values_at(:_template, :_layout)
|
92
|
-
_render_template(template, layout, options)
|
34
|
+
# Determine the template to be rendered using the given options.
|
35
|
+
def _determine_template(options) #:nodoc:
|
36
|
+
if options.key?(:inline)
|
37
|
+
handler = Template.handler_class_for_extension(options[:type] || "erb")
|
38
|
+
Template.new(options[:inline], "inline template", handler, {})
|
39
|
+
elsif options.key?(:text)
|
40
|
+
Template::Text.new(options[:text], formats.try(:first))
|
41
|
+
elsif options.key?(:file)
|
42
|
+
with_fallbacks { find_template(options[:file], options[:prefix]) }
|
43
|
+
elsif options.key?(:template)
|
44
|
+
options[:template].respond_to?(:render) ?
|
45
|
+
options[:template] : find_template(options[:template], options[:prefix])
|
46
|
+
end
|
93
47
|
end
|
94
48
|
|
95
|
-
|
49
|
+
# Renders the given template. An string representing the layout can be
|
50
|
+
# supplied as well.
|
51
|
+
def _render_template(template, layout = nil, options = {}) #:nodoc:
|
96
52
|
locals = options[:locals] || {}
|
53
|
+
layout = find_layout(layout) if layout
|
97
54
|
|
98
55
|
ActiveSupport::Notifications.instrument("action_view.render_template",
|
99
|
-
:identifier => template.identifier, :layout => layout.try(:
|
56
|
+
:identifier => template.identifier, :layout => layout.try(:virtual_path)) do
|
100
57
|
|
101
|
-
content = template.render(self, locals)
|
58
|
+
content = template.render(self, locals) { |*name| _layout_for(*name) }
|
102
59
|
@_content_for[:layout] = content
|
103
60
|
|
104
|
-
if layout
|
105
|
-
@_layout = layout.identifier
|
106
|
-
content = _render_layout(layout, locals)
|
107
|
-
end
|
108
|
-
|
61
|
+
content = _render_layout(layout, locals) if layout
|
109
62
|
content
|
110
63
|
end
|
111
64
|
end
|
112
|
-
|
113
|
-
def _render_layout(layout, locals, &block)
|
114
|
-
layout.render(self, locals){ |*name| _layout_for(*name, &block) }
|
115
|
-
end
|
116
65
|
end
|
117
66
|
end
|
data/lib/action_view/template.rb
CHANGED
@@ -1,8 +1,7 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
# This is so that templates compiled in this file are UTF-8
|
3
|
-
|
4
|
-
require '
|
5
|
-
require "action_view/template/resolver"
|
3
|
+
require 'active_support/core_ext/array/wrap'
|
4
|
+
require 'active_support/core_ext/object/blank'
|
6
5
|
|
7
6
|
module ActionView
|
8
7
|
class Template
|
@@ -16,28 +15,28 @@ module ActionView
|
|
16
15
|
end
|
17
16
|
|
18
17
|
extend Template::Handlers
|
19
|
-
|
18
|
+
|
19
|
+
attr_reader :source, :identifier, :handler, :virtual_path, :formats
|
20
20
|
|
21
21
|
def initialize(source, identifier, handler, details)
|
22
22
|
@source = source
|
23
23
|
@identifier = identifier
|
24
24
|
@handler = handler
|
25
|
-
|
25
|
+
|
26
|
+
@virtual_path = details[:virtual_path]
|
26
27
|
@method_names = {}
|
27
28
|
|
28
|
-
format
|
29
|
-
|
30
|
-
handler.respond_to?(:default_format) ? handler.default_format.to_sym.to_s : "html"
|
31
|
-
end
|
32
|
-
@mime_type = Mime::Type.lookup_by_extension(format.to_s)
|
33
|
-
@formats = [format.to_sym]
|
34
|
-
@formats << :html if format == :js
|
35
|
-
@details[:formats] = Array.wrap(format.to_sym)
|
29
|
+
format = details[:format] || :html
|
30
|
+
@formats = Array.wrap(format).map(&:to_sym)
|
36
31
|
end
|
37
32
|
|
38
33
|
def render(view, locals, &block)
|
39
|
-
|
40
|
-
|
34
|
+
# Notice that we use a bang in this instrumentation because you don't want to
|
35
|
+
# consume this in production. This is only slow if it's being listened to.
|
36
|
+
ActiveSupport::Notifications.instrument("action_view.render_template!", :virtual_path => @virtual_path) do
|
37
|
+
method_name = compile(locals, view)
|
38
|
+
view.send(method_name, locals, &block)
|
39
|
+
end
|
41
40
|
rescue Exception => e
|
42
41
|
if e.is_a?(Template::Error)
|
43
42
|
e.sub_template_of(self)
|
@@ -47,21 +46,18 @@ module ActionView
|
|
47
46
|
end
|
48
47
|
end
|
49
48
|
|
50
|
-
|
49
|
+
def mime_type
|
50
|
+
@mime_type ||= Mime::Type.lookup_by_extension(@formats.first.to_s) if @formats.first
|
51
|
+
end
|
52
|
+
|
51
53
|
def variable_name
|
52
|
-
@variable_name ||=
|
54
|
+
@variable_name ||= @virtual_path[%r'_?(\w+)(\.\w+)*$', 1].to_sym
|
53
55
|
end
|
54
56
|
|
55
|
-
# TODO: Figure out how to abstract this
|
56
57
|
def counter_name
|
57
58
|
@counter_name ||= "#{variable_name}_counter".to_sym
|
58
59
|
end
|
59
60
|
|
60
|
-
# TODO: kill hax
|
61
|
-
def partial?
|
62
|
-
@details[:partial]
|
63
|
-
end
|
64
|
-
|
65
61
|
def inspect
|
66
62
|
if defined?(Rails.root)
|
67
63
|
identifier.sub("#{Rails.root}/", '')
|
@@ -87,7 +83,7 @@ module ActionView
|
|
87
83
|
|
88
84
|
source = <<-end_src
|
89
85
|
def #{method_name}(local_assigns)
|
90
|
-
_old_virtual_path, @_virtual_path = @_virtual_path, #{@
|
86
|
+
_old_virtual_path, @_virtual_path = @_virtual_path, #{@virtual_path.inspect};_old_output_buffer = output_buffer;#{locals_code};#{code}
|
91
87
|
ensure
|
92
88
|
@_virtual_path, self.output_buffer = _old_virtual_path, _old_output_buffer
|
93
89
|
end
|
@@ -1,6 +1,26 @@
|
|
1
1
|
require "active_support/core_ext/enumerable"
|
2
2
|
|
3
3
|
module ActionView
|
4
|
+
class ActionViewError < StandardError #:nodoc:
|
5
|
+
end
|
6
|
+
|
7
|
+
class MissingTemplate < ActionViewError #:nodoc:
|
8
|
+
attr_reader :path
|
9
|
+
|
10
|
+
def initialize(paths, path, details, partial)
|
11
|
+
@path = path
|
12
|
+
display_paths = paths.compact.map{ |p| p.to_s.inspect }.join(", ")
|
13
|
+
template_type = if partial
|
14
|
+
"partial"
|
15
|
+
elsif path =~ /layouts/i
|
16
|
+
'layout'
|
17
|
+
else
|
18
|
+
'template'
|
19
|
+
end
|
20
|
+
|
21
|
+
super("Missing #{template_type} #{path} with #{details.inspect} in view paths #{display_paths}")
|
22
|
+
end
|
23
|
+
end
|
4
24
|
class Template
|
5
25
|
# The Template::Error exception is raised when the compilation of the template fails. This exception then gathers a
|
6
26
|
# bunch of intimate details and uses it to report a very precise exception message.
|
@@ -73,11 +93,11 @@ module ActionView
|
|
73
93
|
end
|
74
94
|
|
75
95
|
def to_s
|
76
|
-
"\n#{self.class} (#{message}) #{source_location}:\n" +
|
96
|
+
"\n#{self.class} (#{message}) #{source_location}:\n" +
|
77
97
|
"#{source_extract}\n #{clean_backtrace.join("\n ")}\n\n"
|
78
98
|
end
|
79
99
|
|
80
|
-
# don't do anything nontrivial here. Any raised exception from here becomes fatal
|
100
|
+
# don't do anything nontrivial here. Any raised exception from here becomes fatal
|
81
101
|
# (and can't be rescued).
|
82
102
|
def backtrace
|
83
103
|
@backtrace
|
@@ -3,10 +3,24 @@ require 'active_support/core_ext/string/output_safety'
|
|
3
3
|
require 'erubis'
|
4
4
|
|
5
5
|
module ActionView
|
6
|
+
class OutputBuffer < ActiveSupport::SafeBuffer
|
7
|
+
def <<(value)
|
8
|
+
super(value.to_s)
|
9
|
+
end
|
10
|
+
alias :append= :<<
|
11
|
+
|
12
|
+
def append_if_string=(value)
|
13
|
+
if value.is_a?(String) && !value.is_a?(NonConcattingString)
|
14
|
+
ActiveSupport::Deprecation.warn("<% %> style block helpers are deprecated. Please use <%= %>", caller)
|
15
|
+
self << value
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
6
20
|
module Template::Handlers
|
7
21
|
class Erubis < ::Erubis::Eruby
|
8
22
|
def add_preamble(src)
|
9
|
-
src << "@output_buffer =
|
23
|
+
src << "@output_buffer = ActionView::OutputBuffer.new;"
|
10
24
|
end
|
11
25
|
|
12
26
|
def add_text(src, text)
|
@@ -14,16 +28,26 @@ module ActionView
|
|
14
28
|
src << "@output_buffer.safe_concat('" << escape_text(text) << "');"
|
15
29
|
end
|
16
30
|
|
31
|
+
BLOCK_EXPR = /(do|\{)(\s*\|[^|]*\|)?\s*\Z/
|
32
|
+
|
17
33
|
def add_expr_literal(src, code)
|
18
|
-
if code =~
|
19
|
-
src <<
|
34
|
+
if code =~ BLOCK_EXPR
|
35
|
+
src << '@output_buffer.append= ' << code
|
36
|
+
else
|
37
|
+
src << '@output_buffer.append= (' << code << ');'
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def add_stmt(src, code)
|
42
|
+
if code =~ BLOCK_EXPR
|
43
|
+
src << '@output_buffer.append_if_string= ' << code
|
20
44
|
else
|
21
|
-
|
45
|
+
super
|
22
46
|
end
|
23
47
|
end
|
24
48
|
|
25
49
|
def add_expr_escaped(src, code)
|
26
|
-
src << '@output_buffer
|
50
|
+
src << '@output_buffer.append= ' << escaped_expr(code) << ';'
|
27
51
|
end
|
28
52
|
|
29
53
|
def add_postamble(src)
|
@@ -42,14 +66,14 @@ module ActionView
|
|
42
66
|
self.erb_trim_mode = '-'
|
43
67
|
|
44
68
|
self.default_format = Mime::HTML
|
45
|
-
|
46
|
-
cattr_accessor :
|
47
|
-
self.
|
69
|
+
|
70
|
+
cattr_accessor :erb_implementation
|
71
|
+
self.erb_implementation = Erubis
|
48
72
|
|
49
73
|
def compile(template)
|
50
74
|
source = template.source.gsub(/\A(<%(#.*coding[:=]\s*(\S+)\s*)-?%>)\s*\n?/, '')
|
51
75
|
erb = "<% __in_erb_template=true %>#{source}"
|
52
|
-
result = self.class.
|
76
|
+
result = self.class.erb_implementation.new(erb, :trim=>(self.class.erb_trim_mode == "-")).src
|
53
77
|
result = "#{$2}\n#{result}" if $2
|
54
78
|
result
|
55
79
|
end
|
@@ -1,164 +1,106 @@
|
|
1
1
|
require "pathname"
|
2
2
|
require "active_support/core_ext/class"
|
3
|
-
require "active_support/core_ext/array/wrap"
|
4
3
|
require "action_view/template"
|
5
4
|
|
6
5
|
module ActionView
|
7
|
-
# Abstract superclass
|
8
6
|
class Resolver
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
def self.register_detail(name, options = {})
|
14
|
-
registered_details[name] = lambda do |val|
|
15
|
-
val = Array.wrap(val || yield)
|
16
|
-
val |= [nil] unless options[:allow_nil] == false
|
17
|
-
val
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
register_detail(:locale) { [I18n.locale] }
|
22
|
-
register_detail(:formats) { Mime::SET.symbols }
|
23
|
-
register_detail(:handlers, :allow_nil => false) do
|
24
|
-
Template::Handlers.extensions
|
25
|
-
end
|
26
|
-
|
27
|
-
def initialize(options = {})
|
28
|
-
@cache = options[:cache]
|
29
|
-
@cached = {}
|
7
|
+
def initialize
|
8
|
+
@cached = Hash.new { |h1,k1| h1[k1] =
|
9
|
+
Hash.new { |h2,k2| h2[k2] = Hash.new { |h3, k3| h3[k3] = {} } } }
|
30
10
|
end
|
31
11
|
|
32
|
-
|
33
|
-
|
34
|
-
find_all(*args).first
|
12
|
+
def clear_cache
|
13
|
+
@cached.clear
|
35
14
|
end
|
36
15
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
cached([name, details, prefix, partial]) do
|
42
|
-
find_templates(name, details, prefix, partial)
|
16
|
+
# Normalizes the arguments and passes it on to find_template.
|
17
|
+
def find_all(name, prefix=nil, partial=false, details={}, key=nil)
|
18
|
+
cached(key, prefix, name, partial) do
|
19
|
+
find_templates(name, prefix, partial, details)
|
43
20
|
end
|
44
21
|
end
|
45
22
|
|
46
23
|
private
|
47
24
|
|
25
|
+
def caching?
|
26
|
+
@caching ||= !defined?(Rails.application) || Rails.application.config.cache_classes
|
27
|
+
end
|
28
|
+
|
48
29
|
# This is what child classes implement. No defaults are needed
|
49
30
|
# because Resolver guarantees that the arguments are present and
|
50
31
|
# normalized.
|
51
|
-
def find_templates(name,
|
32
|
+
def find_templates(name, prefix, partial, details)
|
52
33
|
raise NotImplementedError
|
53
34
|
end
|
54
35
|
|
55
|
-
def
|
56
|
-
|
57
|
-
|
58
|
-
details.delete(:formats) if details[:formats] == [:"*/*"]
|
59
|
-
registered_details.each do |k, v|
|
60
|
-
details[k] = v.call(details[k])
|
61
|
-
end
|
62
|
-
details
|
63
|
-
end
|
64
|
-
|
65
|
-
# Support legacy foo.erb names even though we now ignore .erb
|
66
|
-
# as well as incorrectly putting part of the path in the template
|
67
|
-
# name instead of the prefix.
|
68
|
-
def normalize_name(name, prefix)
|
69
|
-
handlers = Template::Handlers.extensions.join('|')
|
70
|
-
name = name.to_s.gsub(/\.(?:#{handlers})$/, '')
|
71
|
-
|
72
|
-
parts = name.split('/')
|
73
|
-
return parts.pop, [prefix, *parts].compact.join("/")
|
74
|
-
end
|
75
|
-
|
76
|
-
def cached(key)
|
77
|
-
return yield unless @cache
|
78
|
-
return @cached[key] if @cached.key?(key)
|
79
|
-
@cached[key] = yield
|
36
|
+
def cached(key, prefix, name, partial)
|
37
|
+
return yield unless key && caching?
|
38
|
+
@cached[key][prefix][name][partial] ||= yield
|
80
39
|
end
|
81
40
|
end
|
82
41
|
|
83
42
|
class PathResolver < Resolver
|
84
|
-
|
85
43
|
EXTENSION_ORDER = [:locale, :formats, :handlers]
|
86
44
|
|
87
45
|
def to_s
|
88
46
|
@path.to_s
|
89
47
|
end
|
90
|
-
alias to_path to_s
|
91
|
-
|
92
|
-
def find_templates(name, details, prefix, partial)
|
93
|
-
path = build_path(name, details, prefix, partial)
|
94
|
-
query(path, EXTENSION_ORDER.map { |ext| details[ext] })
|
95
|
-
end
|
48
|
+
alias :to_path :to_s
|
96
49
|
|
97
50
|
private
|
98
51
|
|
99
|
-
def
|
52
|
+
def find_templates(name, prefix, partial, details)
|
53
|
+
path = build_path(name, prefix, partial, details)
|
54
|
+
query(path, EXTENSION_ORDER.map { |ext| details[ext] }, details[:formats])
|
55
|
+
end
|
56
|
+
|
57
|
+
def build_path(name, prefix, partial, details)
|
100
58
|
path = ""
|
101
59
|
path << "#{prefix}/" unless prefix.empty?
|
102
60
|
path << (partial ? "_#{name}" : name)
|
103
61
|
path
|
104
62
|
end
|
105
63
|
|
106
|
-
def query(path, exts)
|
64
|
+
def query(path, exts, formats)
|
107
65
|
query = File.join(@path, path)
|
66
|
+
|
108
67
|
exts.each do |ext|
|
109
|
-
query << '{' << ext.map {|e| e && ".#{e}" }.join(',') << '}'
|
68
|
+
query << '{' << ext.map {|e| e && ".#{e}" }.join(',') << ',}'
|
110
69
|
end
|
111
70
|
|
112
71
|
Dir[query].reject { |p| File.directory?(p) }.map do |p|
|
113
|
-
|
72
|
+
handler, format = extract_handler_and_format(p, formats)
|
73
|
+
Template.new(File.read(p), File.expand_path(p), handler,
|
74
|
+
:virtual_path => path, :format => format)
|
114
75
|
end
|
115
76
|
end
|
116
77
|
|
117
|
-
#
|
118
|
-
#
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
details = (m[4]||"").split('.').reject { |e| e.empty? }
|
124
|
-
handler = Template.handler_class_for_extension(m[5])
|
78
|
+
# Extract handler and formats from path. If a format cannot be a found neither
|
79
|
+
# from the path, or the handler, we should return the array of formats given
|
80
|
+
# to the resolver.
|
81
|
+
def extract_handler_and_format(path, default_formats)
|
82
|
+
pieces = File.basename(path).split(".")
|
83
|
+
pieces.shift
|
125
84
|
|
126
|
-
|
127
|
-
|
85
|
+
handler = Template.handler_class_for_extension(pieces.pop)
|
86
|
+
format = pieces.last && Mime[pieces.last] && pieces.pop.to_sym
|
87
|
+
format ||= handler.default_format if handler.respond_to?(:default_format)
|
88
|
+
format ||= default_formats
|
128
89
|
|
129
|
-
|
130
|
-
|
131
|
-
return handler, :format => format, :locale => locale, :partial => partial,
|
132
|
-
:virtual_path => virtual_path
|
133
|
-
end
|
90
|
+
[handler, format]
|
134
91
|
end
|
135
92
|
end
|
136
93
|
|
137
94
|
class FileSystemResolver < PathResolver
|
138
|
-
def initialize(path
|
95
|
+
def initialize(path)
|
139
96
|
raise ArgumentError, "path already is a Resolver class" if path.is_a?(Resolver)
|
140
|
-
super(
|
97
|
+
super()
|
141
98
|
@path = Pathname.new(path).expand_path
|
142
99
|
end
|
143
|
-
end
|
144
|
-
|
145
|
-
# TODO: remove hack
|
146
|
-
class FileSystemResolverWithFallback < Resolver
|
147
|
-
def initialize(path, options = {})
|
148
|
-
super(options)
|
149
|
-
@paths = [FileSystemResolver.new(path, options), FileSystemResolver.new("", options), FileSystemResolver.new("/", options)]
|
150
|
-
end
|
151
100
|
|
152
|
-
def
|
153
|
-
|
154
|
-
template = p.find_templates(*args)
|
155
|
-
return template unless template.empty?
|
156
|
-
end
|
157
|
-
[]
|
158
|
-
end
|
159
|
-
|
160
|
-
def to_s
|
161
|
-
@paths.first.to_s
|
101
|
+
def eql?(resolver)
|
102
|
+
self.class.equal?(resolver.class) && to_path == resolver.to_path
|
162
103
|
end
|
104
|
+
alias :== :eql?
|
163
105
|
end
|
164
106
|
end
|