actionpack 3.0.0.beta4 → 3.0.0.rc

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 (102) hide show
  1. data/CHANGELOG +36 -0
  2. data/{README → README.rdoc} +79 -137
  3. data/lib/abstract_controller.rb +1 -0
  4. data/lib/abstract_controller/asset_paths.rb +1 -1
  5. data/lib/abstract_controller/base.rb +3 -12
  6. data/lib/abstract_controller/rendering.rb +2 -2
  7. data/lib/abstract_controller/view_paths.rb +2 -1
  8. data/lib/action_controller.rb +1 -2
  9. data/lib/action_controller/base.rb +3 -9
  10. data/lib/action_controller/log_subscriber.rb +56 -0
  11. data/lib/action_controller/metal.rb +10 -3
  12. data/lib/action_controller/metal/helpers.rb +5 -4
  13. data/lib/action_controller/metal/hide_actions.rb +3 -3
  14. data/lib/action_controller/metal/instrumentation.rb +2 -1
  15. data/lib/action_controller/metal/mime_responds.rb +13 -10
  16. data/lib/action_controller/metal/rack_delegation.rb +0 -4
  17. data/lib/action_controller/metal/request_forgery_protection.rb +1 -1
  18. data/lib/action_controller/metal/rescue.rb +9 -0
  19. data/lib/action_controller/metal/responder.rb +13 -5
  20. data/lib/action_controller/metal/streaming.rb +2 -0
  21. data/lib/action_controller/metal/url_for.rb +5 -5
  22. data/lib/action_controller/railtie.rb +14 -23
  23. data/lib/action_controller/record_identifier.rb +6 -25
  24. data/lib/action_controller/test_case.rb +18 -6
  25. data/lib/action_controller/vendor/html-scanner/html/node.rb +1 -0
  26. data/lib/action_controller/vendor/html-scanner/html/tokenizer.rb +1 -0
  27. data/lib/action_dispatch.rb +6 -0
  28. data/lib/action_dispatch/http/cache.rb +2 -2
  29. data/lib/action_dispatch/http/filter_parameters.rb +10 -66
  30. data/lib/action_dispatch/http/mime_type.rb +1 -1
  31. data/lib/action_dispatch/http/parameter_filter.rb +72 -0
  32. data/lib/action_dispatch/http/parameters.rb +31 -2
  33. data/lib/action_dispatch/http/request.rb +4 -1
  34. data/lib/action_dispatch/http/upload.rb +2 -2
  35. data/lib/action_dispatch/middleware/callbacks.rb +4 -4
  36. data/lib/action_dispatch/middleware/cookies.rb +39 -6
  37. data/lib/action_dispatch/middleware/flash.rb +9 -2
  38. data/lib/action_dispatch/middleware/session/abstract_store.rb +121 -36
  39. data/lib/action_dispatch/middleware/session/cookie_store.rb +26 -19
  40. data/lib/action_dispatch/middleware/session/mem_cache_store.rb +9 -1
  41. data/lib/action_dispatch/middleware/show_exceptions.rb +2 -2
  42. data/lib/action_dispatch/middleware/stack.rb +12 -5
  43. data/lib/action_dispatch/railtie.rb +1 -1
  44. data/lib/action_dispatch/routing.rb +11 -13
  45. data/lib/action_dispatch/routing/deprecated_mapper.rb +6 -388
  46. data/lib/action_dispatch/routing/mapper.rb +364 -234
  47. data/lib/action_dispatch/routing/polymorphic_routes.rb +186 -0
  48. data/lib/action_dispatch/routing/route.rb +11 -2
  49. data/lib/action_dispatch/routing/route_set.rb +62 -28
  50. data/lib/action_dispatch/routing/url_for.rb +2 -1
  51. data/lib/action_dispatch/testing/assertions.rb +0 -2
  52. data/lib/action_dispatch/testing/assertions/routing.rb +0 -1
  53. data/lib/action_dispatch/testing/assertions/selector.rb +20 -24
  54. data/lib/action_dispatch/testing/integration.rb +2 -2
  55. data/lib/action_dispatch/testing/test_response.rb +2 -2
  56. data/lib/action_pack/version.rb +1 -1
  57. data/lib/action_view.rb +1 -0
  58. data/lib/action_view/base.rb +20 -21
  59. data/lib/action_view/context.rb +9 -12
  60. data/lib/action_view/helpers.rb +0 -2
  61. data/lib/action_view/helpers/active_model_helper.rb +17 -2
  62. data/lib/action_view/helpers/asset_tag_helper.rb +15 -33
  63. data/lib/action_view/helpers/atom_feed_helper.rb +5 -3
  64. data/lib/action_view/helpers/cache_helper.rb +4 -2
  65. data/lib/action_view/helpers/capture_helper.rb +4 -4
  66. data/lib/action_view/helpers/csrf_helper.rb +3 -1
  67. data/lib/action_view/helpers/date_helper.rb +10 -5
  68. data/lib/action_view/helpers/debug_helper.rb +3 -1
  69. data/lib/action_view/helpers/form_helper.rb +36 -30
  70. data/lib/action_view/helpers/form_options_helper.rb +7 -6
  71. data/lib/action_view/helpers/form_tag_helper.rb +17 -6
  72. data/lib/action_view/helpers/javascript_helper.rb +1 -0
  73. data/lib/action_view/helpers/number_helper.rb +16 -45
  74. data/lib/action_view/helpers/prototype_helper.rb +14 -16
  75. data/lib/action_view/helpers/raw_output_helper.rb +9 -0
  76. data/lib/action_view/helpers/record_tag_helper.rb +5 -0
  77. data/lib/action_view/helpers/sanitize_helper.rb +26 -20
  78. data/lib/action_view/helpers/scriptaculous_helper.rb +6 -5
  79. data/lib/action_view/helpers/tag_helper.rb +2 -1
  80. data/lib/action_view/helpers/text_helper.rb +24 -111
  81. data/lib/action_view/helpers/translation_helper.rb +17 -10
  82. data/lib/action_view/helpers/url_helper.rb +26 -33
  83. data/lib/action_view/log_subscriber.rb +28 -0
  84. data/lib/action_view/lookup_context.rb +2 -0
  85. data/lib/action_view/paths.rb +1 -0
  86. data/lib/action_view/railtie.rb +15 -3
  87. data/lib/action_view/render/layouts.rb +2 -1
  88. data/lib/action_view/render/partials.rb +3 -1
  89. data/lib/action_view/render/rendering.rb +2 -1
  90. data/lib/action_view/template.rb +12 -8
  91. data/lib/action_view/template/error.rb +1 -0
  92. data/lib/action_view/template/handlers.rb +1 -0
  93. data/lib/action_view/template/resolver.rb +2 -1
  94. data/lib/action_view/template/text.rb +1 -0
  95. data/lib/action_view/test_case.rb +42 -20
  96. metadata +44 -23
  97. data/lib/action_controller/polymorphic_routes.rb +0 -182
  98. data/lib/action_controller/railties/log_subscriber.rb +0 -56
  99. data/lib/action_controller/railties/url_helpers.rb +0 -14
  100. data/lib/action_dispatch/testing/assertions/model.rb +0 -19
  101. data/lib/action_view/helpers/record_identification_helper.rb +0 -20
  102. data/lib/action_view/railties/log_subscriber.rb +0 -24
@@ -1,21 +1,28 @@
1
1
  require 'action_view/helpers/tag_helper'
2
2
 
3
3
  module ActionView
4
+ # = Action View Translation Helpers
4
5
  module Helpers
5
6
  module TranslationHelper
6
- # Delegates to I18n#translate but also performs three additional functions. First, it'll catch MissingTranslationData exceptions
7
- # and turn them into inline spans that contains the missing key, such that you can see in a view what is missing where.
7
+ # Delegates to I18n#translate but also performs three additional functions.
8
+ # First, it'll catch MissingTranslationData exceptions and turn them into
9
+ # inline spans that contains the missing key, such that you can see in a
10
+ # view what is missing where.
8
11
  #
9
- # Second, it'll scope the key by the current partial if the key starts with a period. So if you call translate(".foo") from the
10
- # people/index.html.erb template, you'll actually be calling I18n.translate("people.index.foo"). This makes it less repetitive
11
- # to translate many keys within the same partials and gives you a simple framework for scoping them consistently. If you don't
12
- # prepend the key with a period, nothing is converted.
12
+ # Second, it'll scope the key by the current partial if the key starts
13
+ # with a period. So if you call <tt>translate(".foo")</tt> from the
14
+ # <tt>people/index.html.erb</tt> template, you'll actually be calling
15
+ # <tt>I18n.translate("people.index.foo")</tt>. This makes it less repetitive
16
+ # to translate many keys within the same partials and gives you a simple framework
17
+ # for scoping them consistently. If you don't prepend the key with a period,
18
+ # nothing is converted.
13
19
  #
14
- # Third, itll mark the translation as safe HTML if the key has the suffix "_html" or the last element of the key is the word
15
- # "html". For example, calling translate("footer_html") or translate("footer.html") will return a safe HTML string that won’t
16
- # be escaped by other HTML helper methods. This naming convention helps to identify translations that include HTML tags so that
20
+ # Third, it'll mark the translation as safe HTML if the key has the suffix
21
+ # "_html" or the last element of the key is the word "html". For example,
22
+ # calling translate("footer_html") or translate("footer.html") will return
23
+ # a safe HTML string that won't be escaped by other HTML helper methods. This
24
+ # naming convention helps to identify translations that include HTML tags so that
17
25
  # you know what kind of output to expect when you call translate in a template.
18
-
19
26
  def translate(key, options = {})
20
27
  translation = I18n.translate(scope_key_by_partial(key), options.merge!(:raise => true))
21
28
  if html_safe_translation_key?(key) && translation.respond_to?(:html_safe)
@@ -4,6 +4,7 @@ require 'active_support/core_ext/hash/keys'
4
4
  require 'action_dispatch'
5
5
 
6
6
  module ActionView
7
+ # = Action View URL Helpers
7
8
  module Helpers #:nodoc:
8
9
  # Provides a set of methods for making links and getting URLs that
9
10
  # depend on the routing subsystem (see ActionDispatch::Routing).
@@ -11,8 +12,8 @@ module ActionView
11
12
  # and controllers.
12
13
  module UrlHelper
13
14
  # This helper may be included in any class that includes the
14
- # URL helpers of a router (router.url_helpers). Some methods
15
- # provided here will only work in the context of a request
15
+ # URL helpers of a routes (routes.url_helpers). Some methods
16
+ # provided here will only work in the4 context of a request
16
17
  # (link_to_unless_current, for instance), which must be provided
17
18
  # as a method called #request on the context.
18
19
 
@@ -37,9 +38,6 @@ module ActionView
37
38
  # <tt>:only_path</tt> is <tt>true</tt> so you'll get the relative "/controller/action"
38
39
  # instead of the fully qualified URL like "http://example.com/controller/action".
39
40
  #
40
- # When called from a view, +url_for+ returns an HTML escaped url. If you
41
- # need an unescaped url, pass <tt>:escape => false</tt> in the +options+.
42
- #
43
41
  # ==== Options
44
42
  # * <tt>:anchor</tt> - Specifies the anchor name to be appended to the path.
45
43
  # * <tt>:only_path</tt> - If true, returns the relative URL (omitting the protocol, host name, and port) (<tt>true</tt> by default unless <tt>:host</tt> is specified).
@@ -49,7 +47,6 @@ module ActionView
49
47
  # * <tt>:protocol</tt> - Overrides the default (current) protocol if provided.
50
48
  # * <tt>:user</tt> - Inline HTTP authentication (only plucked out if <tt>:password</tt> is also present).
51
49
  # * <tt>:password</tt> - Inline HTTP authentication (only plucked out if <tt>:user</tt> is also present).
52
- # * <tt>:escape</tt> - Determines whether the returned URL will be HTML escaped or not (<tt>true</tt> by default).
53
50
  #
54
51
  # ==== Relying on named routes
55
52
  #
@@ -71,10 +68,7 @@ module ActionView
71
68
  # <%= url_for(:action => 'play', :anchor => 'player') %>
72
69
  # # => /messages/play/#player
73
70
  #
74
- # <%= url_for(:action => 'checkout', :anchor => 'tax&ship') %>
75
- # # => /testing/jump/#tax&amp;ship
76
- #
77
- # <%= url_for(:action => 'checkout', :anchor => 'tax&ship', :escape => false) %>
71
+ # <%= url_for(:action => 'jump', :anchor => 'tax&ship') %>
78
72
  # # => /testing/jump/#tax&ship
79
73
  #
80
74
  # <%= url_for(Workshop.new) %>
@@ -99,21 +93,17 @@ module ActionView
99
93
  options ||= {}
100
94
  url = case options
101
95
  when String
102
- escape = true
103
96
  options
104
97
  when Hash
105
- options = { :only_path => options[:host].nil? }.update(options.symbolize_keys)
106
- escape = options.key?(:escape) ? options.delete(:escape) : false
98
+ options = options.symbolize_keys.reverse_merge!(:only_path => options[:host].nil?)
107
99
  super
108
100
  when :back
109
- escape = false
110
101
  controller.request.env["HTTP_REFERER"] || 'javascript:history.back()'
111
102
  else
112
- escape = false
113
103
  polymorphic_path(options)
114
104
  end
115
105
 
116
- escape ? escape_once(url).html_safe : url
106
+ url
117
107
  end
118
108
 
119
109
  # Creates a link tag of the given +name+ using a URL created by the set
@@ -253,8 +243,8 @@ module ActionView
253
243
  tag_options = nil
254
244
  end
255
245
 
256
- href_attr = "href=\"#{url}\"" unless href
257
- "<a #{href_attr}#{tag_options}>#{ERB::Util.h(name || url)}</a>".html_safe
246
+ href_attr = "href=\"#{html_escape(url)}\"" unless href
247
+ "<a #{href_attr}#{tag_options}>#{html_escape(name || url)}</a>".html_safe
258
248
  end
259
249
  end
260
250
 
@@ -338,7 +328,7 @@ module ActionView
338
328
 
339
329
  html_options.merge!("type" => "submit", "value" => name)
340
330
 
341
- ("<form method=\"#{form_method}\" action=\"#{escape_once url}\" #{"data-remote=\"true\"" if remote} class=\"button_to\"><div>" +
331
+ ("<form method=\"#{form_method}\" action=\"#{html_escape(url)}\" #{"data-remote=\"true\"" if remote} class=\"button_to\"><div>" +
342
332
  method_tag + tag("input", html_options) + request_token_tag + "</div></form>").html_safe
343
333
  end
344
334
 
@@ -408,7 +398,7 @@ module ActionView
408
398
  def link_to_unless(condition, name, options = {}, html_options = {}, &block)
409
399
  if condition
410
400
  if block_given?
411
- block.arity <= 1 ? yield(name) : yield(name, options, html_options)
401
+ block.arity <= 1 ? capture(name, &block) : capture(name, options, html_options, &block)
412
402
  else
413
403
  name
414
404
  end
@@ -484,24 +474,27 @@ module ActionView
484
474
  # :subject => "This is an example email"
485
475
  # # => <a href="mailto:me@domain.com?cc=ccaddress@domain.com&subject=This%20is%20an%20example%20email">My email</a>
486
476
  def mail_to(email_address, name = nil, html_options = {})
477
+ email_address = html_escape(email_address)
478
+
487
479
  html_options = html_options.stringify_keys
488
480
  encode = html_options.delete("encode").to_s
489
481
  cc, bcc, subject, body = html_options.delete("cc"), html_options.delete("bcc"), html_options.delete("subject"), html_options.delete("body")
490
482
 
491
- string = ''
492
- extras = ''
493
- extras << "cc=#{Rack::Utils.escape(cc).gsub("+", "%20")}&" unless cc.nil?
494
- extras << "bcc=#{Rack::Utils.escape(bcc).gsub("+", "%20")}&" unless bcc.nil?
495
- extras << "body=#{Rack::Utils.escape(body).gsub("+", "%20")}&" unless body.nil?
496
- extras << "subject=#{Rack::Utils.escape(subject).gsub("+", "%20")}&" unless subject.nil?
497
- extras = "?" << extras.gsub!(/&?$/,"") unless extras.empty?
498
-
499
- email_address_obfuscated = html_escape(email_address)
483
+ extras = []
484
+ extras << "cc=#{Rack::Utils.escape(cc).gsub("+", "%20")}" unless cc.nil?
485
+ extras << "bcc=#{Rack::Utils.escape(bcc).gsub("+", "%20")}" unless bcc.nil?
486
+ extras << "body=#{Rack::Utils.escape(body).gsub("+", "%20")}" unless body.nil?
487
+ extras << "subject=#{Rack::Utils.escape(subject).gsub("+", "%20")}" unless subject.nil?
488
+ extras = extras.empty? ? '' : '?' + html_escape(extras.join('&'))
489
+
490
+ email_address_obfuscated = email_address.dup
500
491
  email_address_obfuscated.gsub!(/@/, html_options.delete("replace_at")) if html_options.has_key?("replace_at")
501
492
  email_address_obfuscated.gsub!(/\./, html_options.delete("replace_dot")) if html_options.has_key?("replace_dot")
502
493
 
494
+ string = ''
495
+
503
496
  if encode == "javascript"
504
- "document.write('#{content_tag("a", name || email_address_obfuscated.html_safe, html_options.merge({ "href" => "mailto:"+email_address+extras }))}');".each_byte do |c|
497
+ "document.write('#{content_tag("a", name || email_address_obfuscated.html_safe, html_options.merge("href" => "mailto:#{email_address}#{extras}".html_safe))}');".each_byte do |c|
505
498
  string << sprintf("%%%x", c)
506
499
  end
507
500
  "<script type=\"#{Mime::JS}\">eval(decodeURIComponent('#{string}'))</script>".html_safe
@@ -518,9 +511,9 @@ module ActionView
518
511
  char = c.chr
519
512
  string << (char =~ /\w/ ? sprintf("%%%x", c) : char)
520
513
  end
521
- content_tag "a", name || email_address_encoded.html_safe, html_options.merge({ "href" => "#{string}#{extras}" })
514
+ content_tag "a", name || email_address_encoded.html_safe, html_options.merge("href" => "#{string}#{extras}".html_safe)
522
515
  else
523
- content_tag "a", name || email_address_obfuscated.html_safe, html_options.merge({ "href" => "mailto:#{email_address}#{extras}" })
516
+ content_tag "a", name || email_address_obfuscated.html_safe, html_options.merge("href" => "mailto:#{email_address}#{extras}".html_safe)
524
517
  end
525
518
  end
526
519
 
@@ -573,7 +566,7 @@ module ActionView
573
566
  "in a #request method"
574
567
  end
575
568
 
576
- url_string = CGI.unescapeHTML(url_for(options))
569
+ url_string = url_for(options)
577
570
 
578
571
  # We ignore any extra parameters in the request_uri if the
579
572
  # submitted url doesn't have any either. This lets the function
@@ -0,0 +1,28 @@
1
+ module ActionView
2
+ # = Action View Log Subscriber
3
+ #
4
+ # Provides functionality so that Rails can output logs from Action View.
5
+ class LogSubscriber < ActiveSupport::LogSubscriber
6
+ def render_template(event)
7
+ message = "Rendered #{from_rails_root(event.payload[:identifier])}"
8
+ message << " within #{from_rails_root(event.payload[:layout])}" if event.payload[:layout]
9
+ message << (" (%.1fms)" % event.duration)
10
+ info(message)
11
+ end
12
+ alias :render_partial :render_template
13
+ alias :render_collection :render_template
14
+
15
+ # TODO: Ideally, ActionView should have its own logger so it does not depend on AC.logger
16
+ def logger
17
+ ActionController::Base.logger if defined?(ActionController::Base)
18
+ end
19
+
20
+ protected
21
+
22
+ def from_rails_root(string)
23
+ string.sub("#{Rails.root}/", "").sub(/^app\/views\//, "")
24
+ end
25
+ end
26
+ end
27
+
28
+ ActionView::LogSubscriber.attach_to :action_view
@@ -2,6 +2,8 @@ require 'active_support/core_ext/array/wrap'
2
2
  require 'active_support/core_ext/object/blank'
3
3
 
4
4
  module ActionView
5
+ # = Action View Lookup Context
6
+ #
5
7
  # LookupContext is the object responsible to hold all information required to lookup
6
8
  # templates, i.e. view paths and details. The LookupContext is also responsible to
7
9
  # generate a key, given to view paths, used in the resolver cache lookup. Since
@@ -1,4 +1,5 @@
1
1
  module ActionView #:nodoc:
2
+ # = Action View PathSet
2
3
  class PathSet < Array #:nodoc:
3
4
  %w(initialize << concat insert push unshift).each do |method|
4
5
  class_eval <<-METHOD, __FILE__, __LINE__ + 1
@@ -2,11 +2,11 @@ require "action_view"
2
2
  require "rails"
3
3
 
4
4
  module ActionView
5
+ # = Action View Railtie
5
6
  class Railtie < Rails::Railtie
6
7
  config.action_view = ActiveSupport::OrderedOptions.new
7
-
8
- require "action_view/railties/log_subscriber"
9
- log_subscriber :action_view, ActionView::Railties::LogSubscriber.new
8
+ config.action_view.stylesheet_expansions = {}
9
+ config.action_view.javascript_expansions = { :defaults => ['prototype', 'effects', 'dragdrop', 'controls', 'rails'] }
10
10
 
11
11
  initializer "action_view.cache_asset_timestamps" do |app|
12
12
  unless app.config.cache_classes
@@ -16,6 +16,18 @@ module ActionView
16
16
  end
17
17
  end
18
18
 
19
+ initializer "action_view.javascript_expansions" do |app|
20
+ ActiveSupport.on_load(:action_view) do
21
+ ActionView::Helpers::AssetTagHelper.register_javascript_expansion(
22
+ app.config.action_view.delete(:javascript_expansions)
23
+ )
24
+
25
+ ActionView::Helpers::AssetTagHelper.register_stylesheet_expansion(
26
+ app.config.action_view.delete(:stylesheet_expansions)
27
+ )
28
+ end
29
+ end
30
+
19
31
  initializer "action_view.set_configs" do |app|
20
32
  ActiveSupport.on_load(:action_view) do
21
33
  app.config.action_view.each do |k,v|
@@ -1,4 +1,5 @@
1
1
  module ActionView
2
+ # = Action View Layouts
2
3
  module Layouts
3
4
  # Returns the contents that are yielded to a layout, given a name or a block.
4
5
  #
@@ -55,7 +56,7 @@ module ActionView
55
56
  end
56
57
 
57
58
  # This is the method which actually finds the layout using details in the lookup
58
- # context object. If no layout is found, it checkes if at least a layout with
59
+ # context object. If no layout is found, it checks if at least a layout with
59
60
  # the given name exists across all details before raising the error.
60
61
  def find_layout(layout)
61
62
  begin
@@ -1,6 +1,8 @@
1
1
  require 'active_support/core_ext/object/blank'
2
2
 
3
3
  module ActionView
4
+ # = Action View Partials
5
+ #
4
6
  # There's also a convenience method for rendering sub templates within the current controller that depends on a
5
7
  # single object (we call this kind of sub templates for partials). It relies on the fact that partials should
6
8
  # follow the naming convention of being prefixed with an underscore -- as to separate them from regular
@@ -316,7 +318,7 @@ module ActionView
316
318
 
317
319
  object.class.model_name.partial_path.dup.tap do |partial|
318
320
  path = @view.controller_path
319
- partial.insert(0, "#{File.dirname(path)}/") if path.include?(?/)
321
+ partial.insert(0, "#{File.dirname(path)}/") if partial.include?(?/) && path.include?(?/)
320
322
  end
321
323
  end
322
324
  end
@@ -1,6 +1,7 @@
1
1
  require 'active_support/core_ext/object/try'
2
2
 
3
3
  module ActionView
4
+ # = Action View Rendering
4
5
  module Rendering
5
6
  # Returns the result of a render that's dictated by the options hash. The primary options are:
6
7
  #
@@ -56,7 +57,7 @@ module ActionView
56
57
  :identifier => template.identifier, :layout => layout.try(:virtual_path)) do
57
58
 
58
59
  content = template.render(self, locals) { |*name| _layout_for(*name) }
59
- @_content_for[:layout] = content
60
+ @_content_for[:layout] = content if layout
60
61
 
61
62
  content = _render_layout(layout, locals) if layout
62
63
  content
@@ -3,6 +3,7 @@ require 'active_support/core_ext/object/blank'
3
3
  require 'active_support/core_ext/kernel/singleton_class'
4
4
 
5
5
  module ActionView
6
+ # = Action View Template
6
7
  class Template
7
8
  extend ActiveSupport::Autoload
8
9
 
@@ -155,11 +156,12 @@ module ActionView
155
156
  end
156
157
 
157
158
  def inspect
158
- if defined?(Rails.root)
159
- identifier.sub("#{Rails.root}/", '')
160
- else
161
- identifier
162
- end
159
+ @inspect ||=
160
+ if defined?(Rails.root)
161
+ identifier.sub("#{Rails.root}/", '')
162
+ else
163
+ identifier
164
+ end
163
165
  end
164
166
 
165
167
  private
@@ -266,9 +268,11 @@ module ActionView
266
268
  end
267
269
 
268
270
  def build_method_name(locals)
269
- # TODO: is locals.keys.hash reliably the same?
270
- @method_names[locals.keys.hash] ||=
271
- "_render_template_#{@identifier.hash}_#{__id__}_#{locals.keys.hash}".gsub('-', "_")
271
+ @method_names[locals.keys.hash] ||= "_#{identifier_method_name}__#{@identifier.hash}_#{__id__}_#{locals.keys.hash}".gsub('-', "_")
272
+ end
273
+
274
+ def identifier_method_name
275
+ @identifier_method_name ||= inspect.gsub(/[^a-z_]/, '_')
272
276
  end
273
277
  end
274
278
  end
@@ -1,6 +1,7 @@
1
1
  require "active_support/core_ext/enumerable"
2
2
 
3
3
  module ActionView
4
+ # = Action View Errors
4
5
  class ActionViewError < StandardError #:nodoc:
5
6
  end
6
7
 
@@ -1,4 +1,5 @@
1
1
  module ActionView #:nodoc:
2
+ # = Action View Template Handlers
2
3
  class Template
3
4
  module Handlers #:nodoc:
4
5
  autoload :ERB, 'action_view/template/handlers/erb'
@@ -3,6 +3,7 @@ require "active_support/core_ext/class"
3
3
  require "action_view/template"
4
4
 
5
5
  module ActionView
6
+ # = Action View Resolver
6
7
  class Resolver
7
8
  def initialize
8
9
  @cached = Hash.new { |h1,k1| h1[k1] =
@@ -98,7 +99,7 @@ module ActionView
98
99
  def initialize(path)
99
100
  raise ArgumentError, "path already is a Resolver class" if path.is_a?(Resolver)
100
101
  super()
101
- @path = Pathname.new(path).expand_path
102
+ @path = File.expand_path(path)
102
103
  end
103
104
 
104
105
  def eql?(resolver)
@@ -1,4 +1,5 @@
1
1
  module ActionView #:nodoc:
2
+ # = Action View Text Template
2
3
  class Template
3
4
  class Text < String #:nodoc:
4
5
  attr_accessor :mime_type
@@ -4,6 +4,7 @@ require 'action_controller/test_case'
4
4
  require 'action_view'
5
5
 
6
6
  module ActionView
7
+ # = Action View Test Case
7
8
  class TestCase < ActiveSupport::TestCase
8
9
  class TestController < ActionController::Base
9
10
  include ActionDispatch::TestProcess
@@ -36,7 +37,7 @@ module ActionView
36
37
  include ActionController::TemplateAssertions
37
38
  include ActionView::Context
38
39
 
39
- include ActionController::PolymorphicRoutes
40
+ include ActionDispatch::Routing::PolymorphicRoutes
40
41
  include ActionController::RecordIdentifier
41
42
 
42
43
  include AbstractController::Helpers
@@ -84,6 +85,7 @@ module ActionView
84
85
 
85
86
  def setup_with_controller
86
87
  @controller = ActionView::TestCase::TestController.new
88
+ @request = @controller.request
87
89
  @output_buffer = ActiveSupport::SafeBuffer.new
88
90
  @rendered = ''
89
91
 
@@ -97,10 +99,15 @@ module ActionView
97
99
  end
98
100
 
99
101
  def render(options = {}, local_assigns = {}, &block)
100
- @rendered << output = _view.render(options, local_assigns, &block)
102
+ view.assign(_assigns)
103
+ @rendered << output = view.render(options, local_assigns, &block)
101
104
  output
102
105
  end
103
106
 
107
+ def locals
108
+ @locals ||= {}
109
+ end
110
+
104
111
  included do
105
112
  setup :setup_with_controller
106
113
  end
@@ -130,36 +137,51 @@ module ActionView
130
137
  end
131
138
  end
132
139
 
133
- def _view
134
- @_view ||= begin
135
- view = ActionView::Base.new(ActionController::Base.view_paths, _assigns, @controller)
140
+ module Locals
141
+ attr_accessor :locals
142
+
143
+ def _render_partial(options)
144
+ locals[options[:partial]] = options[:locals]
145
+ super(options)
146
+ end
147
+ end
148
+
149
+ # The instance of ActionView::Base that is used by +render+.
150
+ def view
151
+ @view ||= begin
152
+ view = ActionView::Base.new(ActionController::Base.view_paths, {}, @controller)
136
153
  view.singleton_class.send :include, _helpers
137
- view.singleton_class.send :include, @controller._router.url_helpers
154
+ view.singleton_class.send :include, @controller._routes.url_helpers
138
155
  view.singleton_class.send :delegate, :alert, :notice, :to => "request.flash"
156
+ view.extend(Locals)
157
+ view.locals = self.locals
139
158
  view.output_buffer = self.output_buffer
140
159
  view
141
160
  end
142
161
  end
143
162
 
163
+ alias_method :_view, :view
164
+
144
165
  EXCLUDE_IVARS = %w{
166
+ @_assertion_wrapped
145
167
  @_result
168
+ @controller
169
+ @layouts
170
+ @locals
171
+ @method_name
146
172
  @output_buffer
173
+ @partials
147
174
  @rendered
175
+ @request
176
+ @routes
148
177
  @templates
149
- @view_context_class
150
- @layouts
151
- @partials
152
- @controller
153
-
154
- @method_name
155
- @fixture_cache
156
- @loaded_fixtures
157
178
  @test_passed
179
+ @view
180
+ @view_context_class
158
181
  }
159
182
 
160
183
  def _instance_variables
161
- instance_variables - EXCLUDE_IVARS
162
- instance_variables
184
+ instance_variables.map(&:to_s) - EXCLUDE_IVARS
163
185
  end
164
186
 
165
187
  def _assigns
@@ -170,13 +192,13 @@ module ActionView
170
192
  end
171
193
  end
172
194
 
173
- def _router
174
- @controller._router if @controller.respond_to?(:_router)
195
+ def _routes
196
+ @controller._routes if @controller.respond_to?(:_routes)
175
197
  end
176
198
 
177
199
  def method_missing(selector, *args)
178
- if @controller.respond_to?(:_router) &&
179
- @controller._router.named_routes.helpers.include?(selector)
200
+ if @controller.respond_to?(:_routes) &&
201
+ @controller._routes.named_routes.helpers.include?(selector)
180
202
  @controller.__send__(selector, *args)
181
203
  else
182
204
  super