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
@@ -49,11 +49,10 @@ module ActionView
49
49
  #
50
50
  def content_tag_for(tag_name, record, *args, &block)
51
51
  prefix = args.first.is_a?(Hash) ? nil : args.shift
52
- options = args.first.is_a?(Hash) ? args.shift : {}
53
- concat content_tag(tag_name, capture(&block),
54
- options.merge({ :class => "#{dom_class(record)} #{options[:class]}".strip, :id => dom_id(record, prefix) })),
55
- block.binding
52
+ options = args.extract_options!
53
+ options.merge!({ :class => "#{dom_class(record)} #{options[:class]}".strip, :id => dom_id(record, prefix) })
54
+ content_tag(tag_name, options, &block)
56
55
  end
57
56
  end
58
57
  end
59
- end
58
+ end
@@ -1,22 +1,27 @@
1
1
  require 'action_view/helpers/tag_helper'
2
- require 'html/document'
2
+
3
+ begin
4
+ require 'html/document'
5
+ rescue LoadError
6
+ html_scanner_path = "#{File.dirname(__FILE__)}/../../action_controller/vendor/html-scanner"
7
+ if File.directory?(html_scanner_path)
8
+ $:.unshift html_scanner_path
9
+ require 'html/document'
10
+ end
11
+ end
3
12
 
4
13
  module ActionView
5
14
  module Helpers #:nodoc:
6
15
  # The SanitizeHelper module provides a set of methods for scrubbing text of undesired HTML elements.
7
16
  # These helper methods extend ActionView making them callable within your template files.
8
17
  module SanitizeHelper
9
- def self.included(base)
10
- base.extend(ClassMethods)
11
- end
12
-
13
18
  # This +sanitize+ helper will html encode all tags and strip all attributes that aren't specifically allowed.
14
19
  # It also strips href/src tags with invalid protocols, like javascript: especially. It does its best to counter any
15
20
  # tricks that hackers may use, like throwing in unicode/ascii/hex values to get past the javascript: filters. Check out
16
21
  # the extensive test suite.
17
22
  #
18
23
  # <%= sanitize @article.body %>
19
- #
24
+ #
20
25
  # You can add or remove tags/attributes if you want to customize it a bit. See ActionView::Base for full docs on the
21
26
  # available options. You can add tags/attributes for single uses of +sanitize+ by passing either the <tt>:attributes</tt> or <tt>:tags</tt> options:
22
27
  #
@@ -27,27 +32,27 @@ module ActionView
27
32
  # Custom Use (only the mentioned tags and attributes are allowed, nothing else)
28
33
  #
29
34
  # <%= sanitize @article.body, :tags => %w(table tr td), :attributes => %w(id class style)
30
- #
35
+ #
31
36
  # Add table tags to the default allowed tags
32
- #
37
+ #
33
38
  # Rails::Initializer.run do |config|
34
39
  # config.action_view.sanitized_allowed_tags = 'table', 'tr', 'td'
35
40
  # end
36
- #
41
+ #
37
42
  # Remove tags to the default allowed tags
38
- #
43
+ #
39
44
  # Rails::Initializer.run do |config|
40
45
  # config.after_initialize do
41
46
  # ActionView::Base.sanitized_allowed_tags.delete 'div'
42
47
  # end
43
48
  # end
44
- #
49
+ #
45
50
  # Change allowed default attributes
46
- #
51
+ #
47
52
  # Rails::Initializer.run do |config|
48
53
  # config.action_view.sanitized_allowed_attributes = 'id', 'class', 'style'
49
54
  # end
50
- #
55
+ #
51
56
  # Please note that sanitizing user-provided text does not guarantee that the
52
57
  # resulting markup is valid (conforming to a document type) or even well-formed.
53
58
  # The output may still contain e.g. unescaped '<', '>', '&' characters and
@@ -62,8 +67,8 @@ module ActionView
62
67
  self.class.white_list_sanitizer.sanitize_css(style)
63
68
  end
64
69
 
65
- # Strips all HTML tags from the +html+, including comments. This uses the
66
- # html-scanner tokenizer and so its HTML parsing ability is limited by
70
+ # Strips all HTML tags from the +html+, including comments. This uses the
71
+ # html-scanner tokenizer and so its HTML parsing ability is limited by
67
72
  # that of html-scanner.
68
73
  #
69
74
  # ==== Examples
@@ -73,10 +78,10 @@ module ActionView
73
78
  #
74
79
  # strip_tags("<b>Bold</b> no more! <a href='more.html'>See more here</a>...")
75
80
  # # => Bold no more! See more here...
76
- #
81
+ #
77
82
  # strip_tags("<div id='top-bar'>Welcome to my website!</div>")
78
83
  # # => Welcome to my website!
79
- def strip_tags(html)
84
+ def strip_tags(html)
80
85
  self.class.full_sanitizer.sanitize(html)
81
86
  end
82
87
 
@@ -96,21 +101,48 @@ module ActionView
96
101
  end
97
102
 
98
103
  module ClassMethods #:nodoc:
99
- def self.extended(base)
100
- class << base
101
- attr_writer :full_sanitizer, :link_sanitizer, :white_list_sanitizer
102
-
103
- # we want these to be class methods on ActionView::Base, they'll get mattr_readers for these below.
104
- helper_def = [:sanitized_protocol_separator, :sanitized_uri_attributes, :sanitized_bad_tags, :sanitized_allowed_tags,
105
- :sanitized_allowed_attributes, :sanitized_allowed_css_properties, :sanitized_allowed_css_keywords,
106
- :sanitized_shorthand_css_properties, :sanitized_allowed_protocols, :sanitized_protocol_separator=].collect! do |prop|
107
- prop = prop.to_s
108
- "def #{prop}(#{:value if prop =~ /=$/}) white_list_sanitizer.#{prop.sub /sanitized_/, ''} #{:value if prop =~ /=$/} end"
109
- end.join("\n")
110
- eval helper_def
111
- end
112
- end
113
-
104
+ attr_writer :full_sanitizer, :link_sanitizer, :white_list_sanitizer
105
+
106
+ def sanitized_protocol_separator
107
+ white_list_sanitizer.protocol_separator
108
+ end
109
+
110
+ def sanitized_uri_attributes
111
+ white_list_sanitizer.uri_attributes
112
+ end
113
+
114
+ def sanitized_bad_tags
115
+ white_list_sanitizer.bad_tags
116
+ end
117
+
118
+ def sanitized_allowed_tags
119
+ white_list_sanitizer.allowed_tags
120
+ end
121
+
122
+ def sanitized_allowed_attributes
123
+ white_list_sanitizer.allowed_attributes
124
+ end
125
+
126
+ def sanitized_allowed_css_properties
127
+ white_list_sanitizer.allowed_css_properties
128
+ end
129
+
130
+ def sanitized_allowed_css_keywords
131
+ white_list_sanitizer.allowed_css_keywords
132
+ end
133
+
134
+ def sanitized_shorthand_css_properties
135
+ white_list_sanitizer.shorthand_css_properties
136
+ end
137
+
138
+ def sanitized_allowed_protocols
139
+ white_list_sanitizer.allowed_protocols
140
+ end
141
+
142
+ def sanitized_protocol_separator=(value)
143
+ white_list_sanitizer.protocol_separator = value
144
+ end
145
+
114
146
  # Gets the HTML::FullSanitizer instance used by +strip_tags+. Replace with
115
147
  # any object that responds to +sanitize+.
116
148
  #
@@ -184,7 +216,7 @@ module ActionView
184
216
  HTML::WhiteListSanitizer.allowed_attributes.merge(attributes)
185
217
  end
186
218
 
187
- # Adds to the Set of allowed CSS properties for the #sanitize and +sanitize_css+ heleprs.
219
+ # Adds to the Set of allowed CSS properties for the #sanitize and +sanitize_css+ helpers.
188
220
  #
189
221
  # Rails::Initializer.run do |config|
190
222
  # config.action_view.sanitized_allowed_css_properties = 'expression'
@@ -95,7 +95,7 @@ module ActionView
95
95
  # * <tt>:containment</tt> - Takes an element or array of elements to treat as
96
96
  # potential drop targets (defaults to the original target element).
97
97
  #
98
- # * <tt>:only</tt> - A CSS class name or arry of class names used to filter
98
+ # * <tt>:only</tt> - A CSS class name or array of class names used to filter
99
99
  # out child elements as candidates.
100
100
  #
101
101
  # * <tt>:scroll</tt> - Determines whether to scroll the list during drag
@@ -193,7 +193,7 @@ module ActionView
193
193
  #
194
194
  # * <tt>:onDrop</tt> - Called when a +draggable_element+ is dropped onto
195
195
  # this element. Override this callback with a JavaScript expression to
196
- # change the default drop behavour. Example:
196
+ # change the default drop behaviour. Example:
197
197
  #
198
198
  # :onDrop => "function(draggable_element, droppable_element, event) { alert('I like bananas') }"
199
199
  #
@@ -9,17 +9,17 @@ module ActionView
9
9
  module TagHelper
10
10
  include ERB::Util
11
11
 
12
- BOOLEAN_ATTRIBUTES = %w(disabled readonly multiple).to_set
12
+ BOOLEAN_ATTRIBUTES = %w(disabled readonly multiple checked).to_set
13
13
  BOOLEAN_ATTRIBUTES.merge(BOOLEAN_ATTRIBUTES.map(&:to_sym))
14
14
 
15
- # Returns an empty HTML tag of type +name+ which by default is XHTML
16
- # compliant. Set +open+ to true to create an open tag compatible
17
- # with HTML 4.0 and below. Add HTML attributes by passing an attributes
15
+ # Returns an empty HTML tag of type +name+ which by default is XHTML
16
+ # compliant. Set +open+ to true to create an open tag compatible
17
+ # with HTML 4.0 and below. Add HTML attributes by passing an attributes
18
18
  # hash to +options+. Set +escape+ to false to disable attribute value
19
19
  # escaping.
20
20
  #
21
21
  # ==== Options
22
- # The +options+ hash is used with attributes with no value like (<tt>disabled</tt> and
22
+ # The +options+ hash is used with attributes with no value like (<tt>disabled</tt> and
23
23
  # <tt>readonly</tt>), which you can give a value of true in the +options+ hash. You can use
24
24
  # symbols or strings for the attribute names.
25
25
  #
@@ -30,7 +30,7 @@ module ActionView
30
30
  # tag("br", nil, true)
31
31
  # # => <br>
32
32
  #
33
- # tag("input", { :type => 'text', :disabled => true })
33
+ # tag("input", { :type => 'text', :disabled => true })
34
34
  # # => <input type="text" disabled="disabled" />
35
35
  #
36
36
  # tag("img", { :src => "open & shut.png" })
@@ -43,13 +43,13 @@ module ActionView
43
43
  end
44
44
 
45
45
  # Returns an HTML block tag of type +name+ surrounding the +content+. Add
46
- # HTML attributes by passing an attributes hash to +options+.
46
+ # HTML attributes by passing an attributes hash to +options+.
47
47
  # Instead of passing the content as an argument, you can also use a block
48
48
  # in which case, you pass your +options+ as the second parameter.
49
49
  # Set escape to false to disable attribute value escaping.
50
50
  #
51
51
  # ==== Options
52
- # The +options+ hash is used with attributes with no value like (<tt>disabled</tt> and
52
+ # The +options+ hash is used with attributes with no value like (<tt>disabled</tt> and
53
53
  # <tt>readonly</tt>), which you can give a value of true in the +options+ hash. You can use
54
54
  # symbols or strings for the attribute names.
55
55
  #
@@ -64,16 +64,19 @@ module ActionView
64
64
  # <% content_tag :div, :class => "strong" do -%>
65
65
  # Hello world!
66
66
  # <% end -%>
67
- # # => <div class="strong"><p>Hello world!</p></div>
67
+ # # => <div class="strong">Hello world!</div>
68
68
  def content_tag(name, content_or_options_with_block = nil, options = nil, escape = true, &block)
69
69
  if block_given?
70
70
  options = content_or_options_with_block if content_or_options_with_block.is_a?(Hash)
71
- content = capture(&block)
72
- content_tag = content_tag_string(name, content, options, escape)
73
- block_is_within_action_view?(block) ? concat(content_tag, block.binding) : content_tag
71
+ content_tag = content_tag_string(name, capture(&block), options, escape)
72
+
73
+ if block_called_from_erb?(block)
74
+ concat(content_tag)
75
+ else
76
+ content_tag
77
+ end
74
78
  else
75
- content = content_or_options_with_block
76
- content_tag_string(name, content, options, escape)
79
+ content_tag_string(name, content_or_options_with_block, options, escape)
77
80
  end
78
81
  end
79
82
 
@@ -105,6 +108,22 @@ module ActionView
105
108
  end
106
109
 
107
110
  private
111
+ BLOCK_CALLED_FROM_ERB = 'defined? __in_erb_template'
112
+
113
+ if RUBY_VERSION < '1.9.0'
114
+ # Check whether we're called from an erb template.
115
+ # We'd return a string in any other case, but erb <%= ... %>
116
+ # can't take an <% end %> later on, so we have to use <% ... %>
117
+ # and implicitly concat.
118
+ def block_called_from_erb?(block)
119
+ block && eval(BLOCK_CALLED_FROM_ERB, block)
120
+ end
121
+ else
122
+ def block_called_from_erb?(block)
123
+ block && eval(BLOCK_CALLED_FROM_ERB, block.binding)
124
+ end
125
+ end
126
+
108
127
  def content_tag_string(name, content, options, escape = true)
109
128
  tag_options = tag_options(options, escape) if options
110
129
  "<#{name}#{tag_options}>#{content}</#{name}>"
@@ -114,10 +133,12 @@ module ActionView
114
133
  unless options.blank?
115
134
  attrs = []
116
135
  if escape
117
- options.each do |key, value|
118
- next unless value
119
- value = BOOLEAN_ATTRIBUTES.include?(key) ? key : escape_once(value)
120
- attrs << %(#{key}="#{value}")
136
+ options.each_pair do |key, value|
137
+ if BOOLEAN_ATTRIBUTES.include?(key)
138
+ attrs << %(#{key}="#{key}") if value
139
+ else
140
+ attrs << %(#{key}="#{escape_once(value)}") if !value.nil?
141
+ end
121
142
  end
122
143
  else
123
144
  attrs = options.map { |key, value| %(#{key}="#{value}") }
@@ -125,10 +146,6 @@ module ActionView
125
146
  " #{attrs.sort * ' '}" unless attrs.empty?
126
147
  end
127
148
  end
128
-
129
- def block_is_within_action_view?(block)
130
- eval("defined? _erbout", block.binding)
131
- end
132
149
  end
133
150
  end
134
151
  end
@@ -1,5 +1,14 @@
1
1
  require 'action_view/helpers/tag_helper'
2
- require 'html/document'
2
+
3
+ begin
4
+ require 'html/document'
5
+ rescue LoadError
6
+ html_scanner_path = "#{File.dirname(__FILE__)}/../../action_controller/vendor/html-scanner"
7
+ if File.directory?(html_scanner_path)
8
+ $:.unshift html_scanner_path
9
+ require 'html/document'
10
+ end
11
+ end
3
12
 
4
13
  module ActionView
5
14
  module Helpers #:nodoc:
@@ -15,55 +24,69 @@ module ActionView
15
24
  #
16
25
  # ==== Examples
17
26
  # <%
18
- # concat "hello", binding
27
+ # concat "hello"
19
28
  # # is the equivalent of <%= "hello" %>
20
29
  #
21
30
  # if (logged_in == true):
22
- # concat "Logged in!", binding
31
+ # concat "Logged in!"
23
32
  # else
24
- # concat link_to('login', :action => login), binding
33
+ # concat link_to('login', :action => login)
25
34
  # end
26
35
  # # will either display "Logged in!" or a login link
27
36
  # %>
28
- def concat(string, binding)
29
- eval(ActionView::Base.erb_variable, binding) << string
37
+ def concat(string, unused_binding = nil)
38
+ if unused_binding
39
+ ActiveSupport::Deprecation.warn("The binding argument of #concat is no longer needed. Please remove it from your views and helpers.", caller)
40
+ end
41
+
42
+ output_buffer << string
30
43
  end
31
44
 
32
- if RUBY_VERSION < '1.9'
33
- # If +text+ is longer than +length+, +text+ will be truncated to the length of
34
- # +length+ (defaults to 30) and the last characters will be replaced with the +truncate_string+
35
- # (defaults to "...").
36
- #
37
- # ==== Examples
38
- # truncate("Once upon a time in a world far far away", 14)
39
- # # => Once upon a...
40
- #
41
- # truncate("Once upon a time in a world far far away")
42
- # # => Once upon a time in a world f...
43
- #
44
- # truncate("And they found that many people were sleeping better.", 25, "(clipped)")
45
- # # => And they found that many (clipped)
46
- #
47
- # truncate("And they found that many people were sleeping better.", 15, "... (continued)")
48
- # # => And they found... (continued)
49
- def truncate(text, length = 30, truncate_string = "...")
50
- if text
51
- l = length - truncate_string.chars.length
52
- chars = text.chars
53
- (chars.length > length ? chars[0...l] + truncate_string : text).to_s
54
- end
45
+ # Truncates a given +text+ after a given <tt>:length</tt> if +text+ is longer than <tt>:length</tt>
46
+ # (defaults to 30). The last characters will be replaced with the <tt>:omission</tt> (defaults to "...").
47
+ #
48
+ # ==== Examples
49
+ #
50
+ # truncate("Once upon a time in a world far far away")
51
+ # # => Once upon a time in a world f...
52
+ #
53
+ # truncate("Once upon a time in a world far far away", :length => 14)
54
+ # # => Once upon a...
55
+ #
56
+ # truncate("And they found that many people were sleeping better.", :length => 25, "(clipped)")
57
+ # # => And they found that many (clipped)
58
+ #
59
+ # truncate("And they found that many people were sleeping better.", :omission => "... (continued)", :length => 15)
60
+ # # => And they found... (continued)
61
+ #
62
+ # You can still use <tt>truncate</tt> with the old API that accepts the
63
+ # +length+ as its optional second and the +ellipsis+ as its
64
+ # optional third parameter:
65
+ # truncate("Once upon a time in a world far far away", 14)
66
+ # # => Once upon a time in a world f...
67
+ #
68
+ # truncate("And they found that many people were sleeping better.", 15, "... (continued)")
69
+ # # => And they found... (continued)
70
+ def truncate(text, *args)
71
+ options = args.extract_options!
72
+ unless args.empty?
73
+ ActiveSupport::Deprecation.warn('truncate takes an option hash instead of separate ' +
74
+ 'length and omission arguments', caller)
75
+
76
+ options[:length] = args[0] || 30
77
+ options[:omission] = args[1] || "..."
55
78
  end
56
- else
57
- def truncate(text, length = 30, truncate_string = "...") #:nodoc:
58
- if text
59
- l = length - truncate_string.length
60
- (text.length > length ? text[0...l] + truncate_string : text).to_s
61
- end
79
+ options.reverse_merge!(:length => 30, :omission => "...")
80
+
81
+ if text
82
+ l = options[:length] - options[:omission].mb_chars.length
83
+ chars = text.mb_chars
84
+ (chars.length > options[:length] ? chars[0...l] + options[:omission] : text).to_s
62
85
  end
63
86
  end
64
87
 
65
88
  # Highlights one or more +phrases+ everywhere in +text+ by inserting it into
66
- # a +highlighter+ string. The highlighter can be specialized by passing +highlighter+
89
+ # a <tt>:highlighter</tt> string. The highlighter can be specialized by passing <tt>:highlighter</tt>
67
90
  # as a single-quoted string with \1 where the phrase is to be inserted (defaults to
68
91
  # '<strong class="highlight">\1</strong>')
69
92
  #
@@ -74,75 +97,78 @@ module ActionView
74
97
  # highlight('You searched for: ruby, rails, dhh', 'actionpack')
75
98
  # # => You searched for: ruby, rails, dhh
76
99
  #
77
- # highlight('You searched for: rails', ['for', 'rails'], '<em>\1</em>')
100
+ # highlight('You searched for: rails', ['for', 'rails'], :highlighter => '<em>\1</em>')
78
101
  # # => You searched <em>for</em>: <em>rails</em>
79
102
  #
80
- # highlight('You searched for: rails', 'rails', "<a href='search?q=\1'>\1</a>")
81
- # # => You searched for: <a href='search?q=rails>rails</a>
82
- def highlight(text, phrases, highlighter = '<strong class="highlight">\1</strong>')
103
+ # highlight('You searched for: rails', 'rails', :highlighter => '<a href="search?q=\1">\1</a>')
104
+ # # => You searched for: <a href="search?q=rails">rails</a>
105
+ #
106
+ # You can still use <tt>highlight</tt> with the old API that accepts the
107
+ # +highlighter+ as its optional third parameter:
108
+ # highlight('You searched for: rails', 'rails', '<a href="search?q=\1">\1</a>') # => You searched for: <a href="search?q=rails">rails</a>
109
+ def highlight(text, phrases, *args)
110
+ options = args.extract_options!
111
+ unless args.empty?
112
+ options[:highlighter] = args[0] || '<strong class="highlight">\1</strong>'
113
+ end
114
+ options.reverse_merge!(:highlighter => '<strong class="highlight">\1</strong>')
115
+
83
116
  if text.blank? || phrases.blank?
84
117
  text
85
118
  else
86
119
  match = Array(phrases).map { |p| Regexp.escape(p) }.join('|')
87
- text.gsub(/(#{match})/i, highlighter)
120
+ text.gsub(/(#{match})/i, options[:highlighter])
88
121
  end
89
122
  end
90
123
 
91
- if RUBY_VERSION < '1.9'
92
- # Extracts an excerpt from +text+ that matches the first instance of +phrase+.
93
- # The +radius+ expands the excerpt on each side of the first occurrence of +phrase+ by the number of characters
94
- # defined in +radius+ (which defaults to 100). If the excerpt radius overflows the beginning or end of the +text+,
95
- # then the +excerpt_string+ will be prepended/appended accordingly. The resulting string will be stripped in any case.
96
- # If the +phrase+ isn't found, nil is returned.
97
- #
98
- # ==== Examples
99
- # excerpt('This is an example', 'an', 5)
100
- # # => "...s is an exam..."
101
- #
102
- # excerpt('This is an example', 'is', 5)
103
- # # => "This is a..."
104
- #
105
- # excerpt('This is an example', 'is')
106
- # # => "This is an example"
107
- #
108
- # excerpt('This next thing is an example', 'ex', 2)
109
- # # => "...next..."
110
- #
111
- # excerpt('This is also an example', 'an', 8, '<chop> ')
112
- # # => "<chop> is also an example"
113
- def excerpt(text, phrase, radius = 100, excerpt_string = "...")
114
- if text && phrase
115
- phrase = Regexp.escape(phrase)
116
-
117
- if found_pos = text.chars =~ /(#{phrase})/i
118
- start_pos = [ found_pos - radius, 0 ].max
119
- end_pos = [ [ found_pos + phrase.chars.length + radius - 1, 0].max, text.chars.length ].min
120
-
121
- prefix = start_pos > 0 ? excerpt_string : ""
122
- postfix = end_pos < text.chars.length - 1 ? excerpt_string : ""
123
-
124
- prefix + text.chars[start_pos..end_pos].strip + postfix
125
- else
126
- nil
127
- end
128
- end
124
+ # Extracts an excerpt from +text+ that matches the first instance of +phrase+.
125
+ # The <tt>:radius</tt> option expands the excerpt on each side of the first occurrence of +phrase+ by the number of characters
126
+ # defined in <tt>:radius</tt> (which defaults to 100). If the excerpt radius overflows the beginning or end of the +text+,
127
+ # then the <tt>:omission</tt> option (which defaults to "...") will be prepended/appended accordingly. The resulting string
128
+ # will be stripped in any case. If the +phrase+ isn't found, nil is returned.
129
+ #
130
+ # ==== Examples
131
+ # excerpt('This is an example', 'an', :radius => 5)
132
+ # # => ...s is an exam...
133
+ #
134
+ # excerpt('This is an example', 'is', :radius => 5)
135
+ # # => This is a...
136
+ #
137
+ # excerpt('This is an example', 'is')
138
+ # # => This is an example
139
+ #
140
+ # excerpt('This next thing is an example', 'ex', :radius => 2)
141
+ # # => ...next...
142
+ #
143
+ # excerpt('This is also an example', 'an', :radius => 8, :omission => '<chop> ')
144
+ # # => <chop> is also an example
145
+ #
146
+ # You can still use <tt>excerpt</tt> with the old API that accepts the
147
+ # +radius+ as its optional third and the +ellipsis+ as its
148
+ # optional forth parameter:
149
+ # excerpt('This is an example', 'an', 5) # => ...s is an exam...
150
+ # excerpt('This is also an example', 'an', 8, '<chop> ') # => <chop> is also an example
151
+ def excerpt(text, phrase, *args)
152
+ options = args.extract_options!
153
+ unless args.empty?
154
+ options[:radius] = args[0] || 100
155
+ options[:omission] = args[1] || "..."
129
156
  end
130
- else
131
- def excerpt(text, phrase, radius = 100, excerpt_string = "...") #:nodoc:
132
- if text && phrase
133
- phrase = Regexp.escape(phrase)
157
+ options.reverse_merge!(:radius => 100, :omission => "...")
134
158
 
135
- if found_pos = text =~ /(#{phrase})/i
136
- start_pos = [ found_pos - radius, 0 ].max
137
- end_pos = [ [ found_pos + phrase.length + radius - 1, 0].max, text.length ].min
159
+ if text && phrase
160
+ phrase = Regexp.escape(phrase)
138
161
 
139
- prefix = start_pos > 0 ? excerpt_string : ""
140
- postfix = end_pos < text.length - 1 ? excerpt_string : ""
162
+ if found_pos = text.mb_chars =~ /(#{phrase})/i
163
+ start_pos = [ found_pos - options[:radius], 0 ].max
164
+ end_pos = [ [ found_pos + phrase.mb_chars.length + options[:radius] - 1, 0].max, text.mb_chars.length ].min
141
165
 
142
- prefix + text[start_pos..end_pos].strip + postfix
143
- else
144
- nil
145
- end
166
+ prefix = start_pos > 0 ? options[:omission] : ""
167
+ postfix = end_pos < text.mb_chars.length - 1 ? options[:omission] : ""
168
+
169
+ prefix + text.mb_chars[start_pos..end_pos].strip + postfix
170
+ else
171
+ nil
146
172
  end
147
173
  end
148
174
  end
@@ -172,20 +198,31 @@ module ActionView
172
198
  # (which is 80 by default).
173
199
  #
174
200
  # ==== Examples
175
- # word_wrap('Once upon a time', 4)
176
- # # => Once\nupon\na\ntime
177
- #
178
- # word_wrap('Once upon a time', 8)
179
- # # => Once upon\na time
180
201
  #
181
202
  # word_wrap('Once upon a time')
182
203
  # # => Once upon a time
183
204
  #
184
- # word_wrap('Once upon a time', 1)
205
+ # word_wrap('Once upon a time, in a kingdom called Far Far Away, a king fell ill, and finding a successor to the throne turned out to be more trouble than anyone could have imagined...')
206
+ # # => Once upon a time, in a kingdom called Far Far Away, a king fell ill, and finding\n a successor to the throne turned out to be more trouble than anyone could have\n imagined...
207
+ #
208
+ # word_wrap('Once upon a time', :line_width => 8)
209
+ # # => Once upon\na time
210
+ #
211
+ # word_wrap('Once upon a time', :line_width => 1)
185
212
  # # => Once\nupon\na\ntime
186
- def word_wrap(text, line_width = 80)
213
+ #
214
+ # You can still use <tt>word_wrap</tt> with the old API that accepts the
215
+ # +line_width+ as its optional second parameter:
216
+ # word_wrap('Once upon a time', 8) # => Once upon\na time
217
+ def word_wrap(text, *args)
218
+ options = args.extract_options!
219
+ unless args.blank?
220
+ options[:line_width] = args[0] || 80
221
+ end
222
+ options.reverse_merge!(:line_width => 80)
223
+
187
224
  text.split("\n").collect do |line|
188
- line.length > line_width ? line.gsub(/(.{1,#{line_width}})(\s+|$)/, "\\1\n").strip : line
225
+ line.length > options[:line_width] ? line.gsub(/(.{1,#{options[:line_width]}})(\s+|$)/, "\\1\n").strip : line
189
226
  end * "\n"
190
227
  end
191
228
 
@@ -215,7 +252,7 @@ module ActionView
215
252
  ""
216
253
  else
217
254
  textilized = RedCloth.new(text, [ :hard_breaks ])
218
- textilized.hard_breaks = true if textilized.respond_to?("hard_breaks=")
255
+ textilized.hard_breaks = true if textilized.respond_to?(:hard_breaks=)
219
256
  textilized.to_html
220
257
  end
221
258
  end
@@ -307,9 +344,9 @@ module ActionView
307
344
  text << "</p>"
308
345
  end
309
346
 
310
- # Turns all URLs and e-mail addresses into clickable links. The +link+ parameter
347
+ # Turns all URLs and e-mail addresses into clickable links. The <tt>:link</tt> option
311
348
  # will limit what should be linked. You can add HTML attributes to the links using
312
- # +href_options+. Options for +link+ are <tt>:all</tt> (default),
349
+ # <tt>:href_options</tt>. Possible values for <tt>:link</tt> are <tt>:all</tt> (default),
313
350
  # <tt>:email_addresses</tt>, and <tt>:urls</tt>. If a block is given, each URL and
314
351
  # e-mail address is yielded and the result is used as the link text.
315
352
  #
@@ -318,26 +355,46 @@ module ActionView
318
355
  # # => "Go to <a href=\"http://www.rubyonrails.org\">http://www.rubyonrails.org</a> and
319
356
  # # say hello to <a href=\"mailto:david@loudthinking.com\">david@loudthinking.com</a>"
320
357
  #
321
- # auto_link("Visit http://www.loudthinking.com/ or e-mail david@loudthinking.com", :urls)
358
+ # auto_link("Visit http://www.loudthinking.com/ or e-mail david@loudthinking.com", :link => :urls)
322
359
  # # => "Visit <a href=\"http://www.loudthinking.com/\">http://www.loudthinking.com/</a>
323
360
  # # or e-mail david@loudthinking.com"
324
361
  #
325
- # auto_link("Visit http://www.loudthinking.com/ or e-mail david@loudthinking.com", :email_addresses)
362
+ # auto_link("Visit http://www.loudthinking.com/ or e-mail david@loudthinking.com", :link => :email_addresses)
326
363
  # # => "Visit http://www.loudthinking.com/ or e-mail <a href=\"mailto:david@loudthinking.com\">david@loudthinking.com</a>"
327
364
  #
328
365
  # post_body = "Welcome to my new blog at http://www.myblog.com/. Please e-mail me at me@email.com."
329
- # auto_link(post_body, :all, :target => '_blank') do |text|
366
+ # auto_link(post_body, :href_options => { :target => '_blank' }) do |text|
330
367
  # truncate(text, 15)
331
368
  # end
332
369
  # # => "Welcome to my new blog at <a href=\"http://www.myblog.com/\" target=\"_blank\">http://www.m...</a>.
333
370
  # Please e-mail me at <a href=\"mailto:me@email.com\">me@email.com</a>."
334
371
  #
335
- def auto_link(text, link = :all, href_options = {}, &block)
372
+ #
373
+ # You can still use <tt>auto_link</tt> with the old API that accepts the
374
+ # +link+ as its optional second parameter and the +html_options+ hash
375
+ # as its optional third parameter:
376
+ # post_body = "Welcome to my new blog at http://www.myblog.com/. Please e-mail me at me@email.com."
377
+ # auto_link(post_body, :urls) # => Once upon\na time
378
+ # # => "Welcome to my new blog at <a href=\"http://www.myblog.com/\">http://www.myblog.com</a>.
379
+ # Please e-mail me at me@email.com."
380
+ #
381
+ # auto_link(post_body, :all, :target => "_blank") # => Once upon\na time
382
+ # # => "Welcome to my new blog at <a href=\"http://www.myblog.com/\" target=\"_blank\">http://www.myblog.com</a>.
383
+ # Please e-mail me at <a href=\"mailto:me@email.com\">me@email.com</a>."
384
+ def auto_link(text, *args, &block)#link = :all, href_options = {}, &block)
336
385
  return '' if text.blank?
337
- case link
338
- when :all then auto_link_email_addresses(auto_link_urls(text, href_options, &block), &block)
339
- when :email_addresses then auto_link_email_addresses(text, &block)
340
- when :urls then auto_link_urls(text, href_options, &block)
386
+
387
+ options = args.size == 2 ? {} : args.extract_options! # this is necessary because the old auto_link API has a Hash as its last parameter
388
+ unless args.empty?
389
+ options[:link] = args[0] || :all
390
+ options[:html] = args[1] || {}
391
+ end
392
+ options.reverse_merge!(:link => :all, :html => {})
393
+
394
+ case options[:link].to_sym
395
+ when :all then auto_link_email_addresses(auto_link_urls(text, options[:html], &block), &block)
396
+ when :email_addresses then auto_link_email_addresses(text, &block)
397
+ when :urls then auto_link_urls(text, options[:html], &block)
341
398
  end
342
399
  end
343
400
 
@@ -345,8 +402,10 @@ module ActionView
345
402
  # array every time it is called. This can be used for example, to alternate
346
403
  # classes for table rows. You can use named cycles to allow nesting in loops.
347
404
  # Passing a Hash as the last parameter with a <tt>:name</tt> key will create a
348
- # named cycle. You can manually reset a cycle by calling reset_cycle and passing the
349
- # name of the cycle.
405
+ # named cycle. The default name for a cycle without a +:name+ key is
406
+ # <tt>"default"</tt>. You can manually reset a cycle by calling reset_cycle
407
+ # and passing the name of the cycle. The current cycle string can be obtained
408
+ # anytime using the current_cycle method.
350
409
  #
351
410
  # ==== Examples
352
411
  # # Alternate CSS classes for even and odd numbers...
@@ -393,6 +452,23 @@ module ActionView
393
452
  return cycle.to_s
394
453
  end
395
454
 
455
+ # Returns the current cycle string after a cycle has been started. Useful
456
+ # for complex table highlighing or any other design need which requires
457
+ # the current cycle string in more than one place.
458
+ #
459
+ # ==== Example
460
+ # # Alternate background colors
461
+ # @items = [1,2,3,4]
462
+ # <% @items.each do |item| %>
463
+ # <div style="background-color:<%= cycle("red","white","blue") %>">
464
+ # <span style="background-color:<%= current_cycle %>"><%= item %></span>
465
+ # </div>
466
+ # <% end %>
467
+ def current_cycle(name = "default")
468
+ cycle = get_cycle(name)
469
+ cycle.current_value unless cycle.nil?
470
+ end
471
+
396
472
  # Resets a cycle so that it starts from the first element the next time
397
473
  # it is called. Pass in +name+ to reset a named cycle.
398
474
  #
@@ -429,11 +505,29 @@ module ActionView
429
505
  @index = 0
430
506
  end
431
507
 
508
+ def current_value
509
+ @values[previous_index].to_s
510
+ end
511
+
432
512
  def to_s
433
513
  value = @values[@index].to_s
434
- @index = (@index + 1) % @values.size
514
+ @index = next_index
435
515
  return value
436
516
  end
517
+
518
+ private
519
+
520
+ def next_index
521
+ step_index(1)
522
+ end
523
+
524
+ def previous_index
525
+ step_index(-1)
526
+ end
527
+
528
+ def step_index(n)
529
+ (@index + n) % @values.size
530
+ end
437
531
  end
438
532
 
439
533
  private
@@ -464,8 +558,8 @@ module ActionView
464
558
  [-\w]+ # subdomain or domain
465
559
  (?:\.[-\w]+)* # remaining subdomains or domain
466
560
  (?::\d+)? # port
467
- (?:/(?:(?:[~\w\+@%=\(\)-]|(?:[,.;:'][^\s$]))+)?)* # path
468
- (?:\?[\w\+@%&=.;-]+)? # query string
561
+ (?:/(?:[~\w\+@%=\(\)-]|(?:[,.;:'][^\s$]))*)* # path
562
+ (?:\?[\w\+@%&=.;:-]+)? # query string
469
563
  (?:\#[\w\-]*)? # trailing anchor
470
564
  )
471
565
  ([[:punct:]]|<|$|) # trailing text
@@ -473,8 +567,8 @@ module ActionView
473
567
 
474
568
  # Turns all urls into clickable links. If a block is given, each url
475
569
  # is yielded and the result is used as the link text.
476
- def auto_link_urls(text, href_options = {})
477
- extra_options = tag_options(href_options.stringify_keys) || ""
570
+ def auto_link_urls(text, html_options = {})
571
+ extra_options = tag_options(html_options.stringify_keys) || ""
478
572
  text.gsub(AUTO_LINK_RE) do
479
573
  all, a, b, c, d = $&, $1, $2, $3, $4
480
574
  if a =~ /<a\s/i # don't replace URL's that are already linked