aboutsummaryrefslogtreecommitdiffstats
path: root/activesupport
diff options
context:
space:
mode:
Diffstat (limited to 'activesupport')
-rw-r--r--activesupport/CHANGELOG2
-rw-r--r--activesupport/lib/active_support.rb1
-rw-r--r--activesupport/lib/active_support/core_ext/class/attribute.rb36
-rw-r--r--activesupport/lib/active_support/core_ext/string/output_safety.rb106
-rw-r--r--activesupport/lib/active_support/rescuable.rb8
-rw-r--r--activesupport/test/abstract_unit.rb10
-rw-r--r--activesupport/test/callbacks_test.rb8
-rw-r--r--activesupport/test/core_ext/class/attribute_test.rb47
-rw-r--r--activesupport/test/core_ext/string_ext_test.rb67
-rw-r--r--activesupport/test/fixtures/custom.rb2
-rw-r--r--activesupport/test/fixtures/omgomg.rb2
-rw-r--r--activesupport/test/isolation_test.rb12
-rw-r--r--activesupport/test/multibyte_chars_test.rb22
-rw-r--r--activesupport/test/notifications_test.rb6
-rw-r--r--activesupport/test/safe_buffer_test.rb41
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 = { '&' => '&amp;', '>' => '&gt;', '<' => '&lt;', '"' => '&quot;' }
+ 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 &gt; 0 &amp; a &lt; 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&lt;foo&gt;", @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&lt;foo&gt;", 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&lt;foo&gt;", 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 "&lt;script&gt;", @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 "&lt;script&gt;", @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