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
@@ -1,14 +1,15 @@
1
1
  module ActionView
2
- # There's also a convenience method for rendering sub templates within the current controller that depends on a single object
3
- # (we call this kind of sub templates for partials). It relies on the fact that partials should follow the naming convention of being
4
- # prefixed with an underscore -- as to separate them from regular templates that could be rendered on their own.
2
+ # There's also a convenience method for rendering sub templates within the current controller that depends on a
3
+ # single object (we call this kind of sub templates for partials). It relies on the fact that partials should
4
+ # follow the naming convention of being prefixed with an underscore -- as to separate them from regular
5
+ # templates that could be rendered on their own.
5
6
  #
6
7
  # In a template for Advertiser#account:
7
8
  #
8
9
  # <%= render :partial => "account" %>
9
10
  #
10
- # This would render "advertiser/_account.erb" and pass the instance variable @account in as a local variable +account+ to
11
- # the template for display.
11
+ # This would render "advertiser/_account.erb" and pass the instance variable @account in as a local variable
12
+ # +account+ to the template for display.
12
13
  #
13
14
  # In another template for Advertiser#buy, we could have:
14
15
  #
@@ -18,24 +19,24 @@ module ActionView
18
19
  # <%= render :partial => "ad", :locals => { :ad => ad } %>
19
20
  # <% end %>
20
21
  #
21
- # This would first render "advertiser/_account.erb" with @buyer passed in as the local variable +account+, then render
22
- # "advertiser/_ad.erb" and pass the local variable +ad+ to the template for display.
22
+ # This would first render "advertiser/_account.erb" with @buyer passed in as the local variable +account+, then
23
+ # render "advertiser/_ad.erb" and pass the local variable +ad+ to the template for display.
23
24
  #
24
25
  # == Rendering a collection of partials
25
26
  #
26
- # The example of partial use describes a familiar pattern where a template needs to iterate over an array and render a sub
27
- # template for each of the elements. This pattern has been implemented as a single method that accepts an array and renders
28
- # a partial by the same name as the elements contained within. So the three-lined example in "Using partials" can be rewritten
29
- # with a single line:
27
+ # The example of partial use describes a familiar pattern where a template needs to iterate over an array and
28
+ # render a sub template for each of the elements. This pattern has been implemented as a single method that
29
+ # accepts an array and renders a partial by the same name as the elements contained within. So the three-lined
30
+ # example in "Using partials" can be rewritten with a single line:
30
31
  #
31
32
  # <%= render :partial => "ad", :collection => @advertisements %>
32
33
  #
33
- # This will render "advertiser/_ad.erb" and pass the local variable +ad+ to the template for display. An iteration counter
34
- # will automatically be made available to the template with a name of the form +partial_name_counter+. In the case of the
35
- # example above, the template would be fed +ad_counter+.
34
+ # This will render "advertiser/_ad.erb" and pass the local variable +ad+ to the template for display. An
35
+ # iteration counter will automatically be made available to the template with a name of the form
36
+ # +partial_name_counter+. In the case of the example above, the template would be fed +ad_counter+.
36
37
  #
37
- # NOTE: Due to backwards compatibility concerns, the collection can't be one of hashes. Normally you'd also just keep domain objects,
38
- # like Active Records, in there.
38
+ # NOTE: Due to backwards compatibility concerns, the collection can't be one of hashes. Normally you'd also
39
+ # just keep domain objects, like Active Records, in there.
39
40
  #
40
41
  # == Rendering shared partials
41
42
  #
@@ -47,8 +48,9 @@ module ActionView
47
48
  #
48
49
  # == Rendering partials with layouts
49
50
  #
50
- # Partials can have their own layouts applied to them. These layouts are different than the ones that are specified globally
51
- # for the entire action, but they work in a similar fashion. Imagine a list with two types of users:
51
+ # Partials can have their own layouts applied to them. These layouts are different than the ones that are
52
+ # specified globally for the entire action, but they work in a similar fashion. Imagine a list with two types
53
+ # of users:
52
54
  #
53
55
  # <%# app/views/users/index.html.erb &>
54
56
  # Here's the administrator:
@@ -68,7 +70,7 @@ module ActionView
68
70
  #
69
71
  # <%# app/views/users/_editor.html.erb &>
70
72
  # <div id="editor">
71
- # Deadline: $<%= user.deadline %>
73
+ # Deadline: <%= user.deadline %>
72
74
  # <%= yield %>
73
75
  # </div>
74
76
  #
@@ -82,7 +84,7 @@ module ActionView
82
84
  #
83
85
  # Here's the editor:
84
86
  # <div id="editor">
85
- # Deadline: $<%= user.deadline %>
87
+ # Deadline: <%= user.deadline %>
86
88
  # Name: <%= user.name %>
87
89
  # </div>
88
90
  #
@@ -101,58 +103,101 @@ module ActionView
101
103
  # </div>
102
104
  #
103
105
  # As you can see, the <tt>:locals</tt> hash is shared between both the partial and its layout.
106
+ #
107
+ # If you pass arguments to "yield" then this will be passed to the block. One way to use this is to pass
108
+ # an array to layout and treat it as an enumerable.
109
+ #
110
+ # <%# app/views/users/_user.html.erb &>
111
+ # <div class="user">
112
+ # Budget: $<%= user.budget %>
113
+ # <%= yield user %>
114
+ # </div>
115
+ #
116
+ # <%# app/views/users/index.html.erb &>
117
+ # <% render :layout => @users do |user| %>
118
+ # Title: <%= user.title %>
119
+ # <% end %>
120
+ #
121
+ # This will render the layout for each user and yield to the block, passing the user, each time.
122
+ #
123
+ # You can also yield multiple times in one layout and use block arguments to differentiate the sections.
124
+ #
125
+ # <%# app/views/users/_user.html.erb &>
126
+ # <div class="user">
127
+ # <%= yield user, :header %>
128
+ # Budget: $<%= user.budget %>
129
+ # <%= yield user, :footer %>
130
+ # </div>
131
+ #
132
+ # <%# app/views/users/index.html.erb &>
133
+ # <% render :layout => @users do |user, section| %>
134
+ # <%- case section when :header -%>
135
+ # Title: <%= user.title %>
136
+ # <%- when :footer -%>
137
+ # Deadline: <%= user.deadline %>
138
+ # <%- end -%>
139
+ # <% end %>
104
140
  module Partials
141
+ extend ActiveSupport::Memoizable
142
+
105
143
  private
106
- def render_partial(partial_path, object_assigns = nil, local_assigns = {}) #:nodoc:
107
- case partial_path
144
+ def render_partial(options = {}) #:nodoc:
145
+ local_assigns = options[:locals] || {}
146
+
147
+ case partial_path = options[:partial]
108
148
  when String, Symbol, NilClass
109
- # Render the template
110
- ActionView::PartialTemplate.new(self, partial_path, object_assigns, local_assigns).render_template
149
+ if options.has_key?(:collection)
150
+ render_partial_collection(options)
151
+ else
152
+ _pick_partial_template(partial_path).render_partial(self, options[:object], local_assigns)
153
+ end
111
154
  when ActionView::Helpers::FormBuilder
112
155
  builder_partial_path = partial_path.class.to_s.demodulize.underscore.sub(/_builder$/, '')
113
- render_partial(builder_partial_path, object_assigns, (local_assigns || {}).merge(builder_partial_path.to_sym => partial_path))
156
+ local_assigns.merge!(builder_partial_path.to_sym => partial_path)
157
+ render_partial(:partial => builder_partial_path, :object => options[:object], :locals => local_assigns)
114
158
  when Array, ActiveRecord::Associations::AssociationCollection, ActiveRecord::NamedScope::Scope
115
- if partial_path.any?
116
- collection = partial_path
117
- render_partial_collection(nil, collection, nil, local_assigns)
118
- else
119
- ""
120
- end
159
+ render_partial_collection(options.except(:partial).merge(:collection => partial_path))
121
160
  else
122
- render_partial(ActionController::RecordIdentifier.partial_path(partial_path, controller.class.controller_path), partial_path, local_assigns)
161
+ object = partial_path
162
+ render_partial(
163
+ :partial => ActionController::RecordIdentifier.partial_path(object, controller.class.controller_path),
164
+ :object => object,
165
+ :locals => local_assigns
166
+ )
123
167
  end
124
168
  end
125
169
 
126
- def render_partial_collection(partial_path, collection, partial_spacer_template = nil, local_assigns = {}) #:nodoc:
127
- return " " if collection.empty?
170
+ def render_partial_collection(options = {}) #:nodoc:
171
+ return nil if options[:collection].blank?
128
172
 
129
- local_assigns = local_assigns ? local_assigns.clone : {}
130
- spacer = partial_spacer_template ? render(:partial => partial_spacer_template) : ''
173
+ partial = options[:partial]
174
+ spacer = options[:spacer_template] ? render(:partial => options[:spacer_template]) : ''
175
+ local_assigns = options[:locals] ? options[:locals].clone : {}
176
+ as = options[:as]
131
177
 
132
- if partial_path.nil?
133
- render_partial_collection_with_unknown_partial_path(collection, local_assigns)
134
- else
135
- render_partial_collection_with_known_partial_path(collection, partial_path, local_assigns)
178
+ index = 0
179
+ options[:collection].map do |object|
180
+ _partial_path ||= partial ||
181
+ ActionController::RecordIdentifier.partial_path(object, controller.class.controller_path)
182
+ template = _pick_partial_template(_partial_path)
183
+ local_assigns[template.counter_name] = index
184
+ result = template.render_partial(self, object, local_assigns.dup, as)
185
+ index += 1
186
+ result
136
187
  end.join(spacer)
137
188
  end
138
189
 
139
- def render_partial_collection_with_known_partial_path(collection, partial_path, local_assigns)
140
- template = ActionView::PartialTemplate.new(self, partial_path, nil, local_assigns)
141
- collection.map do |element|
142
- template.render_member(element)
190
+ def _pick_partial_template(partial_path) #:nodoc:
191
+ if partial_path.include?('/')
192
+ path = File.join(File.dirname(partial_path), "_#{File.basename(partial_path)}")
193
+ elsif controller
194
+ path = "#{controller.class.controller_path}/_#{partial_path}"
195
+ else
196
+ path = "_#{partial_path}"
143
197
  end
144
- end
145
198
 
146
- def render_partial_collection_with_unknown_partial_path(collection, local_assigns)
147
- templates = Hash.new
148
- i = 0
149
- collection.map do |element|
150
- partial_path = ActionController::RecordIdentifier.partial_path(element, controller.class.controller_path)
151
- template = templates[partial_path] ||= ActionView::PartialTemplate.new(self, partial_path, nil, local_assigns)
152
- template.counter = i
153
- i += 1
154
- template.render_member(element)
155
- end
199
+ _pick_template(path)
156
200
  end
201
+ memoize :_pick_partial_template
157
202
  end
158
203
  end
@@ -0,0 +1,125 @@
1
+ module ActionView #:nodoc:
2
+ class PathSet < Array #:nodoc:
3
+ def self.type_cast(obj)
4
+ if obj.is_a?(String)
5
+ if Base.warn_cache_misses && defined?(Rails) && Rails.initialized?
6
+ Base.logger.debug "[PERFORMANCE] Processing view path during a " +
7
+ "request. This an expense disk operation that should be done at " +
8
+ "boot. You can manually process this view path with " +
9
+ "ActionView::Base.process_view_paths(#{obj.inspect}) and set it " +
10
+ "as your view path"
11
+ end
12
+ Path.new(obj)
13
+ else
14
+ obj
15
+ end
16
+ end
17
+
18
+ def initialize(*args)
19
+ super(*args).map! { |obj| self.class.type_cast(obj) }
20
+ end
21
+
22
+ def <<(obj)
23
+ super(self.class.type_cast(obj))
24
+ end
25
+
26
+ def concat(array)
27
+ super(array.map! { |obj| self.class.type_cast(obj) })
28
+ end
29
+
30
+ def insert(index, obj)
31
+ super(index, self.class.type_cast(obj))
32
+ end
33
+
34
+ def push(*objs)
35
+ super(*objs.map { |obj| self.class.type_cast(obj) })
36
+ end
37
+
38
+ def unshift(*objs)
39
+ super(*objs.map { |obj| self.class.type_cast(obj) })
40
+ end
41
+
42
+ class Path #:nodoc:
43
+ def self.eager_load_templates!
44
+ @eager_load_templates = true
45
+ end
46
+
47
+ def self.eager_load_templates?
48
+ @eager_load_templates || false
49
+ end
50
+
51
+ attr_reader :path, :paths
52
+ delegate :to_s, :to_str, :hash, :inspect, :to => :path
53
+
54
+ def initialize(path, load = true)
55
+ raise ArgumentError, "path already is a Path class" if path.is_a?(Path)
56
+ @path = path.freeze
57
+ reload! if load
58
+ end
59
+
60
+ def ==(path)
61
+ to_str == path.to_str
62
+ end
63
+
64
+ def eql?(path)
65
+ to_str == path.to_str
66
+ end
67
+
68
+ def [](path)
69
+ raise "Unloaded view path! #{@path}" unless @loaded
70
+ @paths[path]
71
+ end
72
+
73
+ def loaded?
74
+ @loaded ? true : false
75
+ end
76
+
77
+ def load
78
+ reload! unless loaded?
79
+ self
80
+ end
81
+
82
+ # Rebuild load path directory cache
83
+ def reload!
84
+ @paths = {}
85
+
86
+ templates_in_path do |template|
87
+ # Eager load memoized methods and freeze cached template
88
+ template.freeze if self.class.eager_load_templates?
89
+
90
+ @paths[template.path] = template
91
+ @paths[template.path_without_extension] ||= template
92
+ end
93
+
94
+ @paths.freeze
95
+ @loaded = true
96
+ end
97
+
98
+ private
99
+ def templates_in_path
100
+ (Dir.glob("#{@path}/**/*/**") | Dir.glob("#{@path}/**")).each do |file|
101
+ unless File.directory?(file)
102
+ yield Template.new(file.split("#{self}/").last, self)
103
+ end
104
+ end
105
+ end
106
+ end
107
+
108
+ def load
109
+ each { |path| path.load }
110
+ end
111
+
112
+ def reload!
113
+ each { |path| path.reload! }
114
+ end
115
+
116
+ def [](template_path)
117
+ each do |path|
118
+ if template = path[template_path]
119
+ return template
120
+ end
121
+ end
122
+ nil
123
+ end
124
+ end
125
+ end
@@ -0,0 +1,102 @@
1
+ module ActionView
2
+ # NOTE: The template that this mixin is being included into is frozen
3
+ # so you cannot set or modify any instance variables
4
+ module Renderable #:nodoc:
5
+ extend ActiveSupport::Memoizable
6
+
7
+ def self.included(base)
8
+ @@mutex = Mutex.new
9
+ end
10
+
11
+ def filename
12
+ 'compiled-template'
13
+ end
14
+
15
+ def handler
16
+ Template.handler_class_for_extension(extension)
17
+ end
18
+ memoize :handler
19
+
20
+ def compiled_source
21
+ handler.call(self)
22
+ end
23
+ memoize :compiled_source
24
+
25
+ def render(view, local_assigns = {})
26
+ compile(local_assigns)
27
+
28
+ stack = view.instance_variable_get(:@_render_stack)
29
+ stack.push(self)
30
+
31
+ # This is only used for TestResponse to set rendered_template
32
+ unless is_a?(InlineTemplate) || view.instance_variable_get(:@_first_render)
33
+ view.instance_variable_set(:@_first_render, self)
34
+ end
35
+
36
+ view.send(:_evaluate_assigns_and_ivars)
37
+ view.send(:_set_controller_content_type, mime_type) if respond_to?(:mime_type)
38
+
39
+ result = view.send(method_name(local_assigns), local_assigns) do |*names|
40
+ ivar = :@_proc_for_layout
41
+ if !view.instance_variable_defined?(:"@content_for_#{names.first}") && view.instance_variable_defined?(ivar) && (proc = view.instance_variable_get(ivar))
42
+ view.capture(*names, &proc)
43
+ elsif view.instance_variable_defined?(ivar = :"@content_for_#{names.first || :layout}")
44
+ view.instance_variable_get(ivar)
45
+ end
46
+ end
47
+
48
+ stack.pop
49
+ result
50
+ end
51
+
52
+ def method_name(local_assigns)
53
+ if local_assigns && local_assigns.any?
54
+ local_assigns_keys = "locals_#{local_assigns.keys.map { |k| k.to_s }.sort.join('_')}"
55
+ end
56
+ ['_run', extension, method_segment, local_assigns_keys].compact.join('_').to_sym
57
+ end
58
+
59
+ private
60
+ # Compile and evaluate the template's code (if necessary)
61
+ def compile(local_assigns)
62
+ render_symbol = method_name(local_assigns)
63
+
64
+ @@mutex.synchronize do
65
+ if recompile?(render_symbol)
66
+ compile!(render_symbol, local_assigns)
67
+ end
68
+ end
69
+ end
70
+
71
+ def compile!(render_symbol, local_assigns)
72
+ locals_code = local_assigns.keys.map { |key| "#{key} = local_assigns[:#{key}];" }.join
73
+
74
+ source = <<-end_src
75
+ def #{render_symbol}(local_assigns)
76
+ old_output_buffer = output_buffer;#{locals_code};#{compiled_source}
77
+ ensure
78
+ self.output_buffer = old_output_buffer
79
+ end
80
+ end_src
81
+
82
+ begin
83
+ ActionView::Base::CompiledTemplates.module_eval(source, filename, 0)
84
+ rescue Exception => e # errors from template code
85
+ if logger = defined?(ActionController) && Base.logger
86
+ logger.debug "ERROR: compiling #{render_symbol} RAISED #{e}"
87
+ logger.debug "Function body: #{source}"
88
+ logger.debug "Backtrace: #{e.backtrace.join("\n")}"
89
+ end
90
+
91
+ raise ActionView::TemplateError.new(self, {}, e)
92
+ end
93
+ end
94
+
95
+ # Method to check whether template compilation is necessary.
96
+ # The template will be compiled if the file has not been compiled yet, or
97
+ # if local_assigns has a new key, which isn't supported by the compiled code yet.
98
+ def recompile?(symbol)
99
+ !(ActionView::PathSet::Path.eager_load_templates? && Base::CompiledTemplates.method_defined?(symbol))
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,48 @@
1
+ module ActionView
2
+ # NOTE: The template that this mixin is being included into is frozen
3
+ # so you cannot set or modify any instance variables
4
+ module RenderablePartial #:nodoc:
5
+ extend ActiveSupport::Memoizable
6
+
7
+ def variable_name
8
+ name.sub(/\A_/, '').to_sym
9
+ end
10
+ memoize :variable_name
11
+
12
+ def counter_name
13
+ "#{variable_name}_counter".to_sym
14
+ end
15
+ memoize :counter_name
16
+
17
+ def render(view, local_assigns = {})
18
+ if defined? ActionController
19
+ ActionController::Base.benchmark("Rendered #{path_without_format_and_extension}", Logger::DEBUG, false) do
20
+ super
21
+ end
22
+ else
23
+ super
24
+ end
25
+ end
26
+
27
+ def render_partial(view, object = nil, local_assigns = {}, as = nil)
28
+ object ||= local_assigns[:object] ||
29
+ local_assigns[variable_name]
30
+
31
+ if view.respond_to?(:controller)
32
+ ivar = :"@#{variable_name}"
33
+ object ||=
34
+ if view.controller.instance_variable_defined?(ivar)
35
+ ActiveSupport::Deprecation::DeprecatedObjectProxy.new(
36
+ view.controller.instance_variable_get(ivar),
37
+ "#{ivar} will no longer be implicitly assigned to #{variable_name}")
38
+ end
39
+ end
40
+
41
+ # Ensure correct object is reassigned to other accessors
42
+ local_assigns[:object] = local_assigns[variable_name] = object
43
+ local_assigns[as] = object if as
44
+
45
+ render_template(view, local_assigns)
46
+ end
47
+ end
48
+ end