diff options
Diffstat (limited to 'activesupport/lib')
4 files changed, 126 insertions, 25 deletions
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/class/attribute.rb b/activesupport/lib/active_support/core_ext/class/attribute.rb new file mode 100644 index 0000000000..d74219cb93 --- /dev/null +++ b/activesupport/lib/active_support/core_ext/class/attribute.rb @@ -0,0 +1,36 @@ +require 'active_support/core_ext/object/metaclass' +require 'active_support/core_ext/module/delegation' + +class Class + # Declare a class-level attribute whose value is inheritable and + # overwritable by subclasses: + # + # class Base + # class_attribute :setting + # end + # + # class Subclass < Base + # end + # + # Base.setting = true + # Subclass.setting # => true + # Subclass.setting = false + # Subclass.setting # => false + # Base.setting # => true + # + # This matches normal Ruby method inheritance: think of writing an attribute + # on a subclass as overriding the reader method. + # + # For convenience, a query method is defined as well: + # + # Subclass.setting? # => false + def class_attribute(*attrs) + attrs.each do |attr| + metaclass.send(:define_method, attr) { } + metaclass.send(:define_method, "#{attr}?") { !!send(attr) } + metaclass.send(:define_method, "#{attr}=") do |value| + metaclass.send(:define_method, attr) { value } + end + end + end +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/lib/active_support/rescuable.rb b/activesupport/lib/active_support/rescuable.rb index 6e660f8647..e4c1651acf 100644 --- a/activesupport/lib/active_support/rescuable.rb +++ b/activesupport/lib/active_support/rescuable.rb @@ -1,4 +1,4 @@ -require 'active_support/core_ext/class/inheritable_attributes' +require 'active_support/core_ext/class/attribute' require 'active_support/core_ext/proc' require 'active_support/core_ext/string/inflections' require 'active_support/core_ext/array/extract_options' @@ -9,7 +9,7 @@ module ActiveSupport extend Concern included do - class_inheritable_accessor :rescue_handlers + class_attribute :rescue_handlers self.rescue_handlers = [] end @@ -67,7 +67,7 @@ module ActiveSupport end # put the new handler at the end because the list is read in reverse - rescue_handlers << [key, options[:with]] + self.rescue_handlers += [[key, options[:with]]] end end end @@ -83,7 +83,7 @@ module ActiveSupport def handler_for_rescue(exception) # We go from right to left because pairs are pushed onto rescue_handlers # as rescue_from declarations are found. - _, rescuer = rescue_handlers.reverse.detect do |klass_name, handler| + _, rescuer = self.class.rescue_handlers.reverse.detect do |klass_name, handler| # The purpose of allowing strings in rescue_from is to support the # declaration of handler associations for exception classes whose # definition is yet unknown. |