actionpack 2.2.3 → 2.3.2
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 +433 -375
- data/MIT-LICENSE +1 -1
- data/README +21 -75
- data/Rakefile +1 -1
- data/lib/action_controller.rb +80 -43
- data/lib/action_controller/assertions/model_assertions.rb +1 -0
- data/lib/action_controller/assertions/response_assertions.rb +43 -16
- data/lib/action_controller/assertions/routing_assertions.rb +1 -1
- data/lib/action_controller/assertions/selector_assertions.rb +17 -12
- data/lib/action_controller/assertions/tag_assertions.rb +1 -4
- data/lib/action_controller/base.rb +153 -82
- data/lib/action_controller/benchmarking.rb +9 -9
- data/lib/action_controller/caching.rb +9 -11
- data/lib/action_controller/caching/actions.rb +11 -18
- data/lib/action_controller/caching/fragments.rb +28 -20
- data/lib/action_controller/caching/pages.rb +13 -15
- data/lib/action_controller/caching/sweeping.rb +2 -2
- data/lib/action_controller/cgi_ext.rb +0 -1
- data/lib/action_controller/cgi_ext/cookie.rb +2 -0
- data/lib/action_controller/cgi_process.rb +54 -162
- data/lib/action_controller/cookies.rb +13 -25
- data/lib/action_controller/dispatcher.rb +43 -122
- data/lib/action_controller/failsafe.rb +52 -0
- data/lib/action_controller/flash.rb +38 -47
- data/lib/action_controller/helpers.rb +13 -9
- data/lib/action_controller/http_authentication.rb +203 -23
- data/lib/action_controller/integration.rb +126 -70
- data/lib/action_controller/layout.rb +36 -39
- data/lib/action_controller/middleware_stack.rb +119 -0
- data/lib/action_controller/middlewares.rb +13 -0
- data/lib/action_controller/mime_responds.rb +19 -4
- data/lib/action_controller/mime_type.rb +8 -0
- data/lib/action_controller/params_parser.rb +71 -0
- data/lib/action_controller/performance_test.rb +0 -1
- data/lib/action_controller/polymorphic_routes.rb +36 -30
- data/lib/action_controller/reloader.rb +14 -0
- data/lib/action_controller/request.rb +107 -499
- data/lib/action_controller/request_forgery_protection.rb +7 -39
- data/lib/action_controller/rescue.rb +55 -35
- data/lib/action_controller/resources.rb +34 -31
- data/lib/action_controller/response.rb +99 -57
- data/lib/action_controller/rewindable_input.rb +28 -0
- data/lib/action_controller/routing.rb +7 -7
- data/lib/action_controller/routing/builder.rb +4 -1
- data/lib/action_controller/routing/optimisations.rb +1 -1
- data/lib/action_controller/routing/recognition_optimisation.rb +1 -2
- data/lib/action_controller/routing/route.rb +15 -5
- data/lib/action_controller/routing/route_set.rb +82 -35
- data/lib/action_controller/routing/segments.rb +35 -0
- data/lib/action_controller/session/abstract_store.rb +181 -0
- data/lib/action_controller/session/cookie_store.rb +197 -175
- data/lib/action_controller/session/mem_cache_store.rb +36 -83
- data/lib/action_controller/session_management.rb +26 -134
- data/lib/action_controller/streaming.rb +24 -7
- data/lib/action_controller/templates/rescues/diagnostics.erb +2 -2
- data/lib/action_controller/templates/rescues/template_error.erb +2 -2
- data/lib/action_controller/test_case.rb +87 -30
- data/lib/action_controller/test_process.rb +145 -104
- data/lib/action_controller/uploaded_file.rb +44 -0
- data/lib/action_controller/url_rewriter.rb +3 -6
- data/lib/action_controller/vendor/html-scanner.rb +16 -0
- data/lib/action_controller/vendor/html-scanner/html/selector.rb +1 -1
- data/lib/action_controller/vendor/rack-1.0/rack.rb +89 -0
- data/lib/action_controller/vendor/rack-1.0/rack/adapter/camping.rb +22 -0
- data/lib/action_controller/vendor/rack-1.0/rack/auth/abstract/handler.rb +37 -0
- data/lib/action_controller/vendor/rack-1.0/rack/auth/abstract/request.rb +37 -0
- data/lib/action_controller/vendor/rack-1.0/rack/auth/basic.rb +58 -0
- data/lib/action_controller/vendor/rack-1.0/rack/auth/digest/md5.rb +124 -0
- data/lib/action_controller/vendor/rack-1.0/rack/auth/digest/nonce.rb +51 -0
- data/lib/action_controller/vendor/rack-1.0/rack/auth/digest/params.rb +55 -0
- data/lib/action_controller/vendor/rack-1.0/rack/auth/digest/request.rb +40 -0
- data/lib/action_controller/vendor/rack-1.0/rack/auth/openid.rb +480 -0
- data/lib/action_controller/vendor/rack-1.0/rack/builder.rb +63 -0
- data/lib/action_controller/vendor/rack-1.0/rack/cascade.rb +36 -0
- data/lib/action_controller/vendor/rack-1.0/rack/chunked.rb +49 -0
- data/lib/action_controller/vendor/rack-1.0/rack/commonlogger.rb +61 -0
- data/lib/action_controller/vendor/rack-1.0/rack/conditionalget.rb +45 -0
- data/lib/action_controller/vendor/rack-1.0/rack/content_length.rb +29 -0
- data/lib/action_controller/vendor/rack-1.0/rack/content_type.rb +23 -0
- data/lib/action_controller/vendor/rack-1.0/rack/deflater.rb +85 -0
- data/lib/action_controller/vendor/rack-1.0/rack/directory.rb +153 -0
- data/lib/action_controller/vendor/rack-1.0/rack/file.rb +88 -0
- data/lib/action_controller/vendor/rack-1.0/rack/handler.rb +48 -0
- data/lib/action_controller/vendor/rack-1.0/rack/handler/cgi.rb +61 -0
- data/lib/action_controller/vendor/rack-1.0/rack/handler/evented_mongrel.rb +8 -0
- data/lib/action_controller/vendor/rack-1.0/rack/handler/fastcgi.rb +89 -0
- data/lib/action_controller/vendor/rack-1.0/rack/handler/lsws.rb +55 -0
- data/lib/action_controller/vendor/rack-1.0/rack/handler/mongrel.rb +84 -0
- data/lib/action_controller/vendor/rack-1.0/rack/handler/scgi.rb +59 -0
- data/lib/action_controller/vendor/rack-1.0/rack/handler/swiftiplied_mongrel.rb +8 -0
- data/lib/action_controller/vendor/rack-1.0/rack/handler/thin.rb +18 -0
- data/lib/action_controller/vendor/rack-1.0/rack/handler/webrick.rb +67 -0
- data/lib/action_controller/vendor/rack-1.0/rack/head.rb +19 -0
- data/lib/action_controller/vendor/rack-1.0/rack/lint.rb +462 -0
- data/lib/action_controller/vendor/rack-1.0/rack/lobster.rb +65 -0
- data/lib/action_controller/vendor/rack-1.0/rack/lock.rb +16 -0
- data/lib/action_controller/vendor/rack-1.0/rack/methodoverride.rb +27 -0
- data/lib/action_controller/vendor/rack-1.0/rack/mime.rb +204 -0
- data/lib/action_controller/vendor/rack-1.0/rack/mock.rb +160 -0
- data/lib/action_controller/vendor/rack-1.0/rack/recursive.rb +57 -0
- data/lib/action_controller/vendor/rack-1.0/rack/reloader.rb +64 -0
- data/lib/action_controller/vendor/rack-1.0/rack/request.rb +241 -0
- data/lib/action_controller/vendor/rack-1.0/rack/response.rb +179 -0
- data/lib/action_controller/vendor/rack-1.0/rack/session/abstract/id.rb +142 -0
- data/lib/action_controller/vendor/rack-1.0/rack/session/cookie.rb +91 -0
- data/lib/action_controller/vendor/rack-1.0/rack/session/memcache.rb +109 -0
- data/lib/action_controller/vendor/rack-1.0/rack/session/pool.rb +100 -0
- data/lib/action_controller/vendor/rack-1.0/rack/showexceptions.rb +349 -0
- data/lib/action_controller/vendor/rack-1.0/rack/showstatus.rb +106 -0
- data/lib/action_controller/vendor/rack-1.0/rack/static.rb +38 -0
- data/lib/action_controller/vendor/rack-1.0/rack/urlmap.rb +55 -0
- data/lib/action_controller/vendor/rack-1.0/rack/utils.rb +392 -0
- data/lib/action_controller/verification.rb +1 -1
- data/lib/action_pack.rb +1 -1
- data/lib/action_pack/version.rb +2 -2
- data/lib/action_view.rb +22 -17
- data/lib/action_view/base.rb +53 -79
- data/lib/action_view/erb/util.rb +38 -0
- data/lib/action_view/helpers.rb +24 -5
- data/lib/action_view/helpers/active_record_helper.rb +2 -2
- data/lib/action_view/helpers/asset_tag_helper.rb +81 -50
- data/lib/action_view/helpers/atom_feed_helper.rb +1 -1
- data/lib/action_view/helpers/benchmark_helper.rb +26 -5
- data/lib/action_view/helpers/date_helper.rb +82 -7
- data/lib/action_view/helpers/form_helper.rb +295 -64
- data/lib/action_view/helpers/form_options_helper.rb +160 -18
- data/lib/action_view/helpers/form_tag_helper.rb +2 -2
- data/lib/action_view/helpers/number_helper.rb +31 -18
- data/lib/action_view/helpers/prototype_helper.rb +2 -12
- data/lib/action_view/helpers/sanitize_helper.rb +0 -10
- data/lib/action_view/helpers/scriptaculous_helper.rb +1 -0
- data/lib/action_view/helpers/tag_helper.rb +3 -4
- data/lib/action_view/helpers/text_helper.rb +99 -122
- data/lib/action_view/helpers/translation_helper.rb +19 -1
- data/lib/action_view/helpers/url_helper.rb +25 -2
- data/lib/action_view/inline_template.rb +1 -1
- data/lib/action_view/locale/en.yml +19 -1
- data/lib/action_view/partials.rb +46 -9
- data/lib/action_view/paths.rb +28 -84
- data/lib/action_view/reloadable_template.rb +117 -0
- data/lib/action_view/renderable.rb +28 -35
- data/lib/action_view/renderable_partial.rb +3 -4
- data/lib/action_view/template.rb +172 -31
- data/lib/action_view/template_error.rb +8 -9
- data/lib/action_view/template_handler.rb +1 -1
- data/lib/action_view/template_handlers.rb +9 -6
- data/lib/action_view/template_handlers/erb.rb +2 -39
- data/lib/action_view/template_handlers/rjs.rb +1 -0
- data/lib/action_view/test_case.rb +27 -1
- data/test/abstract_unit.rb +23 -17
- data/test/active_record_unit.rb +5 -4
- data/test/activerecord/active_record_store_test.rb +139 -106
- data/test/activerecord/render_partial_with_record_identification_test.rb +5 -21
- data/test/controller/action_pack_assertions_test.rb +25 -23
- data/test/controller/addresses_render_test.rb +3 -6
- data/test/controller/assert_select_test.rb +83 -70
- data/test/controller/base_test.rb +11 -13
- data/test/controller/benchmark_test.rb +3 -3
- data/test/controller/caching_test.rb +34 -24
- data/test/controller/capture_test.rb +3 -6
- data/test/controller/content_type_test.rb +3 -6
- data/test/controller/cookie_test.rb +31 -66
- data/test/controller/deprecation/deprecated_base_methods_test.rb +9 -11
- data/test/controller/dispatcher_test.rb +23 -28
- data/test/controller/fake_models.rb +8 -0
- data/test/controller/filters_test.rb +6 -2
- data/test/controller/flash_test.rb +2 -6
- data/test/controller/helper_test.rb +15 -1
- data/test/controller/html-scanner/document_test.rb +1 -1
- data/test/controller/html-scanner/sanitizer_test.rb +1 -1
- data/test/controller/http_basic_authentication_test.rb +88 -0
- data/test/controller/http_digest_authentication_test.rb +178 -0
- data/test/controller/integration_test.rb +56 -52
- data/test/controller/layout_test.rb +46 -44
- data/test/controller/middleware_stack_test.rb +90 -0
- data/test/controller/mime_responds_test.rb +7 -11
- data/test/controller/mime_type_test.rb +9 -0
- data/test/controller/polymorphic_routes_test.rb +235 -151
- data/test/controller/rack_test.rb +52 -81
- data/test/controller/redirect_test.rb +6 -14
- data/test/controller/render_test.rb +273 -60
- data/test/controller/request/json_params_parsing_test.rb +45 -0
- data/test/controller/request/multipart_params_parsing_test.rb +223 -0
- data/test/controller/request/query_string_parsing_test.rb +120 -0
- data/test/controller/request/url_encoded_params_parsing_test.rb +184 -0
- data/test/controller/request/xml_params_parsing_test.rb +88 -0
- data/test/controller/request_forgery_protection_test.rb +17 -98
- data/test/controller/request_test.rb +45 -530
- data/test/controller/rescue_test.rb +45 -22
- data/test/controller/resources_test.rb +112 -37
- data/test/controller/routing_test.rb +1442 -1384
- data/test/controller/selector_test.rb +3 -3
- data/test/controller/send_file_test.rb +30 -3
- data/test/controller/session/cookie_store_test.rb +169 -240
- data/test/controller/session/mem_cache_store_test.rb +94 -148
- data/test/controller/session/test_session_test.rb +58 -0
- data/test/controller/test_test.rb +32 -13
- data/test/controller/url_rewriter_test.rb +54 -4
- data/test/controller/verification_test.rb +1 -1
- data/test/controller/view_paths_test.rb +15 -15
- data/test/controller/webservice_test.rb +178 -147
- data/test/fixtures/alternate_helpers/foo_helper.rb +3 -0
- data/test/fixtures/layout_tests/alt/layouts/alt.rhtml +0 -0
- data/test/fixtures/layouts/default_html.html.erb +1 -0
- data/test/fixtures/layouts/xhr.html.erb +2 -0
- data/test/fixtures/multipart/empty +10 -0
- data/test/fixtures/multipart/hello.txt +1 -0
- data/test/fixtures/multipart/none +9 -0
- data/test/fixtures/public/500.da.html +1 -0
- data/test/fixtures/quiz/questions/_question.html.erb +1 -0
- data/test/fixtures/replies.yml +1 -1
- data/test/fixtures/test/_one.html.erb +1 -0
- data/test/fixtures/test/_two.html.erb +1 -0
- data/test/fixtures/test/dont_pick_me +1 -0
- data/test/fixtures/test/hello.builder +1 -1
- data/test/fixtures/test/hello_world.da.html.erb +1 -0
- data/test/fixtures/test/hello_world.erb~ +1 -0
- data/test/fixtures/test/hello_world.pt-BR.html.erb +1 -0
- data/test/fixtures/test/malformed/malformed.en.html.erb~ +1 -0
- data/test/fixtures/test/malformed/malformed.erb~ +1 -0
- data/test/fixtures/test/malformed/malformed.html.erb~ +1 -0
- data/test/fixtures/test/render_explicit_html_template.js.rjs +1 -0
- data/test/fixtures/test/render_implicit_html_template.js.rjs +1 -0
- data/test/fixtures/test/render_implicit_html_template_from_xhr_request.da.html.erb +1 -0
- data/test/fixtures/test/render_implicit_html_template_from_xhr_request.html.erb +1 -0
- data/test/fixtures/test/render_implicit_js_template_without_layout.js.erb +1 -0
- data/test/fixtures/test/utf8.html.erb +2 -0
- data/test/template/active_record_helper_i18n_test.rb +31 -33
- data/test/template/active_record_helper_test.rb +34 -0
- data/test/template/asset_tag_helper_test.rb +52 -14
- data/test/template/atom_feed_helper_test.rb +3 -5
- data/test/template/benchmark_helper_test.rb +50 -24
- data/test/template/compiled_templates_test.rb +177 -33
- data/test/template/date_helper_i18n_test.rb +88 -81
- data/test/template/date_helper_test.rb +427 -43
- data/test/template/form_helper_test.rb +243 -44
- data/test/template/form_options_helper_test.rb +631 -565
- data/test/template/form_tag_helper_test.rb +9 -2
- data/test/template/javascript_helper_test.rb +0 -5
- data/test/template/number_helper_i18n_test.rb +60 -48
- data/test/template/number_helper_test.rb +1 -0
- data/test/template/render_test.rb +117 -35
- data/test/template/test_test.rb +4 -6
- data/test/template/text_helper_test.rb +129 -50
- data/test/template/translation_helper_test.rb +23 -19
- data/test/template/url_helper_test.rb +35 -2
- data/test/view/test_case_test.rb +8 -0
- metadata +197 -23
- data/lib/action_controller/assertions.rb +0 -69
- data/lib/action_controller/caching/sql_cache.rb +0 -18
- data/lib/action_controller/cgi_ext/session.rb +0 -53
- data/lib/action_controller/components.rb +0 -169
- data/lib/action_controller/rack_process.rb +0 -297
- data/lib/action_controller/request_profiler.rb +0 -169
- data/lib/action_controller/session/active_record_store.rb +0 -340
- data/lib/action_controller/session/drb_server.rb +0 -32
- data/lib/action_controller/session/drb_store.rb +0 -35
- data/test/controller/cgi_test.rb +0 -269
- data/test/controller/components_test.rb +0 -156
- data/test/controller/http_authentication_test.rb +0 -54
- data/test/controller/integration_upload_test.rb +0 -43
- data/test/controller/session_fixation_test.rb +0 -89
- data/test/controller/session_management_test.rb +0 -178
- data/test/fixtures/test/hello_world.js +0 -1
data/lib/action_view/paths.rb
CHANGED
@@ -2,19 +2,16 @@ module ActionView #:nodoc:
|
|
2
2
|
class PathSet < Array #:nodoc:
|
3
3
|
def self.type_cast(obj)
|
4
4
|
if obj.is_a?(String)
|
5
|
-
if Base.
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
"ActionView::Base.process_view_paths(#{obj.inspect}) and set it " +
|
10
|
-
"as your view path"
|
5
|
+
if Base.cache_template_loading?
|
6
|
+
Template::EagerPath.new(obj.to_s)
|
7
|
+
else
|
8
|
+
ReloadableTemplate::ReloadablePath.new(obj.to_s)
|
11
9
|
end
|
12
|
-
Path.new(obj)
|
13
10
|
else
|
14
11
|
obj
|
15
12
|
end
|
16
13
|
end
|
17
|
-
|
14
|
+
|
18
15
|
def initialize(*args)
|
19
16
|
super(*args).map! { |obj| self.class.type_cast(obj) }
|
20
17
|
end
|
@@ -38,88 +35,35 @@ module ActionView #:nodoc:
|
|
38
35
|
def unshift(*objs)
|
39
36
|
super(*objs.map { |obj| self.class.type_cast(obj) })
|
40
37
|
end
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
@eager_load_templates = true
|
45
|
-
end
|
46
|
-
|
47
|
-
def self.eager_load_templates?
|
48
|
-
@eager_load_templates || false
|
49
|
-
end
|
50
|
-
|
51
|
-
attr_reader :path, :paths
|
52
|
-
delegate :to_s, :to_str, :hash, :inspect, :to => :path
|
53
|
-
|
54
|
-
def initialize(path, load = true)
|
55
|
-
raise ArgumentError, "path already is a Path class" if path.is_a?(Path)
|
56
|
-
@path = path.freeze
|
57
|
-
reload! if load
|
58
|
-
end
|
59
|
-
|
60
|
-
def ==(path)
|
61
|
-
to_str == path.to_str
|
62
|
-
end
|
63
|
-
|
64
|
-
def eql?(path)
|
65
|
-
to_str == path.to_str
|
66
|
-
end
|
67
|
-
|
68
|
-
def [](path)
|
69
|
-
raise "Unloaded view path! #{@path}" unless @loaded
|
70
|
-
@paths[path]
|
71
|
-
end
|
72
|
-
|
73
|
-
def loaded?
|
74
|
-
@loaded ? true : false
|
75
|
-
end
|
76
|
-
|
77
|
-
def load
|
78
|
-
reload! unless loaded?
|
79
|
-
self
|
80
|
-
end
|
81
|
-
|
82
|
-
# Rebuild load path directory cache
|
83
|
-
def reload!
|
84
|
-
@paths = {}
|
85
|
-
|
86
|
-
templates_in_path do |template|
|
87
|
-
# Eager load memoized methods and freeze cached template
|
88
|
-
template.freeze if self.class.eager_load_templates?
|
89
|
-
|
90
|
-
@paths[template.path] = template
|
91
|
-
@paths[template.path_without_extension] ||= template
|
92
|
-
end
|
93
|
-
|
94
|
-
@paths.freeze
|
95
|
-
@loaded = true
|
96
|
-
end
|
97
|
-
|
98
|
-
private
|
99
|
-
def templates_in_path
|
100
|
-
(Dir.glob("#{@path}/**/*/**") | Dir.glob("#{@path}/**")).each do |file|
|
101
|
-
unless File.directory?(file)
|
102
|
-
yield Template.new(file.split("#{self}/").last, self)
|
103
|
-
end
|
104
|
-
end
|
105
|
-
end
|
106
|
-
end
|
107
|
-
|
108
|
-
def load
|
109
|
-
each { |path| path.load }
|
38
|
+
|
39
|
+
def load!
|
40
|
+
each(&:load!)
|
110
41
|
end
|
111
42
|
|
112
|
-
def
|
113
|
-
|
114
|
-
|
43
|
+
def find_template(original_template_path, format = nil, html_fallback = true)
|
44
|
+
return original_template_path if original_template_path.respond_to?(:render)
|
45
|
+
template_path = original_template_path.sub(/^\//, '')
|
115
46
|
|
116
|
-
|
117
|
-
|
118
|
-
|
47
|
+
each do |load_path|
|
48
|
+
if format && (template = load_path["#{template_path}.#{I18n.locale}.#{format}"])
|
49
|
+
return template
|
50
|
+
elsif format && (template = load_path["#{template_path}.#{format}"])
|
51
|
+
return template
|
52
|
+
elsif template = load_path["#{template_path}.#{I18n.locale}"]
|
53
|
+
return template
|
54
|
+
elsif template = load_path[template_path]
|
55
|
+
return template
|
56
|
+
# Try to find html version if the format is javascript
|
57
|
+
elsif format == :js && html_fallback && template = load_path["#{template_path}.#{I18n.locale}.html"]
|
58
|
+
return template
|
59
|
+
elsif format == :js && html_fallback && template = load_path["#{template_path}.html"]
|
119
60
|
return template
|
120
61
|
end
|
121
62
|
end
|
122
|
-
|
63
|
+
|
64
|
+
return Template.new(original_template_path, original_template_path =~ /\A\// ? "" : ".") if File.file?(original_template_path)
|
65
|
+
|
66
|
+
raise MissingTemplate.new(self, original_template_path, format)
|
123
67
|
end
|
124
68
|
end
|
125
69
|
end
|
@@ -0,0 +1,117 @@
|
|
1
|
+
module ActionView #:nodoc:
|
2
|
+
class ReloadableTemplate < Template
|
3
|
+
|
4
|
+
class TemplateDeleted < ActionView::ActionViewError
|
5
|
+
end
|
6
|
+
|
7
|
+
class ReloadablePath < Template::Path
|
8
|
+
|
9
|
+
def initialize(path)
|
10
|
+
super
|
11
|
+
@paths = {}
|
12
|
+
new_request!
|
13
|
+
end
|
14
|
+
|
15
|
+
def new_request!
|
16
|
+
@disk_cache = {}
|
17
|
+
end
|
18
|
+
alias_method :load!, :new_request!
|
19
|
+
|
20
|
+
def [](path)
|
21
|
+
if found_template = @paths[path]
|
22
|
+
begin
|
23
|
+
found_template.reset_cache_if_stale!
|
24
|
+
rescue TemplateDeleted
|
25
|
+
unregister_template(found_template)
|
26
|
+
self[path]
|
27
|
+
end
|
28
|
+
else
|
29
|
+
load_all_templates_from_dir(templates_dir_from_path(path))
|
30
|
+
# don't ever hand out a template without running a stale check
|
31
|
+
(new_template = @paths[path]) && new_template.reset_cache_if_stale!
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
def register_template_from_file(template_full_file_path)
|
37
|
+
if !@paths[relative_path = relative_path_for_template_file(template_full_file_path)] && File.file?(template_full_file_path)
|
38
|
+
register_template(ReloadableTemplate.new(relative_path, self))
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def register_template(template)
|
43
|
+
template.accessible_paths.each do |path|
|
44
|
+
@paths[path] = template
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# remove (probably deleted) template from cache
|
49
|
+
def unregister_template(template)
|
50
|
+
template.accessible_paths.each do |template_path|
|
51
|
+
@paths.delete(template_path) if @paths[template_path] == template
|
52
|
+
end
|
53
|
+
# fill in any newly created gaps
|
54
|
+
@paths.values.uniq.each do |template|
|
55
|
+
template.accessible_paths.each {|path| @paths[path] ||= template}
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
# load all templates from the directory of the requested template
|
60
|
+
def load_all_templates_from_dir(dir)
|
61
|
+
# hit disk only once per template-dir/request
|
62
|
+
@disk_cache[dir] ||= template_files_from_dir(dir).each {|template_file| register_template_from_file(template_file)}
|
63
|
+
end
|
64
|
+
|
65
|
+
def templates_dir_from_path(path)
|
66
|
+
dirname = File.dirname(path)
|
67
|
+
File.join(@path, dirname == '.' ? '' : dirname)
|
68
|
+
end
|
69
|
+
|
70
|
+
# get all the template filenames from the dir
|
71
|
+
def template_files_from_dir(dir)
|
72
|
+
Dir.glob(File.join(dir, '*'))
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
module Unfreezable
|
77
|
+
def freeze; self; end
|
78
|
+
end
|
79
|
+
|
80
|
+
def initialize(*args)
|
81
|
+
super
|
82
|
+
|
83
|
+
# we don't ever want to get frozen
|
84
|
+
extend Unfreezable
|
85
|
+
end
|
86
|
+
|
87
|
+
def mtime
|
88
|
+
File.mtime(filename)
|
89
|
+
end
|
90
|
+
|
91
|
+
attr_accessor :previously_last_modified
|
92
|
+
|
93
|
+
def stale?
|
94
|
+
previously_last_modified.nil? || previously_last_modified < mtime
|
95
|
+
rescue Errno::ENOENT => e
|
96
|
+
undef_my_compiled_methods!
|
97
|
+
raise TemplateDeleted
|
98
|
+
end
|
99
|
+
|
100
|
+
def reset_cache_if_stale!
|
101
|
+
if stale?
|
102
|
+
flush_cache 'source', 'compiled_source'
|
103
|
+
undef_my_compiled_methods!
|
104
|
+
@previously_last_modified = mtime
|
105
|
+
end
|
106
|
+
self
|
107
|
+
end
|
108
|
+
|
109
|
+
# remove any compiled methods that look like they might belong to me
|
110
|
+
def undef_my_compiled_methods!
|
111
|
+
ActionView::Base::CompiledTemplates.public_instance_methods.grep(/#{Regexp.escape(method_name_without_locals)}(?:_locals_)?/).each do |m|
|
112
|
+
ActionView::Base::CompiledTemplates.send(:remove_method, m)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
end
|
117
|
+
end
|
@@ -1,13 +1,11 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
1
3
|
module ActionView
|
2
4
|
# NOTE: The template that this mixin is being included into is frozen
|
3
5
|
# so you cannot set or modify any instance variables
|
4
6
|
module Renderable #:nodoc:
|
5
7
|
extend ActiveSupport::Memoizable
|
6
8
|
|
7
|
-
def self.included(base)
|
8
|
-
@@mutex = Mutex.new
|
9
|
-
end
|
10
|
-
|
11
9
|
def filename
|
12
10
|
'compiled-template'
|
13
11
|
end
|
@@ -20,40 +18,38 @@ module ActionView
|
|
20
18
|
def compiled_source
|
21
19
|
handler.call(self)
|
22
20
|
end
|
23
|
-
|
21
|
+
|
22
|
+
def method_name_without_locals
|
23
|
+
['_run', extension, method_segment].compact.join('_')
|
24
|
+
end
|
25
|
+
memoize :method_name_without_locals
|
24
26
|
|
25
27
|
def render(view, local_assigns = {})
|
26
28
|
compile(local_assigns)
|
27
29
|
|
28
|
-
|
29
|
-
|
30
|
+
view.with_template self do
|
31
|
+
view.send(:_evaluate_assigns_and_ivars)
|
32
|
+
view.send(:_set_controller_content_type, mime_type) if respond_to?(:mime_type)
|
30
33
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
result = view.send(method_name(local_assigns), local_assigns) do |*names|
|
40
|
-
ivar = :@_proc_for_layout
|
41
|
-
if !view.instance_variable_defined?(:"@content_for_#{names.first}") && view.instance_variable_defined?(ivar) && (proc = view.instance_variable_get(ivar))
|
42
|
-
view.capture(*names, &proc)
|
43
|
-
elsif view.instance_variable_defined?(ivar = :"@content_for_#{names.first || :layout}")
|
44
|
-
view.instance_variable_get(ivar)
|
34
|
+
view.send(method_name(local_assigns), local_assigns) do |*names|
|
35
|
+
ivar = :@_proc_for_layout
|
36
|
+
if !view.instance_variable_defined?(:"@content_for_#{names.first}") && view.instance_variable_defined?(ivar) && (proc = view.instance_variable_get(ivar))
|
37
|
+
view.capture(*names, &proc)
|
38
|
+
elsif view.instance_variable_defined?(ivar = :"@content_for_#{names.first || :layout}")
|
39
|
+
view.instance_variable_get(ivar)
|
40
|
+
end
|
45
41
|
end
|
46
42
|
end
|
47
|
-
|
48
|
-
stack.pop
|
49
|
-
result
|
50
43
|
end
|
51
44
|
|
52
45
|
def method_name(local_assigns)
|
53
46
|
if local_assigns && local_assigns.any?
|
54
|
-
|
47
|
+
method_name = method_name_without_locals.dup
|
48
|
+
method_name << "_locals_#{local_assigns.keys.map { |k| k.to_s }.sort.join('_')}"
|
49
|
+
else
|
50
|
+
method_name = method_name_without_locals
|
55
51
|
end
|
56
|
-
|
52
|
+
method_name.to_sym
|
57
53
|
end
|
58
54
|
|
59
55
|
private
|
@@ -61,10 +57,8 @@ module ActionView
|
|
61
57
|
def compile(local_assigns)
|
62
58
|
render_symbol = method_name(local_assigns)
|
63
59
|
|
64
|
-
|
65
|
-
|
66
|
-
compile!(render_symbol, local_assigns)
|
67
|
-
end
|
60
|
+
if !Base::CompiledTemplates.method_defined?(render_symbol) || recompile?
|
61
|
+
compile!(render_symbol, local_assigns)
|
68
62
|
end
|
69
63
|
end
|
70
64
|
|
@@ -81,6 +75,8 @@ module ActionView
|
|
81
75
|
|
82
76
|
begin
|
83
77
|
ActionView::Base::CompiledTemplates.module_eval(source, filename, 0)
|
78
|
+
rescue Errno::ENOENT => e
|
79
|
+
raise e # Missing template file, re-raise for Base to rescue
|
84
80
|
rescue Exception => e # errors from template code
|
85
81
|
if logger = defined?(ActionController) && Base.logger
|
86
82
|
logger.debug "ERROR: compiling #{render_symbol} RAISED #{e}"
|
@@ -92,11 +88,8 @@ module ActionView
|
|
92
88
|
end
|
93
89
|
end
|
94
90
|
|
95
|
-
|
96
|
-
|
97
|
-
# if local_assigns has a new key, which isn't supported by the compiled code yet.
|
98
|
-
def recompile?(symbol)
|
99
|
-
!(ActionView::PathSet::Path.eager_load_templates? && Base::CompiledTemplates.method_defined?(symbol))
|
91
|
+
def recompile?
|
92
|
+
false
|
100
93
|
end
|
101
94
|
end
|
102
95
|
end
|
@@ -25,12 +25,11 @@ module ActionView
|
|
25
25
|
end
|
26
26
|
|
27
27
|
def render_partial(view, object = nil, local_assigns = {}, as = nil)
|
28
|
-
object ||= local_assigns[:object] ||
|
29
|
-
local_assigns[variable_name]
|
28
|
+
object ||= local_assigns[:object] || local_assigns[variable_name]
|
30
29
|
|
31
|
-
if view.respond_to?(:controller)
|
30
|
+
if object.nil? && view.respond_to?(:controller)
|
32
31
|
ivar = :"@#{variable_name}"
|
33
|
-
object
|
32
|
+
object =
|
34
33
|
if view.controller.instance_variable_defined?(ivar)
|
35
34
|
ActiveSupport::Deprecation::DeprecatedObjectProxy.new(
|
36
35
|
view.controller.instance_variable_get(ivar),
|
data/lib/action_view/template.rb
CHANGED
@@ -1,24 +1,141 @@
|
|
1
|
-
require 'action_controller/mime_type'
|
2
|
-
|
3
1
|
module ActionView #:nodoc:
|
4
2
|
class Template
|
3
|
+
class Path
|
4
|
+
attr_reader :path, :paths
|
5
|
+
delegate :hash, :inspect, :to => :path
|
6
|
+
|
7
|
+
def initialize(path)
|
8
|
+
raise ArgumentError, "path already is a Path class" if path.is_a?(Path)
|
9
|
+
@path = (path.ends_with?(File::SEPARATOR) ? path.to(-2) : path).freeze
|
10
|
+
end
|
11
|
+
|
12
|
+
def to_s
|
13
|
+
if defined?(RAILS_ROOT)
|
14
|
+
path.to_s.sub(/^#{Regexp.escape(File.expand_path(RAILS_ROOT))}\//, '')
|
15
|
+
else
|
16
|
+
path.to_s
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def to_str
|
21
|
+
path.to_str
|
22
|
+
end
|
23
|
+
|
24
|
+
def ==(path)
|
25
|
+
to_str == path.to_str
|
26
|
+
end
|
27
|
+
|
28
|
+
def eql?(path)
|
29
|
+
to_str == path.to_str
|
30
|
+
end
|
31
|
+
|
32
|
+
# Returns a ActionView::Template object for the given path string. The
|
33
|
+
# input path should be relative to the view path directory,
|
34
|
+
# +hello/index.html.erb+. This method also has a special exception to
|
35
|
+
# match partial file names without a handler extension. So
|
36
|
+
# +hello/index.html+ will match the first template it finds with a
|
37
|
+
# known template extension, +hello/index.html.erb+. Template extensions
|
38
|
+
# should not be confused with format extensions +html+, +js+, +xml+,
|
39
|
+
# etc. A format must be supplied to match a formated file. +hello/index+
|
40
|
+
# will never match +hello/index.html.erb+.
|
41
|
+
def [](path)
|
42
|
+
end
|
43
|
+
|
44
|
+
def load!
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.new_and_loaded(path)
|
48
|
+
returning new(path) do |path|
|
49
|
+
path.load!
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
def relative_path_for_template_file(full_file_path)
|
55
|
+
full_file_path.split("#{@path}/").last
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
class EagerPath < Path
|
60
|
+
def load!
|
61
|
+
return if @loaded
|
62
|
+
|
63
|
+
@paths = {}
|
64
|
+
templates_in_path do |template|
|
65
|
+
template.load!
|
66
|
+
template.accessible_paths.each do |path|
|
67
|
+
@paths[path] = template
|
68
|
+
end
|
69
|
+
end
|
70
|
+
@paths.freeze
|
71
|
+
@loaded = true
|
72
|
+
end
|
73
|
+
|
74
|
+
def [](path)
|
75
|
+
load! unless @loaded
|
76
|
+
@paths[path]
|
77
|
+
end
|
78
|
+
|
79
|
+
private
|
80
|
+
def templates_in_path
|
81
|
+
(Dir.glob("#{@path}/**/*/**") | Dir.glob("#{@path}/**")).each do |file|
|
82
|
+
yield create_template(file) unless File.directory?(file)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def create_template(file)
|
87
|
+
Template.new(relative_path_for_template_file(file), self)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
5
91
|
extend TemplateHandlers
|
6
92
|
extend ActiveSupport::Memoizable
|
7
93
|
include Renderable
|
8
94
|
|
9
|
-
|
95
|
+
# Templates that are exempt from layouts
|
96
|
+
@@exempt_from_layout = Set.new([/\.rjs$/])
|
97
|
+
|
98
|
+
# Don't render layouts for templates with the given extensions.
|
99
|
+
def self.exempt_from_layout(*extensions)
|
100
|
+
regexps = extensions.collect do |extension|
|
101
|
+
extension.is_a?(Regexp) ? extension : /\.#{Regexp.escape(extension.to_s)}$/
|
102
|
+
end
|
103
|
+
@@exempt_from_layout.merge(regexps)
|
104
|
+
end
|
105
|
+
|
106
|
+
attr_accessor :template_path, :filename, :load_path, :base_path
|
107
|
+
attr_accessor :locale, :name, :format, :extension
|
10
108
|
delegate :to_s, :to => :path
|
11
109
|
|
12
|
-
def initialize(template_path,
|
13
|
-
template_path = template_path.dup
|
14
|
-
@
|
110
|
+
def initialize(template_path, load_path)
|
111
|
+
@template_path = template_path.dup
|
112
|
+
@load_path, @filename = load_path, File.join(load_path, template_path)
|
113
|
+
@base_path, @name, @locale, @format, @extension = split(template_path)
|
15
114
|
@base_path.to_s.gsub!(/\/$/, '') # Push to split method
|
16
|
-
@load_path, @filename = find_full_path(template_path, load_paths)
|
17
115
|
|
18
116
|
# Extend with partial super powers
|
19
117
|
extend RenderablePartial if @name =~ /^_/
|
20
118
|
end
|
21
119
|
|
120
|
+
def accessible_paths
|
121
|
+
paths = []
|
122
|
+
|
123
|
+
if valid_extension?(extension)
|
124
|
+
paths << path
|
125
|
+
paths << path_without_extension
|
126
|
+
if multipart?
|
127
|
+
formats = format.split(".")
|
128
|
+
paths << "#{path_without_format_and_extension}.#{formats.first}"
|
129
|
+
paths << "#{path_without_format_and_extension}.#{formats.second}"
|
130
|
+
end
|
131
|
+
else
|
132
|
+
# template without explicit template handler should only be reachable through its exact path
|
133
|
+
paths << template_path
|
134
|
+
end
|
135
|
+
|
136
|
+
paths
|
137
|
+
end
|
138
|
+
|
22
139
|
def format_and_extension
|
23
140
|
(extensions = [format, extension].compact.join(".")).blank? ? nil : extensions
|
24
141
|
end
|
@@ -33,22 +150,22 @@ module ActionView #:nodoc:
|
|
33
150
|
end
|
34
151
|
|
35
152
|
def mime_type
|
36
|
-
Mime::Type.lookup_by_extension(format) if format
|
153
|
+
Mime::Type.lookup_by_extension(format) if format && defined?(::Mime)
|
37
154
|
end
|
38
155
|
memoize :mime_type
|
39
156
|
|
40
157
|
def path
|
41
|
-
[base_path, [name, format, extension].compact.join('.')].compact.join('/')
|
158
|
+
[base_path, [name, locale, format, extension].compact.join('.')].compact.join('/')
|
42
159
|
end
|
43
160
|
memoize :path
|
44
161
|
|
45
162
|
def path_without_extension
|
46
|
-
[base_path, [name, format].compact.join('.')].compact.join('/')
|
163
|
+
[base_path, [name, locale, format].compact.join('.')].compact.join('/')
|
47
164
|
end
|
48
165
|
memoize :path_without_extension
|
49
166
|
|
50
167
|
def path_without_format_and_extension
|
51
|
-
[base_path, name].compact.join('/')
|
168
|
+
[base_path, [name, locale].compact.join('.')].compact.join('/')
|
52
169
|
end
|
53
170
|
memoize :path_without_format_and_extension
|
54
171
|
|
@@ -59,6 +176,10 @@ module ActionView #:nodoc:
|
|
59
176
|
end
|
60
177
|
memoize :relative_path
|
61
178
|
|
179
|
+
def exempt_from_layout?
|
180
|
+
@@exempt_from_layout.any? { |exempted| path =~ exempted }
|
181
|
+
end
|
182
|
+
|
62
183
|
def source
|
63
184
|
File.read(filename)
|
64
185
|
end
|
@@ -81,36 +202,56 @@ module ActionView #:nodoc:
|
|
81
202
|
end
|
82
203
|
end
|
83
204
|
|
205
|
+
def load!
|
206
|
+
freeze
|
207
|
+
end
|
208
|
+
|
84
209
|
private
|
85
210
|
def valid_extension?(extension)
|
86
|
-
Template.
|
211
|
+
!Template.registered_template_handler(extension).nil?
|
87
212
|
end
|
88
213
|
|
89
|
-
def
|
90
|
-
|
91
|
-
load_paths.each do |load_path|
|
92
|
-
file = [load_path, path].compact.join('/')
|
93
|
-
return load_path, file if File.file?(file)
|
94
|
-
end
|
95
|
-
raise MissingTemplate.new(load_paths, path)
|
214
|
+
def valid_locale?(locale)
|
215
|
+
I18n.available_locales.include?(locale.to_sym)
|
96
216
|
end
|
97
217
|
|
98
218
|
# Returns file split into an array
|
99
|
-
# [base_path, name, format, extension]
|
219
|
+
# [base_path, name, locale, format, extension]
|
100
220
|
def split(file)
|
101
|
-
if m = file.match(/^(.*\/)?([^\.]+)
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
221
|
+
if m = file.to_s.match(/^(.*\/)?([^\.]+)\.(.*)$/)
|
222
|
+
base_path = m[1]
|
223
|
+
name = m[2]
|
224
|
+
extensions = m[3]
|
225
|
+
else
|
226
|
+
return
|
227
|
+
end
|
228
|
+
|
229
|
+
locale = nil
|
230
|
+
format = nil
|
231
|
+
extension = nil
|
232
|
+
|
233
|
+
if m = extensions.split(".")
|
234
|
+
if valid_locale?(m[0]) && m[1] && valid_extension?(m[2]) # All three
|
235
|
+
locale = m[0]
|
236
|
+
format = m[1]
|
237
|
+
extension = m[2]
|
238
|
+
elsif m[0] && m[1] && valid_extension?(m[2]) # Multipart formats
|
239
|
+
format = "#{m[0]}.#{m[1]}"
|
240
|
+
extension = m[2]
|
241
|
+
elsif valid_locale?(m[0]) && valid_extension?(m[1]) # locale and extension
|
242
|
+
locale = m[0]
|
243
|
+
extension = m[1]
|
244
|
+
elsif valid_extension?(m[1]) # format and extension
|
245
|
+
format = m[0]
|
246
|
+
extension = m[1]
|
247
|
+
elsif valid_extension?(m[0]) # Just extension
|
248
|
+
extension = m[0]
|
249
|
+
else # No extension
|
250
|
+
format = m[0]
|
112
251
|
end
|
113
252
|
end
|
253
|
+
|
254
|
+
[base_path, name, locale, format, extension]
|
114
255
|
end
|
115
256
|
end
|
116
257
|
end
|