diff options
31 files changed, 178 insertions, 195 deletions
diff --git a/actionpack/lib/action_view.rb b/actionpack/lib/action_view.rb index 93aa69c060..20a2a63621 100644 --- a/actionpack/lib/action_view.rb +++ b/actionpack/lib/action_view.rb @@ -56,7 +56,9 @@ module ActionView autoload :TestCase, 'action_view/test_case' end -require 'action_view/erb/util' +require 'active_support/core_ext/string/output_safety' require 'action_view/base' +ActionView::SafeBuffer = ActiveSupport::SafeBuffer + I18n.load_path << "#{File.dirname(__FILE__)}/action_view/locale/en.yml" diff --git a/actionpack/lib/action_view/base.rb b/actionpack/lib/action_view/base.rb index 07ef3f2140..148d507f1c 100644 --- a/actionpack/lib/action_view/base.rb +++ b/actionpack/lib/action_view/base.rb @@ -284,7 +284,7 @@ module ActionView #:nodoc: @helpers = self.class.helpers || Module.new @_controller = controller - @_content_for = Hash.new {|h,k| h[k] = ActionView::SafeBuffer.new } + @_content_for = Hash.new {|h,k| h[k] = ActiveSupport::SafeBuffer.new } @_virtual_path = nil self.view_paths = view_paths end diff --git a/actionpack/lib/action_view/erb/util.rb b/actionpack/lib/action_view/erb/util.rb deleted file mode 100644 index aef859b3ac..0000000000 --- a/actionpack/lib/action_view/erb/util.rb +++ /dev/null @@ -1,49 +0,0 @@ -require 'erb' - -class ERB - module Util - HTML_ESCAPE = { '&' => '&', '>' => '>', '<' => '<', '"' => '"' } - JSON_ESCAPE = { '&' => '\u0026', '>' => '\u003E', '<' => '\u003C' } - - # A utility method for escaping HTML tag characters. - # This method is also aliased as <tt>h</tt>. - # - # In your ERb templates, use this method to escape any unsafe content. For example: - # <%=h @person.name %> - # - # ==== Example: - # puts html_escape("is a > 0 & a < 10?") - # # => is a > 0 & a < 10? - def html_escape(s) - s = s.to_s - if s.html_safe? - s - else - s.gsub(/[&"><]/) { |special| HTML_ESCAPE[special] }.html_safe! - end - end - - undef :h - alias h html_escape - - module_function :html_escape - module_function :h - - # A utility method for escaping HTML entities in JSON strings. - # This method is also aliased as <tt>j</tt>. - # - # In your ERb templates, use this method to escape any HTML entities: - # <%=j @person.to_json %> - # - # ==== Example: - # puts json_escape("is a > 0 & a < 10?") - # # => is a \u003E 0 \u0026 a \u003C 10? - def json_escape(s) - s.to_s.gsub(/[&"><]/) { |special| JSON_ESCAPE[special] } - end - - alias j json_escape - module_function :j - module_function :json_escape - end -end diff --git a/actionpack/lib/action_view/helpers/active_model_helper.rb b/actionpack/lib/action_view/helpers/active_model_helper.rb index 87b7adf6c4..e106bb0897 100644 --- a/actionpack/lib/action_view/helpers/active_model_helper.rb +++ b/actionpack/lib/action_view/helpers/active_model_helper.rb @@ -6,7 +6,7 @@ require 'active_support/core_ext/kernel/reporting' module ActionView class Base - @@field_error_proc = Proc.new{ |html_tag, instance| "<div class=\"fieldWithErrors\">#{html_tag}</div>".html_safe! } + @@field_error_proc = Proc.new{ |html_tag, instance| "<div class=\"fieldWithErrors\">#{html_tag}</div>".html_safe } cattr_accessor :field_error_proc end @@ -86,12 +86,11 @@ module ActionView submit_value = options[:submit_value] || options[:action].gsub(/[^\w]/, '').capitalize contents = form_tag({:action => action}, :method =>(options[:method] || 'post'), :enctype => options[:multipart] ? 'multipart/form-data': nil) - contents << hidden_field(record_name, :id) unless record.new_record? - contents << all_input_tags(record, record_name, options) + contents.safe_concat hidden_field(record_name, :id) unless record.new_record? + contents.safe_concat all_input_tags(record, record_name, options) yield contents if block_given? - contents << submit_tag(submit_value) - contents << '</form>' - contents.html_safe! + contents.safe_concat submit_tag(submit_value) + contents.safe_concat('</form>') end # Returns a string containing the error message attached to the +method+ on the +object+ if one exists. diff --git a/actionpack/lib/action_view/helpers/asset_tag_helper.rb b/actionpack/lib/action_view/helpers/asset_tag_helper.rb index 4df99f8293..96976ce45f 100644 --- a/actionpack/lib/action_view/helpers/asset_tag_helper.rb +++ b/actionpack/lib/action_view/helpers/asset_tag_helper.rb @@ -293,7 +293,7 @@ module ActionView else sources = expand_javascript_sources(sources, recursive) ensure_javascript_sources!(sources) if cache - sources.collect { |source| javascript_src_tag(source, options) }.join("\n").html_safe! + sources.collect { |source| javascript_src_tag(source, options) }.join("\n").html_safe end end @@ -444,7 +444,7 @@ module ActionView else sources = expand_stylesheet_sources(sources, recursive) ensure_stylesheet_sources!(sources) if cache - sources.collect { |source| stylesheet_tag(source, options) }.join("\n").html_safe! + sources.collect { |source| stylesheet_tag(source, options) }.join("\n").html_safe end end @@ -588,7 +588,7 @@ module ActionView if sources.is_a?(Array) content_tag("video", options) do - sources.map { |source| tag("source", :src => source) }.join.html_safe! + sources.map { |source| tag("source", :src => source) }.join.html_safe end else options[:src] = path_to_video(sources) diff --git a/actionpack/lib/action_view/helpers/date_helper.rb b/actionpack/lib/action_view/helpers/date_helper.rb index 34f38b0a8a..8be2f76bd6 100644 --- a/actionpack/lib/action_view/helpers/date_helper.rb +++ b/actionpack/lib/action_view/helpers/date_helper.rb @@ -616,7 +616,7 @@ module ActionView build_selects_from_types(order) else - "#{select_date}#{@options[:datetime_separator]}#{select_time}".html_safe! + "#{select_date}#{@options[:datetime_separator]}#{select_time}".html_safe end end @@ -835,7 +835,7 @@ module ActionView select_html << prompt_option_tag(type, @options[:prompt]) + "\n" if @options[:prompt] select_html << select_options_as_html.to_s - (content_tag(:select, select_html, select_options) + "\n").html_safe! + (content_tag(:select, select_html, select_options) + "\n").html_safe end # Builds a prompt option tag with supplied options or from default options @@ -865,7 +865,7 @@ module ActionView :id => input_id_from_type(type), :name => input_name_from_type(type), :value => value - }) + "\n").html_safe! + }) + "\n").html_safe end # Returns the name attribute for the input tag @@ -896,7 +896,7 @@ module ActionView separator = separator(type) unless type == order.first # don't add on last field select.insert(0, separator.to_s + send("select_#{type}").to_s) end - select.html_safe! + select.html_safe end # Returns the separator for a given datetime component @@ -916,15 +916,15 @@ module ActionView class InstanceTag #:nodoc: def to_date_select_tag(options = {}, html_options = {}) - datetime_selector(options, html_options).select_date.html_safe! + datetime_selector(options, html_options).select_date.html_safe end def to_time_select_tag(options = {}, html_options = {}) - datetime_selector(options, html_options).select_time.html_safe! + datetime_selector(options, html_options).select_time.html_safe end def to_datetime_select_tag(options = {}, html_options = {}) - datetime_selector(options, html_options).select_datetime.html_safe! + datetime_selector(options, html_options).select_datetime.html_safe end private diff --git a/actionpack/lib/action_view/helpers/debug_helper.rb b/actionpack/lib/action_view/helpers/debug_helper.rb index 885945fde3..e637dc1474 100644 --- a/actionpack/lib/action_view/helpers/debug_helper.rb +++ b/actionpack/lib/action_view/helpers/debug_helper.rb @@ -27,10 +27,10 @@ module ActionView def debug(object) begin Marshal::dump(object) - "<pre class='debug_dump'>#{h(object.to_yaml).gsub(" ", " ")}</pre>".html_safe! + "<pre class='debug_dump'>#{h(object.to_yaml).gsub(" ", " ")}</pre>".html_safe rescue Exception => e # errors from Marshal or YAML # Object couldn't be dumped, perhaps because of singleton methods -- this is the fallback - "<code class='debug_dump'>#{h(object.inspect)}</code>".html_safe! + "<code class='debug_dump'>#{h(object.inspect)}</code>".html_safe end end end diff --git a/actionpack/lib/action_view/helpers/form_helper.rb b/actionpack/lib/action_view/helpers/form_helper.rb index a72357cf3d..76998a6ea1 100644 --- a/actionpack/lib/action_view/helpers/form_helper.rb +++ b/actionpack/lib/action_view/helpers/form_helper.rb @@ -311,7 +311,7 @@ module ActionView concat(form_tag(options.delete(:url) || {}, options.delete(:html) || {})) fields_for(object_name, *(args << options), &proc) - concat('</form>'.html_safe!) + safe_concat('</form>') end def apply_form_for_options!(object_or_array, options) #:nodoc: @@ -879,7 +879,7 @@ module ActionView end hidden = tag("input", "name" => options["name"], "type" => "hidden", "value" => options['disabled'] && checked ? checked_value : unchecked_value) checkbox = tag("input", options) - (hidden + checkbox).html_safe! + (hidden + checkbox).html_safe end def to_boolean_select_tag(options = {}) diff --git a/actionpack/lib/action_view/helpers/form_options_helper.rb b/actionpack/lib/action_view/helpers/form_options_helper.rb index 02ad637509..0ffe770f5f 100644 --- a/actionpack/lib/action_view/helpers/form_options_helper.rb +++ b/actionpack/lib/action_view/helpers/form_options_helper.rb @@ -296,7 +296,7 @@ module ActionView options << %(<option value="#{html_escape(value.to_s)}"#{selected_attribute}#{disabled_attribute}>#{html_escape(text.to_s)}</option>) end - options_for_select.join("\n").html_safe! + options_for_select.join("\n").html_safe end # Returns a string of option tags that have been compiled by iterating over the +collection+ and assigning the diff --git a/actionpack/lib/action_view/helpers/form_tag_helper.rb b/actionpack/lib/action_view/helpers/form_tag_helper.rb index 597cf311cb..9b8471c6c6 100644 --- a/actionpack/lib/action_view/helpers/form_tag_helper.rb +++ b/actionpack/lib/action_view/helpers/form_tag_helper.rb @@ -446,7 +446,7 @@ module ActionView concat(tag(:fieldset, options, true)) concat(content_tag(:legend, legend)) unless legend.blank? concat(content) - concat("</fieldset>".html_safe!) + safe_concat("</fieldset>") end private @@ -474,14 +474,14 @@ module ActionView def form_tag_html(html_options) extra_tags = extra_tags_for_form(html_options) - (tag(:form, html_options, true) + extra_tags).html_safe! + (tag(:form, html_options, true) + extra_tags).html_safe end def form_tag_in_block(html_options, &block) content = capture(&block) concat(form_tag_html(html_options)) concat(content) - concat("</form>".html_safe!) + safe_concat("</form>") end def token_tag diff --git a/actionpack/lib/action_view/helpers/number_helper.rb b/actionpack/lib/action_view/helpers/number_helper.rb index 64b71663c3..3d3502a08b 100644 --- a/actionpack/lib/action_view/helpers/number_helper.rb +++ b/actionpack/lib/action_view/helpers/number_helper.rb @@ -92,7 +92,7 @@ module ActionView :precision => precision, :delimiter => delimiter, :separator => separator) - ).gsub(/%u/, unit).html_safe! + ).gsub(/%u/, unit).html_safe rescue number end diff --git a/actionpack/lib/action_view/helpers/prototype_helper.rb b/actionpack/lib/action_view/helpers/prototype_helper.rb index d335d89274..7eb6bceca0 100644 --- a/actionpack/lib/action_view/helpers/prototype_helper.rb +++ b/actionpack/lib/action_view/helpers/prototype_helper.rb @@ -610,7 +610,7 @@ module ActionView # page.hide 'spinner' # end def update_page(&block) - JavaScriptGenerator.new(@template, &block).to_s.html_safe! + JavaScriptGenerator.new(@template, &block).to_s.html_safe end # Works like update_page but wraps the generated JavaScript in a <script> diff --git a/actionpack/lib/action_view/helpers/raw_output_helper.rb b/actionpack/lib/action_view/helpers/raw_output_helper.rb index 79b0e4ee75..8c7f41177d 100644 --- a/actionpack/lib/action_view/helpers/raw_output_helper.rb +++ b/actionpack/lib/action_view/helpers/raw_output_helper.rb @@ -2,7 +2,7 @@ module ActionView #:nodoc: module Helpers #:nodoc: module RawOutputHelper def raw(stringish) - stringish.to_s.html_safe! + stringish.to_s.html_safe end end end diff --git a/actionpack/lib/action_view/helpers/sanitize_helper.rb b/actionpack/lib/action_view/helpers/sanitize_helper.rb index 657d26f0a2..28e40f8560 100644 --- a/actionpack/lib/action_view/helpers/sanitize_helper.rb +++ b/actionpack/lib/action_view/helpers/sanitize_helper.rb @@ -50,11 +50,7 @@ module ActionView # confuse browsers. # def sanitize(html, options = {}) - returning self.class.white_list_sanitizer.sanitize(html, options) do |sanitized| - if sanitized - sanitized.html_safe! - end - end + self.class.white_list_sanitizer.sanitize(html, options).try(:html_safe) end # Sanitizes a block of CSS code. Used by +sanitize+ when it comes across a style attribute. @@ -77,11 +73,7 @@ module ActionView # strip_tags("<div id='top-bar'>Welcome to my website!</div>") # # => Welcome to my website! def strip_tags(html) - returning self.class.full_sanitizer.sanitize(html) do |sanitized| - if sanitized - sanitized.html_safe! - end - end + self.class.full_sanitizer.sanitize(html).try(:html_safe) end # Strips all link tags from +text+ leaving just the link text. diff --git a/actionpack/lib/action_view/helpers/tag_helper.rb b/actionpack/lib/action_view/helpers/tag_helper.rb index ceddbd8cc1..ffab662dbf 100644 --- a/actionpack/lib/action_view/helpers/tag_helper.rb +++ b/actionpack/lib/action_view/helpers/tag_helper.rb @@ -41,7 +41,7 @@ module ActionView # tag("img", { :src => "open & shut.png" }, false, false) # # => <img src="open & shut.png" /> def tag(name, options = nil, open = false, escape = true) - "<#{name}#{tag_options(options, escape) if options}#{open ? ">" : " />"}".html_safe! + "<#{name}#{tag_options(options, escape) if options}#{open ? ">" : " />"}".html_safe end # Returns an HTML block tag of type +name+ surrounding the +content+. Add @@ -94,7 +94,7 @@ module ActionView # cdata_section(File.read("hello_world.txt")) # # => <![CDATA[<hello from a text file]]> def cdata_section(content) - "<![CDATA[#{content}]]>".html_safe! + "<![CDATA[#{content}]]>".html_safe end # Returns an escaped version of +html+ without affecting existing escaped entities. @@ -128,7 +128,7 @@ module ActionView def content_tag_string(name, content, options, escape = true) tag_options = tag_options(options, escape) if options - "<#{name}#{tag_options}>#{content}</#{name}>".html_safe! + "<#{name}#{tag_options}>#{content}</#{name}>".html_safe end def tag_options(options, escape = true) @@ -143,7 +143,7 @@ module ActionView attrs << %(#{key}="#{final_value}") end end - " #{attrs.sort * ' '}".html_safe! unless attrs.empty? + " #{attrs.sort * ' '}".html_safe unless attrs.empty? end end end diff --git a/actionpack/lib/action_view/helpers/text_helper.rb b/actionpack/lib/action_view/helpers/text_helper.rb index 814d86812d..412e0c82cb 100644 --- a/actionpack/lib/action_view/helpers/text_helper.rb +++ b/actionpack/lib/action_view/helpers/text_helper.rb @@ -24,14 +24,14 @@ module ActionView # end # # will either display "Logged in!" or a login link # %> - def concat(string, unused_binding = nil) - if unused_binding - ActiveSupport::Deprecation.warn("The binding argument of #concat is no longer needed. Please remove it from your views and helpers.", caller) - end - + def concat(string) output_buffer << string end + def safe_concat(string) + output_buffer.safe_concat(string) + end + # Truncates a given +text+ after a given <tt>:length</tt> if +text+ is longer than <tt>:length</tt> # (defaults to 30). The last characters will be replaced with the <tt>:omission</tt> (defaults to "...") # for a total length not exceeding <tt>:length</tt>. diff --git a/actionpack/lib/action_view/helpers/translation_helper.rb b/actionpack/lib/action_view/helpers/translation_helper.rb index ad18339c60..c348ea7a0d 100644 --- a/actionpack/lib/action_view/helpers/translation_helper.rb +++ b/actionpack/lib/action_view/helpers/translation_helper.rb @@ -12,7 +12,7 @@ module ActionView # prepend the key with a period, nothing is converted. def translate(key, options = {}) options[:raise] = true - I18n.translate(scope_key_by_partial(key), options).html_safe! + I18n.translate(scope_key_by_partial(key), options).html_safe rescue I18n::MissingTranslationData => e keys = I18n.send(:normalize_translation_keys, e.locale, e.key, e.options[:scope]) content_tag('span', keys.join(', '), :class => 'translation_missing') diff --git a/actionpack/lib/action_view/helpers/url_helper.rb b/actionpack/lib/action_view/helpers/url_helper.rb index 4301647a2c..168a3bdbc0 100644 --- a/actionpack/lib/action_view/helpers/url_helper.rb +++ b/actionpack/lib/action_view/helpers/url_helper.rb @@ -98,7 +98,7 @@ module ActionView polymorphic_path(options) end - escape ? escape_once(url).html_safe! : url + escape ? escape_once(url).html_safe : url end # Creates a link tag of the given +name+ using a URL created by the set @@ -208,7 +208,7 @@ module ActionView if block_given? options = args.first || {} html_options = args.second - concat(link_to(capture(&block), options, html_options).html_safe!) + safe_concat(link_to(capture(&block), options, html_options)) else name = args[0] options = args[1] || {} @@ -226,7 +226,7 @@ module ActionView end href_attr = "href=\"#{url}\"" unless href - "<a #{href_attr}#{tag_options}>#{ERB::Util.h(name || url)}</a>".html_safe! + "<a #{href_attr}#{tag_options}>#{ERB::Util.h(name || url)}</a>".html_safe end end @@ -312,7 +312,7 @@ module ActionView html_options.merge!("type" => "submit", "value" => name) ("<form method=\"#{form_method}\" action=\"#{escape_once url}\" #{"data-remote=\"true\"" if remote} class=\"button-to\"><div>" + - method_tag + tag("input", html_options) + request_token_tag + "</div></form>").html_safe! + method_tag + tag("input", html_options) + request_token_tag + "</div></form>").html_safe end diff --git a/actionpack/lib/action_view/render/partials.rb b/actionpack/lib/action_view/render/partials.rb index 8c936ae09e..8b6dce0c1c 100644 --- a/actionpack/lib/action_view/render/partials.rb +++ b/actionpack/lib/action_view/render/partials.rb @@ -240,7 +240,7 @@ module ActionView end result = @template ? collection_with_template : collection_without_template - result.join(spacer).html_safe! + result.join(spacer).html_safe end def collection_with_template(template = @template) diff --git a/actionpack/lib/action_view/safe_buffer.rb b/actionpack/lib/action_view/safe_buffer.rb deleted file mode 100644 index 6be05b9e1e..0000000000 --- a/actionpack/lib/action_view/safe_buffer.rb +++ /dev/null @@ -1,27 +0,0 @@ -module ActionView #:nodoc: - class SafeBuffer < String - def <<(value) - if value.html_safe? - super(value) - else - super(ERB::Util.h(value)) - end - end - - def concat(value) - self << value - end - - def html_safe? - true - end - - def html_safe! - self - end - - def to_s - self - end - end -end
\ No newline at end of file diff --git a/actionpack/lib/action_view/test_case.rb b/actionpack/lib/action_view/test_case.rb index 3095d84e13..fc29acea6d 100644 --- a/actionpack/lib/action_view/test_case.rb +++ b/actionpack/lib/action_view/test_case.rb @@ -53,7 +53,7 @@ module ActionView setup :setup_with_controller def setup_with_controller @controller = TestController.new - @output_buffer = ActionView::SafeBuffer.new + @output_buffer = ActiveSupport::SafeBuffer.new @rendered = '' self.class.send(:include_helper_modules!) diff --git a/actionpack/test/controller/caching_test.rb b/actionpack/test/controller/caching_test.rb index 8a13d1e5f1..de92fc56fd 100644 --- a/actionpack/test/controller/caching_test.rb +++ b/actionpack/test/controller/caching_test.rb @@ -611,7 +611,7 @@ class FragmentCachingTest < ActionController::TestCase @store.write('views/expensive', 'fragment content') fragment_computed = false - buffer = 'generated till now -> ' + buffer = 'generated till now -> '.html_safe @controller.fragment_for(buffer, 'expensive') { fragment_computed = true } assert fragment_computed @@ -622,7 +622,7 @@ class FragmentCachingTest < ActionController::TestCase @store.write('views/expensive', 'fragment content') fragment_computed = false - buffer = 'generated till now -> ' + buffer = 'generated till now -> '.html_safe @controller.fragment_for(buffer, 'expensive') { fragment_computed = true } assert !fragment_computed diff --git a/actionpack/test/controller/output_escaping_test.rb b/actionpack/test/controller/output_escaping_test.rb index 7332f3f1e3..43a8c05cda 100644 --- a/actionpack/test/controller/output_escaping_test.rb +++ b/actionpack/test/controller/output_escaping_test.rb @@ -13,7 +13,7 @@ class OutputEscapingTest < ActiveSupport::TestCase test "escapeHTML shouldn't touch explicitly safe strings" do # TODO this seems easier to compose and reason about, but # this should be verified - assert_equal "<", ERB::Util.h("<".html_safe!) + assert_equal "<", ERB::Util.h("<".html_safe) end end diff --git a/actionpack/test/template/erb_util_test.rb b/actionpack/test/template/erb_util_test.rb index fa6b263965..06155b1f30 100644 --- a/actionpack/test/template/erb_util_test.rb +++ b/actionpack/test/template/erb_util_test.rb @@ -22,7 +22,7 @@ class ErbUtilTest < Test::Unit::TestCase end def test_html_escape_passes_html_escpe_unmodified - escaped = h("<p>".html_safe!) + escaped = h("<p>".html_safe) assert_equal "<p>", escaped assert escaped.html_safe? end diff --git a/actionpack/test/template/form_helper_test.rb b/actionpack/test/template/form_helper_test.rb index caeca9db10..aafc318b76 100644 --- a/actionpack/test/template/form_helper_test.rb +++ b/actionpack/test/template/form_helper_test.rb @@ -1170,7 +1170,7 @@ class FormHelperTest < ActionView::TestCase (field_helpers - %w(hidden_field)).each do |selector| src = <<-END_SRC def #{selector}(field, *args, &proc) - ("<label for='\#{field}'>\#{field.to_s.humanize}:</label> " + super + "<br/>").html_safe! + ("<label for='\#{field}'>\#{field.to_s.humanize}:</label> " + super + "<br/>").html_safe end END_SRC class_eval src, __FILE__, __LINE__ diff --git a/actionpack/test/template/form_tag_helper_test.rb b/actionpack/test/template/form_tag_helper_test.rb index 553ec44fad..3635c7548e 100644 --- a/actionpack/test/template/form_tag_helper_test.rb +++ b/actionpack/test/template/form_tag_helper_test.rb @@ -335,19 +335,19 @@ class FormTagHelperTest < ActionView::TestCase expected = %(<fieldset><legend>Your details</legend>Hello world!</fieldset>) assert_dom_equal expected, output_buffer - self.output_buffer = '' + self.output_buffer = ''.html_safe field_set_tag { concat "Hello world!" } expected = %(<fieldset>Hello world!</fieldset>) assert_dom_equal expected, output_buffer - self.output_buffer = '' + self.output_buffer = ''.html_safe field_set_tag('') { concat "Hello world!" } expected = %(<fieldset>Hello world!</fieldset>) assert_dom_equal expected, output_buffer - self.output_buffer = '' + self.output_buffer = ''.html_safe field_set_tag('', :class => 'format') { concat "Hello world!" } expected = %(<fieldset class="format">Hello world!</fieldset>) diff --git a/actionpack/test/template/safe_buffer_test.rb b/actionpack/test/template/safe_buffer_test.rb index 6a18201d16..41a95e068b 100644 --- a/actionpack/test/template/safe_buffer_test.rb +++ b/actionpack/test/template/safe_buffer_test.rb @@ -16,7 +16,7 @@ class SafeBufferTest < ActionView::TestCase end test "Should NOT escape a safe value passed to it" do - @buffer << "<script>".html_safe! + @buffer << "<script>".html_safe assert_equal "<script>", @buffer end diff --git a/actionpack/test/template/test_case_test.rb b/actionpack/test/template/test_case_test.rb index 9a448ce328..be2c6b3108 100644 --- a/actionpack/test/template/test_case_test.rb +++ b/actionpack/test/template/test_case_test.rb @@ -160,7 +160,7 @@ module ActionView class AssertionsTest < ActionView::TestCase def render_from_helper form_tag('/foo') do - concat render(:text => '<ul><li>foo</li></ul>').html_safe! + safe_concat render(:text => '<ul><li>foo</li></ul>') end end helper_method :render_from_helper diff --git a/activesupport/lib/active_support.rb b/activesupport/lib/active_support.rb index 833ae351b9..ae31d191c0 100644 --- a/activesupport/lib/active_support.rb +++ b/activesupport/lib/active_support.rb @@ -67,5 +67,6 @@ module ActiveSupport autoload :XmlMini end + autoload :SafeBuffer, "active_support/core_ext/string/output_safety" autoload :TestCase end diff --git a/activesupport/lib/active_support/core_ext/string/output_safety.rb b/activesupport/lib/active_support/core_ext/string/output_safety.rb index ceed90ce79..3977971e8d 100644 --- a/activesupport/lib/active_support/core_ext/string/output_safety.rb +++ b/activesupport/lib/active_support/core_ext/string/output_safety.rb @@ -1,3 +1,53 @@ +require "erb" + +class ERB + module Util + HTML_ESCAPE = { '&' => '&', '>' => '>', '<' => '<', '"' => '"' } + JSON_ESCAPE = { '&' => '\u0026', '>' => '\u003E', '<' => '\u003C' } + + # A utility method for escaping HTML tag characters. + # This method is also aliased as <tt>h</tt>. + # + # In your ERb templates, use this method to escape any unsafe content. For example: + # <%=h @person.name %> + # + # ==== Example: + # puts html_escape("is a > 0 & a < 10?") + # # => is a > 0 & a < 10? + def html_escape(s) + s = s.to_s + if s.html_safe? + s + else + s.gsub(/[&"><]/) { |special| HTML_ESCAPE[special] }.html_safe + end + end + + undef :h + alias h html_escape + + module_function :html_escape + module_function :h + + # A utility method for escaping HTML entities in JSON strings. + # This method is also aliased as <tt>j</tt>. + # + # In your ERb templates, use this method to escape any HTML entities: + # <%=j @person.to_json %> + # + # ==== Example: + # puts json_escape("is a > 0 & a < 10?") + # # => is a \u003E 0 \u0026 a \u003C 10? + def json_escape(s) + s.to_s.gsub(/[&"><]/) { |special| JSON_ESCAPE[special] } + end + + alias j json_escape + module_function :j + module_function :json_escape + end +end + class Object def html_safe? false @@ -10,32 +60,46 @@ class Fixnum end end -class String - attr_accessor :_rails_html_safe - alias html_safe? _rails_html_safe +module ActiveSupport #:nodoc: + class SafeBuffer < String + alias safe_concat concat - def html_safe! - @_rails_html_safe = true - self - end + def concat(value) + if value.html_safe? + super(value) + else + super(ERB::Util.h(value)) + end + end - def html_safe - dup.html_safe! - end + def +(other) + dup.concat(other) + end + + def <<(value) + self.concat(value) + end + + def html_safe? + true + end + + def html_safe + self + end - alias original_plus + - def +(other) - result = original_plus(other) - result._rails_html_safe = html_safe? && other.html_safe? - result + def to_s + self + end end +end - alias original_concat << - alias safe_concat << - def <<(other) - @_rails_html_safe = false unless other.html_safe? - result = original_concat(other) +class String + def html_safe! + raise "You can't call html_safe! on a String" end - alias concat << + def html_safe + ActiveSupport::SafeBuffer.new(self) + end end
\ No newline at end of file diff --git a/activesupport/test/core_ext/string_ext_test.rb b/activesupport/test/core_ext/string_ext_test.rb index 9a805bc010..ca26f91e8c 100644 --- a/activesupport/test/core_ext/string_ext_test.rb +++ b/activesupport/test/core_ext/string_ext_test.rb @@ -342,12 +342,12 @@ class OutputSafetyTest < ActiveSupport::TestCase end test "A string can be marked safe" do - @string.html_safe! - assert @string.html_safe? + string = @string.html_safe + assert string.html_safe? end test "Marking a string safe returns the string" do - assert_equal @string, @string.html_safe! + assert_equal @string, @string.html_safe end test "A fixnum is safe by default" do @@ -361,7 +361,7 @@ class OutputSafetyTest < ActiveSupport::TestCase end end - @string.html_safe! + @string.html_safe @string << klass.new assert_equal "helloother", @string @@ -369,44 +369,44 @@ class OutputSafetyTest < ActiveSupport::TestCase end test "Adding a safe string to another safe string returns a safe string" do - @other_string = "other".html_safe! - @string.html_safe! - @combination = @other_string + @string + @other_string = "other".html_safe + string = @string.html_safe + @combination = @other_string + string assert_equal "otherhello", @combination assert @combination.html_safe? end - test "Adding an unsafe string to a safe string returns an unsafe string" do - @other_string = "other".html_safe! - @combination = @other_string + @string - @other_combination = @string + @other_string + test "Adding an unsafe string to a safe string escapes it and returns a safe string" do + @other_string = "other".html_safe + @combination = @other_string + "<foo>" + @other_combination = @string + "<foo>" - assert_equal "otherhello", @combination - assert_equal "helloother", @other_combination + assert_equal "other<foo>", @combination + assert_equal "hello<foo>", @other_combination - assert !@combination.html_safe? + assert @combination.html_safe? assert !@other_combination.html_safe? end test "Concatting safe onto unsafe yields unsafe" do @other_string = "other" - @string.html_safe! + @string.html_safe @other_string.concat(@string) assert !@other_string.html_safe? end - test "Concatting unsafe onto safe yields unsafe" do - @other_string = "other".html_safe! - - @other_string.concat(@string) - assert !@other_string.html_safe? + test "Concatting unsafe onto safe yields escaped safe" do + @other_string = "other".html_safe + string = @other_string.concat("<foo>") + assert_equal "other<foo>", string + assert string.html_safe? end test "Concatting safe onto safe yields safe" do - @other_string = "other".html_safe! - @string.html_safe! + @other_string = "other".html_safe + @string.html_safe @other_string.concat(@string) assert @other_string.html_safe? @@ -414,31 +414,32 @@ class OutputSafetyTest < ActiveSupport::TestCase test "Concatting safe onto unsafe with << yields unsafe" do @other_string = "other" - @string.html_safe! + @string.html_safe @other_string << @string assert !@other_string.html_safe? end - test "Concatting unsafe onto safe with << yields unsafe" do - @other_string = "other".html_safe! - - @other_string << @string - assert !@other_string.html_safe? + test "Concatting unsafe onto safe with << yields escaped safe" do + @other_string = "other".html_safe + string = @other_string << "<foo>" + assert_equal "other<foo>", string + assert string.html_safe? end test "Concatting safe onto safe with << yields safe" do - @other_string = "other".html_safe! - @string.html_safe! + @other_string = "other".html_safe + @string.html_safe @other_string << @string assert @other_string.html_safe? end test "Concatting a fixnum to safe always yields safe" do - @string.html_safe! - @string.concat(13) - assert @string.html_safe? + string = @string.html_safe + string = string.concat(13) + assert_equal "hello".concat(13), string + assert string.html_safe? end end |