actionpack 2.1.2 → 2.2.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 (200) hide show
  1. data/CHANGELOG +223 -7
  2. data/README +6 -12
  3. data/Rakefile +11 -11
  4. data/lib/action_controller.rb +9 -9
  5. data/lib/action_controller/assertions/response_assertions.rb +29 -78
  6. data/lib/action_controller/assertions/routing_assertions.rb +33 -33
  7. data/lib/action_controller/assertions/selector_assertions.rb +9 -5
  8. data/lib/action_controller/base.rb +227 -161
  9. data/lib/action_controller/benchmarking.rb +37 -24
  10. data/lib/action_controller/caching/actions.rb +53 -21
  11. data/lib/action_controller/caching/fragments.rb +10 -36
  12. data/lib/action_controller/caching/sweeping.rb +3 -3
  13. data/lib/action_controller/cgi_ext/session.rb +2 -22
  14. data/lib/action_controller/cgi_process.rb +8 -46
  15. data/lib/action_controller/components.rb +4 -1
  16. data/lib/action_controller/cookies.rb +10 -0
  17. data/lib/action_controller/dispatcher.rb +49 -15
  18. data/lib/action_controller/filters.rb +48 -10
  19. data/lib/action_controller/headers.rb +16 -14
  20. data/lib/action_controller/helpers.rb +2 -2
  21. data/lib/action_controller/http_authentication.rb +1 -1
  22. data/lib/action_controller/integration.rb +57 -60
  23. data/lib/action_controller/layout.rb +27 -53
  24. data/lib/action_controller/mime_responds.rb +5 -1
  25. data/lib/action_controller/mime_type.rb +64 -42
  26. data/lib/action_controller/mime_types.rb +2 -1
  27. data/lib/action_controller/performance_test.rb +16 -0
  28. data/lib/action_controller/polymorphic_routes.rb +16 -9
  29. data/lib/action_controller/rack_process.rb +303 -0
  30. data/lib/action_controller/request.rb +205 -97
  31. data/lib/action_controller/request_forgery_protection.rb +2 -2
  32. data/lib/action_controller/request_profiler.rb +0 -0
  33. data/lib/action_controller/rescue.rb +20 -115
  34. data/lib/action_controller/resources.rb +186 -83
  35. data/lib/action_controller/response.rb +140 -26
  36. data/lib/action_controller/routing.rb +28 -30
  37. data/lib/action_controller/routing/builder.rb +45 -54
  38. data/lib/action_controller/routing/optimisations.rb +31 -21
  39. data/lib/action_controller/routing/recognition_optimisation.rb +33 -27
  40. data/lib/action_controller/routing/route.rb +162 -147
  41. data/lib/action_controller/routing/route_set.rb +8 -7
  42. data/lib/action_controller/routing/routing_ext.rb +4 -1
  43. data/lib/action_controller/routing/segments.rb +50 -21
  44. data/lib/action_controller/session/cookie_store.rb +3 -2
  45. data/lib/action_controller/session/drb_server.rb +7 -7
  46. data/lib/action_controller/session_management.rb +6 -2
  47. data/lib/action_controller/streaming.rb +15 -8
  48. data/lib/action_controller/templates/rescues/diagnostics.erb +2 -2
  49. data/lib/action_controller/templates/rescues/template_error.erb +2 -2
  50. data/lib/action_controller/test_case.rb +66 -2
  51. data/lib/action_controller/test_process.rb +71 -66
  52. data/lib/action_controller/translation.rb +13 -0
  53. data/lib/action_controller/url_rewriter.rb +90 -13
  54. data/lib/action_controller/vendor/html-scanner/html/node.rb +9 -2
  55. data/lib/action_controller/vendor/html-scanner/html/sanitizer.rb +1 -1
  56. data/lib/action_controller/vendor/html-scanner/html/selector.rb +2 -2
  57. data/lib/action_controller/verification.rb +2 -2
  58. data/lib/action_pack/version.rb +1 -1
  59. data/lib/action_view.rb +19 -11
  60. data/lib/action_view/base.rb +184 -150
  61. data/lib/action_view/helpers.rb +38 -0
  62. data/lib/action_view/helpers/active_record_helper.rb +56 -27
  63. data/lib/action_view/helpers/asset_tag_helper.rb +356 -153
  64. data/lib/action_view/helpers/atom_feed_helper.rb +74 -19
  65. data/lib/action_view/helpers/benchmark_helper.rb +3 -3
  66. data/lib/action_view/helpers/cache_helper.rb +1 -2
  67. data/lib/action_view/helpers/capture_helper.rb +19 -44
  68. data/lib/action_view/helpers/date_helper.rb +486 -296
  69. data/lib/action_view/helpers/debug_helper.rb +20 -13
  70. data/lib/action_view/helpers/form_helper.rb +71 -30
  71. data/lib/action_view/helpers/form_options_helper.rb +15 -85
  72. data/lib/action_view/helpers/form_tag_helper.rb +61 -38
  73. data/lib/action_view/helpers/javascript_helper.rb +80 -89
  74. data/lib/action_view/helpers/number_helper.rb +179 -74
  75. data/lib/action_view/helpers/prototype_helper.rb +216 -201
  76. data/lib/action_view/helpers/record_tag_helper.rb +4 -5
  77. data/lib/action_view/helpers/sanitize_helper.rb +65 -33
  78. data/lib/action_view/helpers/scriptaculous_helper.rb +2 -2
  79. data/lib/action_view/helpers/tag_helper.rb +39 -22
  80. data/lib/action_view/helpers/text_helper.rb +212 -118
  81. data/lib/action_view/helpers/translation_helper.rb +21 -0
  82. data/lib/action_view/helpers/url_helper.rb +100 -58
  83. data/lib/action_view/inline_template.rb +13 -14
  84. data/lib/action_view/locale/en.yml +91 -0
  85. data/lib/action_view/partials.rb +100 -55
  86. data/lib/action_view/paths.rb +125 -0
  87. data/lib/action_view/renderable.rb +102 -0
  88. data/lib/action_view/renderable_partial.rb +48 -0
  89. data/lib/action_view/template.rb +90 -101
  90. data/lib/action_view/template_error.rb +11 -21
  91. data/lib/action_view/template_handler.rb +8 -28
  92. data/lib/action_view/template_handlers.rb +45 -0
  93. data/lib/action_view/template_handlers/builder.rb +5 -15
  94. data/lib/action_view/template_handlers/erb.rb +9 -6
  95. data/lib/action_view/template_handlers/rjs.rb +2 -17
  96. data/lib/action_view/test_case.rb +7 -4
  97. data/test/abstract_unit.rb +4 -1
  98. data/test/active_record_unit.rb +28 -30
  99. data/test/activerecord/render_partial_with_record_identification_test.rb +25 -12
  100. data/test/controller/action_pack_assertions_test.rb +8 -37
  101. data/test/controller/addresses_render_test.rb +0 -3
  102. data/test/controller/assert_select_test.rb +51 -24
  103. data/test/controller/base_test.rb +4 -4
  104. data/test/controller/caching_test.rb +136 -66
  105. data/test/controller/capture_test.rb +1 -21
  106. data/test/controller/cgi_test.rb +157 -10
  107. data/test/controller/components_test.rb +41 -25
  108. data/test/controller/content_type_test.rb +49 -17
  109. data/test/controller/cookie_test.rb +1 -1
  110. data/test/controller/deprecation/deprecated_base_methods_test.rb +0 -3
  111. data/test/controller/dispatcher_test.rb +9 -1
  112. data/test/controller/filter_params_test.rb +2 -2
  113. data/test/controller/filters_test.rb +13 -13
  114. data/test/controller/html-scanner/cdata_node_test.rb +15 -0
  115. data/test/controller/html-scanner/node_test.rb +21 -0
  116. data/test/controller/html-scanner/sanitizer_test.rb +14 -0
  117. data/test/controller/integration_test.rb +167 -6
  118. data/test/controller/layout_test.rb +11 -68
  119. data/test/controller/logging_test.rb +46 -0
  120. data/test/controller/mime_responds_test.rb +61 -59
  121. data/test/controller/mime_type_test.rb +6 -6
  122. data/test/controller/polymorphic_routes_test.rb +37 -2
  123. data/test/controller/rack_test.rb +323 -0
  124. data/test/controller/redirect_test.rb +72 -71
  125. data/test/controller/render_test.rb +1120 -108
  126. data/test/controller/request_forgery_protection_test.rb +66 -52
  127. data/test/controller/request_test.rb +103 -146
  128. data/test/controller/rescue_test.rb +20 -24
  129. data/test/controller/resources_test.rb +408 -25
  130. data/test/controller/routing_test.rb +1774 -1774
  131. data/test/controller/send_file_test.rb +0 -4
  132. data/test/controller/session/cookie_store_test.rb +53 -1
  133. data/test/controller/test_test.rb +15 -37
  134. data/test/controller/translation_test.rb +26 -0
  135. data/test/controller/url_rewriter_test.rb +27 -28
  136. data/test/controller/view_paths_test.rb +48 -47
  137. data/test/fixtures/_top_level_partial.html.erb +1 -0
  138. data/test/fixtures/_top_level_partial_only.erb +1 -0
  139. data/test/fixtures/developers/_developer.erb +1 -0
  140. data/test/fixtures/fun/games/_game.erb +1 -0
  141. data/test/fixtures/fun/serious/games/_game.erb +1 -0
  142. data/test/fixtures/functional_caching/formatted_fragment_cached.html.erb +3 -0
  143. data/test/fixtures/functional_caching/formatted_fragment_cached.js.rjs +6 -0
  144. data/test/fixtures/functional_caching/formatted_fragment_cached.xml.builder +5 -0
  145. data/test/fixtures/functional_caching/inline_fragment_cached.html.erb +2 -0
  146. data/test/fixtures/layouts/_column.html.erb +2 -0
  147. data/test/fixtures/projects/_project.erb +1 -0
  148. data/test/fixtures/public/javascripts/subdir/subdir.js +1 -0
  149. data/test/fixtures/public/stylesheets/subdir/subdir.css +1 -0
  150. data/test/fixtures/replies/_reply.erb +1 -0
  151. data/test/fixtures/test/_counter.html.erb +1 -0
  152. data/test/fixtures/test/_customer.erb +1 -1
  153. data/test/fixtures/test/_customer_with_var.erb +1 -0
  154. data/test/fixtures/test/_layout_for_block_with_args.html.erb +3 -0
  155. data/test/fixtures/test/_local_inspector.html.erb +1 -0
  156. data/test/fixtures/test/_partial_with_only_html_version.html.erb +1 -0
  157. data/test/fixtures/test/hello.builder +1 -1
  158. data/test/fixtures/test/hyphen-ated.erb +1 -0
  159. data/test/fixtures/test/implicit_content_type.atom.builder +2 -0
  160. data/test/fixtures/test/nested_layout.erb +3 -0
  161. data/test/fixtures/test/non_erb_block_content_for.builder +1 -1
  162. data/test/fixtures/test/sub_template_raise.html.erb +1 -0
  163. data/test/fixtures/test/template.erb +1 -0
  164. data/test/fixtures/test/using_layout_around_block_with_args.html.erb +1 -0
  165. data/test/template/active_record_helper_i18n_test.rb +46 -0
  166. data/test/template/active_record_helper_test.rb +24 -24
  167. data/test/template/asset_tag_helper_test.rb +161 -29
  168. data/test/template/atom_feed_helper_test.rb +114 -5
  169. data/test/template/compiled_templates_test.rb +59 -0
  170. data/test/template/date_helper_i18n_test.rb +113 -0
  171. data/test/template/date_helper_test.rb +403 -109
  172. data/test/template/form_helper_test.rb +213 -154
  173. data/test/template/form_options_helper_test.rb +249 -897
  174. data/test/template/form_tag_helper_test.rb +80 -32
  175. data/test/template/javascript_helper_test.rb +17 -18
  176. data/test/template/number_helper_i18n_test.rb +54 -0
  177. data/test/template/number_helper_test.rb +43 -13
  178. data/test/template/prototype_helper_test.rb +101 -84
  179. data/test/template/record_tag_helper_test.rb +24 -20
  180. data/test/template/render_test.rb +193 -0
  181. data/test/template/sanitize_helper_test.rb +3 -3
  182. data/test/template/tag_helper_test.rb +34 -14
  183. data/test/template/text_helper_test.rb +83 -9
  184. data/test/template/translation_helper_test.rb +28 -0
  185. data/test/template/url_helper_test.rb +55 -18
  186. metadata +57 -18
  187. data/lib/action_view/helpers/javascripts/controls.js +0 -963
  188. data/lib/action_view/helpers/javascripts/dragdrop.js +0 -972
  189. data/lib/action_view/helpers/javascripts/effects.js +0 -1120
  190. data/lib/action_view/helpers/javascripts/prototype.js +0 -4225
  191. data/lib/action_view/partial_template.rb +0 -70
  192. data/lib/action_view/template_finder.rb +0 -177
  193. data/lib/action_view/template_handlers/compilable.rb +0 -128
  194. data/test/controller/custom_handler_test.rb +0 -45
  195. data/test/controller/new_render_test.rb +0 -945
  196. data/test/fixtures/test/block_content_for.erb +0 -2
  197. data/test/fixtures/test/erb_content_for.erb +0 -2
  198. data/test/template/deprecated_erb_variable_test.rb +0 -9
  199. data/test/template/template_finder_test.rb +0 -73
  200. data/test/template/template_object_test.rb +0 -95
@@ -150,7 +150,14 @@ module HTML #:nodoc:
150
150
  end
151
151
 
152
152
  if scanner.skip(/!\[CDATA\[/)
153
- scanner.scan_until(/\]\]>/)
153
+ unless scanner.skip_until(/\]\]>/)
154
+ if strict
155
+ raise "expected ]]> (got #{scanner.rest.inspect} for #{content})"
156
+ else
157
+ scanner.skip_until(/\Z/)
158
+ end
159
+ end
160
+
154
161
  return CDATA.new(parent, line, pos, scanner.pre_match.gsub(/<!\[CDATA\[/, ''))
155
162
  end
156
163
 
@@ -265,7 +272,7 @@ module HTML #:nodoc:
265
272
  # itself.
266
273
  class CDATA < Text #:nodoc:
267
274
  def to_s
268
- "<![CDATA[#{super}]>"
275
+ "<![CDATA[#{super}]]>"
269
276
  end
270
277
  end
271
278
 
@@ -160,7 +160,7 @@ module HTML
160
160
  if !options[:attributes].include?(attr_name) || contains_bad_protocols?(attr_name, value)
161
161
  node.attributes.delete(attr_name)
162
162
  else
163
- node.attributes[attr_name] = attr_name == 'style' ? sanitize_css(value) : CGI::escapeHTML(value)
163
+ node.attributes[attr_name] = attr_name == 'style' ? sanitize_css(value) : CGI::escapeHTML(CGI::unescapeHTML(value))
164
164
  end
165
165
  end
166
166
  end
@@ -64,7 +64,7 @@ module HTML
64
64
  #
65
65
  # When using a combination of the above, the element name comes first
66
66
  # followed by identifier, class names, attributes, pseudo classes and
67
- # negation in any order. Do not seprate these parts with spaces!
67
+ # negation in any order. Do not separate these parts with spaces!
68
68
  # Space separation is used for descendant selectors.
69
69
  #
70
70
  # For example:
@@ -158,7 +158,7 @@ module HTML
158
158
  # * <tt>:not(selector)</tt> -- Match the element only if the element does not
159
159
  # match the simple selector.
160
160
  #
161
- # As you can see, <tt>:nth-child<tt> pseudo class and its varient can get quite
161
+ # As you can see, <tt>:nth-child<tt> pseudo class and its variant can get quite
162
162
  # tricky and the CSS specification doesn't do a much better job explaining it.
163
163
  # But after reading the examples and trying a few combinations, it's easy to
164
164
  # figure out.
@@ -80,7 +80,7 @@ module ActionController #:nodoc:
80
80
  # array (may also be a single value).
81
81
  def verify(options={})
82
82
  before_filter :only => options[:only], :except => options[:except] do |c|
83
- c.send! :verify_action, options
83
+ c.__send__ :verify_action, options
84
84
  end
85
85
  end
86
86
  end
@@ -116,7 +116,7 @@ module ActionController #:nodoc:
116
116
  end
117
117
 
118
118
  def apply_redirect_to(redirect_to_option) # :nodoc:
119
- (redirect_to_option.is_a?(Symbol) && redirect_to_option != :back) ? self.send!(redirect_to_option) : redirect_to_option
119
+ (redirect_to_option.is_a?(Symbol) && redirect_to_option != :back) ? self.__send__(redirect_to_option) : redirect_to_option
120
120
  end
121
121
 
122
122
  def apply_remaining_actions(options) # :nodoc:
@@ -1,7 +1,7 @@
1
1
  module ActionPack #:nodoc:
2
2
  module VERSION #:nodoc:
3
3
  MAJOR = 2
4
- MINOR = 1
4
+ MINOR = 2
5
5
  TINY = 2
6
6
 
7
7
  STRING = [MAJOR, MINOR, TINY].join('.')
@@ -21,25 +21,33 @@
21
21
  # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
22
  #++
23
23
 
24
- require 'action_view/template_handler'
25
- require 'action_view/template_handlers/compilable'
26
- require 'action_view/template_handlers/builder'
27
- require 'action_view/template_handlers/erb'
28
- require 'action_view/template_handlers/rjs'
24
+ begin
25
+ require 'active_support'
26
+ rescue LoadError
27
+ activesupport_path = "#{File.dirname(__FILE__)}/../../activesupport/lib"
28
+ if File.directory?(activesupport_path)
29
+ $:.unshift activesupport_path
30
+ require 'active_support'
31
+ end
32
+ end
33
+
34
+ require 'action_view/template_handlers'
35
+ require 'action_view/renderable'
36
+ require 'action_view/renderable_partial'
29
37
 
30
- require 'action_view/template_finder'
31
38
  require 'action_view/template'
32
- require 'action_view/partial_template'
33
39
  require 'action_view/inline_template'
40
+ require 'action_view/paths'
34
41
 
35
42
  require 'action_view/base'
36
43
  require 'action_view/partials'
37
44
  require 'action_view/template_error'
38
45
 
46
+ I18n.load_path << "#{File.dirname(__FILE__)}/action_view/locale/en.yml"
47
+
48
+ require 'action_view/helpers'
49
+
39
50
  ActionView::Base.class_eval do
40
51
  include ActionView::Partials
41
-
42
- ActionView::Base.helper_modules.each do |helper_module|
43
- include helper_module
44
- end
52
+ include ActionView::Helpers
45
53
  end
@@ -1,17 +1,23 @@
1
1
  module ActionView #:nodoc:
2
2
  class ActionViewError < StandardError #:nodoc:
3
3
  end
4
-
4
+
5
5
  class MissingTemplate < ActionViewError #:nodoc:
6
+ def initialize(paths, path, template_format = nil)
7
+ full_template_path = path.include?('.') ? path : "#{path}.erb"
8
+ display_paths = paths.join(':')
9
+ template_type = (path =~ /layouts/i) ? 'layout' : 'template'
10
+ super("Missing #{template_type} #{full_template_path} in view path #{display_paths}")
11
+ end
6
12
  end
7
13
 
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.
14
+ # 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
15
+ # (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
16
  # If the template file has a <tt>.rjs</tt> extension then it will use ActionView::Helpers::PrototypeHelper::JavaScriptGenerator.
11
- #
17
+ #
12
18
  # = ERb
13
- #
14
- # You trigger ERb by using embeddings such as <% %>, <% -%>, and <%= %>. The <%= %> tag set is used when you want output. Consider the
19
+ #
20
+ # You trigger ERb by using embeddings such as <% %>, <% -%>, and <%= %>. The <%= %> tag set is used when you want output. Consider the
15
21
  # following loop for names:
16
22
  #
17
23
  # <b>Names of all the people</b>
@@ -51,7 +57,7 @@ module ActionView #:nodoc:
51
57
  # <title><%= @page_title %></title>
52
58
  #
53
59
  # == Passing local variables to sub templates
54
- #
60
+ #
55
61
  # You can pass local variables to sub templates by using a hash with the variable names as keys and the objects as values:
56
62
  #
57
63
  # <%= render "shared/header", { :headline => "Welcome", :person => person } %>
@@ -77,8 +83,8 @@ module ActionView #:nodoc:
77
83
  #
78
84
  # == Builder
79
85
  #
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.
86
+ # Builder templates are a more programmatic alternative to ERb. They are especially useful for generating XML content. An XmlMarkup object
87
+ # named +xml+ is automatically made available to templates with a <tt>.builder</tt> extension.
82
88
  #
83
89
  # Here are some basic examples:
84
90
  #
@@ -87,7 +93,7 @@ module ActionView #:nodoc:
87
93
  # xml.a("A Link", "href"=>"http://onestepback.org") # => <a href="http://onestepback.org">A Link</a>
88
94
  # xml.target("name"=>"compile", "option"=>"fast") # => <target option="fast" name="compile"\>
89
95
  # # NOTE: order of attributes is not specified.
90
- #
96
+ #
91
97
  # Any method with a block will be treated as an XML markup tag with nested markup in the block. For example, the following:
92
98
  #
93
99
  # xml.div {
@@ -111,7 +117,7 @@ module ActionView #:nodoc:
111
117
  # xml.description "Basecamp: Recent items"
112
118
  # xml.language "en-us"
113
119
  # xml.ttl "40"
114
- #
120
+ #
115
121
  # for item in @recent_items
116
122
  # xml.item do
117
123
  # xml.title(item_title(item))
@@ -119,7 +125,7 @@ module ActionView #:nodoc:
119
125
  # xml.pubDate(item_pubDate(item))
120
126
  # xml.guid(@person.firm.account.url + @recent_items.url(item))
121
127
  # xml.link(@person.firm.account.url + @recent_items.url(item))
122
- #
128
+ #
123
129
  # xml.tag!("dc:creator", item.author_name) if item_has_creator?(item)
124
130
  # end
125
131
  # end
@@ -130,12 +136,12 @@ module ActionView #:nodoc:
130
136
  #
131
137
  # == JavaScriptGenerator
132
138
  #
133
- # JavaScriptGenerator templates end in <tt>.rjs</tt>. Unlike conventional templates which are used to
134
- # render the results of an action, these templates generate instructions on how to modify an already rendered page. This makes it easy to
135
- # modify multiple elements on your page in one declarative Ajax response. Actions with these templates are called in the background with Ajax
139
+ # JavaScriptGenerator templates end in <tt>.rjs</tt>. Unlike conventional templates which are used to
140
+ # render the results of an action, these templates generate instructions on how to modify an already rendered page. This makes it easy to
141
+ # modify multiple elements on your page in one declarative Ajax response. Actions with these templates are called in the background with Ajax
136
142
  # and make updates to the page where the request originated from.
137
- #
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.
143
+ #
144
+ # 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.
139
145
  #
140
146
  # When an <tt>.rjs</tt> action is called with +link_to_remote+, the generated JavaScript is automatically evaluated. Example:
141
147
  #
@@ -145,203 +151,231 @@ module ActionView #:nodoc:
145
151
  #
146
152
  # page.replace_html 'sidebar', :partial => 'sidebar'
147
153
  # page.remove "person-#{@person.id}"
148
- # page.visual_effect :highlight, 'user-list'
154
+ # page.visual_effect :highlight, 'user-list'
149
155
  #
150
156
  # This refreshes the sidebar, removes a person element and highlights the user list.
151
- #
157
+ #
152
158
  # See the ActionView::Helpers::PrototypeHelper::GeneratorMethods documentation for more details.
153
159
  class Base
154
160
  include ERB::Util
161
+ extend ActiveSupport::Memoizable
155
162
 
156
- attr_reader :finder
157
- attr_accessor :base_path, :assigns, :template_extension, :first_render
163
+ attr_accessor :base_path, :assigns, :template_extension
158
164
  attr_accessor :controller
159
-
165
+
160
166
  attr_writer :template_format
161
- attr_accessor :current_render_extension
162
-
163
- # Specify trim mode for the ERB compiler. Defaults to '-'.
164
- # See ERb documentation for suitable values.
165
- @@erb_trim_mode = '-'
166
- cattr_accessor :erb_trim_mode
167
-
168
- # Specify whether file modification times should be checked to see if a template needs recompilation
169
- @@cache_template_loading = false
170
- cattr_accessor :cache_template_loading
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)
167
+
168
+ attr_accessor :output_buffer
169
+
170
+ class << self
171
+ delegate :erb_trim_mode=, :to => 'ActionView::TemplateHandlers::ERB'
172
+ delegate :logger, :to => 'ActionController::Base'
173
+ end
174
+
175
+ # Templates that are exempt from layouts
176
+ @@exempt_from_layout = Set.new([/\.rjs$/])
177
+
178
+ # Don't render layouts for templates with the given extensions.
179
+ def self.exempt_from_layout(*extensions)
180
+ regexps = extensions.collect do |extension|
181
+ extension.is_a?(Regexp) ? extension : /\.#{Regexp.escape(extension.to_s)}$/
182
+ end
183
+ @@exempt_from_layout.merge(regexps)
175
184
  end
176
185
 
177
186
  # Specify whether RJS responses should be wrapped in a try/catch block
178
- # that alert()s the caught exception (and then re-raises it).
187
+ # that alert()s the caught exception (and then re-raises it).
179
188
  @@debug_rjs = false
180
189
  cattr_accessor :debug_rjs
181
190
 
182
- @@erb_variable = '_erbout'
183
- cattr_accessor :erb_variable
184
- class << self
185
- deprecate :erb_variable= => 'The erb variable will no longer be configurable. Use the concat helper method instead of appending to it directly.'
186
- end
191
+ # A warning will be displayed whenever an action results in a cache miss on your view paths.
192
+ @@warn_cache_misses = false
193
+ cattr_accessor :warn_cache_misses
187
194
 
188
195
  attr_internal :request
189
196
 
190
197
  delegate :request_forgery_protection_token, :template, :params, :session, :cookies, :response, :headers,
191
- :flash, :logger, :action_name, :to => :controller
192
-
198
+ :flash, :logger, :action_name, :controller_name, :to => :controller
199
+
193
200
  module CompiledTemplates #:nodoc:
194
201
  # holds compiled template code
195
202
  end
196
203
  include CompiledTemplates
197
204
 
198
- # Maps inline templates to their method names
199
- cattr_accessor :method_names
200
- @@method_names = {}
201
- # Map method names to the names passed in local assigns so far
202
- @@template_args = {}
205
+ def self.process_view_paths(value)
206
+ ActionView::PathSet.new(Array(value))
207
+ end
203
208
 
204
- # Cache public asset paths
205
- cattr_reader :computed_public_paths
206
- @@computed_public_paths = {}
209
+ attr_reader :helpers
207
210
 
208
- class ObjectWrapper < Struct.new(:value) #:nodoc:
209
- end
211
+ class ProxyModule < Module
212
+ def initialize(receiver)
213
+ @receiver = receiver
214
+ end
210
215
 
211
- def self.helper_modules #:nodoc:
212
- helpers = []
213
- Dir.entries(File.expand_path("#{File.dirname(__FILE__)}/helpers")).sort.each do |file|
214
- next unless file =~ /^([a-z][a-z_]*_helper).rb$/
215
- require "action_view/helpers/#{$1}"
216
- helper_module_name = $1.camelize
217
- if Helpers.const_defined?(helper_module_name)
218
- helpers << Helpers.const_get(helper_module_name)
219
- end
216
+ def include(*args)
217
+ super(*args)
218
+ @receiver.extend(*args)
220
219
  end
221
- return helpers
222
220
  end
223
221
 
224
222
  def initialize(view_paths = [], assigns_for_first_render = {}, controller = nil)#:nodoc:
225
223
  @assigns = assigns_for_first_render
226
224
  @assigns_added = nil
225
+ @_render_stack = []
227
226
  @controller = controller
228
- @finder = TemplateFinder.new(self, view_paths)
227
+ @helpers = ProxyModule.new(self)
228
+ self.view_paths = view_paths
229
229
  end
230
230
 
231
- # Renders the template present at <tt>template_path</tt>. If <tt>use_full_path</tt> is set to true,
232
- # it's relative to the view_paths array, otherwise it's absolute. The hash in <tt>local_assigns</tt>
233
- # is made available as local variables.
234
- def render_file(template_path, use_full_path = true, local_assigns = {}) #:nodoc:
235
- if defined?(ActionMailer) && defined?(ActionMailer::Base) && controller.is_a?(ActionMailer::Base) && !template_path.include?("/")
236
- raise ActionViewError, <<-END_ERROR
237
- Due to changes in ActionMailer, you need to provide the mailer_name along with the template name.
238
-
239
- render "user_mailer/signup"
240
- render :file => "user_mailer/signup"
231
+ attr_reader :view_paths
241
232
 
242
- If you are rendering a subtemplate, you must now use controller-like partial syntax:
243
-
244
- render :partial => 'signup' # no mailer_name necessary
245
- END_ERROR
246
- end
247
-
248
- Template.new(self, template_path, use_full_path, local_assigns).render_template
233
+ def view_paths=(paths)
234
+ @view_paths = self.class.process_view_paths(paths)
249
235
  end
250
-
251
- # Renders the template present at <tt>template_path</tt> (relative to the view_paths array).
236
+
237
+ # Renders the template present at <tt>template_path</tt> (relative to the view_paths array).
252
238
  # The hash in <tt>local_assigns</tt> is made available as local variables.
253
239
  def render(options = {}, local_assigns = {}, &block) #:nodoc:
240
+ local_assigns ||= {}
241
+
254
242
  if options.is_a?(String)
255
- render_file(options, true, local_assigns)
243
+ ActiveSupport::Deprecation.warn(
244
+ "Calling render with a string will render a partial from Rails 2.3. " +
245
+ "Change this call to render(:file => '#{options}', :locals => locals_hash)."
246
+ )
247
+
248
+ render(:file => options, :locals => local_assigns)
256
249
  elsif options == :update
257
250
  update_page(&block)
258
251
  elsif options.is_a?(Hash)
259
- use_full_path = options[:use_full_path]
260
- options = options.reverse_merge(:locals => {}, :use_full_path => true)
261
-
262
- if partial_layout = options.delete(:layout)
263
- if block_given?
264
- wrap_content_for_layout capture(&block) do
265
- concat(render(options.merge(:partial => partial_layout)), block.binding)
266
- end
267
- else
268
- wrap_content_for_layout render(options) do
269
- render(options.merge(:partial => partial_layout))
270
- end
271
- end
252
+ options = options.reverse_merge(:locals => {})
253
+ if options[:layout]
254
+ _render_with_layout(options, local_assigns, &block)
272
255
  elsif options[:file]
273
- render_file(options[:file], use_full_path || false, options[:locals])
274
- elsif options[:partial] && options[:collection]
275
- render_partial_collection(options[:partial], options[:collection], options[:spacer_template], options[:locals])
256
+ _pick_template(options[:file]).render_template(self, options[:locals])
276
257
  elsif options[:partial]
277
- render_partial(options[:partial], ActionView::Base::ObjectWrapper.new(options[:object]), options[:locals])
258
+ render_partial(options)
278
259
  elsif options[:inline]
279
- template = InlineTemplate.new(self, options[:inline], options[:locals], options[:type])
280
- render_template(template)
260
+ InlineTemplate.new(options[:inline], options[:type]).render(self, options[:locals])
261
+ elsif options[:text]
262
+ options[:text]
281
263
  end
282
264
  end
283
265
  end
284
266
 
285
- def render_template(template) #:nodoc:
286
- template.render_template
267
+ # The format to be used when choosing between multiple templates with
268
+ # the same name but differing formats. See +Request#template_format+
269
+ # for more details.
270
+ def template_format
271
+ if defined? @template_format
272
+ @template_format
273
+ elsif controller && controller.respond_to?(:request)
274
+ @template_format = controller.request.template_format
275
+ else
276
+ @template_format = :html
277
+ end
287
278
  end
288
279
 
289
- # Returns true is the file may be rendered implicitly.
290
- def file_public?(template_path)#:nodoc:
291
- template_path.split('/').last[0,1] != '_'
280
+ # Access the current template being rendered.
281
+ # Returns a ActionView::Template object.
282
+ def template
283
+ @_render_stack.last
292
284
  end
293
285
 
294
- # Returns a symbolized version of the <tt>:format</tt> parameter of the request,
295
- # or <tt>:html</tt> by default.
296
- #
297
- # EXCEPTION: If the <tt>:format</tt> parameter is not set, the Accept header will be examined for
298
- # whether it contains the JavaScript mime type as its first priority. If that's the case,
299
- # it will be used. This ensures that Ajax applications can use the same URL to support both
300
- # JavaScript and non-JavaScript users.
301
- def template_format
302
- return @template_format if @template_format
303
-
304
- if controller && controller.respond_to?(:request)
305
- parameter_format = controller.request.parameters[:format]
306
- accept_format = controller.request.accepts.first
286
+ private
287
+ # Evaluates the local assigns and controller ivars, pushes them to the view.
288
+ def _evaluate_assigns_and_ivars #:nodoc:
289
+ unless @assigns_added
290
+ @assigns.each { |key, value| instance_variable_set("@#{key}", value) }
291
+ _copy_ivars_from_controller
292
+ @assigns_added = true
293
+ end
294
+ end
307
295
 
308
- case
309
- when parameter_format.blank? && accept_format != :js
310
- @template_format = :html
311
- when parameter_format.blank? && accept_format == :js
312
- @template_format = :js
313
- else
314
- @template_format = parameter_format.to_sym
296
+ def _copy_ivars_from_controller #:nodoc:
297
+ if @controller
298
+ variables = @controller.instance_variable_names
299
+ variables -= @controller.protected_instance_variables if @controller.respond_to?(:protected_instance_variables)
300
+ variables.each { |name| instance_variable_set(name, @controller.instance_variable_get(name)) }
315
301
  end
316
- else
317
- @template_format = :html
318
302
  end
319
- end
320
303
 
321
- private
322
- def wrap_content_for_layout(content)
323
- original_content_for_layout = @content_for_layout
324
- @content_for_layout = content
325
- returning(yield) { @content_for_layout = original_content_for_layout }
304
+ def _set_controller_content_type(content_type) #:nodoc:
305
+ if controller.respond_to?(:response)
306
+ controller.response.content_type ||= content_type
307
+ end
326
308
  end
327
309
 
328
- # Evaluate the local assigns and pushes them to the view.
329
- def evaluate_assigns
330
- unless @assigns_added
331
- assign_variables_from_controller
332
- @assigns_added = true
310
+ def _pick_template(template_path)
311
+ return template_path if template_path.respond_to?(:render)
312
+
313
+ path = template_path.sub(/^\//, '')
314
+ if m = path.match(/(.*)\.(\w+)$/)
315
+ template_file_name, template_file_extension = m[1], m[2]
316
+ else
317
+ template_file_name = path
318
+ end
319
+
320
+ # OPTIMIZE: Checks to lookup template in view path
321
+ if template = self.view_paths["#{template_file_name}.#{template_format}"]
322
+ template
323
+ elsif template = self.view_paths[template_file_name]
324
+ template
325
+ elsif (first_render = @_render_stack.first) && first_render.respond_to?(:format_and_extension) &&
326
+ (template = self.view_paths["#{template_file_name}.#{first_render.format_and_extension}"])
327
+ template
328
+ elsif template_format == :js && template = self.view_paths["#{template_file_name}.html"]
329
+ @template_format = :html
330
+ template
331
+ else
332
+ template = Template.new(template_path, view_paths)
333
+
334
+ if self.class.warn_cache_misses && logger
335
+ logger.debug "[PERFORMANCE] Rendering a template that was " +
336
+ "not found in view path. Templates outside the view path are " +
337
+ "not cached and result in expensive disk operations. Move this " +
338
+ "file into #{view_paths.join(':')} or add the folder to your " +
339
+ "view path list"
340
+ end
341
+
342
+ template
333
343
  end
334
344
  end
345
+ memoize :_pick_template
335
346
 
336
- # Assigns instance variables from the controller to the view.
337
- def assign_variables_from_controller
338
- @assigns.each { |key, value| instance_variable_set("@#{key}", value) }
347
+ def _exempt_from_layout?(template_path) #:nodoc:
348
+ template = _pick_template(template_path).to_s
349
+ @@exempt_from_layout.any? { |ext| template =~ ext }
350
+ rescue ActionView::MissingTemplate
351
+ return false
339
352
  end
340
-
341
- def execute(template)
342
- send(template.method, template.locals) do |*names|
343
- instance_variable_get "@content_for_#{names.first || 'layout'}"
344
- end
353
+
354
+ def _render_with_layout(options, local_assigns, &block) #:nodoc:
355
+ partial_layout = options.delete(:layout)
356
+
357
+ if block_given?
358
+ begin
359
+ @_proc_for_layout = block
360
+ concat(render(options.merge(:partial => partial_layout)))
361
+ ensure
362
+ @_proc_for_layout = nil
363
+ end
364
+ else
365
+ begin
366
+ original_content_for_layout = @content_for_layout if defined?(@content_for_layout)
367
+ @content_for_layout = render(options)
368
+
369
+ if (options[:inline] || options[:file] || options[:text])
370
+ @cached_content_for_layout = @content_for_layout
371
+ render(:file => partial_layout, :locals => local_assigns)
372
+ else
373
+ render(options.merge(:partial => partial_layout))
374
+ end
375
+ ensure
376
+ @content_for_layout = original_content_for_layout
377
+ end
378
+ end
345
379
  end
346
380
  end
347
381
  end