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.

Files changed (264) hide show
  1. data/CHANGELOG +433 -375
  2. data/MIT-LICENSE +1 -1
  3. data/README +21 -75
  4. data/Rakefile +1 -1
  5. data/lib/action_controller.rb +80 -43
  6. data/lib/action_controller/assertions/model_assertions.rb +1 -0
  7. data/lib/action_controller/assertions/response_assertions.rb +43 -16
  8. data/lib/action_controller/assertions/routing_assertions.rb +1 -1
  9. data/lib/action_controller/assertions/selector_assertions.rb +17 -12
  10. data/lib/action_controller/assertions/tag_assertions.rb +1 -4
  11. data/lib/action_controller/base.rb +153 -82
  12. data/lib/action_controller/benchmarking.rb +9 -9
  13. data/lib/action_controller/caching.rb +9 -11
  14. data/lib/action_controller/caching/actions.rb +11 -18
  15. data/lib/action_controller/caching/fragments.rb +28 -20
  16. data/lib/action_controller/caching/pages.rb +13 -15
  17. data/lib/action_controller/caching/sweeping.rb +2 -2
  18. data/lib/action_controller/cgi_ext.rb +0 -1
  19. data/lib/action_controller/cgi_ext/cookie.rb +2 -0
  20. data/lib/action_controller/cgi_process.rb +54 -162
  21. data/lib/action_controller/cookies.rb +13 -25
  22. data/lib/action_controller/dispatcher.rb +43 -122
  23. data/lib/action_controller/failsafe.rb +52 -0
  24. data/lib/action_controller/flash.rb +38 -47
  25. data/lib/action_controller/helpers.rb +13 -9
  26. data/lib/action_controller/http_authentication.rb +203 -23
  27. data/lib/action_controller/integration.rb +126 -70
  28. data/lib/action_controller/layout.rb +36 -39
  29. data/lib/action_controller/middleware_stack.rb +119 -0
  30. data/lib/action_controller/middlewares.rb +13 -0
  31. data/lib/action_controller/mime_responds.rb +19 -4
  32. data/lib/action_controller/mime_type.rb +8 -0
  33. data/lib/action_controller/params_parser.rb +71 -0
  34. data/lib/action_controller/performance_test.rb +0 -1
  35. data/lib/action_controller/polymorphic_routes.rb +36 -30
  36. data/lib/action_controller/reloader.rb +14 -0
  37. data/lib/action_controller/request.rb +107 -499
  38. data/lib/action_controller/request_forgery_protection.rb +7 -39
  39. data/lib/action_controller/rescue.rb +55 -35
  40. data/lib/action_controller/resources.rb +34 -31
  41. data/lib/action_controller/response.rb +99 -57
  42. data/lib/action_controller/rewindable_input.rb +28 -0
  43. data/lib/action_controller/routing.rb +7 -7
  44. data/lib/action_controller/routing/builder.rb +4 -1
  45. data/lib/action_controller/routing/optimisations.rb +1 -1
  46. data/lib/action_controller/routing/recognition_optimisation.rb +1 -2
  47. data/lib/action_controller/routing/route.rb +15 -5
  48. data/lib/action_controller/routing/route_set.rb +82 -35
  49. data/lib/action_controller/routing/segments.rb +35 -0
  50. data/lib/action_controller/session/abstract_store.rb +181 -0
  51. data/lib/action_controller/session/cookie_store.rb +197 -175
  52. data/lib/action_controller/session/mem_cache_store.rb +36 -83
  53. data/lib/action_controller/session_management.rb +26 -134
  54. data/lib/action_controller/streaming.rb +24 -7
  55. data/lib/action_controller/templates/rescues/diagnostics.erb +2 -2
  56. data/lib/action_controller/templates/rescues/template_error.erb +2 -2
  57. data/lib/action_controller/test_case.rb +87 -30
  58. data/lib/action_controller/test_process.rb +145 -104
  59. data/lib/action_controller/uploaded_file.rb +44 -0
  60. data/lib/action_controller/url_rewriter.rb +3 -6
  61. data/lib/action_controller/vendor/html-scanner.rb +16 -0
  62. data/lib/action_controller/vendor/html-scanner/html/selector.rb +1 -1
  63. data/lib/action_controller/vendor/rack-1.0/rack.rb +89 -0
  64. data/lib/action_controller/vendor/rack-1.0/rack/adapter/camping.rb +22 -0
  65. data/lib/action_controller/vendor/rack-1.0/rack/auth/abstract/handler.rb +37 -0
  66. data/lib/action_controller/vendor/rack-1.0/rack/auth/abstract/request.rb +37 -0
  67. data/lib/action_controller/vendor/rack-1.0/rack/auth/basic.rb +58 -0
  68. data/lib/action_controller/vendor/rack-1.0/rack/auth/digest/md5.rb +124 -0
  69. data/lib/action_controller/vendor/rack-1.0/rack/auth/digest/nonce.rb +51 -0
  70. data/lib/action_controller/vendor/rack-1.0/rack/auth/digest/params.rb +55 -0
  71. data/lib/action_controller/vendor/rack-1.0/rack/auth/digest/request.rb +40 -0
  72. data/lib/action_controller/vendor/rack-1.0/rack/auth/openid.rb +480 -0
  73. data/lib/action_controller/vendor/rack-1.0/rack/builder.rb +63 -0
  74. data/lib/action_controller/vendor/rack-1.0/rack/cascade.rb +36 -0
  75. data/lib/action_controller/vendor/rack-1.0/rack/chunked.rb +49 -0
  76. data/lib/action_controller/vendor/rack-1.0/rack/commonlogger.rb +61 -0
  77. data/lib/action_controller/vendor/rack-1.0/rack/conditionalget.rb +45 -0
  78. data/lib/action_controller/vendor/rack-1.0/rack/content_length.rb +29 -0
  79. data/lib/action_controller/vendor/rack-1.0/rack/content_type.rb +23 -0
  80. data/lib/action_controller/vendor/rack-1.0/rack/deflater.rb +85 -0
  81. data/lib/action_controller/vendor/rack-1.0/rack/directory.rb +153 -0
  82. data/lib/action_controller/vendor/rack-1.0/rack/file.rb +88 -0
  83. data/lib/action_controller/vendor/rack-1.0/rack/handler.rb +48 -0
  84. data/lib/action_controller/vendor/rack-1.0/rack/handler/cgi.rb +61 -0
  85. data/lib/action_controller/vendor/rack-1.0/rack/handler/evented_mongrel.rb +8 -0
  86. data/lib/action_controller/vendor/rack-1.0/rack/handler/fastcgi.rb +89 -0
  87. data/lib/action_controller/vendor/rack-1.0/rack/handler/lsws.rb +55 -0
  88. data/lib/action_controller/vendor/rack-1.0/rack/handler/mongrel.rb +84 -0
  89. data/lib/action_controller/vendor/rack-1.0/rack/handler/scgi.rb +59 -0
  90. data/lib/action_controller/vendor/rack-1.0/rack/handler/swiftiplied_mongrel.rb +8 -0
  91. data/lib/action_controller/vendor/rack-1.0/rack/handler/thin.rb +18 -0
  92. data/lib/action_controller/vendor/rack-1.0/rack/handler/webrick.rb +67 -0
  93. data/lib/action_controller/vendor/rack-1.0/rack/head.rb +19 -0
  94. data/lib/action_controller/vendor/rack-1.0/rack/lint.rb +462 -0
  95. data/lib/action_controller/vendor/rack-1.0/rack/lobster.rb +65 -0
  96. data/lib/action_controller/vendor/rack-1.0/rack/lock.rb +16 -0
  97. data/lib/action_controller/vendor/rack-1.0/rack/methodoverride.rb +27 -0
  98. data/lib/action_controller/vendor/rack-1.0/rack/mime.rb +204 -0
  99. data/lib/action_controller/vendor/rack-1.0/rack/mock.rb +160 -0
  100. data/lib/action_controller/vendor/rack-1.0/rack/recursive.rb +57 -0
  101. data/lib/action_controller/vendor/rack-1.0/rack/reloader.rb +64 -0
  102. data/lib/action_controller/vendor/rack-1.0/rack/request.rb +241 -0
  103. data/lib/action_controller/vendor/rack-1.0/rack/response.rb +179 -0
  104. data/lib/action_controller/vendor/rack-1.0/rack/session/abstract/id.rb +142 -0
  105. data/lib/action_controller/vendor/rack-1.0/rack/session/cookie.rb +91 -0
  106. data/lib/action_controller/vendor/rack-1.0/rack/session/memcache.rb +109 -0
  107. data/lib/action_controller/vendor/rack-1.0/rack/session/pool.rb +100 -0
  108. data/lib/action_controller/vendor/rack-1.0/rack/showexceptions.rb +349 -0
  109. data/lib/action_controller/vendor/rack-1.0/rack/showstatus.rb +106 -0
  110. data/lib/action_controller/vendor/rack-1.0/rack/static.rb +38 -0
  111. data/lib/action_controller/vendor/rack-1.0/rack/urlmap.rb +55 -0
  112. data/lib/action_controller/vendor/rack-1.0/rack/utils.rb +392 -0
  113. data/lib/action_controller/verification.rb +1 -1
  114. data/lib/action_pack.rb +1 -1
  115. data/lib/action_pack/version.rb +2 -2
  116. data/lib/action_view.rb +22 -17
  117. data/lib/action_view/base.rb +53 -79
  118. data/lib/action_view/erb/util.rb +38 -0
  119. data/lib/action_view/helpers.rb +24 -5
  120. data/lib/action_view/helpers/active_record_helper.rb +2 -2
  121. data/lib/action_view/helpers/asset_tag_helper.rb +81 -50
  122. data/lib/action_view/helpers/atom_feed_helper.rb +1 -1
  123. data/lib/action_view/helpers/benchmark_helper.rb +26 -5
  124. data/lib/action_view/helpers/date_helper.rb +82 -7
  125. data/lib/action_view/helpers/form_helper.rb +295 -64
  126. data/lib/action_view/helpers/form_options_helper.rb +160 -18
  127. data/lib/action_view/helpers/form_tag_helper.rb +2 -2
  128. data/lib/action_view/helpers/number_helper.rb +31 -18
  129. data/lib/action_view/helpers/prototype_helper.rb +2 -12
  130. data/lib/action_view/helpers/sanitize_helper.rb +0 -10
  131. data/lib/action_view/helpers/scriptaculous_helper.rb +1 -0
  132. data/lib/action_view/helpers/tag_helper.rb +3 -4
  133. data/lib/action_view/helpers/text_helper.rb +99 -122
  134. data/lib/action_view/helpers/translation_helper.rb +19 -1
  135. data/lib/action_view/helpers/url_helper.rb +25 -2
  136. data/lib/action_view/inline_template.rb +1 -1
  137. data/lib/action_view/locale/en.yml +19 -1
  138. data/lib/action_view/partials.rb +46 -9
  139. data/lib/action_view/paths.rb +28 -84
  140. data/lib/action_view/reloadable_template.rb +117 -0
  141. data/lib/action_view/renderable.rb +28 -35
  142. data/lib/action_view/renderable_partial.rb +3 -4
  143. data/lib/action_view/template.rb +172 -31
  144. data/lib/action_view/template_error.rb +8 -9
  145. data/lib/action_view/template_handler.rb +1 -1
  146. data/lib/action_view/template_handlers.rb +9 -6
  147. data/lib/action_view/template_handlers/erb.rb +2 -39
  148. data/lib/action_view/template_handlers/rjs.rb +1 -0
  149. data/lib/action_view/test_case.rb +27 -1
  150. data/test/abstract_unit.rb +23 -17
  151. data/test/active_record_unit.rb +5 -4
  152. data/test/activerecord/active_record_store_test.rb +139 -106
  153. data/test/activerecord/render_partial_with_record_identification_test.rb +5 -21
  154. data/test/controller/action_pack_assertions_test.rb +25 -23
  155. data/test/controller/addresses_render_test.rb +3 -6
  156. data/test/controller/assert_select_test.rb +83 -70
  157. data/test/controller/base_test.rb +11 -13
  158. data/test/controller/benchmark_test.rb +3 -3
  159. data/test/controller/caching_test.rb +34 -24
  160. data/test/controller/capture_test.rb +3 -6
  161. data/test/controller/content_type_test.rb +3 -6
  162. data/test/controller/cookie_test.rb +31 -66
  163. data/test/controller/deprecation/deprecated_base_methods_test.rb +9 -11
  164. data/test/controller/dispatcher_test.rb +23 -28
  165. data/test/controller/fake_models.rb +8 -0
  166. data/test/controller/filters_test.rb +6 -2
  167. data/test/controller/flash_test.rb +2 -6
  168. data/test/controller/helper_test.rb +15 -1
  169. data/test/controller/html-scanner/document_test.rb +1 -1
  170. data/test/controller/html-scanner/sanitizer_test.rb +1 -1
  171. data/test/controller/http_basic_authentication_test.rb +88 -0
  172. data/test/controller/http_digest_authentication_test.rb +178 -0
  173. data/test/controller/integration_test.rb +56 -52
  174. data/test/controller/layout_test.rb +46 -44
  175. data/test/controller/middleware_stack_test.rb +90 -0
  176. data/test/controller/mime_responds_test.rb +7 -11
  177. data/test/controller/mime_type_test.rb +9 -0
  178. data/test/controller/polymorphic_routes_test.rb +235 -151
  179. data/test/controller/rack_test.rb +52 -81
  180. data/test/controller/redirect_test.rb +6 -14
  181. data/test/controller/render_test.rb +273 -60
  182. data/test/controller/request/json_params_parsing_test.rb +45 -0
  183. data/test/controller/request/multipart_params_parsing_test.rb +223 -0
  184. data/test/controller/request/query_string_parsing_test.rb +120 -0
  185. data/test/controller/request/url_encoded_params_parsing_test.rb +184 -0
  186. data/test/controller/request/xml_params_parsing_test.rb +88 -0
  187. data/test/controller/request_forgery_protection_test.rb +17 -98
  188. data/test/controller/request_test.rb +45 -530
  189. data/test/controller/rescue_test.rb +45 -22
  190. data/test/controller/resources_test.rb +112 -37
  191. data/test/controller/routing_test.rb +1442 -1384
  192. data/test/controller/selector_test.rb +3 -3
  193. data/test/controller/send_file_test.rb +30 -3
  194. data/test/controller/session/cookie_store_test.rb +169 -240
  195. data/test/controller/session/mem_cache_store_test.rb +94 -148
  196. data/test/controller/session/test_session_test.rb +58 -0
  197. data/test/controller/test_test.rb +32 -13
  198. data/test/controller/url_rewriter_test.rb +54 -4
  199. data/test/controller/verification_test.rb +1 -1
  200. data/test/controller/view_paths_test.rb +15 -15
  201. data/test/controller/webservice_test.rb +178 -147
  202. data/test/fixtures/alternate_helpers/foo_helper.rb +3 -0
  203. data/test/fixtures/layout_tests/alt/layouts/alt.rhtml +0 -0
  204. data/test/fixtures/layouts/default_html.html.erb +1 -0
  205. data/test/fixtures/layouts/xhr.html.erb +2 -0
  206. data/test/fixtures/multipart/empty +10 -0
  207. data/test/fixtures/multipart/hello.txt +1 -0
  208. data/test/fixtures/multipart/none +9 -0
  209. data/test/fixtures/public/500.da.html +1 -0
  210. data/test/fixtures/quiz/questions/_question.html.erb +1 -0
  211. data/test/fixtures/replies.yml +1 -1
  212. data/test/fixtures/test/_one.html.erb +1 -0
  213. data/test/fixtures/test/_two.html.erb +1 -0
  214. data/test/fixtures/test/dont_pick_me +1 -0
  215. data/test/fixtures/test/hello.builder +1 -1
  216. data/test/fixtures/test/hello_world.da.html.erb +1 -0
  217. data/test/fixtures/test/hello_world.erb~ +1 -0
  218. data/test/fixtures/test/hello_world.pt-BR.html.erb +1 -0
  219. data/test/fixtures/test/malformed/malformed.en.html.erb~ +1 -0
  220. data/test/fixtures/test/malformed/malformed.erb~ +1 -0
  221. data/test/fixtures/test/malformed/malformed.html.erb~ +1 -0
  222. data/test/fixtures/test/render_explicit_html_template.js.rjs +1 -0
  223. data/test/fixtures/test/render_implicit_html_template.js.rjs +1 -0
  224. data/test/fixtures/test/render_implicit_html_template_from_xhr_request.da.html.erb +1 -0
  225. data/test/fixtures/test/render_implicit_html_template_from_xhr_request.html.erb +1 -0
  226. data/test/fixtures/test/render_implicit_js_template_without_layout.js.erb +1 -0
  227. data/test/fixtures/test/utf8.html.erb +2 -0
  228. data/test/template/active_record_helper_i18n_test.rb +31 -33
  229. data/test/template/active_record_helper_test.rb +34 -0
  230. data/test/template/asset_tag_helper_test.rb +52 -14
  231. data/test/template/atom_feed_helper_test.rb +3 -5
  232. data/test/template/benchmark_helper_test.rb +50 -24
  233. data/test/template/compiled_templates_test.rb +177 -33
  234. data/test/template/date_helper_i18n_test.rb +88 -81
  235. data/test/template/date_helper_test.rb +427 -43
  236. data/test/template/form_helper_test.rb +243 -44
  237. data/test/template/form_options_helper_test.rb +631 -565
  238. data/test/template/form_tag_helper_test.rb +9 -2
  239. data/test/template/javascript_helper_test.rb +0 -5
  240. data/test/template/number_helper_i18n_test.rb +60 -48
  241. data/test/template/number_helper_test.rb +1 -0
  242. data/test/template/render_test.rb +117 -35
  243. data/test/template/test_test.rb +4 -6
  244. data/test/template/text_helper_test.rb +129 -50
  245. data/test/template/translation_helper_test.rb +23 -19
  246. data/test/template/url_helper_test.rb +35 -2
  247. data/test/view/test_case_test.rb +8 -0
  248. metadata +197 -23
  249. data/lib/action_controller/assertions.rb +0 -69
  250. data/lib/action_controller/caching/sql_cache.rb +0 -18
  251. data/lib/action_controller/cgi_ext/session.rb +0 -53
  252. data/lib/action_controller/components.rb +0 -169
  253. data/lib/action_controller/rack_process.rb +0 -297
  254. data/lib/action_controller/request_profiler.rb +0 -169
  255. data/lib/action_controller/session/active_record_store.rb +0 -340
  256. data/lib/action_controller/session/drb_server.rb +0 -32
  257. data/lib/action_controller/session/drb_store.rb +0 -35
  258. data/test/controller/cgi_test.rb +0 -269
  259. data/test/controller/components_test.rb +0 -156
  260. data/test/controller/http_authentication_test.rb +0 -54
  261. data/test/controller/integration_upload_test.rb +0 -43
  262. data/test/controller/session_fixation_test.rb +0 -89
  263. data/test/controller/session_management_test.rb +0 -178
  264. data/test/fixtures/test/hello_world.js +0 -1
@@ -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.warn_cache_misses && defined?(Rails) && Rails.initialized?
6
- Base.logger.debug "[PERFORMANCE] Processing view path during a " +
7
- "request. This an expense disk operation that should be done at " +
8
- "boot. You can manually process this view path with " +
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
- class Path #:nodoc:
43
- def self.eager_load_templates!
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 reload!
113
- each { |path| path.reload! }
114
- end
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
- def [](template_path)
117
- each do |path|
118
- if template = path[template_path]
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
- nil
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
- memoize :compiled_source
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
- stack = view.instance_variable_get(:@_render_stack)
29
- stack.push(self)
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
- # This is only used for TestResponse to set rendered_template
32
- unless is_a?(InlineTemplate) || view.instance_variable_get(:@_first_render)
33
- view.instance_variable_set(:@_first_render, self)
34
- end
35
-
36
- view.send(:_evaluate_assigns_and_ivars)
37
- view.send(:_set_controller_content_type, mime_type) if respond_to?(:mime_type)
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
- local_assigns_keys = "locals_#{local_assigns.keys.map { |k| k.to_s }.sort.join('_')}"
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
- ['_run', extension, method_segment, local_assigns_keys].compact.join('_').to_sym
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
- @@mutex.synchronize do
65
- if recompile?(render_symbol)
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
- # Method to check whether template compilation is necessary.
96
- # The template will be compiled if the file has not been compiled yet, or
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),
@@ -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
- attr_accessor :filename, :load_path, :base_path, :name, :format, :extension
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, load_paths = [])
13
- template_path = template_path.dup
14
- @base_path, @name, @format, @extension = split(template_path)
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.template_handler_extensions.include?(extension)
211
+ !Template.registered_template_handler(extension).nil?
87
212
  end
88
213
 
89
- def find_full_path(path, load_paths)
90
- load_paths = Array(load_paths) + [nil]
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(/^(.*\/)?([^\.]+)\.?(\w+)?\.?(\w+)?\.?(\w+)?$/)
102
- if m[5] # Multipart formats
103
- [m[1], m[2], "#{m[3]}.#{m[4]}", m[5]]
104
- elsif m[4] # Single format
105
- [m[1], m[2], m[3], m[4]]
106
- else
107
- if valid_extension?(m[3]) # No format
108
- [m[1], m[2], nil, m[3]]
109
- else # No extension
110
- [m[1], m[2], m[3], nil]
111
- end
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