diff options
Diffstat (limited to 'activesupport')
-rw-r--r-- | activesupport/CHANGELOG | 2 | ||||
-rw-r--r-- | activesupport/lib/active_support.rb | 1 | ||||
-rw-r--r-- | activesupport/lib/active_support/core_ext/class/attribute.rb | 36 | ||||
-rw-r--r-- | activesupport/lib/active_support/core_ext/string/output_safety.rb | 106 | ||||
-rw-r--r-- | activesupport/lib/active_support/rescuable.rb | 8 | ||||
-rw-r--r-- | activesupport/test/abstract_unit.rb | 10 | ||||
-rw-r--r-- | activesupport/test/callbacks_test.rb | 8 | ||||
-rw-r--r-- | activesupport/test/core_ext/class/attribute_test.rb | 47 | ||||
-rw-r--r-- | activesupport/test/core_ext/string_ext_test.rb | 67 | ||||
-rw-r--r-- | activesupport/test/fixtures/custom.rb | 2 | ||||
-rw-r--r-- | activesupport/test/fixtures/omgomg.rb | 2 | ||||
-rw-r--r-- | activesupport/test/isolation_test.rb | 12 | ||||
-rw-r--r-- | activesupport/test/multibyte_chars_test.rb | 22 | ||||
-rw-r--r-- | activesupport/test/notifications_test.rb | 6 | ||||
-rw-r--r-- | activesupport/test/safe_buffer_test.rb | 41 |
15 files changed, 277 insertions, 93 deletions
diff --git a/activesupport/CHANGELOG b/activesupport/CHANGELOG index 787fa26e44..431607f4e0 100644 --- a/activesupport/CHANGELOG +++ b/activesupport/CHANGELOG @@ -1,5 +1,7 @@ *Rails 3.0 (pending)* +* Introduce class_attribute to declare inheritable class attributes. Writing an attribute on a subclass behaves just like overriding the superclass reader method. Unifies and replaces most usage of cattr_accessor, class_inheritable_attribute, superclass_delegating_attribute, and extlib_inheritable_attribute. [Jeremy Kemper, Yehuda Katz] + * Time#- with a DateTime argument behaves the same as with a Time argument, i.e. returns the difference between self and arg as a Float #3476 [Geoff Buesing] * YAML serialization for OrderedHash. #3608 [Gregor Schmidt] 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. diff --git a/activesupport/test/abstract_unit.rb b/activesupport/test/abstract_unit.rb index d91e0415c4..33be6f65bf 100644 --- a/activesupport/test/abstract_unit.rb +++ b/activesupport/test/abstract_unit.rb @@ -1,12 +1,4 @@ -ORIG_ARGV = ARGV.dup - -begin - require File.expand_path('../../../vendor/gems/environment', __FILE__) -rescue LoadError -end - -lib = File.expand_path("#{File.dirname(__FILE__)}/../lib") -$:.unshift(lib) unless $:.include?('lib') || $:.include?(lib) +require File.expand_path('../../../load_paths', __FILE__) require 'test/unit' require 'mocha' diff --git a/activesupport/test/callbacks_test.rb b/activesupport/test/callbacks_test.rb index df98644436..11494e951e 100644 --- a/activesupport/test/callbacks_test.rb +++ b/activesupport/test/callbacks_test.rb @@ -264,12 +264,12 @@ module CallbacksTest define_callbacks :save attr_reader :stuff - set_callback :save, :before, :omg, :per_key => {:if => :yes} + set_callback :save, :before, :action, :per_key => {:if => :yes} def yes() true end - def omg - @stuff = "OMG" + def action + @stuff = "ACTION" end def save @@ -522,7 +522,7 @@ module CallbacksTest def test_save obj = HyphenatedCallbacks.new obj.save - assert_equal obj.stuff, "OMG" + assert_equal obj.stuff, "ACTION" end end end diff --git a/activesupport/test/core_ext/class/attribute_test.rb b/activesupport/test/core_ext/class/attribute_test.rb new file mode 100644 index 0000000000..ef84b9f255 --- /dev/null +++ b/activesupport/test/core_ext/class/attribute_test.rb @@ -0,0 +1,47 @@ +require 'abstract_unit' +require 'active_support/core_ext/class/attribute' + +class ClassAttributeTest < ActiveSupport::TestCase + class Base + class_attribute :setting + end + + class Subclass < Base + end + + def setup + @klass = Class.new { class_attribute :setting } + @sub = Class.new(@klass) + end + + test 'defaults to nil' do + assert_nil @klass.setting + assert_nil @sub.setting + end + + test 'inheritable' do + @klass.setting = 1 + assert_equal 1, @sub.setting + end + + test 'overridable' do + @sub.setting = 1 + assert_nil @klass.setting + + @klass.setting = 2 + assert_equal 1, @sub.setting + + assert_equal 1, Class.new(@sub).setting + end + + test 'query method' do + assert_equal false, @klass.setting? + @klass.setting = 1 + assert_equal true, @klass.setting? + end + + test 'no instance delegates' do + assert_raise(NoMethodError) { @klass.new.setting } + assert_raise(NoMethodError) { @klass.new.setting? } + end +end 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 diff --git a/activesupport/test/fixtures/custom.rb b/activesupport/test/fixtures/custom.rb new file mode 100644 index 0000000000..0eefce0c25 --- /dev/null +++ b/activesupport/test/fixtures/custom.rb @@ -0,0 +1,2 @@ +class Custom +end
\ No newline at end of file diff --git a/activesupport/test/fixtures/omgomg.rb b/activesupport/test/fixtures/omgomg.rb deleted file mode 100644 index a512a93ae4..0000000000 --- a/activesupport/test/fixtures/omgomg.rb +++ /dev/null @@ -1,2 +0,0 @@ -class OmgOmg -end
\ No newline at end of file diff --git a/activesupport/test/isolation_test.rb b/activesupport/test/isolation_test.rb index a7af5e96f6..2c2986ea28 100644 --- a/activesupport/test/isolation_test.rb +++ b/activesupport/test/isolation_test.rb @@ -59,15 +59,15 @@ elsif ENV['CHILD'] end test "resets requires one" do - assert !defined?(OmgOmg) - assert_equal 0, $LOADED_FEATURES.grep(/fixtures\/omgomg/).size - require File.expand_path(File.join(File.dirname(__FILE__), "fixtures", "omgomg")) + assert !defined?(Custom) + assert_equal 0, $LOADED_FEATURES.grep(/fixtures\/custom/).size + require File.expand_path(File.join(File.dirname(__FILE__), "fixtures", "custom")) end test "resets requires two" do - assert !defined?(OmgOmg) - assert_equal 0, $LOADED_FEATURES.grep(/fixtures\/omgomg/).size - require File.expand_path(File.join(File.dirname(__FILE__), "fixtures", "omgomg")) + assert !defined?(Custom) + assert_equal 0, $LOADED_FEATURES.grep(/fixtures\/custom/).size + require File.expand_path(File.join(File.dirname(__FILE__), "fixtures", "custom")) end end else diff --git a/activesupport/test/multibyte_chars_test.rb b/activesupport/test/multibyte_chars_test.rb index 0e489c10e1..0f68dcfe23 100644 --- a/activesupport/test/multibyte_chars_test.rb +++ b/activesupport/test/multibyte_chars_test.rb @@ -301,10 +301,10 @@ class MultibyteCharsUTF8BehaviourTest < Test::Unit::TestCase assert_equal " #{UNICODE_STRING}", @chars.rjust(5) assert_equal " #{UNICODE_STRING}", @chars.rjust(7) assert_equal "---#{UNICODE_STRING}", @chars.rjust(7, '-') - assert_equal "ααα#{UNICODE_STRING}", @chars.rjust(7, 'α') + assert_equal "αα#{UNICODE_STRING}", @chars.rjust(7, 'α') assert_equal "aba#{UNICODE_STRING}", @chars.rjust(7, 'ab') assert_equal "αηα#{UNICODE_STRING}", @chars.rjust(7, 'αη') - assert_equal "αηαη#{UNICODE_STRING}", @chars.rjust(8, 'αη') + assert_equal "αη#{UNICODE_STRING}", @chars.rjust(8, 'αη') end def test_ljust_should_raise_argument_errors_on_bad_arguments @@ -319,10 +319,10 @@ class MultibyteCharsUTF8BehaviourTest < Test::Unit::TestCase assert_equal "#{UNICODE_STRING} ", @chars.ljust(5) assert_equal "#{UNICODE_STRING} ", @chars.ljust(7) assert_equal "#{UNICODE_STRING}---", @chars.ljust(7, '-') - assert_equal "#{UNICODE_STRING}ααα", @chars.ljust(7, 'α') + assert_equal "#{UNICODE_STRING}αα", @chars.ljust(7, 'α') assert_equal "#{UNICODE_STRING}aba", @chars.ljust(7, 'ab') assert_equal "#{UNICODE_STRING}αηα", @chars.ljust(7, 'αη') - assert_equal "#{UNICODE_STRING}αηαη", @chars.ljust(8, 'αη') + assert_equal "#{UNICODE_STRING}αη", @chars.ljust(8, 'αη') end def test_center_should_raise_argument_errors_on_bad_arguments @@ -339,13 +339,13 @@ class MultibyteCharsUTF8BehaviourTest < Test::Unit::TestCase assert_equal " #{UNICODE_STRING} ", @chars.center(7) assert_equal "--#{UNICODE_STRING}--", @chars.center(8, '-') assert_equal "--#{UNICODE_STRING}---", @chars.center(9, '-') - assert_equal "αα#{UNICODE_STRING}αα", @chars.center(8, 'α') - assert_equal "αα#{UNICODE_STRING}ααα", @chars.center(9, 'α') - assert_equal "a#{UNICODE_STRING}ab", @chars.center(7, 'ab') - assert_equal "ab#{UNICODE_STRING}ab", @chars.center(8, 'ab') - assert_equal "abab#{UNICODE_STRING}abab", @chars.center(12, 'ab') - assert_equal "α#{UNICODE_STRING}αη", @chars.center(7, 'αη') - assert_equal "αη#{UNICODE_STRING}αη", @chars.center(8, 'αη') + assert_equal "α#{UNICODE_STRING}α", @chars.center(8, 'α') + assert_equal "α#{UNICODE_STRING}αα", @chars.center(9, 'α') + assert_equal "a#{UNICODE_STRING}", @chars.center(7, 'ab') + assert_equal UNICODE_STRING, @chars.center(8, 'ab') + assert_equal "ab#{UNICODE_STRING}ab", @chars.center(12, 'ab') + assert_equal "α#{UNICODE_STRING}", @chars.center(7, 'αη') + assert_equal UNICODE_STRING, @chars.center(8, 'αη') end def test_lstrip_strips_whitespace_from_the_left_of_the_string diff --git a/activesupport/test/notifications_test.rb b/activesupport/test/notifications_test.rb index d3af535c26..0b78b53c73 100644 --- a/activesupport/test/notifications_test.rb +++ b/activesupport/test/notifications_test.rb @@ -77,7 +77,7 @@ module Notifications def test_instrument_with_bang_returns_result_even_on_failure begin instrument!(:awesome, :payload => "notifications") do - raise "OMG" + raise "FAIL" end flunk rescue @@ -126,10 +126,10 @@ module Notifications def test_instrument_does_not_publish_when_exception_is_raised begin instrument(:awesome, :payload => "notifications") do - raise "OMG" + raise "FAIL" end rescue RuntimeError => e - assert_equal "OMG", e.message + assert_equal "FAIL", e.message end drain diff --git a/activesupport/test/safe_buffer_test.rb b/activesupport/test/safe_buffer_test.rb new file mode 100644 index 0000000000..bf61f9e58c --- /dev/null +++ b/activesupport/test/safe_buffer_test.rb @@ -0,0 +1,41 @@ +require 'abstract_unit' + +class SafeBufferTest < ActiveSupport::TestCase + def setup + @buffer = ActiveSupport::SafeBuffer.new + end + + test "Should look like a string" do + assert @buffer.is_a?(String) + assert_equal "", @buffer + end + + test "Should escape a raw string which is passed to them" do + @buffer << "<script>" + assert_equal "<script>", @buffer + end + + test "Should NOT escape a safe value passed to it" do + @buffer << "<script>".html_safe + assert_equal "<script>", @buffer + end + + test "Should not mess with an innocuous string" do + @buffer << "Hello" + assert_equal "Hello", @buffer + end + + test "Should not mess with a previously escape test" do + @buffer << ERB::Util.html_escape("<script>") + assert_equal "<script>", @buffer + end + + test "Should be considered safe" do + assert @buffer.html_safe? + end + + test "Should return a safe buffer when calling to_s" do + new_buffer = @buffer.to_s + assert_equal ActiveSupport::SafeBuffer, new_buffer.class + end +end |