actionpack 3.0.20 → 3.1.0.beta1
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 +88 -142
- data/MIT-LICENSE +1 -1
- data/README.rdoc +5 -6
- data/lib/abstract_controller.rb +1 -0
- data/lib/abstract_controller/asset_paths.rb +2 -2
- data/lib/abstract_controller/base.rb +24 -19
- data/lib/abstract_controller/callbacks.rb +19 -19
- data/lib/abstract_controller/helpers.rb +11 -13
- data/lib/abstract_controller/layouts.rb +4 -5
- data/lib/abstract_controller/railties/routes_helpers.rb +18 -0
- data/lib/abstract_controller/rendering.rb +34 -31
- data/lib/abstract_controller/url_for.rb +27 -0
- data/lib/abstract_controller/view_paths.rb +31 -6
- data/lib/action_controller.rb +5 -3
- data/lib/action_controller/base.rb +15 -16
- data/lib/action_controller/caching.rb +2 -2
- data/lib/action_controller/caching/actions.rb +11 -12
- data/lib/action_controller/caching/fragments.rb +41 -19
- data/lib/action_controller/caching/pages.rb +3 -9
- data/lib/action_controller/caching/sweeping.rb +0 -1
- data/lib/action_controller/deprecated.rb +1 -1
- data/lib/action_controller/log_subscriber.rb +1 -1
- data/lib/action_controller/metal.rb +78 -20
- data/lib/action_controller/metal/compatibility.rb +0 -9
- data/lib/action_controller/metal/conditional_get.rb +9 -9
- data/lib/action_controller/metal/data_streaming.rb +145 -0
- data/lib/action_controller/metal/force_ssl.rb +35 -0
- data/lib/action_controller/metal/head.rb +1 -1
- data/lib/action_controller/metal/helpers.rb +37 -44
- data/lib/action_controller/metal/hide_actions.rb +2 -3
- data/lib/action_controller/metal/http_authentication.rb +41 -38
- data/lib/action_controller/metal/implicit_render.rb +13 -13
- data/lib/action_controller/metal/instrumentation.rb +2 -2
- data/lib/action_controller/metal/mime_responds.rb +25 -19
- data/lib/action_controller/metal/params_wrapper.rb +224 -0
- data/lib/action_controller/metal/redirecting.rb +6 -2
- data/lib/action_controller/metal/renderers.rb +50 -36
- data/lib/action_controller/metal/rendering.rb +34 -25
- data/lib/action_controller/metal/request_forgery_protection.rb +18 -36
- data/lib/action_controller/metal/responder.rb +47 -12
- data/lib/action_controller/metal/streaming.rb +244 -138
- data/lib/action_controller/metal/testing.rb +0 -9
- data/lib/action_controller/metal/url_for.rb +12 -14
- data/lib/action_controller/railtie.rb +19 -37
- data/lib/action_controller/railties/paths.rb +24 -0
- data/lib/action_controller/record_identifier.rb +4 -10
- data/lib/action_controller/test_case.rb +36 -19
- data/lib/action_controller/vendor/html-scanner/html/node.rb +5 -5
- data/lib/action_controller/vendor/html-scanner/html/sanitizer.rb +3 -3
- data/lib/action_controller/vendor/html-scanner/html/selector.rb +2 -0
- data/lib/action_dispatch.rb +4 -1
- data/lib/action_dispatch/http/cache.rb +5 -32
- data/lib/action_dispatch/http/filter_parameters.rb +3 -1
- data/lib/action_dispatch/http/mime_negotiation.rb +22 -3
- data/lib/action_dispatch/http/mime_type.rb +45 -5
- data/lib/action_dispatch/http/rack_cache.rb +58 -0
- data/lib/action_dispatch/http/request.rb +27 -41
- data/lib/action_dispatch/http/response.rb +56 -54
- data/lib/action_dispatch/http/upload.rb +1 -11
- data/lib/action_dispatch/http/url.rb +102 -42
- data/lib/action_dispatch/middleware/callbacks.rb +8 -25
- data/lib/action_dispatch/middleware/closed_error.rb +7 -0
- data/lib/action_dispatch/middleware/cookies.rb +37 -15
- data/lib/action_dispatch/middleware/flash.rb +80 -11
- data/lib/action_dispatch/middleware/params_parser.rb +2 -2
- data/lib/action_dispatch/middleware/reloader.rb +76 -0
- data/lib/action_dispatch/middleware/session/abstract_store.rb +56 -226
- data/lib/action_dispatch/middleware/session/cookie_store.rb +20 -44
- data/lib/action_dispatch/middleware/session/mem_cache_store.rb +7 -46
- data/lib/action_dispatch/middleware/show_exceptions.rb +15 -2
- data/lib/action_dispatch/middleware/stack.rb +50 -17
- data/lib/action_dispatch/middleware/static.rb +41 -29
- data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb +3 -3
- data/lib/action_dispatch/middleware/templates/rescues/_trace.erb +3 -3
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb +3 -3
- data/lib/action_dispatch/middleware/templates/rescues/layout.erb +4 -2
- data/lib/action_dispatch/middleware/templates/rescues/template_error.erb +2 -6
- data/lib/action_dispatch/railtie.rb +8 -0
- data/lib/action_dispatch/routing.rb +13 -1
- data/lib/action_dispatch/routing/mapper.rb +345 -227
- data/lib/action_dispatch/routing/polymorphic_routes.rb +33 -13
- data/lib/action_dispatch/routing/redirection.rb +110 -0
- data/lib/action_dispatch/routing/route.rb +15 -13
- data/lib/action_dispatch/routing/route_set.rb +116 -90
- data/lib/action_dispatch/routing/routes_proxy.rb +35 -0
- data/lib/action_dispatch/routing/url_for.rb +25 -1
- data/lib/action_dispatch/testing/assertions/response.rb +8 -10
- data/lib/action_dispatch/testing/assertions/routing.rb +15 -15
- data/lib/action_dispatch/testing/assertions/selector.rb +13 -220
- data/lib/action_dispatch/testing/integration.rb +37 -28
- data/lib/action_dispatch/testing/performance_test.rb +1 -3
- data/lib/action_dispatch/testing/test_process.rb +1 -1
- data/lib/action_dispatch/testing/test_request.rb +9 -3
- data/lib/action_dispatch/testing/test_response.rb +4 -111
- data/lib/action_pack.rb +1 -1
- data/lib/action_pack/version.rb +3 -3
- data/lib/action_view.rb +39 -24
- data/lib/action_view/base.rb +61 -86
- data/lib/action_view/buffers.rb +43 -0
- data/lib/action_view/context.rb +21 -24
- data/lib/action_view/flows.rb +79 -0
- data/lib/action_view/helpers.rb +8 -6
- data/lib/action_view/helpers/active_model_helper.rb +0 -23
- data/lib/action_view/helpers/asset_paths.rb +79 -0
- data/lib/action_view/helpers/asset_tag_helper.rb +30 -500
- data/lib/action_view/helpers/asset_tag_helpers/asset_include_tag.rb +147 -0
- data/lib/action_view/helpers/asset_tag_helpers/asset_paths.rb +101 -0
- data/lib/action_view/helpers/asset_tag_helpers/javascript_tag_helpers.rb +200 -0
- data/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb +152 -0
- data/lib/action_view/helpers/atom_feed_helper.rb +2 -2
- data/lib/action_view/helpers/cache_helper.rb +11 -19
- data/lib/action_view/helpers/capture_helper.rb +19 -8
- data/lib/action_view/helpers/controller_helper.rb +21 -0
- data/lib/action_view/helpers/csrf_helper.rb +22 -4
- data/lib/action_view/helpers/date_helper.rb +36 -22
- data/lib/action_view/helpers/form_helper.rb +199 -113
- data/lib/action_view/helpers/form_options_helper.rb +10 -11
- data/lib/action_view/helpers/form_tag_helper.rb +94 -22
- data/lib/action_view/helpers/javascript_helper.rb +24 -107
- data/lib/action_view/helpers/number_helper.rb +36 -33
- data/lib/action_view/helpers/output_safety_helper.rb +38 -0
- data/lib/action_view/helpers/record_tag_helper.rb +6 -6
- data/lib/action_view/helpers/rendering_helper.rb +90 -0
- data/lib/action_view/helpers/sanitize_helper.rb +2 -2
- data/lib/action_view/helpers/sprockets_helper.rb +69 -0
- data/lib/action_view/helpers/tag_helper.rb +34 -12
- data/lib/action_view/helpers/text_helper.rb +30 -145
- data/lib/action_view/helpers/translation_helper.rb +10 -17
- data/lib/action_view/helpers/url_helper.rb +70 -67
- data/lib/action_view/locale/en.yml +1 -1
- data/lib/action_view/lookup_context.rb +36 -14
- data/lib/action_view/{paths.rb → path_set.rb} +9 -8
- data/lib/action_view/railtie.rb +12 -4
- data/lib/action_view/renderer/abstract_renderer.rb +36 -0
- data/lib/action_view/{render/partials.rb → renderer/partial_renderer.rb} +147 -146
- data/lib/action_view/renderer/renderer.rb +54 -0
- data/lib/action_view/renderer/streaming_template_renderer.rb +106 -0
- data/lib/action_view/renderer/template_renderer.rb +74 -0
- data/lib/action_view/template.rb +91 -54
- data/lib/action_view/template/error.rb +11 -8
- data/lib/action_view/template/handler.rb +9 -1
- data/lib/action_view/template/handlers.rb +9 -9
- data/lib/action_view/template/handlers/builder.rb +4 -4
- data/lib/action_view/template/handlers/erb.rb +21 -41
- data/lib/action_view/template/resolver.rb +171 -57
- data/lib/action_view/template/text.rb +0 -4
- data/lib/action_view/test_case.rb +32 -16
- data/lib/action_view/testing/resolvers.rb +16 -10
- data/lib/sprockets/railtie.rb +100 -0
- metadata +162 -140
- checksums.yaml +0 -7
- data/lib/action_controller/deprecated/base.rb +0 -143
- data/lib/action_controller/deprecated/dispatcher.rb +0 -28
- data/lib/action_controller/deprecated/url_writer.rb +0 -14
- data/lib/action_dispatch/routing/deprecated_mapper.rb +0 -525
- data/lib/action_view/helpers/prototype_helper.rb +0 -851
- data/lib/action_view/helpers/raw_output_helper.rb +0 -18
- data/lib/action_view/helpers/scriptaculous_helper.rb +0 -263
- data/lib/action_view/render/layouts.rb +0 -83
- data/lib/action_view/render/rendering.rb +0 -67
- data/lib/action_view/template/handlers/rjs.rb +0 -17
@@ -1,4 +1,4 @@
|
|
1
|
-
require
|
1
|
+
require 'action_dispatch/http/mime_type'
|
2
2
|
require 'active_support/core_ext/class/attribute'
|
3
3
|
|
4
4
|
# Legacy TemplateHandler stub
|
@@ -7,6 +7,8 @@ module ActionView
|
|
7
7
|
module Handlers #:nodoc:
|
8
8
|
module Compilable
|
9
9
|
def self.included(base)
|
10
|
+
ActiveSupport::Deprecation.warn "Including Compilable in your template handler is deprecated. " <<
|
11
|
+
"Since Rails 3, all the API your template handler needs to implement is to respond to #call."
|
10
12
|
base.extend(ClassMethods)
|
11
13
|
end
|
12
14
|
|
@@ -26,6 +28,12 @@ module ActionView
|
|
26
28
|
class_attribute :default_format
|
27
29
|
self.default_format = Mime::HTML
|
28
30
|
|
31
|
+
def self.inherited(base)
|
32
|
+
ActiveSupport::Deprecation.warn "Inheriting from ActionView::Template::Handler is deprecated. " <<
|
33
|
+
"Since Rails 3, all the API your template handler needs to implement is to respond to #call."
|
34
|
+
super
|
35
|
+
end
|
36
|
+
|
29
37
|
def self.call(template)
|
30
38
|
raise "Need to implement #{self.class.name}#call(template)"
|
31
39
|
end
|
@@ -3,17 +3,11 @@ module ActionView #:nodoc:
|
|
3
3
|
class Template
|
4
4
|
module Handlers #:nodoc:
|
5
5
|
autoload :ERB, 'action_view/template/handlers/erb'
|
6
|
-
autoload :RJS, 'action_view/template/handlers/rjs'
|
7
6
|
autoload :Builder, 'action_view/template/handlers/builder'
|
8
7
|
|
9
8
|
def self.extended(base)
|
10
|
-
base.register_default_template_handler :erb, ERB
|
11
|
-
base.register_template_handler :
|
12
|
-
base.register_template_handler :builder, Builder
|
13
|
-
|
14
|
-
# TODO: Depreciate old template extensions
|
15
|
-
base.register_template_handler :rhtml, ERB
|
16
|
-
base.register_template_handler :rxml, Builder
|
9
|
+
base.register_default_template_handler :erb, ERB.new
|
10
|
+
base.register_template_handler :builder, Builder.new
|
17
11
|
end
|
18
12
|
|
19
13
|
@@template_handlers = {}
|
@@ -48,7 +42,13 @@ module ActionView #:nodoc:
|
|
48
42
|
end
|
49
43
|
|
50
44
|
def handler_class_for_extension(extension)
|
51
|
-
|
45
|
+
ActiveSupport::Deprecation.warn "handler_class_for_extension is deprecated. " <<
|
46
|
+
"Please use handler_for_extension instead", caller
|
47
|
+
handler_for_extension(extension)
|
48
|
+
end
|
49
|
+
|
50
|
+
def handler_for_extension(extension)
|
51
|
+
registered_template_handler(extension) || @@default_template_handlers
|
52
52
|
end
|
53
53
|
end
|
54
54
|
end
|
@@ -1,11 +1,11 @@
|
|
1
1
|
module ActionView
|
2
2
|
module Template::Handlers
|
3
|
-
class Builder
|
4
|
-
|
5
|
-
|
3
|
+
class Builder
|
4
|
+
# Default format used by Builder.
|
5
|
+
class_attribute :default_format
|
6
6
|
self.default_format = Mime::XML
|
7
7
|
|
8
|
-
def
|
8
|
+
def call(template)
|
9
9
|
require 'builder'
|
10
10
|
"xml = ::Builder::XmlMarkup.new(:indent => 2);" +
|
11
11
|
"self.output_buffer = xml.target!;" +
|
@@ -1,34 +1,14 @@
|
|
1
1
|
require 'active_support/core_ext/class/attribute_accessors'
|
2
|
-
require '
|
3
|
-
require
|
2
|
+
require 'action_view/template'
|
3
|
+
require 'action_view/template/handler'
|
4
4
|
require 'erubis'
|
5
5
|
|
6
6
|
module ActionView
|
7
|
-
class OutputBuffer < ActiveSupport::SafeBuffer
|
8
|
-
def initialize(*)
|
9
|
-
super
|
10
|
-
encode! if encoding_aware?
|
11
|
-
end
|
12
|
-
|
13
|
-
def <<(value)
|
14
|
-
super(value.to_s)
|
15
|
-
end
|
16
|
-
alias :append= :<<
|
17
|
-
alias :safe_append= :safe_concat
|
18
|
-
|
19
|
-
def append_if_string=(value)
|
20
|
-
if value.is_a?(String) && !value.is_a?(NonConcattingString)
|
21
|
-
ActiveSupport::Deprecation.warn("<% %> style block helpers are deprecated. Please use <%= %>", caller)
|
22
|
-
self << value
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
7
|
class Template
|
28
8
|
module Handlers
|
29
9
|
class Erubis < ::Erubis::Eruby
|
30
10
|
def add_preamble(src)
|
31
|
-
src << "@output_buffer = ActionView::OutputBuffer.new;"
|
11
|
+
src << "@output_buffer = output_buffer || ActionView::OutputBuffer.new;"
|
32
12
|
end
|
33
13
|
|
34
14
|
def add_text(src, text)
|
@@ -46,14 +26,6 @@ module ActionView
|
|
46
26
|
end
|
47
27
|
end
|
48
28
|
|
49
|
-
def add_stmt(src, code)
|
50
|
-
if code =~ BLOCK_EXPR
|
51
|
-
src << '@output_buffer.append_if_string= ' << code
|
52
|
-
else
|
53
|
-
super
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
29
|
def add_expr_escaped(src, code)
|
58
30
|
if code =~ BLOCK_EXPR
|
59
31
|
src << "@output_buffer.safe_append= " << code
|
@@ -67,28 +39,35 @@ module ActionView
|
|
67
39
|
end
|
68
40
|
end
|
69
41
|
|
70
|
-
class ERB
|
71
|
-
include Compilable
|
72
|
-
|
73
|
-
##
|
74
|
-
# :singleton-method:
|
42
|
+
class ERB
|
75
43
|
# Specify trim mode for the ERB compiler. Defaults to '-'.
|
76
|
-
# See
|
77
|
-
|
44
|
+
# See ERB documentation for suitable values.
|
45
|
+
class_attribute :erb_trim_mode
|
78
46
|
self.erb_trim_mode = '-'
|
79
47
|
|
48
|
+
# Default format used by ERB.
|
49
|
+
class_attribute :default_format
|
80
50
|
self.default_format = Mime::HTML
|
81
51
|
|
82
|
-
|
52
|
+
# Default implementation used.
|
53
|
+
class_attribute :erb_implementation
|
83
54
|
self.erb_implementation = Erubis
|
84
55
|
|
85
56
|
ENCODING_TAG = Regexp.new("\\A(<%#{ENCODING_FLAG}-?%>)[ \\t]*")
|
86
57
|
|
87
|
-
def self.
|
58
|
+
def self.call(template)
|
59
|
+
new.call(template)
|
60
|
+
end
|
61
|
+
|
62
|
+
def supports_streaming?
|
88
63
|
true
|
89
64
|
end
|
90
65
|
|
91
|
-
def
|
66
|
+
def handles_encoding?
|
67
|
+
true
|
68
|
+
end
|
69
|
+
|
70
|
+
def call(template)
|
92
71
|
if template.source.encoding_aware?
|
93
72
|
# First, convert to BINARY, so in case the encoding is
|
94
73
|
# wrong, we can still find an encoding tag
|
@@ -114,6 +93,7 @@ module ActionView
|
|
114
93
|
end
|
115
94
|
|
116
95
|
private
|
96
|
+
|
117
97
|
def valid_encoding(string, encoding)
|
118
98
|
# If a magic encoding comment was found, tag the
|
119
99
|
# String with this encoding. This is for a case
|
@@ -5,9 +5,35 @@ require "action_view/template"
|
|
5
5
|
module ActionView
|
6
6
|
# = Action View Resolver
|
7
7
|
class Resolver
|
8
|
+
# Keeps all information about view path and builds virtual path.
|
9
|
+
class Path < String
|
10
|
+
attr_reader :name, :prefix, :partial, :virtual
|
11
|
+
alias_method :partial?, :partial
|
12
|
+
|
13
|
+
def initialize(name, prefix, partial)
|
14
|
+
@name, @prefix, @partial = name, prefix, partial
|
15
|
+
rebuild(@name, @prefix, @partial)
|
16
|
+
end
|
17
|
+
|
18
|
+
def rebuild(name, prefix, partial)
|
19
|
+
@virtual = ""
|
20
|
+
@virtual << "#{prefix}/" unless prefix.empty?
|
21
|
+
@virtual << (partial ? "_#{name}" : name)
|
22
|
+
|
23
|
+
self.replace(@virtual)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
cattr_accessor :caching
|
28
|
+
self.caching = true
|
29
|
+
|
30
|
+
class << self
|
31
|
+
alias :caching? :caching
|
32
|
+
end
|
33
|
+
|
8
34
|
def initialize
|
9
|
-
@cached = Hash.new { |h1,k1| h1[k1] =
|
10
|
-
Hash.new { |
|
35
|
+
@cached = Hash.new { |h1,k1| h1[k1] = Hash.new { |h2,k2|
|
36
|
+
h2[k2] = Hash.new { |h3,k3| h3[k3] = Hash.new { |h4,k4| h4[k4] = {} } } } }
|
11
37
|
end
|
12
38
|
|
13
39
|
def clear_cache
|
@@ -15,63 +41,96 @@ module ActionView
|
|
15
41
|
end
|
16
42
|
|
17
43
|
# Normalizes the arguments and passes it on to find_template.
|
18
|
-
def find_all(name, prefix=nil, partial=false, details={}, key=nil)
|
19
|
-
cached(key, prefix,
|
44
|
+
def find_all(name, prefix=nil, partial=false, details={}, key=nil, locals=[])
|
45
|
+
cached(key, [name, prefix, partial], details, locals) do
|
20
46
|
find_templates(name, prefix, partial, details)
|
21
47
|
end
|
22
48
|
end
|
23
49
|
|
24
50
|
private
|
25
51
|
|
26
|
-
|
27
|
-
@caching ||= !defined?(Rails.application) || Rails.application.config.cache_classes
|
28
|
-
end
|
52
|
+
delegate :caching?, :to => "self.class"
|
29
53
|
|
30
54
|
# This is what child classes implement. No defaults are needed
|
31
55
|
# because Resolver guarantees that the arguments are present and
|
32
56
|
# normalized.
|
33
57
|
def find_templates(name, prefix, partial, details)
|
34
|
-
raise NotImplementedError
|
58
|
+
raise NotImplementedError, "Subclasses must implement a find_templates(name, prefix, partial, details) method"
|
35
59
|
end
|
36
60
|
|
37
|
-
|
38
|
-
|
39
|
-
|
61
|
+
# Helpers that builds a path. Useful for building virtual paths.
|
62
|
+
def build_path(name, prefix, partial)
|
63
|
+
Path.new(name, prefix, partial)
|
64
|
+
end
|
65
|
+
|
66
|
+
# Handles templates caching. If a key is given and caching is on
|
67
|
+
# always check the cache before hitting the resolver. Otherwise,
|
68
|
+
# it always hits the resolver but check if the resolver is fresher
|
69
|
+
# before returning it.
|
70
|
+
def cached(key, path_info, details, locals) #:nodoc:
|
71
|
+
name, prefix, partial = path_info
|
72
|
+
locals = sort_locals(locals)
|
73
|
+
|
74
|
+
if key && caching?
|
75
|
+
@cached[key][name][prefix][partial][locals] ||= decorate(yield, path_info, details, locals)
|
76
|
+
else
|
77
|
+
fresh = decorate(yield, path_info, details, locals)
|
78
|
+
return fresh unless key
|
79
|
+
|
80
|
+
scope = @cached[key][name][prefix][partial]
|
81
|
+
cache = scope[locals]
|
82
|
+
mtime = cache && cache.map(&:updated_at).max
|
83
|
+
|
84
|
+
if !mtime || fresh.empty? || fresh.any? { |t| t.updated_at > mtime }
|
85
|
+
scope[locals] = fresh
|
86
|
+
else
|
87
|
+
cache
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
# Ensures all the resolver information is set in the template.
|
93
|
+
def decorate(templates, path_info, details, locals) #:nodoc:
|
94
|
+
cached = nil
|
95
|
+
templates.each do |t|
|
96
|
+
t.locals = locals
|
97
|
+
t.formats = details[:formats] || [:html] if t.formats.empty?
|
98
|
+
t.virtual_path ||= (cached ||= build_path(*path_info))
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
if :symbol.respond_to?("<=>")
|
103
|
+
def sort_locals(locals) #:nodoc:
|
104
|
+
locals.sort.freeze
|
105
|
+
end
|
106
|
+
else
|
107
|
+
def sort_locals(locals) #:nodoc:
|
108
|
+
locals = locals.map{ |l| l.to_s }
|
109
|
+
locals.sort!
|
110
|
+
locals.freeze
|
111
|
+
end
|
40
112
|
end
|
41
113
|
end
|
42
114
|
|
43
115
|
class PathResolver < Resolver
|
44
|
-
|
116
|
+
EXTENSIONS = [:locale, :formats, :handlers]
|
117
|
+
DEFAULT_PATTERN = ":prefix/:action{.:locale,}{.:formats,}{.:handlers,}"
|
45
118
|
|
46
|
-
def
|
47
|
-
@
|
119
|
+
def initialize(pattern=nil)
|
120
|
+
@pattern = pattern || DEFAULT_PATTERN
|
121
|
+
super()
|
48
122
|
end
|
49
|
-
alias :to_path :to_s
|
50
123
|
|
51
|
-
|
124
|
+
private
|
52
125
|
|
53
126
|
def find_templates(name, prefix, partial, details)
|
54
|
-
path = build_path(name, prefix, partial
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
def build_path(name, prefix, partial, details)
|
59
|
-
path = ""
|
60
|
-
path << "#{prefix}/" unless prefix.empty?
|
61
|
-
path << (partial ? "_#{name}" : name)
|
62
|
-
path
|
127
|
+
path = build_path(name, prefix, partial)
|
128
|
+
extensions = Hash[EXTENSIONS.map { |ext| [ext, details[ext]] }.flatten(0)]
|
129
|
+
query(path, extensions, details[:formats])
|
63
130
|
end
|
64
131
|
|
65
132
|
def query(path, exts, formats)
|
66
|
-
query =
|
67
|
-
|
68
|
-
exts.each do |ext|
|
69
|
-
query << '{' << ext.map {|e| e && ".#{e}" }.join(',') << ',}'
|
70
|
-
end
|
71
|
-
|
72
|
-
query.gsub!(/\{\.html,/, "{.html,.text.html,")
|
73
|
-
query.gsub!(/\{\.text,/, "{.text,.text.plain,")
|
74
|
-
|
133
|
+
query = build_query(path, exts)
|
75
134
|
templates = []
|
76
135
|
sanitizer = Hash.new { |h,k| h[k] = Dir["#{File.dirname(k)}/*"] }
|
77
136
|
|
@@ -82,14 +141,31 @@ module ActionView
|
|
82
141
|
contents = File.open(p, "rb") {|io| io.read }
|
83
142
|
|
84
143
|
templates << Template.new(contents, File.expand_path(p), handler,
|
85
|
-
:virtual_path => path, :format => format)
|
144
|
+
:virtual_path => path.virtual, :format => format, :updated_at => mtime(p))
|
86
145
|
end
|
87
146
|
|
88
147
|
templates
|
89
148
|
end
|
90
149
|
|
91
|
-
|
92
|
-
|
150
|
+
# Helper for building query glob string based on resolver's pattern.
|
151
|
+
def build_query(path, exts)
|
152
|
+
query = @pattern.dup
|
153
|
+
query.gsub!(/\:prefix(\/)?/, path.prefix.empty? ? "" : "#{path.prefix}\\1") # prefix can be empty...
|
154
|
+
query.gsub!(/\:action/, path.partial? ? "_#{path.name}" : path.name)
|
155
|
+
|
156
|
+
exts.each { |ext, variants|
|
157
|
+
query.gsub!(/\:#{ext}/, "{#{variants.compact.uniq.join(',')}}")
|
158
|
+
}
|
159
|
+
|
160
|
+
query.gsub!('.{html,', '.{html,text.html,')
|
161
|
+
query.gsub!('.{text,', '.{text,text.plain,')
|
162
|
+
|
163
|
+
File.expand_path(query, @path)
|
164
|
+
end
|
165
|
+
|
166
|
+
# Returns the file mtime from the filesystem.
|
167
|
+
def mtime(p)
|
168
|
+
File.stat(p).mtime
|
93
169
|
end
|
94
170
|
|
95
171
|
# Extract handler and formats from path. If a format cannot be a found neither
|
@@ -98,38 +174,76 @@ module ActionView
|
|
98
174
|
def extract_handler_and_format(path, default_formats)
|
99
175
|
pieces = File.basename(path).split(".")
|
100
176
|
pieces.shift
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
if pieces.last == "html" && pieces[-2] == "text"
|
105
|
-
correct_path = path.gsub(/\.text\.html/, ".html")
|
106
|
-
ActiveSupport::Deprecation.warn "The file `#{path}` uses the deprecated format `text.html`. Please rename it to #{correct_path}", caller
|
107
|
-
end
|
108
|
-
|
109
|
-
if pieces.last == "plain" && pieces[-2] == "text"
|
110
|
-
correct_path = path.gsub(/\.text\.plain/, ".text")
|
111
|
-
pieces.pop
|
112
|
-
ActiveSupport::Deprecation.warn "The file `#{path}` uses the deprecated format `text.plain`. Please rename it to #{correct_path}", caller
|
113
|
-
end
|
114
|
-
|
115
|
-
format = pieces.last && Mime[pieces.last] && pieces.pop.to_sym
|
116
|
-
format ||= handler.default_format if handler.respond_to?(:default_format)
|
117
|
-
format ||= default_formats
|
118
|
-
|
177
|
+
handler = Template.handler_for_extension(pieces.pop)
|
178
|
+
format = pieces.last && Mime[pieces.last]
|
119
179
|
[handler, format]
|
120
180
|
end
|
121
181
|
end
|
122
182
|
|
183
|
+
# A resolver that loads files from the filesystem. It allows to set your own
|
184
|
+
# resolving pattern. Such pattern can be a glob string supported by some variables.
|
185
|
+
#
|
186
|
+
# ==== Examples
|
187
|
+
#
|
188
|
+
# Default pattern, loads views the same way as previous versions of rails, eg. when you're
|
189
|
+
# looking for `users/new` it will produce query glob: `users/new{.{en},}{.{html,js},}{.{erb,haml},}`
|
190
|
+
#
|
191
|
+
# FileSystemResolver.new("/path/to/views", ":prefix/:action{.:locale,}{.:formats,}{.:handlers,}")
|
192
|
+
#
|
193
|
+
# This one allows you to keep files with different formats in seperated subdirectories,
|
194
|
+
# eg. `users/new.html` will be loaded from `users/html/new.erb` or `users/new.html.erb`,
|
195
|
+
# `users/new.js` from `users/js/new.erb` or `users/new.js.erb`, etc.
|
196
|
+
#
|
197
|
+
# FileSystemResolver.new("/path/to/views", ":prefix/{:formats/,}:action{.:locale,}{.:formats,}{.:handlers,}")
|
198
|
+
#
|
199
|
+
# If you don't specify pattern then the default will be used.
|
200
|
+
#
|
201
|
+
# In order to use any of the customized resolvers above in a Rails application, you just need
|
202
|
+
# to configure ActionController::Base.view_paths in an initializer, for example:
|
203
|
+
#
|
204
|
+
# ActionController::Base.view_paths = FileSystemResolver.new(
|
205
|
+
# Rails.root.join("app/views"),
|
206
|
+
# ":prefix{/:locale}/:action{.:formats,}{.:handlers,}"
|
207
|
+
# )
|
208
|
+
#
|
209
|
+
# ==== Pattern format and variables
|
210
|
+
#
|
211
|
+
# Pattern have to be a valid glob string, and it allows you to use the
|
212
|
+
# following variables:
|
213
|
+
#
|
214
|
+
# * <tt>:prefix</tt> - usualy the controller path
|
215
|
+
# * <tt>:action</tt> - name of the action
|
216
|
+
# * <tt>:locale</tt> - possible locale versions
|
217
|
+
# * <tt>:formats</tt> - possible request formats (for example html, json, xml...)
|
218
|
+
# * <tt>:handlers</tt> - possible handlers (for example erb, haml, builder...)
|
219
|
+
#
|
123
220
|
class FileSystemResolver < PathResolver
|
124
|
-
def initialize(path)
|
221
|
+
def initialize(path, pattern=nil)
|
125
222
|
raise ArgumentError, "path already is a Resolver class" if path.is_a?(Resolver)
|
126
|
-
super()
|
223
|
+
super(pattern)
|
127
224
|
@path = File.expand_path(path)
|
128
225
|
end
|
129
226
|
|
227
|
+
def to_s
|
228
|
+
@path.to_s
|
229
|
+
end
|
230
|
+
alias :to_path :to_s
|
231
|
+
|
130
232
|
def eql?(resolver)
|
131
233
|
self.class.equal?(resolver.class) && to_path == resolver.to_path
|
132
234
|
end
|
133
235
|
alias :== :eql?
|
134
236
|
end
|
237
|
+
|
238
|
+
# The same as FileSystemResolver but does not allow templates to store
|
239
|
+
# a virtual path since it is invalid for such resolvers.
|
240
|
+
class FallbackFileSystemResolver < FileSystemResolver
|
241
|
+
def self.instances
|
242
|
+
[new(""), new("/")]
|
243
|
+
end
|
244
|
+
|
245
|
+
def decorate(*)
|
246
|
+
super.each { |t| t.virtual_path = nil }
|
247
|
+
end
|
248
|
+
end
|
135
249
|
end
|