actionpack 2.0.5 → 2.1.0

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 (210) hide show
  1. data/CHANGELOG +149 -7
  2. data/MIT-LICENSE +1 -1
  3. data/README +1 -1
  4. data/Rakefile +5 -6
  5. data/lib/action_controller.rb +2 -2
  6. data/lib/action_controller/assertions/model_assertions.rb +2 -1
  7. data/lib/action_controller/assertions/response_assertions.rb +4 -2
  8. data/lib/action_controller/assertions/routing_assertions.rb +3 -3
  9. data/lib/action_controller/assertions/selector_assertions.rb +30 -27
  10. data/lib/action_controller/assertions/tag_assertions.rb +3 -3
  11. data/lib/action_controller/base.rb +103 -129
  12. data/lib/action_controller/benchmarking.rb +3 -3
  13. data/lib/action_controller/caching.rb +41 -652
  14. data/lib/action_controller/caching/actions.rb +144 -0
  15. data/lib/action_controller/caching/fragments.rb +138 -0
  16. data/lib/action_controller/caching/pages.rb +154 -0
  17. data/lib/action_controller/caching/sql_cache.rb +18 -0
  18. data/lib/action_controller/caching/sweeping.rb +97 -0
  19. data/lib/action_controller/cgi_ext/cookie.rb +27 -23
  20. data/lib/action_controller/cgi_ext/stdinput.rb +1 -0
  21. data/lib/action_controller/cgi_process.rb +6 -4
  22. data/lib/action_controller/components.rb +7 -6
  23. data/lib/action_controller/cookies.rb +31 -19
  24. data/lib/action_controller/dispatcher.rb +51 -84
  25. data/lib/action_controller/filters.rb +295 -421
  26. data/lib/action_controller/flash.rb +1 -6
  27. data/lib/action_controller/headers.rb +31 -0
  28. data/lib/action_controller/helpers.rb +26 -9
  29. data/lib/action_controller/http_authentication.rb +1 -1
  30. data/lib/action_controller/integration.rb +65 -13
  31. data/lib/action_controller/layout.rb +24 -39
  32. data/lib/action_controller/mime_responds.rb +7 -3
  33. data/lib/action_controller/mime_type.rb +25 -9
  34. data/lib/action_controller/mime_types.rb +1 -1
  35. data/lib/action_controller/polymorphic_routes.rb +32 -17
  36. data/lib/action_controller/record_identifier.rb +10 -4
  37. data/lib/action_controller/request.rb +46 -30
  38. data/lib/action_controller/request_forgery_protection.rb +10 -9
  39. data/lib/action_controller/request_profiler.rb +29 -8
  40. data/lib/action_controller/rescue.rb +24 -24
  41. data/lib/action_controller/resources.rb +66 -23
  42. data/lib/action_controller/response.rb +2 -2
  43. data/lib/action_controller/routing.rb +113 -1229
  44. data/lib/action_controller/routing/builder.rb +204 -0
  45. data/lib/action_controller/{routing_optimisation.rb → routing/optimisations.rb} +13 -12
  46. data/lib/action_controller/routing/recognition_optimisation.rb +158 -0
  47. data/lib/action_controller/routing/route.rb +240 -0
  48. data/lib/action_controller/routing/route_set.rb +435 -0
  49. data/lib/action_controller/routing/routing_ext.rb +46 -0
  50. data/lib/action_controller/routing/segments.rb +283 -0
  51. data/lib/action_controller/session/active_record_store.rb +13 -8
  52. data/lib/action_controller/session/cookie_store.rb +20 -17
  53. data/lib/action_controller/session_management.rb +10 -3
  54. data/lib/action_controller/streaming.rb +45 -31
  55. data/lib/action_controller/test_case.rb +33 -23
  56. data/lib/action_controller/test_process.rb +39 -35
  57. data/lib/action_controller/url_rewriter.rb +18 -12
  58. data/lib/action_controller/vendor/html-scanner/html/tokenizer.rb +1 -1
  59. data/lib/action_pack.rb +1 -1
  60. data/lib/action_pack/version.rb +2 -2
  61. data/lib/action_view.rb +11 -3
  62. data/lib/action_view/base.rb +73 -390
  63. data/lib/action_view/helpers/active_record_helper.rb +83 -62
  64. data/lib/action_view/helpers/asset_tag_helper.rb +101 -44
  65. data/lib/action_view/helpers/atom_feed_helper.rb +35 -7
  66. data/lib/action_view/helpers/benchmark_helper.rb +5 -3
  67. data/lib/action_view/helpers/cache_helper.rb +3 -2
  68. data/lib/action_view/helpers/capture_helper.rb +1 -2
  69. data/lib/action_view/helpers/date_helper.rb +104 -82
  70. data/lib/action_view/helpers/form_helper.rb +148 -75
  71. data/lib/action_view/helpers/form_options_helper.rb +44 -23
  72. data/lib/action_view/helpers/form_tag_helper.rb +22 -13
  73. data/lib/action_view/helpers/javascripts/controls.js +1 -1
  74. data/lib/action_view/helpers/javascripts/dragdrop.js +1 -1
  75. data/lib/action_view/helpers/javascripts/effects.js +1 -1
  76. data/lib/action_view/helpers/number_helper.rb +10 -3
  77. data/lib/action_view/helpers/prototype_helper.rb +61 -29
  78. data/lib/action_view/helpers/record_tag_helper.rb +3 -3
  79. data/lib/action_view/helpers/sanitize_helper.rb +23 -17
  80. data/lib/action_view/helpers/scriptaculous_helper.rb +86 -60
  81. data/lib/action_view/helpers/text_helper.rb +153 -125
  82. data/lib/action_view/helpers/url_helper.rb +83 -28
  83. data/lib/action_view/inline_template.rb +20 -0
  84. data/lib/action_view/partial_template.rb +70 -0
  85. data/lib/action_view/partials.rb +31 -73
  86. data/lib/action_view/template.rb +127 -0
  87. data/lib/action_view/template_error.rb +8 -7
  88. data/lib/action_view/template_finder.rb +177 -0
  89. data/lib/action_view/template_handler.rb +18 -1
  90. data/lib/action_view/template_handlers/builder.rb +10 -2
  91. data/lib/action_view/template_handlers/compilable.rb +128 -0
  92. data/lib/action_view/template_handlers/erb.rb +37 -2
  93. data/lib/action_view/template_handlers/rjs.rb +14 -1
  94. data/lib/action_view/test_case.rb +58 -0
  95. data/test/abstract_unit.rb +1 -1
  96. data/test/active_record_unit.rb +3 -6
  97. data/test/activerecord/active_record_store_test.rb +1 -2
  98. data/test/activerecord/render_partial_with_record_identification_test.rb +158 -41
  99. data/test/adv_attr_test.rb +20 -0
  100. data/test/controller/action_pack_assertions_test.rb +16 -19
  101. data/test/controller/addresses_render_test.rb +1 -1
  102. data/test/controller/assert_select_test.rb +13 -6
  103. data/test/controller/base_test.rb +48 -2
  104. data/test/controller/benchmark_test.rb +1 -2
  105. data/test/controller/caching_test.rb +282 -21
  106. data/test/controller/capture_test.rb +1 -1
  107. data/test/controller/cgi_test.rb +1 -1
  108. data/test/controller/components_test.rb +1 -1
  109. data/test/controller/content_type_test.rb +2 -2
  110. data/test/controller/cookie_test.rb +13 -2
  111. data/test/controller/custom_handler_test.rb +14 -10
  112. data/test/controller/deprecation/deprecated_base_methods_test.rb +1 -1
  113. data/test/controller/dispatcher_test.rb +31 -49
  114. data/test/controller/fake_controllers.rb +17 -0
  115. data/test/controller/fake_models.rb +6 -0
  116. data/test/controller/filter_params_test.rb +14 -8
  117. data/test/controller/filters_test.rb +44 -16
  118. data/test/controller/flash_test.rb +2 -2
  119. data/test/controller/header_test.rb +14 -0
  120. data/test/controller/helper_test.rb +19 -15
  121. data/test/controller/html-scanner/document_test.rb +1 -2
  122. data/test/controller/html-scanner/node_test.rb +1 -2
  123. data/test/controller/html-scanner/sanitizer_test.rb +8 -5
  124. data/test/controller/html-scanner/tag_node_test.rb +1 -2
  125. data/test/controller/html-scanner/text_node_test.rb +2 -3
  126. data/test/controller/html-scanner/tokenizer_test.rb +8 -2
  127. data/test/controller/http_authentication_test.rb +1 -1
  128. data/test/controller/integration_test.rb +14 -16
  129. data/test/controller/integration_upload_test.rb +43 -0
  130. data/test/controller/layout_test.rb +26 -6
  131. data/test/controller/mime_responds_test.rb +39 -7
  132. data/test/controller/mime_type_test.rb +29 -5
  133. data/test/controller/new_render_test.rb +105 -34
  134. data/test/controller/polymorphic_routes_test.rb +32 -20
  135. data/test/controller/record_identifier_test.rb +38 -2
  136. data/test/controller/redirect_test.rb +21 -1
  137. data/test/controller/render_test.rb +59 -15
  138. data/test/controller/request_forgery_protection_test.rb +92 -5
  139. data/test/controller/request_test.rb +64 -6
  140. data/test/controller/rescue_test.rb +22 -6
  141. data/test/controller/resources_test.rb +102 -14
  142. data/test/controller/routing_test.rb +231 -19
  143. data/test/controller/selector_test.rb +2 -2
  144. data/test/controller/send_file_test.rb +14 -3
  145. data/test/controller/session/cookie_store_test.rb +16 -4
  146. data/test/controller/session/mem_cache_store_test.rb +3 -4
  147. data/test/controller/session_fixation_test.rb +1 -1
  148. data/test/controller/session_management_test.rb +23 -1
  149. data/test/controller/test_test.rb +39 -18
  150. data/test/controller/url_rewriter_test.rb +35 -1
  151. data/test/controller/verification_test.rb +1 -1
  152. data/test/controller/view_paths_test.rb +15 -12
  153. data/test/controller/webservice_test.rb +48 -3
  154. data/test/fixtures/bad_customers/_bad_customer.html.erb +1 -0
  155. data/test/fixtures/company.rb +1 -0
  156. data/test/fixtures/customers/_customer.html.erb +1 -0
  157. data/test/fixtures/db_definitions/sqlite.sql +6 -0
  158. data/test/fixtures/functional_caching/_partial.erb +3 -0
  159. data/test/fixtures/functional_caching/fragment_cached.html.erb +2 -0
  160. data/test/fixtures/functional_caching/html_fragment_cached_with_partial.html.erb +1 -0
  161. data/test/fixtures/functional_caching/js_fragment_cached_with_partial.js.rjs +1 -0
  162. data/test/fixtures/good_customers/_good_customer.html.erb +1 -0
  163. data/test/fixtures/mascot.rb +3 -0
  164. data/test/fixtures/mascots.yml +4 -0
  165. data/test/fixtures/mascots/_mascot.html.erb +1 -0
  166. data/test/fixtures/multipart/boundary_problem_file +10 -0
  167. data/test/fixtures/public/javascripts/application.js +1 -0
  168. data/test/fixtures/public/javascripts/controls.js +1 -0
  169. data/test/fixtures/public/javascripts/dragdrop.js +1 -0
  170. data/test/fixtures/public/javascripts/effects.js +1 -0
  171. data/test/fixtures/public/javascripts/prototype.js +1 -0
  172. data/test/fixtures/public/javascripts/version.1.0.js +1 -0
  173. data/test/fixtures/public/stylesheets/version.1.0.css +1 -0
  174. data/test/fixtures/reply.rb +1 -0
  175. data/test/fixtures/shared.html.erb +1 -0
  176. data/test/fixtures/symlink_parent/symlinked_layout.erb +5 -0
  177. data/test/fixtures/test/_customer_counter.erb +1 -0
  178. data/test/fixtures/test/_form.erb +1 -0
  179. data/test/fixtures/test/_labelling_form.erb +1 -0
  180. data/test/fixtures/test/_raise.html.erb +1 -0
  181. data/test/fixtures/test/greeting.js.rjs +1 -0
  182. data/test/fixtures/topics/_topic.html.erb +1 -0
  183. data/test/template/active_record_helper_test.rb +25 -8
  184. data/test/template/asset_tag_helper_test.rb +100 -17
  185. data/test/template/atom_feed_helper_test.rb +29 -1
  186. data/test/template/benchmark_helper_test.rb +10 -22
  187. data/test/template/date_helper_test.rb +455 -153
  188. data/test/template/erb_util_test.rb +10 -42
  189. data/test/template/form_helper_test.rb +192 -66
  190. data/test/template/form_options_helper_test.rb +19 -8
  191. data/test/template/form_tag_helper_test.rb +11 -8
  192. data/test/template/javascript_helper_test.rb +3 -9
  193. data/test/template/number_helper_test.rb +6 -3
  194. data/test/template/prototype_helper_test.rb +27 -40
  195. data/test/template/record_tag_helper_test.rb +54 -0
  196. data/test/template/sanitize_helper_test.rb +5 -6
  197. data/test/template/scriptaculous_helper_test.rb +7 -13
  198. data/test/template/tag_helper_test.rb +3 -6
  199. data/test/template/template_finder_test.rb +73 -0
  200. data/test/template/template_object_test.rb +95 -0
  201. data/test/template/test_test.rb +56 -0
  202. data/test/template/text_helper_test.rb +46 -33
  203. data/test/template/url_helper_test.rb +8 -10
  204. metadata +65 -12
  205. data/lib/action_view/compiled_templates.rb +0 -69
  206. data/test/action_view_test.rb +0 -44
  207. data/test/activerecord/fixtures_test.rb +0 -24
  208. data/test/controller/fragment_store_setting_test.rb +0 -47
  209. data/test/template/compiled_templates_test.rb +0 -197
  210. data/test/template/deprecate_ivars_test.rb +0 -51
@@ -16,7 +16,30 @@ module ActionController
16
16
  end
17
17
 
18
18
  class TestCase < ActiveSupport::TestCase
19
+ # When the request.remote_addr remains the default for testing, which is 0.0.0.0, the exception is simply raised inline
20
+ # (bystepping the regular exception handling from rescue_action). If the request.remote_addr is anything else, the regular
21
+ # rescue_action process takes place. This means you can test your rescue_action code by setting remote_addr to something else
22
+ # than 0.0.0.0.
23
+ #
24
+ # The exception is stored in the exception accessor for further inspection.
25
+ module RaiseActionExceptions
26
+ attr_accessor :exception
27
+
28
+ def rescue_action(e)
29
+ self.exception = e
30
+
31
+ if request.remote_addr == "0.0.0.0"
32
+ raise(e)
33
+ else
34
+ super(e)
35
+ end
36
+ end
37
+ end
38
+
39
+ setup :setup_controller_request_and_response
40
+
19
41
  @@controller_class = nil
42
+
20
43
  class << self
21
44
  def tests(controller_class)
22
45
  self.controller_class = controller_class
@@ -31,7 +54,7 @@ module ActionController
31
54
  if current_controller_class = read_inheritable_attribute(:controller_class)
32
55
  current_controller_class
33
56
  else
34
- self.controller_class= determine_default_controller_class(name)
57
+ self.controller_class = determine_default_controller_class(name)
35
58
  end
36
59
  end
37
60
 
@@ -42,32 +65,19 @@ module ActionController
42
65
  end
43
66
 
44
67
  def prepare_controller_class(new_class)
45
- new_class.class_eval do
46
- def rescue_action(e)
47
- raise e
48
- end
49
- end
68
+ new_class.send :include, RaiseActionExceptions
50
69
  end
51
70
  end
52
71
 
53
- def setup_with_controller
72
+ def setup_controller_request_and_response
54
73
  @controller = self.class.controller_class.new
55
- @request = TestRequest.new
56
- @response = TestResponse.new
74
+ @controller.request = @request = TestRequest.new
75
+ @response = TestResponse.new
57
76
  end
58
- alias_method :setup, :setup_with_controller
59
-
60
- def self.method_added(method)
61
- if method.to_s == 'setup'
62
- unless method_defined?(:setup_without_controller)
63
- alias_method :setup_without_controller, :setup
64
- define_method(:setup) do
65
- setup_with_fixtures if respond_to?(:setup_with_fixtures)
66
- setup_with_controller
67
- setup_without_controller
68
- end
69
- end
70
- end
77
+
78
+ # Cause the action to be rescued according to the regular rules for rescue_action when the visitor is not local
79
+ def rescue_action_in_public!
80
+ @request.remote_addr = '208.77.188.166' # example.com
71
81
  end
72
82
  end
73
- end
83
+ end
@@ -1,8 +1,9 @@
1
1
  require 'action_controller/assertions'
2
+ require 'action_controller/test_case'
2
3
 
3
4
  module ActionController #:nodoc:
4
5
  class Base
5
- # Process a test request called with a +TestRequest+ object.
6
+ # Process a test request called with a TestRequest object.
6
7
  def self.process_test(request)
7
8
  new.process_test(request)
8
9
  end
@@ -48,7 +49,7 @@ module ActionController #:nodoc:
48
49
  # Either the RAW_POST_DATA environment variable or the URL-encoded request
49
50
  # parameters.
50
51
  def raw_post
51
- env['RAW_POST_DATA'] ||= url_encoded_request_parameters
52
+ env['RAW_POST_DATA'] ||= returning(url_encoded_request_parameters) { |b| b.force_encoding(Encoding::BINARY) if b.respond_to?(:force_encoding) }
52
53
  end
53
54
 
54
55
  def port=(number)
@@ -154,12 +155,12 @@ module ActionController #:nodoc:
154
155
  # A refactoring of TestResponse to allow the same behavior to be applied
155
156
  # to the "real" CgiResponse class in integration tests.
156
157
  module TestResponseBehavior #:nodoc:
157
- # the response code of the request
158
+ # The response code of the request
158
159
  def response_code
159
160
  headers['Status'][0,3].to_i rescue 0
160
161
  end
161
162
 
162
- # returns a String to ensure compatibility with Net::HTTPResponse
163
+ # Returns a String to ensure compatibility with Net::HTTPResponse
163
164
  def code
164
165
  headers['Status'].to_s.split(' ')[0]
165
166
  end
@@ -168,34 +169,34 @@ module ActionController #:nodoc:
168
169
  headers['Status'].to_s.split(' ',2)[1]
169
170
  end
170
171
 
171
- # was the response successful?
172
+ # Was the response successful?
172
173
  def success?
173
174
  response_code == 200
174
175
  end
175
176
 
176
- # was the URL not found?
177
+ # Was the URL not found?
177
178
  def missing?
178
179
  response_code == 404
179
180
  end
180
181
 
181
- # were we redirected?
182
+ # Were we redirected?
182
183
  def redirect?
183
184
  (300..399).include?(response_code)
184
185
  end
185
186
 
186
- # was there a server-side error?
187
+ # Was there a server-side error?
187
188
  def error?
188
189
  (500..599).include?(response_code)
189
190
  end
190
191
 
191
192
  alias_method :server_error?, :error?
192
193
 
193
- # returns the redirection location or nil
194
+ # Returns the redirection location or nil
194
195
  def redirect_url
195
196
  headers['Location']
196
197
  end
197
198
 
198
- # does the redirect location match this regexp pattern?
199
+ # Does the redirect location match this regexp pattern?
199
200
  def redirect_url_match?( pattern )
200
201
  return false if redirect_url.nil?
201
202
  p = Regexp.new(pattern) if pattern.class == String
@@ -204,7 +205,7 @@ module ActionController #:nodoc:
204
205
  p.match(redirect_url) != nil
205
206
  end
206
207
 
207
- # returns the template path of the file which was used to
208
+ # Returns the template path of the file which was used to
208
209
  # render this response (or nil)
209
210
  def rendered_file(with_controller=false)
210
211
  unless template.first_render.nil?
@@ -216,50 +217,49 @@ module ActionController #:nodoc:
216
217
  end
217
218
  end
218
219
 
219
- # was this template rendered by a file?
220
+ # Was this template rendered by a file?
220
221
  def rendered_with_file?
221
222
  !rendered_file.nil?
222
223
  end
223
224
 
224
- # a shortcut to the flash (or an empty hash if no flash.. hey! that rhymes!)
225
+ # A shortcut to the flash. Returns an empyt hash if no session flash exists.
225
226
  def flash
226
227
  session['flash'] || {}
227
228
  end
228
229
 
229
- # do we have a flash?
230
+ # Do we have a flash?
230
231
  def has_flash?
231
232
  !session['flash'].empty?
232
233
  end
233
234
 
234
- # do we have a flash that has contents?
235
+ # Do we have a flash that has contents?
235
236
  def has_flash_with_contents?
236
237
  !flash.empty?
237
238
  end
238
239
 
239
- # does the specified flash object exist?
240
+ # Does the specified flash object exist?
240
241
  def has_flash_object?(name=nil)
241
242
  !flash[name].nil?
242
243
  end
243
244
 
244
- # does the specified object exist in the session?
245
+ # Does the specified object exist in the session?
245
246
  def has_session_object?(name=nil)
246
247
  !session[name].nil?
247
248
  end
248
249
 
249
- # a shortcut to the template.assigns
250
+ # A shortcut to the template.assigns
250
251
  def template_objects
251
252
  template.assigns || {}
252
253
  end
253
254
 
254
- # does the specified template object exist?
255
+ # Does the specified template object exist?
255
256
  def has_template_object?(name=nil)
256
257
  !template_objects[name].nil?
257
258
  end
258
259
 
259
260
  # Returns the response cookies, converted to a Hash of (name => CGI::Cookie) pairs
260
- # Example:
261
261
  #
262
- # assert_equal ['AuthorOfNewPage'], r.cookies['author'].value
262
+ # assert_equal ['AuthorOfNewPage'], r.cookies['author'].value
263
263
  def cookies
264
264
  headers['cookie'].inject({}) { |hash, cookie| hash[cookie.name] = cookie; hash }
265
265
  end
@@ -340,6 +340,7 @@ module ActionController #:nodoc:
340
340
  @content_type = content_type
341
341
  @original_filename = path.sub(/^.*#{File::SEPARATOR}([^#{File::SEPARATOR}]+)$/) { $1 }
342
342
  @tempfile = Tempfile.new(@original_filename)
343
+ @tempfile.set_encoding(Encoding::BINARY) if @tempfile.respond_to?(:set_encoding)
343
344
  @tempfile.binmode if binary
344
345
  FileUtils.copy_file(path, @tempfile.path)
345
346
  end
@@ -357,7 +358,7 @@ module ActionController #:nodoc:
357
358
 
358
359
  module TestProcess
359
360
  def self.included(base)
360
- # execute the request simulating a specific http method and set/volley the response
361
+ # execute the request simulating a specific HTTP method and set/volley the response
361
362
  %w( get post put delete head ).each do |method|
362
363
  base.class_eval <<-EOV, __FILE__, __LINE__
363
364
  def #{method}(action, parameters = nil, session = nil, flash = nil)
@@ -373,7 +374,7 @@ module ActionController #:nodoc:
373
374
  # Sanity check for required instance variables so we can give an
374
375
  # understandable error message.
375
376
  %w(@controller @request @response).each do |iv_name|
376
- if !(instance_variables.include?(iv_name) || instance_variables.include?(iv_name.to_sym)) || instance_variable_get(iv_name).nil?
377
+ if !(instance_variable_names.include?(iv_name) || instance_variable_names.include?(iv_name.to_sym)) || instance_variable_get(iv_name).nil?
377
378
  raise "#{iv_name} is nil: make sure you set it in your test's setup method."
378
379
  end
379
380
  end
@@ -464,10 +465,13 @@ module ActionController #:nodoc:
464
465
  return super
465
466
  end
466
467
 
467
- # Shortcut for ActionController::TestUploadedFile.new(Test::Unit::TestCase.fixture_path + path, type). Example:
468
+ # Shortcut for <tt>ActionController::TestUploadedFile.new(Test::Unit::TestCase.fixture_path + path, type)</tt>:
469
+ #
468
470
  # post :change_avatar, :avatar => fixture_file_upload('/files/spongebob.png', 'image/png')
469
471
  #
470
- # To upload binary files on Windows, pass :binary as the last parameter. This will not affect other platforms.
472
+ # To upload binary files on Windows, pass <tt>:binary</tt> as the last parameter.
473
+ # This will not affect other platforms:
474
+ #
471
475
  # post :change_avatar, :avatar => fixture_file_upload('/files/spongebob.png', 'image/png', :binary)
472
476
  def fixture_file_upload(path, mime_type = nil, binary = false)
473
477
  ActionController::TestUploadedFile.new(
@@ -482,17 +486,17 @@ module ActionController #:nodoc:
482
486
  # with a new RouteSet instance.
483
487
  #
484
488
  # The new instance is yielded to the passed block. Typically the block
485
- # will create some routes using map.draw { map.connect ... }:
489
+ # will create some routes using <tt>map.draw { map.connect ... }</tt>:
486
490
  #
487
- # with_routing do |set|
488
- # set.draw do |map|
489
- # map.connect ':controller/:action/:id'
490
- # assert_equal(
491
- # ['/content/10/show', {}],
492
- # map.generate(:controller => 'content', :id => 10, :action => 'show')
493
- # end
494
- # end
495
- # end
491
+ # with_routing do |set|
492
+ # set.draw do |map|
493
+ # map.connect ':controller/:action/:id'
494
+ # assert_equal(
495
+ # ['/content/10/show', {}],
496
+ # map.generate(:controller => 'content', :id => 10, :action => 'show')
497
+ # end
498
+ # end
499
+ # end
496
500
  #
497
501
  def with_routing
498
502
  real_routes = ActionController::Routing::Routes
@@ -15,8 +15,8 @@ module ActionController
15
15
  # In addition to providing +url_for+, named routes are also accessible after
16
16
  # including UrlWriter.
17
17
  module UrlWriter
18
- # The default options for urls written by this writer. Typically a :host pair
19
- # is provided.
18
+ # The default options for urls written by this writer. Typically a <tt>:host</tt>
19
+ # pair is provided.
20
20
  mattr_accessor :default_url_options
21
21
  self.default_url_options = {}
22
22
 
@@ -29,20 +29,25 @@ module ActionController
29
29
  # Generate a url based on the options provided, default_url_options and the
30
30
  # routes defined in routes.rb. The following options are supported:
31
31
  #
32
- # * <tt>:only_path</tt> If true, the relative url is returned. Defaults to false.
33
- # * <tt>:protocol</tt> The protocol to connect to. Defaults to 'http'.
34
- # * <tt>:host</tt> Specifies the host the link should be targetted at. If <tt>:only_path</tt> is false, this option must be
35
- # provided either explicitly, or via default_url_options.
36
- # * <tt>:port</tt> Optionally specify the port to connect to.
37
- # * <tt>:anchor</tt> An anchor name to be appended to the path.
38
- # * <tt>:skip_relative_url_root</tt> If true, the url is not constructed using the relative_url_root set in <tt>ActionController::AbstractRequest.relative_url_root</tt>.
32
+ # * <tt>:only_path</tt> - If true, the relative url is returned. Defaults to +false+.
33
+ # * <tt>:protocol</tt> - The protocol to connect to. Defaults to 'http'.
34
+ # * <tt>:host</tt> - Specifies the host the link should be targetted at.
35
+ # If <tt>:only_path</tt> is false, this option must be
36
+ # provided either explicitly, or via +default_url_options+.
37
+ # * <tt>:port</tt> - Optionally specify the port to connect to.
38
+ # * <tt>:anchor</tt> - An anchor name to be appended to the path.
39
+ # * <tt>:skip_relative_url_root</tt> - If true, the url is not constructed using the
40
+ # +relative_url_root+ set in ActionController::AbstractRequest.relative_url_root.
41
+ # * <tt>:trailing_slash</tt> - If true, adds a trailing slash, as in "/archive/2009/"
39
42
  #
40
- # Any other key(:controller, :action, etc...) given to <tt>url_for</tt> is forwarded to the Routes module.
43
+ # Any other key (<tt>:controller</tt>, <tt>:action</tt>, etc.) given to
44
+ # +url_for+ is forwarded to the Routes module.
41
45
  #
42
46
  # Examples:
43
47
  #
44
48
  # url_for :controller => 'tasks', :action => 'testing', :host=>'somehost.org', :port=>'8080' # => 'http://somehost.org:8080/tasks/testing'
45
49
  # url_for :controller => 'tasks', :action => 'testing', :host=>'somehost.org', :anchor => 'ok', :only_path => true # => '/tasks/testing#ok'
50
+ # url_for :controller => 'tasks', :action => 'testing', :trailing_slash=>true # => 'http://somehost.org/tasks/testing/'
46
51
  # url_for :controller => 'tasks', :action => 'testing', :host=>'somehost.org', :number => '33' # => 'http://somehost.org/tasks/testing?number=33'
47
52
  def url_for(options)
48
53
  options = self.class.default_url_options.merge(options)
@@ -61,10 +66,11 @@ module ActionController
61
66
  # Delete the unused options to prevent their appearance in the query string.
62
67
  [:protocol, :host, :port, :skip_relative_url_root].each { |k| options.delete(k) }
63
68
  end
64
-
69
+ trailing_slash = options.delete(:trailing_slash) if options.key?(:trailing_slash)
65
70
  url << ActionController::AbstractRequest.relative_url_root.to_s unless options[:skip_relative_url_root]
66
71
  anchor = "##{CGI.escape options.delete(:anchor).to_param.to_s}" if options[:anchor]
67
- url << Routing::Routes.generate(options, {})
72
+ generated = Routing::Routes.generate(options, {})
73
+ url << (trailing_slash ? generated.sub(/\?|\z/) { "/" + $& } : generated)
68
74
  url << anchor if anchor
69
75
 
70
76
  url
@@ -54,7 +54,7 @@ module HTML #:nodoc:
54
54
  tag << (@scanner.scan_until(/--\s*>/) || @scanner.scan_until(/\Z/))
55
55
  elsif @scanner.scan(/!\[CDATA\[/)
56
56
  tag << @scanner.matched
57
- tag << @scanner.scan_until(/\]\]>/)
57
+ tag << (@scanner.scan_until(/\]\]>/) || @scanner.scan_until(/\Z/))
58
58
  elsif @scanner.scan(/!/) # doctype
59
59
  tag << @scanner.matched
60
60
  tag << consume_quoted_regions
@@ -1,5 +1,5 @@
1
1
  #--
2
- # Copyright (c) 2004-2007 David Heinemeier Hansson
2
+ # Copyright (c) 2004-2008 David Heinemeier Hansson
3
3
  #
4
4
  # Permission is hereby granted, free of charge, to any person obtaining
5
5
  # a copy of this software and associated documentation files (the
@@ -1,8 +1,8 @@
1
1
  module ActionPack #:nodoc:
2
2
  module VERSION #:nodoc:
3
3
  MAJOR = 2
4
- MINOR = 0
5
- TINY = 5
4
+ MINOR = 1
5
+ TINY = 0
6
6
 
7
7
  STRING = [MAJOR, MINOR, TINY].join('.')
8
8
  end
@@ -1,5 +1,5 @@
1
1
  #--
2
- # Copyright (c) 2004-2007 David Heinemeier Hansson
2
+ # Copyright (c) 2004-2008 David Heinemeier Hansson
3
3
  #
4
4
  # Permission is hereby granted, free of charge, to any person obtaining
5
5
  # a copy of this software and associated documentation files (the
@@ -22,16 +22,24 @@
22
22
  #++
23
23
 
24
24
  require 'action_view/template_handler'
25
+ require 'action_view/template_handlers/compilable'
25
26
  require 'action_view/template_handlers/builder'
26
27
  require 'action_view/template_handlers/erb'
27
28
  require 'action_view/template_handlers/rjs'
28
29
 
30
+ require 'action_view/template_finder'
31
+ require 'action_view/template'
32
+ require 'action_view/partial_template'
33
+ require 'action_view/inline_template'
34
+
29
35
  require 'action_view/base'
30
36
  require 'action_view/partials'
31
37
  require 'action_view/template_error'
32
38
 
33
39
  ActionView::Base.class_eval do
34
40
  include ActionView::Partials
35
- end
36
41
 
37
- ActionView::Base.load_helpers
42
+ ActionView::Base.helper_modules.each do |helper_module|
43
+ include helper_module
44
+ end
45
+ end
@@ -1,10 +1,13 @@
1
1
  module ActionView #:nodoc:
2
2
  class ActionViewError < StandardError #:nodoc:
3
3
  end
4
+
5
+ class MissingTemplate < ActionViewError #:nodoc:
6
+ end
4
7
 
5
- # Action View templates can be written in three ways. If the template file has a +.erb+ (or +.rhtml+) extension then it uses a mixture of ERb
6
- # (included in Ruby) and HTML. If the template file has a +.builder+ (or +.rxml+) extension then Jim Weirich's Builder::XmlMarkup library is used.
7
- # If the template file has a +.rjs+ extension then it will use ActionView::Helpers::PrototypeHelper::JavaScriptGenerator.
8
+ # Action View templates can be written in three ways. If the template file has a <tt>.erb</tt> (or <tt>.rhtml</tt>) extension then it uses a mixture of ERb
9
+ # (included in Ruby) and HTML. If the template file has a <tt>.builder</tt> (or <tt>.rxml</tt>) extension then Jim Weirich's Builder::XmlMarkup library is used.
10
+ # If the template file has a <tt>.rjs</tt> extension then it will use ActionView::Helpers::PrototypeHelper::JavaScriptGenerator.
8
11
  #
9
12
  # = ERb
10
13
  #
@@ -21,7 +24,7 @@ module ActionView #:nodoc:
21
24
  #
22
25
  # Hi, Mr. <% puts "Frodo" %>
23
26
  #
24
- # If you absolutely must write from within a function, you can use the TextHelper#concat
27
+ # If you absolutely must write from within a function, you can use the TextHelper#concat.
25
28
  #
26
29
  # <%- and -%> suppress leading and trailing whitespace, including the trailing newline, and can be used interchangeably with <% and %>.
27
30
  #
@@ -43,7 +46,7 @@ module ActionView #:nodoc:
43
46
  # <% @page_title = "A Wonderful Hello" %>
44
47
  # <%= render "shared/header" %>
45
48
  #
46
- # Now the header can pick up on the @page_title variable and use it for outputting a title tag:
49
+ # Now the header can pick up on the <tt>@page_title</tt> variable and use it for outputting a title tag:
47
50
  #
48
51
  # <title><%= @page_title %></title>
49
52
  #
@@ -53,7 +56,7 @@ module ActionView #:nodoc:
53
56
  #
54
57
  # <%= render "shared/header", { :headline => "Welcome", :person => person } %>
55
58
  #
56
- # These can now be accessed in shared/header with:
59
+ # These can now be accessed in <tt>shared/header</tt> with:
57
60
  #
58
61
  # Headline: <%= headline %>
59
62
  # First name: <%= person.first_name %>
@@ -74,13 +77,13 @@ module ActionView #:nodoc:
74
77
  #
75
78
  # == Builder
76
79
  #
77
- # Builder templates are a more programmatic alternative to ERb. They are especially useful for generating XML content. An +XmlMarkup+ object
78
- # named +xml+ is automatically made available to templates with a +.builder+ extension.
80
+ # Builder templates are a more programmatic alternative to ERb. They are especially useful for generating XML content. An XmlMarkup object
81
+ # named +xml+ is automatically made available to templates with a <tt>.builder</tt> extension.
79
82
  #
80
83
  # Here are some basic examples:
81
84
  #
82
85
  # xml.em("emphasized") # => <em>emphasized</em>
83
- # xml.em { xml.b("emph & bold") } # => <em><b>emph &amp; bold</b></em>
86
+ # xml.em { xml.b("emph & bold") } # => <em><b>emph &amp; bold</b></em>
84
87
  # xml.a("A Link", "href"=>"http://onestepback.org") # => <a href="http://onestepback.org">A Link</a>
85
88
  # xml.target("name"=>"compile", "option"=>"fast") # => <target option="fast" name="compile"\>
86
89
  # # NOTE: order of attributes is not specified.
@@ -127,18 +130,18 @@ module ActionView #:nodoc:
127
130
  #
128
131
  # == JavaScriptGenerator
129
132
  #
130
- # JavaScriptGenerator templates end in +.rjs+. Unlike conventional templates which are used to
133
+ # JavaScriptGenerator templates end in <tt>.rjs</tt>. Unlike conventional templates which are used to
131
134
  # render the results of an action, these templates generate instructions on how to modify an already rendered page. This makes it easy to
132
135
  # modify multiple elements on your page in one declarative Ajax response. Actions with these templates are called in the background with Ajax
133
136
  # and make updates to the page where the request originated from.
134
137
  #
135
138
  # An instance of the JavaScriptGenerator object named +page+ is automatically made available to your template, which is implicitly wrapped in an ActionView::Helpers::PrototypeHelper#update_page block.
136
139
  #
137
- # When an .rjs action is called with +link_to_remote+, the generated JavaScript is automatically evaluated. Example:
140
+ # When an <tt>.rjs</tt> action is called with +link_to_remote+, the generated JavaScript is automatically evaluated. Example:
138
141
  #
139
142
  # link_to_remote :url => {:action => 'delete'}
140
143
  #
141
- # The subsequently rendered +delete.rjs+ might look like:
144
+ # The subsequently rendered <tt>delete.rjs</tt> might look like:
142
145
  #
143
146
  # page.replace_html 'sidebar', :partial => 'sidebar'
144
147
  # page.remove "person-#{@person.id}"
@@ -150,16 +153,12 @@ module ActionView #:nodoc:
150
153
  class Base
151
154
  include ERB::Util
152
155
 
153
- attr_reader :first_render
154
- attr_accessor :base_path, :assigns, :template_extension
155
- attr_accessor :controller, :view_paths
156
-
157
- attr_reader :logger, :response, :headers
158
- attr_internal :cookies, :flash, :headers, :params, :request, :response, :session
159
-
160
- delegate :logger, :action_name, :to => :controller
156
+ attr_reader :finder
157
+ attr_accessor :base_path, :assigns, :template_extension, :first_render
158
+ attr_accessor :controller
161
159
 
162
160
  attr_writer :template_format
161
+ attr_accessor :current_render_extension
163
162
 
164
163
  # Specify trim mode for the ERB compiler. Defaults to '-'.
165
164
  # See ERb documentation for suitable values.
@@ -169,18 +168,12 @@ module ActionView #:nodoc:
169
168
  # Specify whether file modification times should be checked to see if a template needs recompilation
170
169
  @@cache_template_loading = false
171
170
  cattr_accessor :cache_template_loading
172
-
173
- # Specify whether file extension lookup should be cached, and whether template base path lookup should be cached.
174
- # Should be +false+ for development environments. Defaults to +true+.
175
- @@cache_template_extensions = true
176
- cattr_accessor :cache_template_extensions
177
-
178
- # Specify whether local_assigns should be able to use string keys.
179
- # Defaults to +true+. String keys are deprecated and will be removed
180
- # shortly.
181
- @@local_assigns_support_string_keys = true
182
- cattr_accessor :local_assigns_support_string_keys
183
171
 
172
+ def self.cache_template_extensions=(*args)
173
+ ActiveSupport::Deprecation.warn("config.action_view.cache_template_extensions option has been deprecated and has no affect. " <<
174
+ "Please remove it from your config files.", caller)
175
+ end
176
+
184
177
  # Specify whether RJS responses should be wrapped in a try/catch block
185
178
  # that alert()s the caught exception (and then re-raises it).
186
179
  @@debug_rjs = false
@@ -189,89 +182,47 @@ module ActionView #:nodoc:
189
182
  @@erb_variable = '_erbout'
190
183
  cattr_accessor :erb_variable
191
184
 
192
- delegate :request_forgery_protection_token, :to => :controller
185
+ attr_internal :request
193
186
 
194
- @@template_handlers = HashWithIndifferentAccess.new
187
+ delegate :request_forgery_protection_token, :template, :params, :session, :cookies, :response, :headers,
188
+ :flash, :logger, :action_name, :to => :controller
195
189
 
196
190
  module CompiledTemplates #:nodoc:
197
191
  # holds compiled template code
198
192
  end
199
193
  include CompiledTemplates
200
194
 
201
- # Maps inline templates to their method names
195
+ # Maps inline templates to their method names
196
+ cattr_accessor :method_names
202
197
  @@method_names = {}
203
- # Map method names to their compile time
204
- @@compile_time = {}
205
198
  # Map method names to the names passed in local assigns so far
206
199
  @@template_args = {}
207
- # Count the number of inline templates
208
- @@inline_template_count = 0
209
- # Maps template paths without extension to their file extension returned by pick_template_extension.
210
- # If for a given path, path.ext1 and path.ext2 exist on the file system, the order of extensions
211
- # used by pick_template_extension determines whether ext1 or ext2 will be stored.
212
- @@cached_template_extension = {}
213
- # Maps template paths / extensions to
214
- @@cached_base_paths = {}
215
200
 
216
201
  # Cache public asset paths
217
202
  cattr_reader :computed_public_paths
218
203
  @@computed_public_paths = {}
219
204
 
220
- @@template_handlers = {}
221
- @@default_template_handlers = nil
222
-
223
205
  class ObjectWrapper < Struct.new(:value) #:nodoc:
224
206
  end
225
207
 
226
- def self.load_helpers #:nodoc:
227
- Dir.entries("#{File.dirname(__FILE__)}/helpers").sort.each do |file|
208
+ def self.helper_modules #:nodoc:
209
+ helpers = []
210
+ Dir.entries(File.expand_path("#{File.dirname(__FILE__)}/helpers")).sort.each do |file|
228
211
  next unless file =~ /^([a-z][a-z_]*_helper).rb$/
229
212
  require "action_view/helpers/#{$1}"
230
213
  helper_module_name = $1.camelize
231
214
  if Helpers.const_defined?(helper_module_name)
232
- include Helpers.const_get(helper_module_name)
215
+ helpers << Helpers.const_get(helper_module_name)
233
216
  end
234
217
  end
218
+ return helpers
235
219
  end
236
220
 
237
- # Register a class that knows how to handle template files with the given
238
- # extension. This can be used to implement new template types.
239
- # The constructor for the class must take the ActiveView::Base instance
240
- # as a parameter, and the class must implement a #render method that
241
- # takes the contents of the template to render as well as the Hash of
242
- # local assigns available to the template. The #render method ought to
243
- # return the rendered template as a string.
244
- def self.register_template_handler(extension, klass)
245
- @@template_handlers[extension.to_sym] = klass
246
- end
247
-
248
- def self.template_handler_extensions
249
- @@template_handler_extensions ||= @@template_handlers.keys.map(&:to_s).sort
250
- end
251
-
252
- def self.register_default_template_handler(extension, klass)
253
- register_template_handler(extension, klass)
254
- @@default_template_handlers = klass
255
- end
256
-
257
- def self.handler_for_extension(extension)
258
- (extension && @@template_handlers[extension.to_sym]) || @@default_template_handlers
259
- end
260
-
261
- register_default_template_handler :erb, TemplateHandlers::ERB
262
- register_template_handler :rjs, TemplateHandlers::RJS
263
- register_template_handler :builder, TemplateHandlers::Builder
264
-
265
- # TODO: Depreciate old template extensions
266
- register_template_handler :rhtml, TemplateHandlers::ERB
267
- register_template_handler :rxml, TemplateHandlers::Builder
268
-
269
221
  def initialize(view_paths = [], assigns_for_first_render = {}, controller = nil)#:nodoc:
270
- @view_paths = view_paths.respond_to?(:find) ? view_paths.dup : [*view_paths].compact
271
222
  @assigns = assigns_for_first_render
272
223
  @assigns_added = nil
273
224
  @controller = controller
274
- @logger = controller && controller.logger
225
+ @finder = TemplateFinder.new(self, view_paths)
275
226
  end
276
227
 
277
228
  # Renders the template present at <tt>template_path</tt>. If <tt>use_full_path</tt> is set to true,
@@ -291,61 +242,27 @@ If you are rendering a subtemplate, you must now use controller-like partial syn
291
242
  END_ERROR
292
243
  end
293
244
 
294
- @first_render ||= template_path
295
- template_path_without_extension, template_extension = path_and_extension(template_path)
296
- if use_full_path
297
- if template_extension
298
- template_file_name = full_template_path(template_path_without_extension, template_extension)
299
- else
300
- template_extension = pick_template_extension(template_path).to_s
301
- unless template_extension
302
- raise ActionViewError, "No template found for #{template_path} in #{view_paths.inspect}"
303
- end
304
- template_file_name = full_template_path(template_path, template_extension)
305
- template_extension = template_extension.gsub(/^.+\./, '') # strip off any formats
306
- end
307
- else
308
- template_file_name = template_path
309
- end
310
-
311
- template_source = nil # Don't read the source until we know that it is required
312
-
313
- if template_file_name.blank?
314
- raise ActionViewError, "Couldn't find template file for #{template_path} in #{view_paths.inspect}"
315
- end
316
-
317
- begin
318
- render_template(template_extension, template_source, template_file_name, local_assigns)
319
- rescue Exception => e
320
- if TemplateError === e
321
- e.sub_template_of(template_file_name)
322
- raise e
323
- else
324
- raise TemplateError.new(find_base_path_for("#{template_path_without_extension}.#{template_extension}") || view_paths.first, template_file_name, @assigns, template_source, e)
325
- end
326
- end
245
+ Template.new(self, template_path, use_full_path, local_assigns).render_template
327
246
  end
328
247
 
329
248
  # Renders the template present at <tt>template_path</tt> (relative to the view_paths array).
330
249
  # The hash in <tt>local_assigns</tt> is made available as local variables.
331
- def render(options = {}, old_local_assigns = {}, &block) #:nodoc:
250
+ def render(options = {}, local_assigns = {}, &block) #:nodoc:
332
251
  if options.is_a?(String)
333
- render_file(options, true, old_local_assigns)
252
+ render_file(options, true, local_assigns)
334
253
  elsif options == :update
335
254
  update_page(&block)
336
255
  elsif options.is_a?(Hash)
337
256
  options = options.reverse_merge(:locals => {}, :use_full_path => true)
338
257
 
339
- if options[:layout]
340
- path, partial_name = partial_pieces(options.delete(:layout))
341
-
258
+ if partial_layout = options.delete(:layout)
342
259
  if block_given?
343
260
  wrap_content_for_layout capture(&block) do
344
- concat(render(options.merge(:partial => "#{path}/#{partial_name}")), block.binding)
261
+ concat(render(options.merge(:partial => partial_layout)), block.binding)
345
262
  end
346
263
  else
347
264
  wrap_content_for_layout render(options) do
348
- render(options.merge(:partial => "#{path}/#{partial_name}"))
265
+ render(options.merge(:partial => partial_layout))
349
266
  end
350
267
  end
351
268
  elsif options[:file]
@@ -355,61 +272,14 @@ If you are rendering a subtemplate, you must now use controller-like partial syn
355
272
  elsif options[:partial]
356
273
  render_partial(options[:partial], ActionView::Base::ObjectWrapper.new(options[:object]), options[:locals])
357
274
  elsif options[:inline]
358
- render_template(options[:type], options[:inline], nil, options[:locals])
275
+ template = InlineTemplate.new(self, options[:inline], options[:locals], options[:type])
276
+ render_template(template)
359
277
  end
360
278
  end
361
279
  end
362
280
 
363
- # Renders the +template+ which is given as a string as either erb or builder depending on <tt>template_extension</tt>.
364
- # The hash in <tt>local_assigns</tt> is made available as local variables.
365
- def render_template(template_extension, template, file_path = nil, local_assigns = {}) #:nodoc:
366
- handler = self.class.handler_for_extension(template_extension)
367
-
368
- if template_handler_is_compilable?(handler)
369
- compile_and_render_template(handler, template, file_path, local_assigns)
370
- else
371
- template ||= read_template_file(file_path, template_extension) # Make sure that a lazyily-read template is loaded.
372
- delegate_render(handler, template, local_assigns)
373
- end
374
- end
375
-
376
- # Gets the full template path with base path for the given template_path and extension.
377
- #
378
- # full_template_path('users/show', 'html.erb')
379
- # # => '~/rails/app/views/users/show.html.erb
380
- #
381
- def full_template_path(template_path, extension)
382
- if @@cache_template_extensions
383
- (@@cached_base_paths[template_path] ||= {})[extension.to_s] ||= find_full_template_path(template_path, extension)
384
- else
385
- find_full_template_path(template_path, extension)
386
- end
387
- end
388
-
389
- # Gets the extension for an existing template with the given template_path.
390
- # Returns the format with the extension if that template exists.
391
- #
392
- # pick_template_extension('users/show')
393
- # # => 'html.erb'
394
- #
395
- # pick_template_extension('users/legacy')
396
- # # => "rhtml"
397
- #
398
- def pick_template_extension(template_path)#:nodoc:
399
- if @@cache_template_extensions
400
- (@@cached_template_extension[template_path] ||= {})[template_format] ||= find_template_extension_for(template_path)
401
- else
402
- find_template_extension_for(template_path)
403
- end
404
- end
405
-
406
- def file_exists?(template_path)#:nodoc:
407
- template_file_name, template_file_extension = path_and_extension(template_path)
408
- if template_file_extension
409
- template_exists?(template_file_name, template_file_extension)
410
- else
411
- template_exists?(template_file_name, pick_template_extension(template_path))
412
- end
281
+ def render_template(template) #:nodoc:
282
+ template.render_template
413
283
  end
414
284
 
415
285
  # Returns true is the file may be rendered implicitly.
@@ -417,31 +287,31 @@ If you are rendering a subtemplate, you must now use controller-like partial syn
417
287
  template_path.split('/').last[0,1] != '_'
418
288
  end
419
289
 
420
- # symbolized version of the :format parameter of the request, or :html by default.
290
+ # Returns a symbolized version of the <tt>:format</tt> parameter of the request,
291
+ # or <tt>:html</tt> by default.
292
+ #
293
+ # EXCEPTION: If the <tt>:format</tt> parameter is not set, the Accept header will be examined for
294
+ # whether it contains the JavaScript mime type as its first priority. If that's the case,
295
+ # it will be used. This ensures that Ajax applications can use the same URL to support both
296
+ # JavaScript and non-JavaScript users.
421
297
  def template_format
422
298
  return @template_format if @template_format
423
- format = controller && controller.respond_to?(:request) && controller.request.parameters[:format]
424
- @template_format = format.blank? ? :html : format.to_sym
425
- end
426
299
 
427
- # Adds a view_path to the front of the view_paths array.
428
- # This change affects the current request only.
429
- #
430
- # @template.prepend_view_path("views/default")
431
- # @template.prepend_view_path(["views/default", "views/custom"])
432
- #
433
- def prepend_view_path(path)
434
- @view_paths.unshift(*path)
435
- end
436
-
437
- # Adds a view_path to the end of the view_paths array.
438
- # This change affects the current request only.
439
- #
440
- # @template.append_view_path("views/default")
441
- # @template.append_view_path(["views/default", "views/custom"])
442
- #
443
- def append_view_path(path)
444
- @view_paths.push(*path)
300
+ if controller && controller.respond_to?(:request)
301
+ parameter_format = controller.request.parameters[:format]
302
+ accept_format = controller.request.accepts.first
303
+
304
+ case
305
+ when parameter_format.blank? && accept_format != :js
306
+ @template_format = :html
307
+ when parameter_format.blank? && accept_format == :js
308
+ @template_format = :js
309
+ else
310
+ @template_format = parameter_format.to_sym
311
+ end
312
+ else
313
+ @template_format = :html
314
+ end
445
315
  end
446
316
 
447
317
  private
@@ -450,62 +320,6 @@ If you are rendering a subtemplate, you must now use controller-like partial syn
450
320
  @content_for_layout = content
451
321
  returning(yield) { @content_for_layout = original_content_for_layout }
452
322
  end
453
-
454
- def find_full_template_path(template_path, extension)
455
- file_name = "#{template_path}.#{extension}"
456
- base_path = find_base_path_for(file_name)
457
- base_path.blank? ? "" : "#{base_path}/#{file_name}"
458
- end
459
-
460
- # Asserts the existence of a template.
461
- def template_exists?(template_path, extension)
462
- file_path = full_template_path(template_path, extension)
463
- !file_path.blank? && @@method_names.has_key?(file_path) || File.exist?(file_path)
464
- end
465
-
466
- # Splits the path and extension from the given template_path and returns as an array.
467
- def path_and_extension(template_path)
468
- template_path_without_extension = template_path.sub(/\.(\w+)$/, '')
469
- [ template_path_without_extension, $1 ]
470
- end
471
-
472
- # Returns the view path that contains the given relative template path.
473
- def find_base_path_for(template_file_name)
474
- view_paths.find { |p| File.file?(File.join(p, template_file_name)) }
475
- end
476
-
477
- # Returns the view path that the full path resides in.
478
- def extract_base_path_from(full_path)
479
- view_paths.find { |p| full_path[0..p.size - 1] == p }
480
- end
481
-
482
- # Determines the template's file extension, such as rhtml, rxml, or rjs.
483
- def find_template_extension_for(template_path)
484
- find_template_extension_from_handler(template_path, true) ||
485
- find_template_extension_from_handler(template_path) ||
486
- find_template_extension_from_first_render()
487
- end
488
-
489
- def find_template_extension_from_handler(template_path, formatted = nil)
490
- checked_template_path = formatted ? "#{template_path}.#{template_format}" : template_path
491
-
492
- self.class.template_handler_extensions.each do |extension|
493
- if template_exists?(checked_template_path, extension)
494
- return formatted ? "#{template_format}.#{extension}" : extension.to_s
495
- end
496
- end
497
- nil
498
- end
499
-
500
- # Determine the template extension from the <tt>@first_render</tt> filename
501
- def find_template_extension_from_first_render
502
- File.basename(@first_render.to_s)[/^[^.]+\.(.+)$/, 1]
503
- end
504
-
505
- # This method reads a template file.
506
- def read_template_file(template_path, extension)
507
- File.read(template_path)
508
- end
509
323
 
510
324
  # Evaluate the local assigns and pushes them to the view.
511
325
  def evaluate_assigns
@@ -515,146 +329,15 @@ If you are rendering a subtemplate, you must now use controller-like partial syn
515
329
  end
516
330
  end
517
331
 
518
- def delegate_render(handler, template, local_assigns)
519
- handler.new(self).render(template, local_assigns)
520
- end
521
-
522
- def delegate_compile(handler, template)
523
- handler.new(self).compile(template)
524
- end
525
-
526
- def template_handler_is_compilable?(handler)
527
- handler.new(self).respond_to?(:compile)
528
- end
529
-
530
332
  # Assigns instance variables from the controller to the view.
531
333
  def assign_variables_from_controller
532
- @assigns.each do |key, value|
533
- if ['logger'].include?(key)
534
- instance_variable_set("@#{key}", ActiveSupport::Deprecation::DeprecatedInstanceVariableProxy.new(self, key.to_sym))
535
- elsif ['action_name'].include?(key)
536
- instance_variable_set("@#{key}", ActiveSupport::Deprecation::DeprecatedInstanceVariable.new(value, key))
537
- else
538
- instance_variable_set("@#{key}", value)
539
- end
540
- end
541
- end
542
-
543
-
544
- # Return true if the given template was compiled for a superset of the keys in local_assigns
545
- def supports_local_assigns?(render_symbol, local_assigns)
546
- local_assigns.empty? ||
547
- ((args = @@template_args[render_symbol]) && local_assigns.all? { |k,_| args.has_key?(k) })
334
+ @assigns.each { |key, value| instance_variable_set("@#{key}", value) }
548
335
  end
549
-
550
- # Method to check whether template compilation is necessary.
551
- # The template will be compiled if the inline template or file has not been compiled yet,
552
- # if local_assigns has a new key, which isn't supported by the compiled code yet,
553
- # or if the file has changed on disk and checking file mods hasn't been disabled.
554
- def compile_template?(template, file_name, local_assigns)
555
- method_key = file_name || template
556
- render_symbol = @@method_names[method_key]
557
-
558
- compile_time = @@compile_time[render_symbol]
559
- if compile_time && supports_local_assigns?(render_symbol, local_assigns)
560
- if file_name && !@@cache_template_loading
561
- template_changed_since?(file_name, compile_time)
562
- end
563
- else
564
- true
565
- end
566
- end
567
-
568
- # Method to handle checking a whether a template has changed since last compile; isolated so that templates
569
- # not stored on the file system can hook and extend appropriately.
570
- def template_changed_since?(file_name, compile_time)
571
- lstat = File.lstat(file_name)
572
- compile_time < lstat.mtime ||
573
- (lstat.symlink? && compile_time < File.stat(file_name).mtime)
574
- end
575
-
576
- # Method to create the source code for a given template.
577
- def create_template_source(handler, template, render_symbol, locals)
578
- body = delegate_compile(handler, template)
579
-
580
- @@template_args[render_symbol] ||= {}
581
- locals_keys = @@template_args[render_symbol].keys | locals
582
- @@template_args[render_symbol] = locals_keys.inject({}) { |h, k| h[k] = true; h }
583
-
584
- locals_code = ""
585
- locals_keys.each do |key|
586
- locals_code << "#{key} = local_assigns[:#{key}]\n"
587
- end
588
-
589
- "def #{render_symbol}(local_assigns)\n#{locals_code}#{body}\nend"
590
- end
591
-
592
- def assign_method_name(handler, template, file_name)
593
- method_key = file_name || template
594
- @@method_names[method_key] ||= compiled_method_name(handler, template, file_name)
595
- end
596
-
597
- def compiled_method_name(handler, template, file_name)
598
- ['_run', handler.to_s.demodulize.underscore, compiled_method_name_file_path_segment(file_name)].compact.join('_').to_sym
599
- end
600
-
601
- def compiled_method_name_file_path_segment(file_name)
602
- if file_name
603
- s = File.expand_path(file_name)
604
- s.sub!(/^#{Regexp.escape(File.expand_path(RAILS_ROOT))}/, '') if defined?(RAILS_ROOT)
605
- s.gsub!(/([^a-zA-Z0-9_])/) { $1.ord }
606
- s
607
- else
608
- (@@inline_template_count += 1).to_s
609
- end
610
- end
611
-
612
- # Compile and evaluate the template's code
613
- def compile_template(handler, template, file_name, local_assigns)
614
- render_symbol = assign_method_name(handler, template, file_name)
615
- render_source = create_template_source(handler, template, render_symbol, local_assigns.keys)
616
- line_offset = @@template_args[render_symbol].size + handler.line_offset
617
-
618
- begin
619
- file_name = 'compiled-template' if file_name.blank?
620
- CompiledTemplates.module_eval(render_source, file_name, -line_offset)
621
- rescue Exception => e # errors from template code
622
- if logger
623
- logger.debug "ERROR: compiling #{render_symbol} RAISED #{e}"
624
- logger.debug "Function body: #{render_source}"
625
- logger.debug "Backtrace: #{e.backtrace.join("\n")}"
626
- end
627
-
628
- raise TemplateError.new(extract_base_path_from(file_name) || view_paths.first, file_name || template, @assigns, template, e)
629
- end
630
-
631
- @@compile_time[render_symbol] = Time.now
632
- # logger.debug "Compiled template #{file_name || template}\n ==> #{render_symbol}" if logger
633
- end
634
-
635
- # Render the provided template with the given local assigns. If the template has not been rendered with the provided
636
- # local assigns yet, or if the template has been updated on disk, then the template will be compiled to a method.
637
- #
638
- # Either, but not both, of template and file_path may be nil. If file_path is given, the template
639
- # will only be read if it has to be compiled.
640
- #
641
- def compile_and_render_template(handler, template = nil, file_path = nil, local_assigns = {}) #:nodoc:
642
- # convert string keys to symbols if requested
643
- local_assigns = local_assigns.symbolize_keys if @@local_assigns_support_string_keys
644
-
645
- # compile the given template, if necessary
646
- if compile_template?(template, file_path, local_assigns)
647
- template ||= read_template_file(file_path, nil)
648
- compile_template(handler, template, file_path, local_assigns)
649
- end
650
-
651
- # Get the method name for this template and run it
652
- method_name = @@method_names[file_path || template]
653
- evaluate_assigns
654
-
655
- send(method_name, local_assigns) do |*name|
656
- instance_variable_get "@content_for_#{name.first || 'layout'}"
657
- end
336
+
337
+ def execute(template)
338
+ send(template.method, template.locals) do |*names|
339
+ instance_variable_get "@content_for_#{names.first || 'layout'}"
340
+ end
658
341
  end
659
342
  end
660
343
  end