aboutsummaryrefslogtreecommitdiffstats
path: root/activesupport
diff options
context:
space:
mode:
Diffstat (limited to 'activesupport')
-rw-r--r--activesupport/CHANGELOG117
-rw-r--r--activesupport/MIT-LICENSE2
-rw-r--r--activesupport/README.rdoc2
-rwxr-xr-x[-rw-r--r--]activesupport/Rakefile17
-rw-r--r--activesupport/bin/generate_tables4
-rw-r--r--activesupport/lib/active_support.rb2
-rw-r--r--activesupport/lib/active_support/backtrace_cleaner.rb2
-rw-r--r--activesupport/lib/active_support/base64.rb6
-rw-r--r--activesupport/lib/active_support/benchmarkable.rb6
-rw-r--r--activesupport/lib/active_support/buffered_logger.rb1
-rw-r--r--activesupport/lib/active_support/cache.rb60
-rw-r--r--activesupport/lib/active_support/cache/file_store.rb7
-rw-r--r--activesupport/lib/active_support/cache/mem_cache_store.rb4
-rw-r--r--activesupport/lib/active_support/cache/strategy/local_cache.rb53
-rw-r--r--activesupport/lib/active_support/callbacks.rb364
-rw-r--r--activesupport/lib/active_support/concern.rb140
-rw-r--r--activesupport/lib/active_support/configurable.rb57
-rw-r--r--activesupport/lib/active_support/core_ext/array/conversions.rb2
-rw-r--r--activesupport/lib/active_support/core_ext/array/random_access.rb12
-rw-r--r--activesupport/lib/active_support/core_ext/array/wrap.rb2
-rw-r--r--activesupport/lib/active_support/core_ext/big_decimal/conversions.rb19
-rw-r--r--activesupport/lib/active_support/core_ext/cgi.rb1
-rw-r--r--activesupport/lib/active_support/core_ext/cgi/escape_skipping_slashes.rb19
-rw-r--r--activesupport/lib/active_support/core_ext/class/attribute.rb36
-rw-r--r--activesupport/lib/active_support/core_ext/class/attribute_accessors.rb4
-rw-r--r--activesupport/lib/active_support/core_ext/class/inheritable_attributes.rb106
-rw-r--r--activesupport/lib/active_support/core_ext/class/subclasses.rb54
-rw-r--r--activesupport/lib/active_support/core_ext/date/calculations.rb24
-rw-r--r--activesupport/lib/active_support/core_ext/date/conversions.rb8
-rw-r--r--activesupport/lib/active_support/core_ext/date/zones.rb6
-rw-r--r--activesupport/lib/active_support/core_ext/date_time/calculations.rb36
-rw-r--r--activesupport/lib/active_support/core_ext/date_time/conversions.rb16
-rw-r--r--activesupport/lib/active_support/core_ext/date_time/zones.rb2
-rw-r--r--activesupport/lib/active_support/core_ext/enumerable.rb15
-rw-r--r--activesupport/lib/active_support/core_ext/float/rounding.rb2
-rw-r--r--activesupport/lib/active_support/core_ext/hash.rb1
-rw-r--r--activesupport/lib/active_support/core_ext/hash/conversions.rb48
-rw-r--r--activesupport/lib/active_support/core_ext/hash/deep_dup.rb11
-rw-r--r--activesupport/lib/active_support/core_ext/hash/indifferent_access.rb4
-rw-r--r--activesupport/lib/active_support/core_ext/hash/keys.rb10
-rw-r--r--activesupport/lib/active_support/core_ext/hash/reverse_merge.rb23
-rw-r--r--activesupport/lib/active_support/core_ext/integer/time.rb4
-rw-r--r--activesupport/lib/active_support/core_ext/kernel/reporting.rb21
-rw-r--r--activesupport/lib/active_support/core_ext/logger.rb49
-rw-r--r--activesupport/lib/active_support/core_ext/module/anonymous.rb2
-rw-r--r--activesupport/lib/active_support/core_ext/module/attr_accessor_with_default.rb27
-rw-r--r--activesupport/lib/active_support/core_ext/module/attr_internal.rb19
-rw-r--r--activesupport/lib/active_support/core_ext/module/attribute_accessors.rb2
-rw-r--r--activesupport/lib/active_support/core_ext/module/delegation.rb2
-rw-r--r--activesupport/lib/active_support/core_ext/module/deprecation.rb2
-rw-r--r--activesupport/lib/active_support/core_ext/module/remove_method.rb2
-rw-r--r--activesupport/lib/active_support/core_ext/module/synchronization.rb5
-rw-r--r--activesupport/lib/active_support/core_ext/numeric/time.rb22
-rw-r--r--activesupport/lib/active_support/core_ext/object.rb1
-rw-r--r--activesupport/lib/active_support/core_ext/object/blank.rb4
-rw-r--r--activesupport/lib/active_support/core_ext/object/instance_variables.rb40
-rw-r--r--activesupport/lib/active_support/core_ext/object/returning.rb43
-rw-r--r--activesupport/lib/active_support/core_ext/object/to_param.rb22
-rw-r--r--activesupport/lib/active_support/core_ext/object/to_query.rb4
-rw-r--r--activesupport/lib/active_support/core_ext/object/try.rb19
-rw-r--r--activesupport/lib/active_support/core_ext/object/with_options.rb24
-rw-r--r--activesupport/lib/active_support/core_ext/range.rb1
-rw-r--r--activesupport/lib/active_support/core_ext/range/conversions.rb2
-rw-r--r--activesupport/lib/active_support/core_ext/range/cover.rb3
-rw-r--r--activesupport/lib/active_support/core_ext/string.rb3
-rw-r--r--activesupport/lib/active_support/core_ext/string/access.rb14
-rw-r--r--activesupport/lib/active_support/core_ext/string/filters.rb6
-rw-r--r--activesupport/lib/active_support/core_ext/string/inflections.rb16
-rw-r--r--activesupport/lib/active_support/core_ext/string/multibyte.rb2
-rw-r--r--activesupport/lib/active_support/core_ext/string/output_safety.rb27
-rw-r--r--activesupport/lib/active_support/core_ext/string/strip.rb26
-rw-r--r--activesupport/lib/active_support/core_ext/time/calculations.rb33
-rw-r--r--activesupport/lib/active_support/core_ext/time/conversions.rb30
-rw-r--r--activesupport/lib/active_support/core_ext/time/zones.rb18
-rw-r--r--activesupport/lib/active_support/core_ext/uri.rb8
-rw-r--r--activesupport/lib/active_support/dependencies.rb190
-rw-r--r--activesupport/lib/active_support/deprecation.rb4
-rw-r--r--activesupport/lib/active_support/deprecation/behaviors.rb7
-rw-r--r--activesupport/lib/active_support/deprecation/proxy_wrappers.rb4
-rw-r--r--activesupport/lib/active_support/deprecation/reporting.rb18
-rw-r--r--activesupport/lib/active_support/duration.rb8
-rw-r--r--activesupport/lib/active_support/file_update_checker.rb2
-rw-r--r--activesupport/lib/active_support/file_watcher.rb36
-rw-r--r--activesupport/lib/active_support/gzip.rb6
-rw-r--r--activesupport/lib/active_support/hash_with_indifferent_access.rb28
-rw-r--r--activesupport/lib/active_support/i18n.rb2
-rw-r--r--activesupport/lib/active_support/i18n_railtie.rb29
-rw-r--r--activesupport/lib/active_support/inflections.rb4
-rw-r--r--activesupport/lib/active_support/inflector/inflections.rb2
-rw-r--r--activesupport/lib/active_support/inflector/transliterate.rb1
-rw-r--r--activesupport/lib/active_support/json/backends/jsongem.rb6
-rw-r--r--activesupport/lib/active_support/json/backends/yajl.rb6
-rw-r--r--activesupport/lib/active_support/json/backends/yaml.rb45
-rw-r--r--activesupport/lib/active_support/json/encoding.rb57
-rw-r--r--activesupport/lib/active_support/lazy_load_hooks.rb18
-rw-r--r--activesupport/lib/active_support/locale/en.yml6
-rw-r--r--activesupport/lib/active_support/log_subscriber.rb71
-rw-r--r--activesupport/lib/active_support/log_subscriber/test_helper.rb9
-rw-r--r--activesupport/lib/active_support/memoizable.rb2
-rw-r--r--activesupport/lib/active_support/message_encryptor.rb36
-rw-r--r--activesupport/lib/active_support/message_verifier.rb16
-rw-r--r--activesupport/lib/active_support/multibyte.rb2
-rw-r--r--activesupport/lib/active_support/multibyte/chars.rb9
-rw-r--r--activesupport/lib/active_support/multibyte/unicode.rb2
-rw-r--r--activesupport/lib/active_support/notifications.rb17
-rw-r--r--activesupport/lib/active_support/ordered_hash.rb29
-rw-r--r--activesupport/lib/active_support/ordered_options.rb30
-rw-r--r--activesupport/lib/active_support/rescuable.rb1
-rw-r--r--activesupport/lib/active_support/secure_random.rb16
-rw-r--r--activesupport/lib/active_support/test_case.rb3
-rw-r--r--activesupport/lib/active_support/testing/assertions.rb14
-rw-r--r--activesupport/lib/active_support/testing/declarative.rb8
-rw-r--r--activesupport/lib/active_support/testing/default.rb9
-rw-r--r--activesupport/lib/active_support/testing/isolation.rb2
-rw-r--r--activesupport/lib/active_support/testing/pending.rb10
-rw-r--r--activesupport/lib/active_support/testing/performance.rb10
-rw-r--r--activesupport/lib/active_support/testing/setup_and_teardown.rb8
-rw-r--r--activesupport/lib/active_support/time_with_zone.rb24
-rw-r--r--activesupport/lib/active_support/version.rb6
-rw-r--r--activesupport/lib/active_support/whiny_nil.rb2
-rw-r--r--activesupport/lib/active_support/xml_mini.rb8
-rw-r--r--activesupport/lib/active_support/xml_mini/libxml.rb1
-rw-r--r--activesupport/lib/active_support/xml_mini/libxmlsax.rb3
-rw-r--r--activesupport/lib/active_support/xml_mini/nokogiri.rb1
-rw-r--r--activesupport/lib/active_support/xml_mini/nokogirisax.rb4
-rw-r--r--activesupport/lib/active_support/xml_mini/rexml.rb3
-rw-r--r--activesupport/test/abstract_unit.rb13
-rw-r--r--activesupport/test/autoloading_fixtures/class_folder/nested_class.rb2
-rw-r--r--activesupport/test/buffered_logger_test.rb4
-rw-r--r--activesupport/test/caching_test.rb19
-rw-r--r--activesupport/test/callback_inheritance_test.rb32
-rw-r--r--activesupport/test/callbacks_test.rb113
-rw-r--r--activesupport/test/class_cache_test.rb108
-rw-r--r--activesupport/test/clean_backtrace_test.rb14
-rw-r--r--activesupport/test/clean_logger_test.rb4
-rw-r--r--activesupport/test/configurable_test.rb26
-rw-r--r--activesupport/test/core_ext/array_ext_test.rb17
-rw-r--r--activesupport/test/core_ext/bigdecimal.rb10
-rw-r--r--activesupport/test/core_ext/bigdecimal_test.rb17
-rw-r--r--activesupport/test/core_ext/cgi_ext_test.rb15
-rw-r--r--activesupport/test/core_ext/class/attribute_accessor_test.rb10
-rw-r--r--activesupport/test/core_ext/class/attribute_test.rb5
-rw-r--r--activesupport/test/core_ext/class/class_inheritable_attributes_test.rb27
-rw-r--r--activesupport/test/core_ext/date_ext_test.rb87
-rw-r--r--activesupport/test/core_ext/date_time_ext_test.rb28
-rw-r--r--activesupport/test/core_ext/duration_test.rb31
-rw-r--r--activesupport/test/core_ext/enumerable_test.rb2
-rw-r--r--activesupport/test/core_ext/hash_ext_test.rb127
-rw-r--r--activesupport/test/core_ext/kernel_test.rb11
-rw-r--r--activesupport/test/core_ext/module/anonymous_test.rb2
-rw-r--r--activesupport/test/core_ext/module/attr_accessor_with_default_test.rb10
-rw-r--r--activesupport/test/core_ext/module/attribute_accessor_test.rb2
-rw-r--r--activesupport/test/core_ext/module/attribute_aliasing_test.rb6
-rw-r--r--activesupport/test/core_ext/module/reachable_test.rb16
-rw-r--r--activesupport/test/core_ext/module/synchronization_test.rb1
-rw-r--r--activesupport/test/core_ext/module_test.rb17
-rw-r--r--activesupport/test/core_ext/numeric_ext_test.rb62
-rw-r--r--activesupport/test/core_ext/object/to_query_test.rb8
-rw-r--r--activesupport/test/core_ext/object_and_class_ext_test.rb55
-rw-r--r--activesupport/test/core_ext/range_ext_test.rb12
-rw-r--r--activesupport/test/core_ext/string_ext_test.rb103
-rw-r--r--activesupport/test/core_ext/time_ext_test.rb38
-rw-r--r--activesupport/test/core_ext/time_with_zone_test.rb32
-rw-r--r--activesupport/test/dependencies_test.rb29
-rw-r--r--activesupport/test/file_watcher_test.rb233
-rw-r--r--activesupport/test/gzip_test.rb13
-rw-r--r--activesupport/test/i18n_test.rb34
-rw-r--r--activesupport/test/inflector_test.rb39
-rw-r--r--activesupport/test/inflector_test_cases.rb1
-rw-r--r--activesupport/test/json/decoding_test.rb24
-rw-r--r--activesupport/test/json/encoding_test.rb96
-rw-r--r--activesupport/test/memoizable_test.rb14
-rw-r--r--activesupport/test/message_encryptor_test.rb14
-rw-r--r--activesupport/test/multibyte_conformance.rb30
-rw-r--r--activesupport/test/notifications_test.rb9
-rw-r--r--activesupport/test/option_merger_test.rb2
-rw-r--r--activesupport/test/ordered_hash_test.rb52
-rw-r--r--activesupport/test/rescuable_test.rb8
-rw-r--r--activesupport/test/safe_buffer_test.rb22
-rw-r--r--activesupport/test/test_case_test.rb61
-rw-r--r--activesupport/test/test_test.rb27
-rw-r--r--activesupport/test/test_xml_mini.rb117
-rw-r--r--activesupport/test/time_zone_test.rb2
-rw-r--r--activesupport/test/whiny_nil_test.rb2
184 files changed, 2994 insertions, 1564 deletions
diff --git a/activesupport/CHANGELOG b/activesupport/CHANGELOG
index 8485e7d46b..373236ce9a 100644
--- a/activesupport/CHANGELOG
+++ b/activesupport/CHANGELOG
@@ -1,4 +1,33 @@
-*Rails 3.0.0 [release candidate] (July 26th, 2010)*
+*Rails 3.1.0 (unreleased)*
+
+* LocalCache strategy is now a real middleware class, not an anonymous class
+posing for pictures.
+
+* ActiveSupport::Dependencies::ClassCache class has been introduced for
+holding references to reloadable classes.
+
+* ActiveSupport::Dependencies::Reference has been refactored to take direct
+advantage of the new ClassCache.
+
+* Backports Range#cover? as an alias for Range#include? in Ruby 1.8 [Diego Carrion, fxn]
+
+* Added weeks_ago and prev_week to Date/DateTime/Time. [Rob Zolkos, fxn]
+
+* Added before_remove_const callback to ActiveSupport::Dependencies.remove_unloadable_constants! [Andrew White]
+
+*Rails 3.0.2 (unreleased)*
+
+* Added before_remove_const callback to ActiveSupport::Dependencies.remove_unloadable_constants! [Andrew White]
+
+*Rails 3.0.1 (October 15, 2010)*
+
+* No Changes, just a version bump.
+
+*Rails 3.0.0 (August 29, 2010)*
+
+* Implemented String#strip_heredoc. [fxn]
+
+* Pluggable cache stores: setting config.cache_store = "custom_store" will require 'active_support/cache/custom_store' and look for the CustomStore constant. #5486 [Mike Perham]
* Removed Object#returning, Object#tap should be used instead. [Santiago Pastorino]
@@ -18,9 +47,6 @@
* Date#since, #ago, #beginning_of_day, #end_of_day, and #xmlschema honor now the user time zone if set. [Geoff Buesing]
-
-*Rails 3.0.0 [beta 4] (June 8th, 2010)*
-
* Extracted String#truncate from TextHelper#truncate [DHH]
* Ruby 1.9: support UTF-8 case folding. #4595 [Norman Clarke]
@@ -73,32 +99,23 @@
* JSON: encode objects that don't have a native JSON representation using to_hash, if available, instead of instance_values (the old fallback) or to_s (other encoders' default). Encode BigDecimal and Regexp encode as strings to conform with other encoders. Try to transcode non-UTF-8 strings. [Jeremy Kemper]
-
-*Rails 3.0.0 [beta 3] (April 13th, 2010)*
-
* HashWithIndifferentAccess: remove inherited symbolize_keys! since its keys are always strings. [Santiago Pastorino]
* Improve transliteration quality. #4374 [Norman Clarke]
* Speed up and add Ruby 1.9 support for ActiveSupport::Multibyte::Chars#tidy_bytes. #4350 [Norman Clarke]
-
-*Rails 3.0.0 [beta 2] (April 1st, 2010)*
-
* Reduced load time by deferring configuration of classes using
ActiveSupport::on_load(:component_name) [YK]
* Rename #metaclass to #singleton_class now that ruby-core has decided [JK]
-* New assertions assert_blank and assert_present. #4299 [Juanjo Bazan]
+* New assertions assert_blank and assert_present. #4299 [Juanjo Bazan]
* Use Object#singleton_class instead of #metaclass. Prefer Ruby's choice. [Jeremy Kemper]
* JSON backend for YAJL. Preferred if available. #2666 [Brian Lopez]
-
-*Rails 3.0.0 [beta 1] (February 4, 2010)*
-
* 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]
@@ -243,10 +260,10 @@ ActiveSupport.escape_html_entities_in_json from true to false to match previousl
* Fix Ruby's Time marshaling bug in pre-1.9 versions of Ruby: utc instances are now correctly unmarshaled with a utc zone instead of the system local zone [#900 state:resolved] [Luca Guidi, Geoff Buesing]
* Add Array#in_groups which splits or iterates over the array in specified number of groups. #579. [Adrian Mugnolo] Example:
-
+
a = (1..10).to_a
- a.in_groups(3) #=> [[1, 2, 3, 4], [5, 6, 7, nil], [8, 9, 10, nil]]
- a.in_groups(3, false) #=> [[1, 2, 3, 4], [5, 6, 7], [8, 9, 10]]
+ a.in_groups(3) # => [[1, 2, 3, 4], [5, 6, 7, nil], [8, 9, 10, nil]]
+ a.in_groups(3, false) # => [[1, 2, 3, 4], [5, 6, 7], [8, 9, 10]]
* Fix TimeWithZone unmarshaling: coerce unmarshaled Time instances to utc, because Ruby's marshaling of Time instances doesn't respect the zone [Geoff Buesing]
@@ -331,7 +348,7 @@ ActiveSupport.escape_html_entities_in_json from true to false to match previousl
* TZInfo: Removing unneeded TimezoneProxy class [Geoff Buesing]
-* TZInfo: Removing unneeded TimezoneIndexDefinition, since we're not including Indexes::Timezones [Geoff Buesing]
+* TZInfo: Removing unneeded TimezoneIndexDefinition, since we're not including Indexes::Timezones [Geoff Buesing]
* Removing unnecessary uses_tzinfo helper from tests, given that TZInfo is now bundled [Geoff Buesing]
@@ -339,7 +356,7 @@ ActiveSupport.escape_html_entities_in_json from true to false to match previousl
* TimeWithZone#marshal_load does zone lookup via Time.get_zone, so that tzinfo/Olson identifiers are handled [Geoff Buesing]
-* Time.zone= accepts TZInfo::Timezone instances and Olson identifiers; wraps result in TimeZone instance [Geoff Buesing]
+* Time.zone= accepts TZInfo::Timezone instances and Olson identifiers; wraps result in TimeZone instance [Geoff Buesing]
* TimeWithZone time conversions don't need to be wrapped in TimeOrDateTime, because TZInfo does this internally [Geoff Buesing]
@@ -433,7 +450,7 @@ ActiveSupport.escape_html_entities_in_json from true to false to match previousl
* TimeZone#to_s uses UTC rather than GMT; reapplying change that was undone in [8679]. #1689 [Cheah Chu Yeow]
-* Time.days_in_month defaults to current year if no year is supplied as argument #10799 [Radar], uses Date.gregorian_leap? to determine leap year, and uses constant lookup to determine days in month [Geoff Buesing]
+* Time.days_in_month defaults to current year if no year is supplied as argument #10799 [Radar], uses Date.gregorian_leap? to determine leap year, and uses constant lookup to determine days in month [Geoff Buesing]
* Adding Time and DateTime #compare_with_coercion, which layers behavior on #<=> so that any combination of Time, DateTime and ActiveSupport::TimeWithZone instances can be chronologically compared [Geoff Buesing]
@@ -510,7 +527,7 @@ ActiveSupport.escape_html_entities_in_json from true to false to match previousl
* Introduce a base class for all test cases used by rails applications. ActiveSupport::TestCase [Michael Koziarski]
- The intention is to use this to reduce the amount of monkeypatching / overriding that
+ The intention is to use this to reduce the amount of monkeypatching / overriding that
is done to test/unit's classes.
* Document Enumerable and Hash #to_json. #9970 [Cheah Chu Yeow]
@@ -679,14 +696,14 @@ ActiveSupport.escape_html_entities_in_json from true to false to match previousl
<name>David</name>
<avatar type="file" name="me.jpg" content_type="image/jpg">R0lGODlhkACZAPUAAM5lcfjrtMQCG=\n</avatar>
</person>
-
+
...becomes:
-
+
attributes = { :person => { :name => "David", :avatar => #<StringIO> } }
attributes[:person][:avatar].content_type # => "image/jpg"
attributes[:person][:avatar].original_filename # => "me.jpg"
attributes[:person][:avatar].read # => binary data of the file
-
+
Which is duck-type compatible with the files that you get when doing multipart uploads through HTML.
* Improved multibyte performance by relying less on exception raising #8159 [Blaine]
@@ -889,11 +906,11 @@ public for compatibility. [Jeremy Kemper]
class Content < ActiveRecord::Base
# has a title attribute
end
-
+
class Email < ActiveRecord::Base
alias_attribute :subject, :title
end
-
+
e = Email.find(1)
e.title # => "Superstars"
e.subject # => "Superstars"
@@ -942,7 +959,7 @@ public for compatibility. [Jeremy Kemper]
* Enhance Symbol#to_proc so it works with list objects, such as multi-dimensional arrays. Closes #5295 [nov@yo.rim.or.jp]. Example:
{1 => "one", 2 => "two", 3 => "three"}.sort_by(&:first).map(&:last)
- #=> ["one", "two", "three"]
+ # => ["one", "two", "three"]
* Added Hash.create_from_xml(string) which will create a hash from a XML string and even typecast if possible [David Heinemeier Hansson]. Example:
@@ -952,9 +969,9 @@ public for compatibility. [Jeremy Kemper]
<created-at type="date">2004-10-10</created-at>
</note>
EOT
-
+
...would return:
-
+
{ :note => { :title => "This is a note", :created_at => Date.new(2004, 10, 10) } }
* Added Jim Weirich's excellent FlexMock class to vendor (Copyright 2003, 2004 by Jim Weirich (jim@weriichhouse.org)) -- it's not automatically required, though, so require 'flexmock' is still necessary [David Heinemeier Hansson]
@@ -966,28 +983,28 @@ public for compatibility. [Jeremy Kemper]
* Add OrderedHash#values. [Sam Stephenson]
* Added Array#to_s(:db) that'll produce a comma-separated list of ids [David Heinemeier Hansson]. Example:
-
+
Purchase.find(:all, :conditions => "product_id IN (#{shops.products.to_s(:db)})"
-* Normalize classify's argument to a String so that it plays nice with Symbols. [Marcel Molina Jr.]
+* Normalize classify's argument to a String so that it plays nice with Symbols. [Marcel Molina Jr.]
* Strip out leading schema name in classify. References #5139. [Michael Schoen]
* Remove Enumerable#first_match since break(value) handles the use case well enough. [Nicholas Seckar]
Enumerable#first_match was like detect, but instead of returning the matching element, the yielded value returned. For example:
-
+
user_xml = adapters(:from => User, :to => Xml).first_match do |adapter|
adapter.adapt @user
end
-
+
But this is just as easily done with:
-
+
user_xml = adapters(:from => User, :to => Xml).each do
break adapter.adapt(@user)
end
-
-* Make Array#in_groups_of just return the grouped collection if a block isn't given. [Marcel Molina Jr.]
+
+* Make Array#in_groups_of just return the grouped collection if a block isn't given. [Marcel Molina Jr.]
* Don't destroy a HashWithIndifferentAccess if symbolize_keys! or stringify_keys! is called on it. Closes #5076. [Marcel Molina Jr., guy.naor@famundo.com]
@@ -999,7 +1016,7 @@ public for compatibility. [Jeremy Kemper]
* Replace Ruby's deprecated append_features in favor of included. [Marcel Molina Jr.]
-* Allow default options in with_options to be overridden. Closes #4480. [murphy@cYcnus.de]
+* Allow default options in with_options to be overridden. Closes #4480. [murphy@cYcnus.de]
* Added Module#alias_method_chain [Jamis Buck]
@@ -1050,7 +1067,7 @@ approximations and shouldn't be used for critical calculations. [Michael Koziars
* Added Hash#to_xml and Array#to_xml that makes it much easier to produce XML from basic structures [David Heinemeier Hansson]. Examples:
{ :name => "David", :street_name => "Paulina", :age => 26, :moved_on => Date.new(2005, 11, 15) }.to_xml
-
+
...returns:
<person>
@@ -1069,7 +1086,7 @@ approximations and shouldn't be used for critical calculations. [Michael Koziars
ex.
- latest_transcripts.group_by(&:day).each do |day, transcripts|
+ latest_transcripts.group_by(&:day).each do |day, transcripts|
p "#{day} -> #{transcripts.map(&:class) * ', '}"
end
"2006-03-01 -> Transcript"
@@ -1093,7 +1110,7 @@ approximations and shouldn't be used for critical calculations. [Michael Koziars
* Add 'around' methods to Logger, to make it easy to log before and after messages for a given block as requested in #3809. [Michael Koziarski] Example:
- logger.around_info("Start rendering component (#{options.inspect}): ",
+ logger.around_info("Start rendering component (#{options.inspect}): ",
"\n\nEnd of component rendering") { yield }
* Added Time#beginning_of_quarter #3607 [cohen.jeff@gmail.com]
@@ -1111,7 +1128,7 @@ approximations and shouldn't be used for critical calculations. [Michael Koziars
delegate :free?, :paying?, :to => :subscription
delegate :overdue?, :to => "subscription.last_payment"
end
-
+
account.free? # => account.subscription.free?
account.overdue? # => account.subscription.last_payment.overdue?
@@ -1126,7 +1143,7 @@ approximations and shouldn't be used for critical calculations. [Michael Koziars
* Add Reloadable::Subclasses which handles the common case where a base class should not be reloaded, but its subclasses should be. [Nicholas Seckar]
* Further improvements to reloading code [Nicholas Seckar, Trevor Squires]
-
+
- All classes/modules which include Reloadable can define reloadable? for fine grained control of reloading
- Class.remove_class uses Module#parent to access the parent module
- Class.remove_class expanded to handle multiple classes in a single call
@@ -1138,7 +1155,7 @@ approximations and shouldn't be used for critical calculations. [Michael Koziars
class Setting
include Reloadable
end
-
+
Reloading a class is done by removing its constant which will cause it to be loaded again on the next reference. [David Heinemeier Hansson]
* Added auto-loading support for classes in modules, so Conductor::Migration will look for conductor/migration.rb and Conductor::Database::Settings will look for conductor/database/settings.rb [Nicholas Seckar]
@@ -1175,7 +1192,7 @@ approximations and shouldn't be used for critical calculations. [Michael Koziars
* Add Symbol#to_proc, which allows for, e.g. [:foo, :bar].map(&:to_s). [Marcel Molina Jr.]
* Added the following methods [Marcel Molina Jr., Sam Stephenson]:
- * Object#copy_instance_variables_from(object) to copy instance variables from one object to another
+ * Object#copy_instance_variables_from(object) to copy instance variables from one object to another
* Object#extended_by to get an instance's included/extended modules
* Object#extend_with_included_modules_from(object) to extend an instance with the modules from another instance
@@ -1226,7 +1243,7 @@ approximations and shouldn't be used for critical calculations. [Michael Koziars
*1.2.0* (October 16th, 2005)
-* Update Exception extension to show the first few framework frames in an application trace. [Nicholas Seckar]
+* Update Exception extension to show the first few framework frames in an application trace. [Nicholas Seckar]
* Added Exception extension to provide support for clean backtraces. [Nicholas Seckar]
@@ -1275,9 +1292,9 @@ approximations and shouldn't be used for critical calculations. [Michael Koziars
Inflector.inflections do |inflect|
inflect.plural /^(ox)$/i, '\1\2en'
inflect.singular /^(ox)en/i, '\1'
-
+
inflect.irregular 'octopus', 'octopi'
-
+
inflect.uncountable "equipment"
end
@@ -1360,9 +1377,9 @@ approximations and shouldn't be used for critical calculations. [Michael Koziars
* Added Object#suppress which allows you to make a saner choice around with exceptions to swallow #980. Example:
suppress(ZeroDivisionError) { 1/0 }
-
+
...instead of:
-
+
1/0 rescue nil # BAD, EVIL, DIRTY.
@@ -1376,7 +1393,7 @@ approximations and shouldn't be used for critical calculations. [Michael Koziars
values << 'baz'
end
end
-
+
foo # => ['bar', 'baz']
diff --git a/activesupport/MIT-LICENSE b/activesupport/MIT-LICENSE
index cd928b856d..5e8b7a9450 100644
--- a/activesupport/MIT-LICENSE
+++ b/activesupport/MIT-LICENSE
@@ -1,4 +1,4 @@
-Copyright (c) 2005-2010 David Heinemeier Hansson
+Copyright (c) 2005-2011 David Heinemeier Hansson
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
diff --git a/activesupport/README.rdoc b/activesupport/README.rdoc
index 77b8a64304..13ca4b3bf1 100644
--- a/activesupport/README.rdoc
+++ b/activesupport/README.rdoc
@@ -14,7 +14,7 @@ The latest version of Active Support can be installed with Rubygems:
Source code can be downloaded as part of the Rails project on GitHub
-* http://github.com/rails/rails/tree/master/activesupport/
+* https://github.com/rails/rails/tree/master/activesupport/
== License
diff --git a/activesupport/Rakefile b/activesupport/Rakefile
index 8e2683ef89..d117ca6356 100644..100755
--- a/activesupport/Rakefile
+++ b/activesupport/Rakefile
@@ -1,7 +1,4 @@
-gem 'rdoc', '>= 2.5.9'
-require 'rdoc'
require 'rake/testtask'
-require 'rdoc/task'
require 'rake/gempackagetask'
task :default => :test
@@ -9,6 +6,7 @@ Rake::TestTask.new do |t|
t.libs << 'test'
t.pattern = 'test/**/*_test.rb'
t.warning = true
+ t.verbose = true
end
namespace :test do
@@ -20,19 +18,6 @@ end
# Create compressed packages
dist_dirs = [ "lib", "test"]
-# Genereate the RDoc documentation
-
-RDoc::Task.new { |rdoc|
- rdoc.rdoc_dir = 'doc'
- rdoc.title = "Active Support -- Utility classes and standard library extensions from Rails"
- rdoc.options << '-f' << 'horo'
- rdoc.options << '--main' << 'README.rdoc'
- rdoc.options << '--charset' << 'utf-8'
- rdoc.rdoc_files.include('README.rdoc', 'CHANGELOG')
- rdoc.rdoc_files.include('lib/active_support.rb')
- rdoc.rdoc_files.include('lib/active_support/**/*.rb')
-}
-
spec = eval(File.read('activesupport.gemspec'))
Rake::GemPackageTask.new(spec) do |p|
diff --git a/activesupport/bin/generate_tables b/activesupport/bin/generate_tables
index 51edb59c77..5fefa429df 100644
--- a/activesupport/bin/generate_tables
+++ b/activesupport/bin/generate_tables
@@ -45,7 +45,7 @@ module ActiveSupport
([0-9]+); # canonical combining class
([A-Z]+); # bidi class
(<([A-Z]*)>)? # decomposition type
- ((\ ?[0-9A-F]+)*); # decompomposition mapping
+ ((\ ?[0-9A-F]+)*); # decomposition mapping
([0-9]*); # decimal digit
([0-9]*); # digit
([^;]*); # numeric
@@ -70,7 +70,7 @@ module ActiveSupport
end
def parse_grapheme_break_property(line)
- if line =~ /^([0-9A-F\.]+)\s*;\s*([\w]+)\s*#/
+ if line =~ /^([0-9A-F.]+)\s*;\s*([\w]+)\s*#/
type = $2.downcase.intern
@ucd.boundary[type] ||= []
if $1.include? '..'
diff --git a/activesupport/lib/active_support.rb b/activesupport/lib/active_support.rb
index ba91e8bba3..6b662ac660 100644
--- a/activesupport/lib/active_support.rb
+++ b/activesupport/lib/active_support.rb
@@ -35,12 +35,14 @@ module ActiveSupport
end
require "active_support/dependencies/autoload"
+require "active_support/version"
module ActiveSupport
extend ActiveSupport::Autoload
autoload :DescendantsTracker
autoload :FileUpdateChecker
+ autoload :FileWatcher
autoload :LogSubscriber
autoload :Notifications
diff --git a/activesupport/lib/active_support/backtrace_cleaner.rb b/activesupport/lib/active_support/backtrace_cleaner.rb
index 8465bc1e10..0e6bc30fa2 100644
--- a/activesupport/lib/active_support/backtrace_cleaner.rb
+++ b/activesupport/lib/active_support/backtrace_cleaner.rb
@@ -8,7 +8,7 @@ module ActiveSupport
# filter or modify the paths of any lines of the backtrace, you can call BacktraceCleaner#remove_filters! These two methods
# will give you a completely untouched backtrace.
#
- # Example:
+ # ==== Example:
#
# bc = BacktraceCleaner.new
# bc.add_filter { |line| line.gsub(Rails.root, '') }
diff --git a/activesupport/lib/active_support/base64.rb b/activesupport/lib/active_support/base64.rb
index b8c01628ce..35014cb3d5 100644
--- a/activesupport/lib/active_support/base64.rb
+++ b/activesupport/lib/active_support/base64.rb
@@ -7,7 +7,7 @@ module ActiveSupport
if defined? ::Base64
Base64 = ::Base64
else
- # Base64 provides utility methods for encoding and de-coding binary data
+ # Base64 provides utility methods for encoding and de-coding binary data
# using a base 64 representation. A base 64 representation of binary data
# consists entirely of printable US-ASCII characters. The Base64 module
# is included in Ruby 1.8, but has been removed in Ruby 1.9.
@@ -15,7 +15,7 @@ module ActiveSupport
# Encodes a string to its base 64 representation. Each 60 characters of
# output is separated by a newline character.
#
- # ActiveSupport::Base64.encode64("Original unencoded string")
+ # ActiveSupport::Base64.encode64("Original unencoded string")
# # => "T3JpZ2luYWwgdW5lbmNvZGVkIHN0cmluZw==\n"
def self.encode64(data)
[data].pack("m")
@@ -23,7 +23,7 @@ module ActiveSupport
# Decodes a base 64 encoded string to its original representation.
#
- # ActiveSupport::Base64.decode64("T3JpZ2luYWwgdW5lbmNvZGVkIHN0cmluZw==")
+ # ActiveSupport::Base64.decode64("T3JpZ2luYWwgdW5lbmNvZGVkIHN0cmluZw==")
# # => "Original unencoded string"
def self.decode64(data)
data.unpack("m").first
diff --git a/activesupport/lib/active_support/benchmarkable.rb b/activesupport/lib/active_support/benchmarkable.rb
index ee02ecb043..df62c18f41 100644
--- a/activesupport/lib/active_support/benchmarkable.rb
+++ b/activesupport/lib/active_support/benchmarkable.rb
@@ -3,10 +3,10 @@ require 'active_support/core_ext/hash/keys'
module ActiveSupport
module Benchmarkable
- # Allows you to measure the execution time of a block
+ # Allows you to measure the execution time of a block
# in a template and records the result to the log. Wrap this block around
# expensive operations or possible bottlenecks to get a time reading
- # for the operation. For example, let's say you thought your file
+ # for the operation. For example, let's say you thought your file
# processing method was taking too long; you could wrap it in a benchmark block.
#
# <% benchmark "Process data files" do %>
@@ -23,7 +23,7 @@ module ActiveSupport
# <%= lowlevel_files_operation %>
# <% end %>
#
- # Finally, you can pass true as the third argument to silence all log activity
+ # Finally, you can pass true as the third argument to silence all log activity
# inside the block. This is great for boiling down a noisy block to just a single statement:
#
# <% benchmark "Process data files", :level => :info, :silence => true do %>
diff --git a/activesupport/lib/active_support/buffered_logger.rb b/activesupport/lib/active_support/buffered_logger.rb
index b861a6f62a..e41731f3e7 100644
--- a/activesupport/lib/active_support/buffered_logger.rb
+++ b/activesupport/lib/active_support/buffered_logger.rb
@@ -1,3 +1,4 @@
+require 'thread'
require 'active_support/core_ext/class/attribute_accessors'
module ActiveSupport
diff --git a/activesupport/lib/active_support/cache.rb b/activesupport/lib/active_support/cache.rb
index 30195bdea5..10c457bb1d 100644
--- a/activesupport/lib/active_support/cache.rb
+++ b/activesupport/lib/active_support/cache.rb
@@ -58,7 +58,14 @@ module ActiveSupport
case store
when Symbol
store_class_name = store.to_s.camelize
- store_class = ActiveSupport::Cache.const_get(store_class_name)
+ store_class =
+ begin
+ require "active_support/cache/#{store}"
+ rescue LoadError => e
+ raise "Could not find cache store adapter for #{store} (#{e})"
+ else
+ ActiveSupport::Cache.const_get(store_class_name)
+ end
store_class.new(*parameters)
when nil
ActiveSupport::Cache::MemoryStore.new
@@ -200,26 +207,26 @@ module ActiveSupport
#
# Setting <tt>:expires_in</tt> will set an expiration time on the cache. All caches
# support auto expiring content after a specified number of seconds. This value can
- # be specified as an option to the construction in which call all entries will be
+ # be specified as an option to the construction in which call all entries will be
# affected. Or it can be supplied to the +fetch+ or +write+ method for just one entry.
#
- # cache = ActiveSupport::Cache::MemoryStore.new(:expire_in => 5.minutes)
- # cache.write(key, value, :expire_in => 1.minute) # Set a lower value for one entry
+ # cache = ActiveSupport::Cache::MemoryStore.new(:expires_in => 5.minutes)
+ # cache.write(key, value, :expires_in => 1.minute) # Set a lower value for one entry
#
# Setting <tt>:race_condition_ttl</tt> is very useful in situations where a cache entry
- # is used very frequently unver heavy load. If a cache expires and due to heavy load
- # seven different processes will try to read data natively and then they all will try to
- # write to cache. To avoid that case the first process to find an expired cache entry will
+ # is used very frequently and is under heavy load. If a cache expires and due to heavy load
+ # seven different processes will try to read data natively and then they all will try to
+ # write to cache. To avoid that case the first process to find an expired cache entry will
# bump the cache expiration time by the value set in <tt>:race_condition_ttl</tt>. Yes
- # this process is extending the time for a stale value by another few seconds. Because
+ # this process is extending the time for a stale value by another few seconds. Because
# of extended life of the previous cache, other processes will continue to use slightly
# stale data for a just a big longer. In the meantime that first process will go ahead
# and will write into cache the new value. After that all the processes will start
# getting new value. The key is to keep <tt>:race_condition_ttl</tt> small.
#
# If the process regenerating the entry errors out, the entry will be regenerated
- # after the specified number of seconds. Also note that the life of stale cache is
- # extended only if it expired recently. Otherwise a new value is generated and
+ # after the specified number of seconds. Also note that the life of stale cache is
+ # extended only if it expired recently. Otherwise a new value is generated and
# <tt>:race_condition_ttl</tt> does not play any role.
#
# # Set all values to expire after one minute.
@@ -410,7 +417,7 @@ module ActiveSupport
raise NotImplementedError.new("#{self.class.name} does not support decrement")
end
- # Cleanup the cache by removing expired entries.
+ # Cleanup the cache by removing expired entries.
#
# Options are passed to the underlying cache implementation.
#
@@ -419,7 +426,7 @@ module ActiveSupport
raise NotImplementedError.new("#{self.class.name} does not support cleanup")
end
- # Clear the entire cache. Be careful with this method since it could
+ # Clear the entire cache. Be careful with this method since it could
# affect other processes if shared cache is being used.
#
# Options are passed to the underlying cache implementation.
@@ -473,23 +480,24 @@ module ActiveSupport
end
end
- # Expand key to be a consistent string value. Invoke +cache_key+ if
- # object responds to +cache_key+. Otherwise, to_param method will be
+ # Expand key to be a consistent string value. Invoke +cache_key+ if
+ # object responds to +cache_key+. Otherwise, to_param method will be
# called. If the key is a Hash, then keys will be sorted alphabetically.
def expanded_key(key) # :nodoc:
- if key.respond_to?(:cache_key)
- key = key.cache_key.to_s
- elsif key.is_a?(Array)
+ return key.cache_key.to_s if key.respond_to?(:cache_key)
+
+ case key
+ when Array
if key.size > 1
- key.collect{|element| expanded_key(element)}.to_param
+ key = key.collect{|element| expanded_key(element)}
else
- key.first.to_param
+ key = key.first
end
- elsif key.is_a?(Hash)
- key = key.to_a.sort{|a,b| a.first.to_s <=> b.first.to_s}.collect{|k,v| "#{k}=#{v}"}.to_param
- else
- key = key.to_param
+ when Hash
+ key = key.sort_by { |k,_| k.to_s }.collect{|k,v| "#{k}=#{v}"}
end
+
+ key.to_param
end
# Prefix a key with the namespace. Namespace and key will be delimited with a colon.
@@ -582,11 +590,7 @@ module ActiveSupport
# Check if the entry is expired. The +expires_in+ parameter can override the
# value set when the entry was created.
def expired?
- if @expires_in && @created_at + @expires_in <= Time.now.to_f
- true
- else
- false
- end
+ @expires_in && @created_at + @expires_in <= Time.now.to_f
end
# Set a new time when the entry will expire.
diff --git a/activesupport/lib/active_support/cache/file_store.rb b/activesupport/lib/active_support/cache/file_store.rb
index 84f6f29572..18182bbb40 100644
--- a/activesupport/lib/active_support/cache/file_store.rb
+++ b/activesupport/lib/active_support/cache/file_store.rb
@@ -1,5 +1,6 @@
require 'active_support/core_ext/file/atomic'
require 'active_support/core_ext/string/conversions'
+require 'rack/utils'
module ActiveSupport
module Cache
@@ -11,8 +12,6 @@ module ActiveSupport
attr_reader :cache_path
DIR_FORMATTER = "%03X"
- ESCAPE_FILENAME_CHARS = /[^a-z0-9_.-]/i
- UNESCAPE_FILENAME_CHARS = /%[0-9A-F]{2}/
def initialize(cache_path, options = nil)
super(options)
@@ -136,7 +135,7 @@ module ActiveSupport
# Translate a key into a file path.
def key_file_path(key)
- fname = key.to_s.gsub(ESCAPE_FILENAME_CHARS){|match| "%#{match.ord.to_s(16).upcase}"}
+ fname = Rack::Utils.escape(key)
hash = Zlib.adler32(fname)
hash, dir_1 = hash.divmod(0x1000)
dir_2 = hash.modulo(0x1000)
@@ -156,7 +155,7 @@ module ActiveSupport
# Translate a file path into a key.
def file_path_key(path)
fname = path[cache_path.size, path.size].split(File::SEPARATOR, 4).last
- fname.gsub(UNESCAPE_FILENAME_CHARS){|match| $1.ord.to_s(16)}
+ Rack::Utils.unescape(fname)
end
# Delete empty directories in the cache.
diff --git a/activesupport/lib/active_support/cache/mem_cache_store.rb b/activesupport/lib/active_support/cache/mem_cache_store.rb
index f32b562368..45263d482f 100644
--- a/activesupport/lib/active_support/cache/mem_cache_store.rb
+++ b/activesupport/lib/active_support/cache/mem_cache_store.rb
@@ -1,7 +1,7 @@
begin
require 'memcache'
rescue LoadError => e
- $stderr.puts "You don't have memcache installed in your application. Please add it to your Gemfile and run bundle install"
+ $stderr.puts "You don't have memcache-client installed in your application. Please add it to your Gemfile and run bundle install"
raise e
end
require 'digest/md5'
@@ -73,7 +73,7 @@ module ActiveSupport
def read_multi(*names)
options = names.extract_options!
options = merged_options(options)
- keys_to_names = names.inject({}){|map, name| map[escape_key(namespaced_key(name, options))] = name; map}
+ keys_to_names = Hash[names.map{|name| [escape_key(namespaced_key(name, options)), name]}]
raw_values = @data.get_multi(keys_to_names.keys, :raw => true)
values = {}
raw_values.each do |key, value|
diff --git a/activesupport/lib/active_support/cache/strategy/local_cache.rb b/activesupport/lib/active_support/cache/strategy/local_cache.rb
index 3edba52fc4..0649a058aa 100644
--- a/activesupport/lib/active_support/cache/strategy/local_cache.rb
+++ b/activesupport/lib/active_support/cache/strategy/local_cache.rb
@@ -16,7 +16,7 @@ module ActiveSupport
@data = {}
end
- # Don't allow synchronizing since it isn't thread safe,
+ # Don't allow synchronizing since it isn't thread safe,
def synchronize # :nodoc:
yield
end
@@ -50,34 +50,39 @@ module ActiveSupport
end
end
- # Middleware class can be inserted as a Rack handler to be local cache for the
- # duration of request.
- def middleware
- @middleware ||= begin
- klass = Class.new
- klass.class_eval(<<-EOS, __FILE__, __LINE__ + 1)
- class << self
- def name
- "ActiveSupport::Cache::Strategy::LocalCache"
- end
- alias :to_s :name
- end
+ #--
+ # This class wraps up local storage for middlewares. Only the middleware method should
+ # construct them.
+ class Middleware # :nodoc:
+ attr_reader :name, :thread_local_key
- def initialize(app)
- @app = app
- end
+ def initialize(name, thread_local_key)
+ @name = name
+ @thread_local_key = thread_local_key
+ @app = nil
+ end
- def call(env)
- Thread.current[:#{thread_local_key}] = LocalStore.new
- @app.call(env)
- ensure
- Thread.current[:#{thread_local_key}] = nil
- end
- EOS
- klass
+ def new(app)
+ @app = app
+ self
+ end
+
+ def call(env)
+ Thread.current[thread_local_key] = LocalStore.new
+ @app.call(env)
+ ensure
+ Thread.current[thread_local_key] = nil
end
end
+ # Middleware class can be inserted as a Rack handler to be local cache for the
+ # duration of request.
+ def middleware
+ @middleware ||= Middleware.new(
+ "ActiveSupport::Cache::Strategy::LocalCache",
+ thread_local_key)
+ end
+
def clear(options = nil) # :nodoc:
local_cache.clear(options) if local_cache
super
diff --git a/activesupport/lib/active_support/callbacks.rb b/activesupport/lib/active_support/callbacks.rb
index 24e407c253..418102352f 100644
--- a/activesupport/lib/active_support/callbacks.rb
+++ b/activesupport/lib/active_support/callbacks.rb
@@ -1,31 +1,33 @@
+require 'active_support/concern'
require 'active_support/descendants_tracker'
require 'active_support/core_ext/array/wrap'
-require 'active_support/core_ext/class/inheritable_attributes'
+require 'active_support/core_ext/class/attribute'
require 'active_support/core_ext/kernel/reporting'
require 'active_support/core_ext/kernel/singleton_class'
module ActiveSupport
- # Callbacks are hooks into the lifecycle of an object that allow you to trigger logic
- # before or after an alteration of the object state.
+ # \Callbacks are code hooks that are run at key points in an object's lifecycle.
+ # The typical use case is to have a base class define a set of callbacks relevant
+ # to the other functionality it supplies, so that subclasses can install callbacks
+ # that enhance or modify the base functionality without needing to override
+ # or redefine methods of the base class.
#
- # Mixing in this module allows you to define callbacks in your class.
+ # Mixing in this module allows you to define the events in the object's lifecycle
+ # that will support callbacks (via +ClassMethods.define_callbacks+), set the instance
+ # methods, procs, or callback objects to be called (via +ClassMethods.set_callback+),
+ # and run the installed callbacks at the appropriate times (via +run_callbacks+).
#
- # Example:
- # class Storage
- # include ActiveSupport::Callbacks
- #
- # define_callbacks :save
- # end
+ # Three kinds of callbacks are supported: before callbacks, run before a certain event;
+ # after callbacks, run after the event; and around callbacks, blocks that surround the
+ # event, triggering it when they yield. Callback code can be contained in instance
+ # methods, procs or lambdas, or callback objects that respond to certain predetermined
+ # methods. See +ClassMethods.set_callback+ for details.
#
- # class ConfigStorage < Storage
- # set_callback :save, :before, :saving_message
- # def saving_message
- # puts "saving..."
- # end
+ # ==== Example
#
- # set_callback :save, :after do |object|
- # puts "saved"
- # end
+ # class Record
+ # include ActiveSupport::Callbacks
+ # define_callbacks :save
#
# def save
# run_callbacks :save do
@@ -34,29 +36,7 @@ module ActiveSupport
# end
# end
#
- # config = ConfigStorage.new
- # config.save
- #
- # Output:
- # saving...
- # - save
- # saved
- #
- # Callbacks from parent classes are inherited.
- #
- # Example:
- # class Storage
- # include ActiveSupport::Callbacks
- #
- # define_callbacks :save
- #
- # set_callback :save, :before, :prepare
- # def prepare
- # puts "preparing save"
- # end
- # end
- #
- # class ConfigStorage < Storage
+ # class PersonRecord < Record
# set_callback :save, :before, :saving_message
# def saving_message
# puts "saving..."
@@ -65,19 +45,12 @@ module ActiveSupport
# set_callback :save, :after do |object|
# puts "saved"
# end
- #
- # def save
- # run_callbacks :save do
- # puts "- save"
- # end
- # end
# end
#
- # config = ConfigStorage.new
- # config.save
+ # person = PersonRecord.new
+ # person.save
#
# Output:
- # preparing save
# saving...
# - save
# saved
@@ -89,11 +62,25 @@ module ActiveSupport
extend ActiveSupport::DescendantsTracker
end
+ # Runs the callbacks for the given event.
+ #
+ # Calls the before and around callbacks in the order they were set, yields
+ # the block (if given one), and then runs the after callbacks in reverse order.
+ # Optionally accepts a key, which will be used to compile an optimized callback
+ # method for each key. See +ClassMethods.define_callbacks+ for more information.
+ #
+ # If the callback chain was halted, returns +false+. Otherwise returns the result
+ # of the block, or +true+ if no block is given.
+ #
+ # run_callbacks :save do
+ # save
+ # end
+ #
def run_callbacks(kind, *args, &block)
send("_run_#{kind}_callbacks", *args, &block)
end
- class Callback
+ class Callback #:nodoc:#
@@_callback_sequence = 0
attr_accessor :chain, :filter, :kind, :options, :per_key, :klass, :raw_filter
@@ -178,49 +165,52 @@ module ActiveSupport
# options[0] is the compiled form of supplied conditions
# options[1] is the "end" for the conditional
#
- if @kind == :before || @kind == :around
- if @kind == :before
- # if condition # before_save :filter_name, :if => :condition
- # filter_name
- # end
- filter = <<-RUBY_EVAL
- unless halted
- result = #{@filter}
- halted = (#{chain.config[:terminator]})
- end
- RUBY_EVAL
-
- [@compiled_options[0], filter, @compiled_options[1]].compact.join("\n")
- else
- # Compile around filters with conditions into proxy methods
- # that contain the conditions.
- #
- # For `around_save :filter_name, :if => :condition':
- #
- # def _conditional_callback_save_17
- # if condition
- # filter_name do
- # yield self
- # end
- # else
- # yield self
- # end
- # end
- #
- name = "_conditional_callback_#{@kind}_#{next_id}"
- @klass.class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
- def #{name}(halted)
- #{@compiled_options[0] || "if true"} && !halted
- #{@filter} do
- yield self
- end
- else
+ case @kind
+ when :before
+ # if condition # before_save :filter_name, :if => :condition
+ # filter_name
+ # end
+ filter = <<-RUBY_EVAL
+ unless halted
+ # This double assignment is to prevent warnings in 1.9.3. I would
+ # remove the `result` variable, but apparently some other
+ # generated code is depending on this variable being set sometimes
+ # and sometimes not.
+ result = result = #{@filter}
+ halted = (#{chain.config[:terminator]})
+ end
+ RUBY_EVAL
+
+ [@compiled_options[0], filter, @compiled_options[1]].compact.join("\n")
+ when :around
+ # Compile around filters with conditions into proxy methods
+ # that contain the conditions.
+ #
+ # For `around_save :filter_name, :if => :condition':
+ #
+ # def _conditional_callback_save_17
+ # if condition
+ # filter_name do
+ # yield self
+ # end
+ # else
+ # yield self
+ # end
+ # end
+ #
+ name = "_conditional_callback_#{@kind}_#{next_id}"
+ @klass.class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
+ def #{name}(halted)
+ #{@compiled_options[0] || "if true"} && !halted
+ #{@filter} do
yield self
end
+ else
+ yield self
end
- RUBY_EVAL
- "#{name}(halted) do"
- end
+ end
+ RUBY_EVAL
+ "#{name}(halted) do"
end
end
@@ -229,15 +219,17 @@ module ActiveSupport
def end(key=nil, object=nil)
return if key && !object.send("_one_time_conditions_valid_#{@callback_id}?")
- if @kind == :around || @kind == :after
+ case @kind
+ when :after
# if condition # after_save :filter_name, :if => :condition
# filter_name
# end
- if @kind == :after
- [@compiled_options[0], @filter, @compiled_options[1]].compact.join("\n")
- else
- "end"
+ [@compiled_options[0], @filter, @compiled_options[1]].compact.join("\n")
+ when :around
+ <<-RUBY_EVAL
+ value
end
+ RUBY_EVAL
end
end
@@ -330,7 +322,7 @@ module ActiveSupport
end
# An Array with a compile method
- class CallbackChain < Array
+ class CallbackChain < Array #:nodoc:#
attr_reader :name, :config
def initialize(name, config)
@@ -375,20 +367,9 @@ module ActiveSupport
end
module ClassMethods
- # Make the run_callbacks :save method. The generated method takes
- # a block that it'll yield to. It'll call the before and around filters
- # in order, yield the block, and then run the after filters.
- #
- # run_callbacks :save do
- # save
- # end
- #
- # The run_callbacks :save method can optionally take a key, which
- # will be used to compile an optimized callback method for each
- # key. See #define_callbacks for more information.
- #
+ # Generate the internal runner method called by +run_callbacks+.
def __define_runner(symbol) #:nodoc:
- body = send("_#{symbol}_callbacks").compile(nil)
+ body = send("_#{symbol}_callbacks").compile
silence_warnings do
undef_method "_run_#{symbol}_callbacks" if method_defined?("_run_#{symbol}_callbacks")
@@ -435,21 +416,52 @@ module ActiveSupport
options = filters.last.is_a?(Hash) ? filters.pop : {}
filters.unshift(block) if block
- ([self] + ActiveSupport::DescendantsTracker.descendants(self)).each do |target|
+ ([self] + ActiveSupport::DescendantsTracker.descendants(self)).reverse.each do |target|
chain = target.send("_#{name}_callbacks")
- yield chain, type, filters, options
+ yield target, chain.dup, type, filters, options
target.__define_runner(name)
end
end
- # Set callbacks for a previously defined callback.
+ # Install a callback for the given event.
#
- # Syntax:
# set_callback :save, :before, :before_meth
# set_callback :save, :after, :after_meth, :if => :condition
- # set_callback :save, :around, lambda { |r| stuff; yield; stuff }
+ # set_callback :save, :around, lambda { |r| stuff; result = yield; stuff }
+ #
+ # The second arguments indicates whether the callback is to be run +:before+,
+ # +:after+, or +:around+ the event. If omitted, +:before+ is assumed. This
+ # means the first example above can also be written as:
+ #
+ # set_callback :save, :before_meth
+ #
+ # The callback can specified as a symbol naming an instance method; as a proc,
+ # lambda, or block; as a string to be instance evaluated; or as an object that
+ # responds to a certain method determined by the <tt>:scope</tt> argument to
+ # +define_callback+.
#
- # Use skip_callback to skip any defined one.
+ # If a proc, lambda, or block is given, its body is evaluated in the context
+ # of the current object. It can also optionally accept the current object as
+ # an argument.
+ #
+ # Before and around callbacks are called in the order that they are set; after
+ # callbacks are called in the reverse order.
+ #
+ # Around callbacks can access the return value from the event, if it
+ # wasn't halted, from the +yield+ call.
+ #
+ # ===== Options
+ #
+ # * <tt>:if</tt> - A symbol naming an instance method or a proc; the callback
+ # will be called only when it returns a true value.
+ # * <tt>:unless</tt> - A symbol naming an instance method or a proc; the callback
+ # will be called only when it returns a false value.
+ # * <tt>:prepend</tt> - If true, the callback will be prepended to the existing
+ # chain rather than appended.
+ # * <tt>:per_key</tt> - A hash with <tt>:if</tt> and <tt>:unless</tt> options;
+ # see "Per-key conditions" below.
+ #
+ # ===== Per-key conditions
#
# When creating or skipping callbacks, you can specify conditions that
# are always the same for a given key. For instance, in Action Pack,
@@ -459,12 +471,12 @@ module ActiveSupport
#
# becomes
#
- # dispatch_callback :before, :authenticate, :per_key => {:unless => proc {|c| c.action_name == "index"}}
+ # set_callback :process_action, :before, :authenticate, :per_key => {:unless => proc {|c| c.action_name == "index"}}
#
- # Per-Key conditions are evaluated only once per use of a given key.
+ # Per-key conditions are evaluated only once per use of a given key.
# In the case of the above example, you would do:
#
- # run_callbacks(:dispatch, action_name) { ... dispatch stuff ... }
+ # run_callbacks(:process_action, action_name) { ... dispatch stuff ... }
#
# In that case, each action_name would get its own compiled callback
# method that took into consideration the per_key conditions. This
@@ -473,27 +485,30 @@ module ActiveSupport
def set_callback(name, *filter_list, &block)
mapped = nil
- __update_callbacks(name, filter_list, block) do |chain, type, filters, options|
+ __update_callbacks(name, filter_list, block) do |target, chain, type, filters, options|
mapped ||= filters.map do |filter|
Callback.new(chain, filter, type, options.dup, self)
end
filters.each do |filter|
- chain.delete_if {|c| c.matches?(type, filter) }
+ chain.delete_if {|c| c.matches?(type, filter) }
end
- options[:prepend] ? chain.unshift(*mapped) : chain.push(*mapped)
+ options[:prepend] ? chain.unshift(*(mapped.reverse)) : chain.push(*mapped)
+
+ target.send("_#{name}_callbacks=", chain)
end
end
- # Skip a previously defined callback.
+ # Skip a previously set callback. Like +set_callback+, <tt>:if</tt> or <tt>:unless</tt>
+ # options may be passed in order to control when the callback is skipped.
#
# class Writer < Person
# skip_callback :validate, :before, :check_membership, :if => lambda { self.age > 18 }
# end
#
def skip_callback(name, *filter_list, &block)
- __update_callbacks(name, filter_list, block) do |chain, type, filters, options|
+ __update_callbacks(name, filter_list, block) do |target, chain, type, filters, options|
filters.each do |filter|
filter = chain.find {|c| c.matches?(type, filter) }
@@ -505,93 +520,98 @@ module ActiveSupport
chain.delete(filter)
end
+ target.send("_#{name}_callbacks=", chain)
end
end
- # Reset callbacks for a given type.
+ # Remove all set callbacks for the given event.
#
def reset_callbacks(symbol)
callbacks = send("_#{symbol}_callbacks")
ActiveSupport::DescendantsTracker.descendants(self).each do |target|
- chain = target.send("_#{symbol}_callbacks")
+ chain = target.send("_#{symbol}_callbacks").dup
callbacks.each { |c| chain.delete(c) }
+ target.send("_#{symbol}_callbacks=", chain)
target.__define_runner(symbol)
end
- callbacks.clear
+ self.send("_#{symbol}_callbacks=", callbacks.dup.clear)
+
__define_runner(symbol)
end
- # Defines callbacks types:
+ # Define sets of events in the object lifecycle that support callbacks.
#
# define_callbacks :validate
+ # define_callbacks :initialize, :save, :destroy
#
- # This macro accepts the following options:
+ # ===== Options
#
- # * <tt>:terminator</tt> - Indicates when a before filter is considered
- # to halted. This is a string to be eval'ed and has the result of the
- # very filter available in the <tt>result</tt> variable:
+ # * <tt>:terminator</tt> - Determines when a before filter will halt the callback
+ # chain, preventing following callbacks from being called and the event from being
+ # triggered. This is a string to be eval'ed. The result of the callback is available
+ # in the <tt>result</tt> variable.
#
- # define_callbacks :validate, :terminator => "result == false"
+ # define_callbacks :validate, :terminator => "result == false"
#
- # In the example above, if any before validate callbacks returns +false+,
- # other callbacks are not executed. Defaults to "false", meaning no value
- # halts the chain.
+ # In this example, if any before validate callbacks returns +false+,
+ # other callbacks are not executed. Defaults to "false", meaning no value
+ # halts the chain.
#
# * <tt>:rescuable</tt> - By default, after filters are not executed if
- # the given block or a before filter raises an error. Set this option to
- # true to change this behavior.
+ # the given block or a before filter raises an error. By setting this option
+ # to <tt>true</tt> exception raised by given block is stored and after
+ # executing all the after callbacks the stored exception is raised.
#
- # * <tt>:scope</tt> - Indicates which methods should be executed when a class
- # is given as callback. Defaults to <tt>[:kind]</tt>.
+ # * <tt>:scope</tt> - Indicates which methods should be executed when an object
+ # is used as a callback.
#
- # class Audit
- # def before(caller)
- # puts 'Audit: before is called'
- # end
+ # class Audit
+ # def before(caller)
+ # puts 'Audit: before is called'
+ # end
#
- # def before_save(caller)
- # puts 'Audit: before_save is called'
- # end
- # end
+ # def before_save(caller)
+ # puts 'Audit: before_save is called'
+ # end
+ # end
#
- # class Account
- # include ActiveSupport::Callbacks
+ # class Account
+ # include ActiveSupport::Callbacks
#
- # define_callbacks :save
- # set_callback :save, :before, Audit.new
+ # define_callbacks :save
+ # set_callback :save, :before, Audit.new
#
- # def save
- # run_callbacks :save do
- # puts 'save in main'
- # end
- # end
- # end
+ # def save
+ # run_callbacks :save do
+ # puts 'save in main'
+ # end
+ # end
+ # end
#
- # In the above case whenever you save an account the method <tt>Audit#before</tt> will
- # be called. On the other hand
+ # In the above case whenever you save an account the method <tt>Audit#before</tt> will
+ # be called. On the other hand
#
- # define_callbacks :save, :scope => [:kind, :name]
+ # define_callbacks :save, :scope => [:kind, :name]
#
- # would trigger <tt>Audit#before_save</tt> instead. That's constructed by calling
- # <tt>"#{kind}_#{name}"</tt> on the given instance. In this case "kind" is "before" and
- # "name" is "save". In this context ":kind" and ":name" have special meanings: ":kind"
- # refers to the kind of callback (before/after/around) and ":name" refers to the
- # method on which callbacks are being defined.
+ # would trigger <tt>Audit#before_save</tt> instead. That's constructed by calling
+ # <tt>#{kind}_#{name}</tt> on the given instance. In this case "kind" is "before" and
+ # "name" is "save". In this context +:kind+ and +:name+ have special meanings: +:kind+
+ # refers to the kind of callback (before/after/around) and +:name+ refers to the
+ # method on which callbacks are being defined.
#
- # A declaration like
+ # A declaration like
#
- # define_callbacks :save, :scope => [:name]
+ # define_callbacks :save, :scope => [:name]
#
- # would call <tt>Audit#save</tt>.
+ # would call <tt>Audit#save</tt>.
#
def define_callbacks(*callbacks)
config = callbacks.last.is_a?(Hash) ? callbacks.pop : {}
callbacks.each do |callback|
- extlib_inheritable_reader("_#{callback}_callbacks") do
- CallbackChain.new(callback, config)
- end
+ class_attribute "_#{callback}_callbacks"
+ send("_#{callback}_callbacks=", CallbackChain.new(callback, config))
__define_runner(callback)
end
end
diff --git a/activesupport/lib/active_support/concern.rb b/activesupport/lib/active_support/concern.rb
index 2d87e8d0e5..81fb859334 100644
--- a/activesupport/lib/active_support/concern.rb
+++ b/activesupport/lib/active_support/concern.rb
@@ -1,39 +1,109 @@
-# A typical module looks like this
-#
-# module M
-# def self.included(base)
-# base.send(:extend, ClassMethods)
-# base.send(:include, InstanceMethods)
-# scope :foo, :conditions => { :created_at => nil }
-# end
-#
-# module ClassMethods
-# def cm; puts 'I am a class method'; end
-# end
-#
-# module InstanceMethods
-# def im; puts 'I am an instance method'; end
-# end
-# end
-#
-# By using <tt>ActiveSupport::Concern</tt> the above module could instead be written as:
-#
-# module M
-# extend ActiveSupport::Concern
-#
-# included do
-# scope :foo, :conditions => { :created_at => nil }
-# end
-#
-# module ClassMethods
-# def cm; puts 'I am a class method'; end
-# end
-#
-# module InstanceMethods
-# def im; puts 'I am an instance method'; end
-# end
-# end
module ActiveSupport
+ # A typical module looks like this:
+ #
+ # module M
+ # def self.included(base)
+ # base.extend ClassMethods
+ # base.send(:include, InstanceMethods)
+ # scope :disabled, where(:disabled => true)
+ # end
+ #
+ # module ClassMethods
+ # ...
+ # end
+ #
+ # module InstanceMethods
+ # ...
+ # end
+ # end
+ #
+ # By using <tt>ActiveSupport::Concern</tt> the above module could instead be written as:
+ #
+ # require 'active_support/concern'
+ #
+ # module M
+ # extend ActiveSupport::Concern
+ #
+ # included do
+ # scope :disabled, where(:disabled => true)
+ # end
+ #
+ # module ClassMethods
+ # ...
+ # end
+ #
+ # module InstanceMethods
+ # ...
+ # end
+ # end
+ #
+ # Moreover, it gracefully handles module dependencies. Given a +Foo+ module and a +Bar+
+ # module which depends on the former, we would typically write the following:
+ #
+ # module Foo
+ # def self.included(base)
+ # base.class_eval do
+ # def self.method_injected_by_foo
+ # ...
+ # end
+ # end
+ # end
+ # end
+ #
+ # module Bar
+ # def self.included(base)
+ # base.method_injected_by_foo
+ # end
+ # end
+ #
+ # class Host
+ # include Foo # We need to include this dependency for Bar
+ # include Bar # Bar is the module that Host really needs
+ # end
+ #
+ # But why should +Host+ care about +Bar+'s dependencies, namely +Foo+? We could try to hide
+ # these from +Host+ directly including +Foo+ in +Bar+:
+ #
+ # module Bar
+ # include Foo
+ # def self.included(base)
+ # base.method_injected_by_foo
+ # end
+ # end
+ #
+ # class Host
+ # include Bar
+ # end
+ #
+ # Unfortunately this won't work, since when +Foo+ is included, its <tt>base</tt> is the +Bar+ module,
+ # not the +Host+ class. With <tt>ActiveSupport::Concern</tt>, module dependencies are properly resolved:
+ #
+ # require 'active_support/concern'
+ #
+ # module Foo
+ # extend ActiveSupport::Concern
+ # included do
+ # class_eval do
+ # def self.method_injected_by_foo
+ # ...
+ # end
+ # end
+ # end
+ # end
+ #
+ # module Bar
+ # extend ActiveSupport::Concern
+ # include Foo
+ #
+ # included do
+ # self.method_injected_by_foo
+ # end
+ # end
+ #
+ # class Host
+ # include Bar # works, Bar takes care now of its dependencies
+ # end
+ #
module Concern
def self.extended(base)
base.instance_variable_set("@_dependencies", [])
diff --git a/activesupport/lib/active_support/configurable.rb b/activesupport/lib/active_support/configurable.rb
index f562e17c75..8c56a21ef7 100644
--- a/activesupport/lib/active_support/configurable.rb
+++ b/activesupport/lib/active_support/configurable.rb
@@ -4,18 +4,52 @@ require 'active_support/core_ext/kernel/singleton_class'
require 'active_support/core_ext/module/delegation'
module ActiveSupport
+ # Configurable provides a <tt>config</tt> method to store and retrieve
+ # configuration options as an <tt>OrderedHash</tt>.
module Configurable
extend ActiveSupport::Concern
+ class Configuration < ActiveSupport::InheritableOptions
+ def compile_methods!
+ self.class.compile_methods!(keys.reject {|key| respond_to?(key)})
+ end
+
+ # compiles reader methods so we don't have to go through method_missing
+ def self.compile_methods!(keys)
+ keys.each do |key|
+ class_eval <<-RUBY, __FILE__, __LINE__ + 1
+ def #{key}; _get(#{key.inspect}); end
+ RUBY
+ end
+ end
+ end
+
module ClassMethods
def config
- @config ||= ActiveSupport::InheritableOptions.new(superclass.respond_to?(:config) ? superclass.config : {})
+ @_config ||= if respond_to?(:superclass) && superclass.respond_to?(:config)
+ superclass.config.inheritable_copy
+ else
+ # create a new "anonymous" class that will host the compiled reader methods
+ Class.new(Configuration).new
+ end
end
def configure
yield config
end
+ # Allows you to add shortcut so that you don't have to refer to attribute through config.
+ # Also look at the example for config to contrast.
+ #
+ # class User
+ # include ActiveSupport::Configurable
+ # config_accessor :allowed_access
+ # end
+ #
+ # user = User.new
+ # user.allowed_access = true
+ # user.allowed_access # => true
+ #
def config_accessor(*names)
names.each do |name|
code, line = <<-RUBY, __LINE__ + 1
@@ -29,8 +63,25 @@ module ActiveSupport
end
end
+ # Reads and writes attributes from a configuration <tt>OrderedHash</tt>.
+ #
+ # require 'active_support/configurable'
+ #
+ # class User
+ # include ActiveSupport::Configurable
+ # end
+ #
+ # user = User.new
+ #
+ # user.config.allowed_access = true
+ # user.config.level = 1
+ #
+ # user.config.allowed_access # => true
+ # user.config.level # => 1
+ #
def config
- @config ||= ActiveSupport::InheritableOptions.new(self.class.config)
+ @_config ||= self.class.config.inheritable_copy
end
end
-end \ No newline at end of file
+end
+
diff --git a/activesupport/lib/active_support/core_ext/array/conversions.rb b/activesupport/lib/active_support/core_ext/array/conversions.rb
index 7585137aca..baefa9cae4 100644
--- a/activesupport/lib/active_support/core_ext/array/conversions.rb
+++ b/activesupport/lib/active_support/core_ext/array/conversions.rb
@@ -26,7 +26,7 @@ class Array
when 0
""
when 1
- self[0].to_s
+ self[0].to_s.dup
when 2
"#{self[0]}#{options[:two_words_connector]}#{self[1]}"
else
diff --git a/activesupport/lib/active_support/core_ext/array/random_access.rb b/activesupport/lib/active_support/core_ext/array/random_access.rb
index edac7278bc..ab1fa7cd5b 100644
--- a/activesupport/lib/active_support/core_ext/array/random_access.rb
+++ b/activesupport/lib/active_support/core_ext/array/random_access.rb
@@ -1,10 +1,10 @@
class Array
- # Backport of Array#sample based on Marc-Andre Lafortune's http://github.com/marcandre/backports/
- # Returns a random element or +n+ random elements from the array.
+ # Backport of Array#sample based on Marc-Andre Lafortune's https://github.com/marcandre/backports/
+ # Returns a random element or +n+ random elements from the array.
# If the array is empty and +n+ is nil, returns <tt>nil</tt>. if +n+ is passed, returns <tt>[]</tt>.
- #
- # [1,2,3,4,5,6].sample # => 4
- # [1,2,3,4,5,6].sample(3) # => [2, 4, 5]
+ #
+ # [1,2,3,4,5,6].sample # => 4
+ # [1,2,3,4,5,6].sample(3) # => [2, 4, 5]
# [].sample # => nil
# [].sample(3) # => []
def sample(n=nil)
@@ -24,4 +24,4 @@ class Array
result[n..size] = []
result
end unless method_defined? :sample
-end \ No newline at end of file
+end
diff --git a/activesupport/lib/active_support/core_ext/array/wrap.rb b/activesupport/lib/active_support/core_ext/array/wrap.rb
index 06b2acd662..7fabae3138 100644
--- a/activesupport/lib/active_support/core_ext/array/wrap.rb
+++ b/activesupport/lib/active_support/core_ext/array/wrap.rb
@@ -10,7 +10,7 @@ class Array
# Array.wrap(nil) # => []
# Array.wrap([1, 2, 3]) # => [1, 2, 3]
# Array.wrap(0) # => [0]
- #
+ #
# This method is similar in purpose to <tt>Kernel#Array</tt>, but there are some differences:
#
# * If the argument responds to +to_ary+ the method is invoked. <tt>Kernel#Array</tt>
diff --git a/activesupport/lib/active_support/core_ext/big_decimal/conversions.rb b/activesupport/lib/active_support/core_ext/big_decimal/conversions.rb
index f7f03f4d95..080604147d 100644
--- a/activesupport/lib/active_support/core_ext/big_decimal/conversions.rb
+++ b/activesupport/lib/active_support/core_ext/big_decimal/conversions.rb
@@ -1,23 +1,38 @@
require 'bigdecimal'
+
+begin
+ require 'psych'
+rescue LoadError
+end
+
require 'yaml'
class BigDecimal
YAML_TAG = 'tag:yaml.org,2002:float'
YAML_MAPPING = { 'Infinity' => '.Inf', '-Infinity' => '-.Inf', 'NaN' => '.NaN' }
- yaml_as YAML_TAG
-
# This emits the number without any scientific notation.
# This is better than self.to_f.to_s since it doesn't lose precision.
#
# Note that reconstituting YAML floats to native floats may lose precision.
def to_yaml(opts = {})
+ return super if defined?(YAML::ENGINE) && !YAML::ENGINE.syck?
+
YAML.quick_emit(nil, opts) do |out|
string = to_s
out.scalar(YAML_TAG, YAML_MAPPING[string] || string, :plain)
end
end
+ def encode_with(coder)
+ string = to_s
+ coder.represent_scalar(nil, YAML_MAPPING[string] || string)
+ end
+
+ def to_d
+ self
+ end
+
DEFAULT_STRING_FORMAT = 'F'
def to_formatted_s(format = DEFAULT_STRING_FORMAT)
_original_to_s(format)
diff --git a/activesupport/lib/active_support/core_ext/cgi.rb b/activesupport/lib/active_support/core_ext/cgi.rb
deleted file mode 100644
index 7279a3d4da..0000000000
--- a/activesupport/lib/active_support/core_ext/cgi.rb
+++ /dev/null
@@ -1 +0,0 @@
-require 'active_support/core_ext/cgi/escape_skipping_slashes'
diff --git a/activesupport/lib/active_support/core_ext/cgi/escape_skipping_slashes.rb b/activesupport/lib/active_support/core_ext/cgi/escape_skipping_slashes.rb
deleted file mode 100644
index d3c3575748..0000000000
--- a/activesupport/lib/active_support/core_ext/cgi/escape_skipping_slashes.rb
+++ /dev/null
@@ -1,19 +0,0 @@
-require 'cgi'
-
-class CGI #:nodoc:
- if RUBY_VERSION >= '1.9'
- def self.escape_skipping_slashes(str)
- str = str.join('/') if str.respond_to? :join
- str.gsub(/([^ \/a-zA-Z0-9_.-])/n) do
- "%#{$1.unpack('H2' * $1.bytesize).join('%').upcase}"
- end.tr(' ', '+')
- end
- else
- def self.escape_skipping_slashes(str)
- str = str.join('/') if str.respond_to? :join
- str.gsub(/([^ \/a-zA-Z0-9_.-])/n) do
- "%#{$1.unpack('H2').first.upcase}"
- end.tr(' ', '+')
- end
- end
-end
diff --git a/activesupport/lib/active_support/core_ext/class/attribute.rb b/activesupport/lib/active_support/core_ext/class/attribute.rb
index bfa57fe1f7..5414b3a18f 100644
--- a/activesupport/lib/active_support/core_ext/class/attribute.rb
+++ b/activesupport/lib/active_support/core_ext/class/attribute.rb
@@ -29,19 +29,19 @@ class Class
# In such cases, you don't want to do changes in places but use setters:
#
# Base.setting = []
- # Base.setting #=> []
- # Subclass.setting #=> []
+ # Base.setting # => []
+ # Subclass.setting # => []
#
# # Appending in child changes both parent and child because it is the same object:
# Subclass.setting << :foo
- # Base.setting #=> [:foo]
- # Subclass.setting #=> [:foo]
+ # Base.setting # => [:foo]
+ # Subclass.setting # => [:foo]
#
# # Use setters to not propagate changes:
# Base.setting = []
# Subclass.setting += [:foo]
- # Base.setting #=> []
- # Subclass.setting #=> [:foo]
+ # Base.setting # => []
+ # Subclass.setting # => [:foo]
#
# For convenience, a query method is defined as well:
#
@@ -72,10 +72,21 @@ class Class
remove_possible_method(:#{name})
define_method(:#{name}) { val }
end
+
+ if singleton_class?
+ class_eval do
+ remove_possible_method(:#{name})
+ def #{name}
+ defined?(@#{name}) ? @#{name} : singleton_class.#{name}
+ end
+ end
+ end
+ val
end
+ remove_method :#{name} if method_defined?(:#{name})
def #{name}
- defined?(@#{name}) ? @#{name} : singleton_class.#{name}
+ defined?(@#{name}) ? @#{name} : self.class.#{name}
end
def #{name}?
@@ -86,4 +97,15 @@ class Class
attr_writer name if instance_writer
end
end
+
+ private
+ def singleton_class?
+ # in case somebody is crazy enough to overwrite allocate
+ allocate = Class.instance_method(:allocate)
+ # object.class always points to a real (non-singleton) class
+ allocate.bind(self).call.class != self
+ rescue TypeError
+ # MRI/YARV/JRuby all disallow creating new instances of a singleton class
+ true
+ end
end
diff --git a/activesupport/lib/active_support/core_ext/class/attribute_accessors.rb b/activesupport/lib/active_support/core_ext/class/attribute_accessors.rb
index 4e35b1b488..a903735acf 100644
--- a/activesupport/lib/active_support/core_ext/class/attribute_accessors.rb
+++ b/activesupport/lib/active_support/core_ext/class/attribute_accessors.rb
@@ -12,8 +12,8 @@ require 'active_support/core_ext/array/extract_options'
# end
#
# Person.hair_colors = [:brown, :black, :blonde, :red]
-# Person.hair_colors #=> [:brown, :black, :blonde, :red]
-# Person.new.hair_colors #=> [:brown, :black, :blonde, :red]
+# Person.hair_colors # => [:brown, :black, :blonde, :red]
+# Person.new.hair_colors # => [:brown, :black, :blonde, :red]
#
# To opt out of the instance writer method, pass :instance_writer => false.
# To opt out of the instance reader method, pass :instance_reader => false.
diff --git a/activesupport/lib/active_support/core_ext/class/inheritable_attributes.rb b/activesupport/lib/active_support/core_ext/class/inheritable_attributes.rb
index e844cf50d1..ca3db2349e 100644
--- a/activesupport/lib/active_support/core_ext/class/inheritable_attributes.rb
+++ b/activesupport/lib/active_support/core_ext/class/inheritable_attributes.rb
@@ -1,13 +1,15 @@
require 'active_support/core_ext/object/duplicable'
require 'active_support/core_ext/array/extract_options'
+require 'active_support/deprecation'
# Retained for backward compatibility. Methods are now included in Class.
module ClassInheritableAttributes # :nodoc:
+ DEPRECATION_WARNING_MESSAGE = "class_inheritable_attribute is deprecated, please use class_attribute method instead. Notice their behavior are slightly different, so refer to class_attribute documentation first"
end
-# It is recommend to use <tt>class_attribute</tt> over methods defined in this file. Please
+# It is recommended to use <tt>class_attribute</tt> over methods defined in this file. Please
# refer to documentation for <tt>class_attribute</tt> for more information. Officially it is not
-# deprected but <tt>class_attribute</tt> is faster.
+# deprecated but <tt>class_attribute</tt> is faster.
#
# Allows attributes to be shared within an inheritance hierarchy. Each descendant gets a copy of
# their parents' attributes, instead of just a pointer to the same. This means that the child can add elements
@@ -22,8 +24,8 @@ end
# end
#
# Person.hair_colors = [:brown, :black, :blonde, :red]
-# Person.hair_colors #=> [:brown, :black, :blonde, :red]
-# Person.new.hair_colors #=> [:brown, :black, :blonde, :red]
+# Person.hair_colors # => [:brown, :black, :blonde, :red]
+# Person.new.hair_colors # => [:brown, :black, :blonde, :red]
#
# To opt out of the instance writer method, pass :instance_writer => false.
# To opt out of the instance reader method, pass :instance_reader => false.
@@ -36,6 +38,7 @@ end
# Person.new.hair_colors # => NoMethodError
class Class # :nodoc:
def class_inheritable_reader(*syms)
+ ActiveSupport::Deprecation.warn ClassInheritableAttributes::DEPRECATION_WARNING_MESSAGE
options = syms.extract_options!
syms.each do |sym|
next if sym.is_a?(Hash)
@@ -54,6 +57,7 @@ class Class # :nodoc:
end
def class_inheritable_writer(*syms)
+ ActiveSupport::Deprecation.warn ClassInheritableAttributes::DEPRECATION_WARNING_MESSAGE
options = syms.extract_options!
syms.each do |sym|
class_eval(<<-EOS, __FILE__, __LINE__ + 1)
@@ -71,6 +75,7 @@ class Class # :nodoc:
end
def class_inheritable_array_writer(*syms)
+ ActiveSupport::Deprecation.warn ClassInheritableAttributes::DEPRECATION_WARNING_MESSAGE
options = syms.extract_options!
syms.each do |sym|
class_eval(<<-EOS, __FILE__, __LINE__ + 1)
@@ -88,6 +93,7 @@ class Class # :nodoc:
end
def class_inheritable_hash_writer(*syms)
+ ActiveSupport::Deprecation.warn ClassInheritableAttributes::DEPRECATION_WARNING_MESSAGE
options = syms.extract_options!
syms.each do |sym|
class_eval(<<-EOS, __FILE__, __LINE__ + 1)
@@ -124,6 +130,7 @@ class Class # :nodoc:
end
def write_inheritable_attribute(key, value)
+ ActiveSupport::Deprecation.warn ClassInheritableAttributes::DEPRECATION_WARNING_MESSAGE
if inheritable_attributes.equal?(EMPTY_INHERITABLE_ATTRIBUTES)
@inheritable_attributes = {}
end
@@ -141,10 +148,12 @@ class Class # :nodoc:
end
def read_inheritable_attribute(key)
+ ActiveSupport::Deprecation.warn ClassInheritableAttributes::DEPRECATION_WARNING_MESSAGE
inheritable_attributes[key]
end
def reset_inheritable_attributes
+ ActiveSupport::Deprecation.warn ClassInheritableAttributes::DEPRECATION_WARNING_MESSAGE
@inheritable_attributes = EMPTY_INHERITABLE_ATTRIBUTES
end
@@ -158,9 +167,9 @@ class Class # :nodoc:
if inheritable_attributes.equal?(EMPTY_INHERITABLE_ATTRIBUTES)
new_inheritable_attributes = EMPTY_INHERITABLE_ATTRIBUTES
else
- new_inheritable_attributes = inheritable_attributes.inject({}) do |memo, (key, value)|
- memo.update(key => value.duplicable? ? value.dup : value)
- end
+ new_inheritable_attributes = Hash[inheritable_attributes.map do |(key, value)|
+ [key, value.duplicable? ? value.dup : value]
+ end]
end
child.instance_variable_set('@inheritable_attributes', new_inheritable_attributes)
@@ -169,86 +178,3 @@ class Class # :nodoc:
alias inherited_without_inheritable_attributes inherited
alias inherited inherited_with_inheritable_attributes
end
-
-class Class
- # Defines class-level inheritable attribute reader. Attributes are available to subclasses,
- # each subclass has a copy of parent's attribute.
- #
- # @param *syms<Array[#to_s]> Array of attributes to define inheritable reader for.
- # @return <Array[#to_s]> Array of attributes converted into inheritable_readers.
- #
- # @api public
- #
- # @todo Do we want to block instance_reader via :instance_reader => false
- # @todo It would be preferable that we do something with a Hash passed in
- # (error out or do the same as other methods above) instead of silently
- # moving on). In particular, this makes the return value of this function
- # less useful.
- def extlib_inheritable_reader(*ivars, &block)
- options = ivars.extract_options!
-
- ivars.each do |ivar|
- self.class_eval <<-RUBY, __FILE__, __LINE__ + 1
- def self.#{ivar}
- return @#{ivar} if self.object_id == #{self.object_id} || defined?(@#{ivar})
- ivar = superclass.#{ivar}
- return nil if ivar.nil? && !#{self}.instance_variable_defined?("@#{ivar}")
- @#{ivar} = ivar.duplicable? ? ivar.dup : ivar
- end
- RUBY
- unless options[:instance_reader] == false
- self.class_eval <<-RUBY, __FILE__, __LINE__ + 1
- def #{ivar}
- self.class.#{ivar}
- end
- RUBY
- end
- instance_variable_set(:"@#{ivar}", yield) if block_given?
- end
- end
-
- # Defines class-level inheritable attribute writer. Attributes are available to subclasses,
- # each subclass has a copy of parent's attribute.
- #
- # @param *syms<Array[*#to_s, Hash{:instance_writer => Boolean}]> Array of attributes to
- # define inheritable writer for.
- # @option syms :instance_writer<Boolean> if true, instance-level inheritable attribute writer is defined.
- # @return <Array[#to_s]> An Array of the attributes that were made into inheritable writers.
- #
- # @api public
- #
- # @todo We need a style for class_eval <<-HEREDOC. I'd like to make it
- # class_eval(<<-RUBY, __FILE__, __LINE__), but we should codify it somewhere.
- def extlib_inheritable_writer(*ivars)
- options = ivars.extract_options!
-
- ivars.each do |ivar|
- self.class_eval <<-RUBY, __FILE__, __LINE__ + 1
- def self.#{ivar}=(obj)
- @#{ivar} = obj
- end
- RUBY
- unless options[:instance_writer] == false
- self.class_eval <<-RUBY, __FILE__, __LINE__ + 1
- def #{ivar}=(obj) self.class.#{ivar} = obj end
- RUBY
- end
-
- self.send("#{ivar}=", yield) if block_given?
- end
- end
-
- # Defines class-level inheritable attribute accessor. Attributes are available to subclasses,
- # each subclass has a copy of parent's attribute.
- #
- # @param *syms<Array[*#to_s, Hash{:instance_writer => Boolean}]> Array of attributes to
- # define inheritable accessor for.
- # @option syms :instance_writer<Boolean> if true, instance-level inheritable attribute writer is defined.
- # @return <Array[#to_s]> An Array of attributes turned into inheritable accessors.
- #
- # @api public
- def extlib_inheritable_accessor(*syms, &block)
- extlib_inheritable_reader(*syms)
- extlib_inheritable_writer(*syms, &block)
- end
-end
diff --git a/activesupport/lib/active_support/core_ext/class/subclasses.rb b/activesupport/lib/active_support/core_ext/class/subclasses.rb
index 3e5d1a2a42..46e9daaa8f 100644
--- a/activesupport/lib/active_support/core_ext/class/subclasses.rb
+++ b/activesupport/lib/active_support/core_ext/class/subclasses.rb
@@ -2,49 +2,35 @@ require 'active_support/core_ext/module/anonymous'
require 'active_support/core_ext/module/reachable'
class Class #:nodoc:
- # Rubinius
- if defined?(Class.__subclasses__)
- alias :subclasses :__subclasses__
+ begin
+ ObjectSpace.each_object(Class.new) {}
def descendants
descendants = []
- __subclasses__.each do |k|
- descendants << k
- descendants.concat k.descendants
+ ObjectSpace.each_object(class << self; self; end) do |k|
+ descendants.unshift k unless k == self
end
descendants
end
- else # MRI
- begin
- ObjectSpace.each_object(Class.new) {}
-
- def descendants
- descendants = []
- ObjectSpace.each_object(class << self; self; end) do |k|
- descendants.unshift k unless k == self
- end
- descendants
- end
- rescue StandardError # JRuby
- def descendants
- descendants = []
- ObjectSpace.each_object(Class) do |k|
- descendants.unshift k if k < self
- end
- descendants.uniq!
- descendants
+ rescue StandardError # JRuby
+ def descendants
+ descendants = []
+ ObjectSpace.each_object(Class) do |k|
+ descendants.unshift k if k < self
end
+ descendants.uniq!
+ descendants
end
+ end
- # Returns an array with the direct children of +self+.
- #
- # Integer.subclasses # => [Bignum, Fixnum]
- def subclasses
- subclasses, chain = [], descendants
- chain.each do |k|
- subclasses << k unless chain.any? { |c| c > k }
- end
- subclasses
+ # Returns an array with the direct children of +self+.
+ #
+ # Integer.subclasses # => [Bignum, Fixnum]
+ def subclasses
+ subclasses, chain = [], descendants
+ chain.each do |k|
+ subclasses << k unless chain.any? { |c| c > k }
end
+ subclasses
end
end
diff --git a/activesupport/lib/active_support/core_ext/date/calculations.rb b/activesupport/lib/active_support/core_ext/date/calculations.rb
index c5b54318ce..724e076407 100644
--- a/activesupport/lib/active_support/core_ext/date/calculations.rb
+++ b/activesupport/lib/active_support/core_ext/date/calculations.rb
@@ -5,9 +5,11 @@ require 'active_support/core_ext/date/zones'
require 'active_support/core_ext/time/zones'
class Date
+ DAYS_INTO_WEEK = { :monday => 0, :tuesday => 1, :wednesday => 2, :thursday => 3, :friday => 4, :saturday => 5, :sunday => 6 }
+
if RUBY_VERSION < '1.9'
undef :>>
-
+
# Backported from 1.9. The one in 1.8 leads to incorrect next_month and
# friends for dates where the calendar reform is involved. It additionally
# prevents an infinite loop fixed in r27013.
@@ -34,9 +36,9 @@ class Date
::Date.current.tomorrow
end
- # Returns Time.zone.today when config.time_zone is set, otherwise just returns Date.today.
+ # Returns Time.zone.today when <tt>Time.zone</tt> or <tt>config.time_zone</tt> are set, otherwise just returns Date.today.
def current
- ::Time.zone_default ? ::Time.zone.today : ::Date.today
+ ::Time.zone ? ::Time.zone.today : ::Date.today
end
end
@@ -127,6 +129,11 @@ class Date
)
end
+ # Returns a new Date/DateTime representing the time a number of specified weeks ago.
+ def weeks_ago(weeks)
+ advance(:weeks => -weeks)
+ end
+
# Returns a new Date/DateTime representing the time a number of specified months ago.
def months_ago(months)
advance(:months => -months)
@@ -156,7 +163,7 @@ class Date
def next_year
years_since(1)
end unless method_defined?(:next_year)
-
+
# Shorthand for months_ago(1)
def prev_month
months_ago(1)
@@ -185,10 +192,15 @@ class Date
alias :sunday :end_of_week
alias :at_end_of_week :end_of_week
+ # Returns a new Date/DateTime representing the start of the given day in the previous week (default is Monday).
+ def prev_week(day = :monday)
+ result = (self - 7).beginning_of_week + DAYS_INTO_WEEK[day]
+ self.acts_like?(:time) ? result.change(:hour => 0) : result
+ end
+
# Returns a new Date/DateTime representing the start of the given day in next week (default is Monday).
def next_week(day = :monday)
- days_into_week = { :monday => 0, :tuesday => 1, :wednesday => 2, :thursday => 3, :friday => 4, :saturday => 5, :sunday => 6}
- result = (self + 7).beginning_of_week + days_into_week[day]
+ result = (self + 7).beginning_of_week + DAYS_INTO_WEEK[day]
self.acts_like?(:time) ? result.change(:hour => 0) : result
end
diff --git a/activesupport/lib/active_support/core_ext/date/conversions.rb b/activesupport/lib/active_support/core_ext/date/conversions.rb
index 092f936961..769ead9544 100644
--- a/activesupport/lib/active_support/core_ext/date/conversions.rb
+++ b/activesupport/lib/active_support/core_ext/date/conversions.rb
@@ -1,5 +1,5 @@
require 'date'
-require 'active_support/inflector'
+require 'active_support/inflector/methods'
require 'active_support/core_ext/date/zones'
class Date
@@ -93,6 +93,12 @@ class Date
::DateTime.civil(year, month, day, 0, 0, 0, 0)
end if RUBY_VERSION < '1.9'
+ def iso8601
+ strftime('%F')
+ end if RUBY_VERSION < '1.9'
+
+ alias_method :rfc3339, :iso8601 if RUBY_VERSION < '1.9'
+
def xmlschema
to_time_in_current_zone.xmlschema
end
diff --git a/activesupport/lib/active_support/core_ext/date/zones.rb b/activesupport/lib/active_support/core_ext/date/zones.rb
index 3a83af6be2..a70b47b7bc 100644
--- a/activesupport/lib/active_support/core_ext/date/zones.rb
+++ b/activesupport/lib/active_support/core_ext/date/zones.rb
@@ -2,10 +2,10 @@ require 'date'
require 'active_support/core_ext/time/zones'
class Date
- # Converts Date to a TimeWithZone in the current zone if Time.zone_default is set,
- # otherwise converts Date to a Time via Date#to_time
+ # Converts Date to a TimeWithZone in the current zone if Time.zone or Time.zone_default
+ # is set, otherwise converts Date to a Time via Date#to_time
def to_time_in_current_zone
- if ::Time.zone_default
+ if ::Time.zone
::Time.zone.local(year, month, day)
else
to_time
diff --git a/activesupport/lib/active_support/core_ext/date_time/calculations.rb b/activesupport/lib/active_support/core_ext/date_time/calculations.rb
index 1dc3933e12..48cf1a435d 100644
--- a/activesupport/lib/active_support/core_ext/date_time/calculations.rb
+++ b/activesupport/lib/active_support/core_ext/date_time/calculations.rb
@@ -1,6 +1,4 @@
require 'rational' unless RUBY_VERSION >= '1.9.2'
-require 'active_support/core_ext/object/acts_like'
-require 'active_support/core_ext/time/zones'
class DateTime
class << self
@@ -9,8 +7,9 @@ class DateTime
::Time.local(2007).utc_offset.to_r / 86400
end
+ # Returns <tt>Time.zone.now.to_datetime</tt> when <tt>Time.zone</tt> or <tt>config.time_zone</tt> are set, otherwise returns <tt>Time.now.to_datetime</tt>.
def current
- ::Time.zone_default ? ::Time.zone.now.to_datetime : ::Time.now.to_datetime
+ ::Time.zone ? ::Time.zone.now.to_datetime : ::Time.now.to_datetime
end
end
@@ -82,6 +81,29 @@ class DateTime
change(:hour => 23, :min => 59, :sec => 59)
end
+ # 1.9.3 defines + and - on DateTime, < 1.9.3 do not.
+ if DateTime.public_instance_methods(false).include?(:+)
+ def plus_with_duration(other) #:nodoc:
+ if ActiveSupport::Duration === other
+ other.since(self)
+ else
+ plus_without_duration(other)
+ end
+ end
+ alias_method :plus_without_duration, :+
+ alias_method :+, :plus_with_duration
+
+ def minus_with_duration(other) #:nodoc:
+ if ActiveSupport::Duration === other
+ plus_with_duration(-other)
+ else
+ minus_without_duration(other)
+ end
+ end
+ alias_method :minus_without_duration, :-
+ alias_method :-, :minus_with_duration
+ end
+
# Adjusts DateTime to UTC by adding its offset value; offset is set to 0
#
# Example:
@@ -104,11 +126,7 @@ class DateTime
end
# Layers additional behavior on DateTime#<=> so that Time and ActiveSupport::TimeWithZone instances can be compared with a DateTime
- def compare_with_coercion(other)
- other = other.comparable_time if other.respond_to?(:comparable_time)
- other = other.to_datetime unless other.acts_like?(:date)
- compare_without_coercion(other)
+ def <=>(other)
+ super other.to_datetime
end
- alias_method :compare_without_coercion, :<=>
- alias_method :<=>, :compare_with_coercion
end
diff --git a/activesupport/lib/active_support/core_ext/date_time/conversions.rb b/activesupport/lib/active_support/core_ext/date_time/conversions.rb
index 47b8aa59fb..21b84b994b 100644
--- a/activesupport/lib/active_support/core_ext/date_time/conversions.rb
+++ b/activesupport/lib/active_support/core_ext/date_time/conversions.rb
@@ -1,4 +1,4 @@
-require 'active_support/inflector'
+require 'active_support/inflector/methods'
require 'active_support/core_ext/time/conversions'
require 'active_support/core_ext/date_time/calculations'
require 'active_support/values/time_zone'
@@ -9,12 +9,12 @@ class DateTime
remove_method :to_time if instance_methods.include?(:to_time)
# Convert to a formatted string. See Time::DATE_FORMATS for predefined formats.
- #
+ #
# This method is aliased to <tt>to_s</tt>.
- #
+ #
# === Examples
# datetime = DateTime.civil(2007, 12, 4, 0, 0, 0, 0) # => Tue, 04 Dec 2007 00:00:00 +0000
- #
+ #
# datetime.to_formatted_s(:db) # => "2007-12-04 00:00:00"
# datetime.to_s(:db) # => "2007-12-04 00:00:00"
# datetime.to_s(:number) # => "20071204000000"
@@ -50,7 +50,7 @@ class DateTime
def formatted_offset(colon = true, alternate_utc_string = nil)
utc? && alternate_utc_string || ActiveSupport::TimeZone.seconds_to_utc_offset(utc_offset, colon)
end
-
+
# Overrides the default inspect method with a human readable one, e.g., "Mon, 21 Feb 2005 14:30:00 +0000"
def readable_inspect
to_s(:rfc822)
@@ -66,7 +66,7 @@ class DateTime
# Attempts to convert self to a Ruby Time object; returns self if out of range of Ruby Time class
# If self has an offset other than 0, self will just be returned unaltered, since there's no clean way to map it to a Time
def to_time
- self.offset == 0 ? ::Time.utc_time(year, month, day, hour, min, sec) : self
+ self.offset == 0 ? ::Time.utc_time(year, month, day, hour, min, sec, sec_fraction * (RUBY_VERSION < '1.9' ? 86400000000 : 1000000)) : self
end
# To be able to keep Times, Dates and DateTimes interchangeable on conversions
@@ -83,8 +83,8 @@ class DateTime
def xmlschema
strftime("%Y-%m-%dT%H:%M:%S%Z")
end unless instance_methods(false).include?(:xmlschema)
-
- # Converts self to a floating-point number of seconds since the Unix epoch
+
+ # Converts self to a floating-point number of seconds since the Unix epoch
def to_f
seconds_since_unix_epoch.to_f
end
diff --git a/activesupport/lib/active_support/core_ext/date_time/zones.rb b/activesupport/lib/active_support/core_ext/date_time/zones.rb
index a7411d54ae..82a4f7ac5a 100644
--- a/activesupport/lib/active_support/core_ext/date_time/zones.rb
+++ b/activesupport/lib/active_support/core_ext/date_time/zones.rb
@@ -9,7 +9,7 @@ class DateTime
# This method is similar to Time#localtime, except that it uses <tt>Time.zone</tt> as the local zone
# instead of the operating system's time zone.
#
- # You can also pass in a TimeZone instance or string that identifies a TimeZone as an argument,
+ # You can also pass in a TimeZone instance or string that identifies a TimeZone as an argument,
# and the conversion will be based on that zone instead of <tt>Time.zone</tt>.
#
# DateTime.new(2000).in_time_zone('Alaska') # => Fri, 31 Dec 1999 15:00:00 AKST -09:00
diff --git a/activesupport/lib/active_support/core_ext/enumerable.rb b/activesupport/lib/active_support/core_ext/enumerable.rb
index f76ed401cd..6d7f771b5d 100644
--- a/activesupport/lib/active_support/core_ext/enumerable.rb
+++ b/activesupport/lib/active_support/core_ext/enumerable.rb
@@ -9,7 +9,7 @@ module Enumerable
#
# Example:
#
- # latest_transcripts.group_by(&:day).each do |day, transcripts|
+ # latest_transcripts.group_by(&:day).each do |day, transcripts|
# p "#{day} -> #{transcripts.map(&:class).join(', ')}"
# end
# "2006-03-01 -> Transcript"
@@ -88,21 +88,18 @@ module Enumerable
# => { "nextangle" => <Person ...>, "chade-" => <Person ...>, ...}
# people.index_by { |person| "#{person.first_name} #{person.last_name}" }
# => { "Chade- Fowlersburg-e" => <Person ...>, "David Heinemeier Hansson" => <Person ...>, ...}
- #
+ #
def index_by
- inject({}) do |accum, elem|
- accum[yield(elem)] = elem
- accum
- end
+ Hash[map { |elem| [yield(elem), elem] }]
end
-
+
# Returns true if the collection has more than 1 element. Functionally equivalent to collection.size > 1.
- # Works with a block too ala any?, so people.many? { |p| p.age > 26 } # => returns true if more than 1 person is over 26.
+ # Can be called with a block too, much like any?, so people.many? { |p| p.age > 26 } returns true if more than 1 person is over 26.
def many?(&block)
size = block_given? ? select(&block).size : self.size
size > 1
end
-
+
# The negative of the Enumerable#include?. Returns true if the collection does not include the object.
def exclude?(object)
!include?(object)
diff --git a/activesupport/lib/active_support/core_ext/float/rounding.rb b/activesupport/lib/active_support/core_ext/float/rounding.rb
index 9bdf5bba7b..0d4fb87665 100644
--- a/activesupport/lib/active_support/core_ext/float/rounding.rb
+++ b/activesupport/lib/active_support/core_ext/float/rounding.rb
@@ -16,4 +16,4 @@ class Float
precisionless_round
end
end
-end
+end if RUBY_VERSION < '1.9'
diff --git a/activesupport/lib/active_support/core_ext/hash.rb b/activesupport/lib/active_support/core_ext/hash.rb
index 501483498d..fd1cda991e 100644
--- a/activesupport/lib/active_support/core_ext/hash.rb
+++ b/activesupport/lib/active_support/core_ext/hash.rb
@@ -1,5 +1,6 @@
require 'active_support/core_ext/hash/conversions'
require 'active_support/core_ext/hash/deep_merge'
+require 'active_support/core_ext/hash/deep_dup'
require 'active_support/core_ext/hash/diff'
require 'active_support/core_ext/hash/except'
require 'active_support/core_ext/hash/indifferent_access'
diff --git a/activesupport/lib/active_support/core_ext/hash/conversions.rb b/activesupport/lib/active_support/core_ext/hash/conversions.rb
index 2763af6121..3005fef44c 100644
--- a/activesupport/lib/active_support/core_ext/hash/conversions.rb
+++ b/activesupport/lib/active_support/core_ext/hash/conversions.rb
@@ -7,7 +7,7 @@ require 'active_support/core_ext/string/inflections'
class Hash
# Returns a string containing an XML representation of its receiver:
- #
+ #
# {"foo" => 1, "bar" => 2}.to_xml
# # =>
# # <?xml version="1.0" encoding="UTF-8"?>
@@ -15,22 +15,34 @@ class Hash
# # <foo type="integer">1</foo>
# # <bar type="integer">2</bar>
# # </hash>
- #
+ #
# To do so, the method loops over the pairs and builds nodes that depend on
# the _values_. Given a pair +key+, +value+:
- #
+ #
# * If +value+ is a hash there's a recursive call with +key+ as <tt>:root</tt>.
- #
+ #
# * If +value+ is an array there's a recursive call with +key+ as <tt>:root</tt>,
# and +key+ singularized as <tt>:children</tt>.
- #
+ #
# * If +value+ is a callable object it must expect one or two arguments. Depending
# on the arity, the callable is invoked with the +options+ hash as first argument
- # with +key+ as <tt>:root</tt>, and +key+ singularized as second argument. Its
- # return value becomes a new node.
- #
+ # with +key+ as <tt>:root</tt>, and +key+ singularized as second argument. The
+ # callable can add nodes by using <tt>options[:builder]</tt>.
+ #
+ # "foo".to_xml(lambda { |options, key| options[:builder].b(key) })
+ # # => "<b>foo</b>"
+ #
# * If +value+ responds to +to_xml+ the method is invoked with +key+ as <tt>:root</tt>.
- #
+ #
+ # class Foo
+ # def to_xml(options)
+ # options[:builder].bar "fooing!"
+ # end
+ # end
+ #
+ # {:foo => Foo.new}.to_xml(:skip_instruct => true)
+ # # => "<hash><bar>fooing!</bar></hash>"
+ #
# * Otherwise, a node with +key+ as tag is created with a string representation of
# +value+ as text node. If +value+ is +nil+ an attribute "nil" set to "true" is added.
# Unless the option <tt>:skip_types</tt> exists and is true, an attribute "type" is
@@ -48,9 +60,9 @@ class Hash
# "DateTime" => "datetime",
# "Time" => "datetime"
# }
- #
+ #
# By default the root node is "hash", but that's configurable via the <tt>:root</tt> option.
- #
+ #
# The default XML builder is a fresh instance of <tt>Builder::XmlMarkup</tt>. You can
# configure your own builder with the <tt>:builder</tt> option. The method also accepts
# options like <tt>:dasherize</tt> and friends, they are forwarded to the builder.
@@ -108,17 +120,14 @@ class Hash
# blank or nil parsed values are represented by nil
elsif value.blank? || value['nil'] == 'true'
nil
- # If the type is the only element which makes it then
+ # If the type is the only element which makes it then
# this still makes the value nil, except if type is
# a XML node(where type['value'] is a Hash)
elsif value['type'] && value.size == 1 && !value['type'].is_a?(::Hash)
nil
else
- xml_value = value.inject({}) do |h,(k,v)|
- h[k] = typecast_xml_value(v)
- h
- end
-
+ xml_value = Hash[value.map { |k,v| [k, typecast_xml_value(v)] }]
+
# Turn { :files => { :file => #<StringIO> } into { :files => #<StringIO> } so it is compatible with
# how multipart uploaded files from HTML appear
xml_value["file"].is_a?(StringIO) ? xml_value["file"] : xml_value
@@ -136,10 +145,7 @@ class Hash
def unrename_keys(params)
case params.class.to_s
when "Hash"
- params.inject({}) do |h,(k,v)|
- h[k.to_s.tr("-", "_")] = unrename_keys(v)
- h
- end
+ Hash[params.map { |k,v| [k.to_s.tr("-", "_"), unrename_keys(v)] } ]
when "Array"
params.map { |v| unrename_keys(v) }
else
diff --git a/activesupport/lib/active_support/core_ext/hash/deep_dup.rb b/activesupport/lib/active_support/core_ext/hash/deep_dup.rb
new file mode 100644
index 0000000000..447142605c
--- /dev/null
+++ b/activesupport/lib/active_support/core_ext/hash/deep_dup.rb
@@ -0,0 +1,11 @@
+class Hash
+ # Returns a deep copy of hash.
+ def deep_dup
+ duplicate = self.dup
+ duplicate.each_pair do |k,v|
+ tv = duplicate[k]
+ duplicate[k] = tv.is_a?(Hash) && v.is_a?(Hash) ? tv.deep_dup : v
+ end
+ duplicate
+ end
+end
diff --git a/activesupport/lib/active_support/core_ext/hash/indifferent_access.rb b/activesupport/lib/active_support/core_ext/hash/indifferent_access.rb
index 0420e206af..aad4b61e16 100644
--- a/activesupport/lib/active_support/core_ext/hash/indifferent_access.rb
+++ b/activesupport/lib/active_support/core_ext/hash/indifferent_access.rb
@@ -7,8 +7,6 @@ class Hash
# {:a => 1}.with_indifferent_access["a"] # => 1
#
def with_indifferent_access
- hash = ActiveSupport::HashWithIndifferentAccess.new(self)
- hash.default = self.default
- hash
+ ActiveSupport::HashWithIndifferentAccess.new_from_hash_copying_default(self)
end
end
diff --git a/activesupport/lib/active_support/core_ext/hash/keys.rb b/activesupport/lib/active_support/core_ext/hash/keys.rb
index 045a6944fa..d8748b1138 100644
--- a/activesupport/lib/active_support/core_ext/hash/keys.rb
+++ b/activesupport/lib/active_support/core_ext/hash/keys.rb
@@ -35,11 +35,13 @@ class Hash
# as keys, this will fail.
#
# ==== Examples
- # { :name => "Rob", :years => "28" }.assert_valid_keys(:name, :age) # => raises "ArgumentError: Unknown key(s): years"
- # { :name => "Rob", :age => "28" }.assert_valid_keys("name", "age") # => raises "ArgumentError: Unknown key(s): name, age"
+ # { :name => "Rob", :years => "28" }.assert_valid_keys(:name, :age) # => raises "ArgumentError: Unknown key: years"
+ # { :name => "Rob", :age => "28" }.assert_valid_keys("name", "age") # => raises "ArgumentError: Unknown key: name"
# { :name => "Rob", :age => "28" }.assert_valid_keys(:name, :age) # => passes, raises nothing
def assert_valid_keys(*valid_keys)
- unknown_keys = keys - [valid_keys].flatten
- raise(ArgumentError, "Unknown key(s): #{unknown_keys.join(", ")}") unless unknown_keys.empty?
+ valid_keys.flatten!
+ each_key do |k|
+ raise(ArgumentError, "Unknown key: #{k}") unless valid_keys.include?(k)
+ end
end
end
diff --git a/activesupport/lib/active_support/core_ext/hash/reverse_merge.rb b/activesupport/lib/active_support/core_ext/hash/reverse_merge.rb
index d7ebd5feef..01863a162b 100644
--- a/activesupport/lib/active_support/core_ext/hash/reverse_merge.rb
+++ b/activesupport/lib/active_support/core_ext/hash/reverse_merge.rb
@@ -1,27 +1,22 @@
class Hash
- # Allows for reverse merging two hashes where the keys in the calling hash take precedence over those
- # in the <tt>other_hash</tt>. This is particularly useful for initializing an option hash with default values:
+ # Merges the caller into +other_hash+. For example,
#
- # def setup(options = {})
- # options.reverse_merge! :size => 25, :velocity => 10
- # end
+ # options = options.reverse_merge(:size => 25, :velocity => 10)
#
- # Using <tt>merge</tt>, the above example would look as follows:
+ # is equivalent to
#
- # def setup(options = {})
- # { :size => 25, :velocity => 10 }.merge(options)
- # end
+ # options = {:size => 25, :velocity => 10}.merge(options)
#
- # The default <tt>:size</tt> and <tt>:velocity</tt> are only set if the +options+ hash passed in doesn't already
- # have the respective key.
+ # This is particularly useful for initializing an options hash
+ # with default values.
def reverse_merge(other_hash)
other_hash.merge(self)
end
- # Performs the opposite of <tt>merge</tt>, with the keys and values from the first hash taking precedence over the second.
- # Modifies the receiver in place.
+ # Destructive +reverse_merge+.
def reverse_merge!(other_hash)
- merge!( other_hash ){|k,o,n| o }
+ # right wins if there is no left
+ merge!( other_hash ){|key,left,right| left }
end
alias_method :reverse_update, :reverse_merge!
diff --git a/activesupport/lib/active_support/core_ext/integer/time.rb b/activesupport/lib/active_support/core_ext/integer/time.rb
index a0ccf0e971..c677400396 100644
--- a/activesupport/lib/active_support/core_ext/integer/time.rb
+++ b/activesupport/lib/active_support/core_ext/integer/time.rb
@@ -1,7 +1,7 @@
class Integer
# Enables the use of time calculations and declarations, like 45.minutes + 2.hours + 4.years.
#
- # These methods use Time#advance for precise date calculations when using from_now, ago, etc.
+ # These methods use Time#advance for precise date calculations when using from_now, ago, etc.
# as well as adding or subtracting their results from a Time object. For example:
#
# # equivalent to Time.now.advance(:months => 1)
@@ -12,7 +12,7 @@ class Integer
#
# # equivalent to Time.now.advance(:months => 4, :years => 5)
# (4.months + 5.years).from_now
- #
+ #
# While these methods provide precise calculation when used as in the examples above, care
# should be taken to note that this is not true if the result of `months', `years', etc is
# converted before use:
diff --git a/activesupport/lib/active_support/core_ext/kernel/reporting.rb b/activesupport/lib/active_support/core_ext/kernel/reporting.rb
index 7c455f66d5..37a827123a 100644
--- a/activesupport/lib/active_support/core_ext/kernel/reporting.rb
+++ b/activesupport/lib/active_support/core_ext/kernel/reporting.rb
@@ -38,7 +38,7 @@ module Kernel
# puts 'But this will'
def silence_stream(stream)
old_stream = stream.dup
- stream.reopen(Config::CONFIG['host_os'] =~ /mswin|mingw/ ? 'NUL:' : '/dev/null')
+ stream.reopen(RbConfig::CONFIG['host_os'] =~ /mswin|mingw/ ? 'NUL:' : '/dev/null')
stream.sync = true
yield
ensure
@@ -59,4 +59,23 @@ module Kernel
raise unless exception_classes.any? { |cls| e.kind_of?(cls) }
end
end
+
+ # Captures the given stream and returns it:
+ #
+ # stream = capture(:stdout){ puts "Cool" }
+ # stream # => "Cool\n"
+ #
+ def capture(stream)
+ begin
+ stream = stream.to_s
+ eval "$#{stream} = StringIO.new"
+ yield
+ result = eval("$#{stream}").string
+ ensure
+ eval("$#{stream} = #{stream.upcase}")
+ end
+
+ result
+ end
+ alias :silence :capture
end
diff --git a/activesupport/lib/active_support/core_ext/logger.rb b/activesupport/lib/active_support/core_ext/logger.rb
index a1c351bfd9..e63a0a9ed9 100644
--- a/activesupport/lib/active_support/core_ext/logger.rb
+++ b/activesupport/lib/active_support/core_ext/logger.rb
@@ -4,18 +4,17 @@ require 'active_support/core_ext/class/attribute_accessors'
class Logger #:nodoc:
def self.define_around_helper(level)
module_eval <<-end_eval, __FILE__, __LINE__ + 1
- def around_#{level}(before_message, after_message, &block) # def around_debug(before_message, after_message, &block)
- self.#{level}(before_message) # self.debug(before_message)
- return_value = block.call(self) # return_value = block.call(self)
- self.#{level}(after_message) # self.debug(after_message)
- return return_value # return return_value
- end # end
+ def around_#{level}(before_message, after_message) # def around_debug(before_message, after_message, &block)
+ self.#{level}(before_message) # self.debug(before_message)
+ return_value = yield(self) # return_value = yield(self)
+ self.#{level}(after_message) # self.debug(after_message)
+ return_value # return_value
+ end # end
end_eval
end
[:debug, :info, :error, :fatal].each {|level| define_around_helper(level) }
end
-
require 'logger'
# Extensions to the built-in Ruby logger.
@@ -65,11 +64,11 @@ class Logger
formatter.datetime_format if formatter.respond_to?(:datetime_format)
end
- alias :old_formatter :formatter if method_defined?(:formatter)
- # Get the current formatter. The default formatter is a SimpleFormatter which only
- # displays the log message
- def formatter
- @formatter ||= SimpleFormatter.new
+ alias :old_initialize :initialize
+ # Overwrite initialize to set a default formatter.
+ def initialize(*args)
+ old_initialize(*args)
+ self.formatter = SimpleFormatter.new
end
# Simple formatter which only displays the message.
@@ -79,30 +78,4 @@ class Logger
"#{String === msg ? msg : msg.inspect}\n"
end
end
-
- private
- alias old_format_message format_message
-
- # Ruby 1.8.3 transposed the msg and progname arguments to format_message.
- # We can't test RUBY_VERSION because some distributions don't keep Ruby
- # and its standard library in sync, leading to installations of Ruby 1.8.2
- # with Logger from 1.8.3 and vice versa.
- if method_defined?(:formatter=)
- def format_message(severity, timestamp, progname, msg)
- formatter.call(severity, timestamp, progname, msg)
- end
- else
- def format_message(severity, timestamp, msg, progname)
- formatter.call(severity, timestamp, progname, msg)
- end
-
- attr_writer :formatter
- public :formatter=
-
- alias old_format_datetime format_datetime
- def format_datetime(datetime) datetime end
-
- alias old_msg2str msg2str
- def msg2str(msg) msg end
- end
end
diff --git a/activesupport/lib/active_support/core_ext/module/anonymous.rb b/activesupport/lib/active_support/core_ext/module/anonymous.rb
index df25a09ec9..3982c9c586 100644
--- a/activesupport/lib/active_support/core_ext/module/anonymous.rb
+++ b/activesupport/lib/active_support/core_ext/module/anonymous.rb
@@ -19,6 +19,6 @@ class Module
def anonymous?
# Uses blank? because the name of an anonymous class is an empty
# string in 1.8, and nil in 1.9.
- name.blank?
+ name.blank?
end
end
diff --git a/activesupport/lib/active_support/core_ext/module/attr_accessor_with_default.rb b/activesupport/lib/active_support/core_ext/module/attr_accessor_with_default.rb
index 28ac89dab9..e3259a0a84 100644
--- a/activesupport/lib/active_support/core_ext/module/attr_accessor_with_default.rb
+++ b/activesupport/lib/active_support/core_ext/module/attr_accessor_with_default.rb
@@ -2,30 +2,29 @@ class Module
# Declare an attribute accessor with an initial default return value.
#
# To give attribute <tt>:age</tt> the initial value <tt>25</tt>:
- #
+ #
# class Person
# attr_accessor_with_default :age, 25
# end
#
- # some_person.age
- # => 25
- # some_person.age = 26
- # some_person.age
- # => 26
+ # person = Person.new
+ # person.age # => 25
+ #
+ # person.age = 26
+ # person.age # => 26
#
# To give attribute <tt>:element_name</tt> a dynamic default value, evaluated
# in scope of self:
#
- # attr_accessor_with_default(:element_name) { name.underscore }
+ # attr_accessor_with_default(:element_name) { name.underscore }
#
- def attr_accessor_with_default(sym, default = nil, &block)
- raise 'Default value or block required' unless !default.nil? || block
- define_method(sym, block_given? ? block : Proc.new { default })
+ def attr_accessor_with_default(sym, default = Proc.new)
+ define_method(sym, block_given? ? default : Proc.new { default })
module_eval(<<-EVAL, __FILE__, __LINE__ + 1)
- def #{sym}=(value) # def age=(value)
- class << self; attr_reader :#{sym} end # class << self; attr_reader :age end
- @#{sym} = value # @age = value
- end # end
+ def #{sym}=(value) # def age=(value)
+ class << self; attr_accessor :#{sym} end # class << self; attr_accessor :age end
+ @#{sym} = value # @age = value
+ end # end
EVAL
end
end
diff --git a/activesupport/lib/active_support/core_ext/module/attr_internal.rb b/activesupport/lib/active_support/core_ext/module/attr_internal.rb
index 28bc30ae26..00db75bfec 100644
--- a/activesupport/lib/active_support/core_ext/module/attr_internal.rb
+++ b/activesupport/lib/active_support/core_ext/module/attr_internal.rb
@@ -1,16 +1,12 @@
class Module
# Declares an attribute reader backed by an internally-named instance variable.
def attr_internal_reader(*attrs)
- attrs.each do |attr|
- module_eval "def #{attr}() #{attr_internal_ivar_name(attr)} end", __FILE__, __LINE__
- end
+ attrs.each {|attr_name| attr_internal_define(attr_name, :reader)}
end
# Declares an attribute writer backed by an internally-named instance variable.
def attr_internal_writer(*attrs)
- attrs.each do |attr|
- module_eval "def #{attr}=(v) #{attr_internal_ivar_name(attr)} = v end", __FILE__, __LINE__
- end
+ attrs.each {|attr_name| attr_internal_define(attr_name, :writer)}
end
# Declares an attribute reader and writer backed by an internally-named instance
@@ -29,4 +25,15 @@ class Module
def attr_internal_ivar_name(attr)
Module.attr_internal_naming_format % attr
end
+
+ def attr_internal_define(attr_name, type)
+ internal_name = attr_internal_ivar_name(attr_name).sub(/\A@/, '')
+ class_eval do # class_eval is necessary on 1.9 or else the methods a made private
+ # use native attr_* methods as they are faster on some Ruby implementations
+ send("attr_#{type}", internal_name)
+ end
+ attr_name, internal_name = "#{attr_name}=", "#{internal_name}=" if type == :writer
+ alias_method attr_name, internal_name
+ remove_method internal_name
+ end
end
diff --git a/activesupport/lib/active_support/core_ext/module/attribute_accessors.rb b/activesupport/lib/active_support/core_ext/module/attribute_accessors.rb
index 2d88cb57e5..871f5cef3b 100644
--- a/activesupport/lib/active_support/core_ext/module/attribute_accessors.rb
+++ b/activesupport/lib/active_support/core_ext/module/attribute_accessors.rb
@@ -11,7 +11,7 @@ class Module
@@#{sym}
end
EOS
-
+
unless options[:instance_reader] == false
class_eval(<<-EOS, __FILE__, __LINE__ + 1)
def #{sym}
diff --git a/activesupport/lib/active_support/core_ext/module/delegation.rb b/activesupport/lib/active_support/core_ext/module/delegation.rb
index 40a1866428..3a7652f5bf 100644
--- a/activesupport/lib/active_support/core_ext/module/delegation.rb
+++ b/activesupport/lib/active_support/core_ext/module/delegation.rb
@@ -113,7 +113,7 @@ class Module
raise ArgumentError, "Can only automatically set the delegation prefix when delegating to a method."
end
- prefix = options[:prefix] && "#{options[:prefix] == true ? to : options[:prefix]}_"
+ prefix = options[:prefix] && "#{options[:prefix] == true ? to : options[:prefix]}_" || ''
file, line = caller.first.split(':', 2)
line = line.to_i
diff --git a/activesupport/lib/active_support/core_ext/module/deprecation.rb b/activesupport/lib/active_support/core_ext/module/deprecation.rb
index 5a5b4e3f80..9c169a2598 100644
--- a/activesupport/lib/active_support/core_ext/module/deprecation.rb
+++ b/activesupport/lib/active_support/core_ext/module/deprecation.rb
@@ -1,3 +1,5 @@
+require 'active_support/deprecation'
+
class Module
# Declare that a method has been deprecated.
# deprecate :foo
diff --git a/activesupport/lib/active_support/core_ext/module/remove_method.rb b/activesupport/lib/active_support/core_ext/module/remove_method.rb
index b8c01aca0e..07d7c9b018 100644
--- a/activesupport/lib/active_support/core_ext/module/remove_method.rb
+++ b/activesupport/lib/active_support/core_ext/module/remove_method.rb
@@ -3,7 +3,7 @@ class Module
remove_method(method)
rescue NameError
end
-
+
def redefine_method(method, &block)
remove_possible_method(method)
define_method(method, &block)
diff --git a/activesupport/lib/active_support/core_ext/module/synchronization.rb b/activesupport/lib/active_support/core_ext/module/synchronization.rb
index de76a069d6..ed16c2f71b 100644
--- a/activesupport/lib/active_support/core_ext/module/synchronization.rb
+++ b/activesupport/lib/active_support/core_ext/module/synchronization.rb
@@ -1,11 +1,12 @@
+require 'thread'
require 'active_support/core_ext/module/aliasing'
require 'active_support/core_ext/array/extract_options'
class Module
# Synchronize access around a method, delegating synchronization to a
- # particular mutex. A mutex (either a Mutex, or any object that responds to
+ # particular mutex. A mutex (either a Mutex, or any object that responds to
# #synchronize and yields to a block) must be provided as a final :with option.
- # The :with option should be a symbol or string, and can represent a method,
+ # The :with option should be a symbol or string, and can represent a method,
# constant, or instance or class variable.
# Example:
# class SharedCache
diff --git a/activesupport/lib/active_support/core_ext/numeric/time.rb b/activesupport/lib/active_support/core_ext/numeric/time.rb
index d1062805c5..e73915ffcf 100644
--- a/activesupport/lib/active_support/core_ext/numeric/time.rb
+++ b/activesupport/lib/active_support/core_ext/numeric/time.rb
@@ -3,7 +3,7 @@ require 'active_support/duration'
class Numeric
# Enables the use of time calculations and declarations, like 45.minutes + 2.hours + 4.years.
#
- # These methods use Time#advance for precise date calculations when using from_now, ago, etc.
+ # These methods use Time#advance for precise date calculations when using from_now, ago, etc.
# as well as adding or subtracting their results from a Time object. For example:
#
# # equivalent to Time.now.advance(:months => 1)
@@ -14,7 +14,7 @@ class Numeric
#
# # equivalent to Time.now.advance(:months => 4, :years => 5)
# (4.months + 5.years).from_now
- #
+ #
# While these methods provide precise calculation when used as in the examples above, care
# should be taken to note that this is not true if the result of `months', `years', etc is
# converted before use:
@@ -25,8 +25,8 @@ class Numeric
# # equivalent to 365.25.days.to_f.from_now
# 1.year.to_f.from_now
#
- # In such cases, Ruby's core
- # Date[http://stdlib.rubyonrails.org/libdoc/date/rdoc/index.html] and
+ # In such cases, Ruby's core
+ # Date[http://stdlib.rubyonrails.org/libdoc/date/rdoc/index.html] and
# Time[http://stdlib.rubyonrails.org/libdoc/time/rdoc/index.html] should be used for precision
# date and time arithmetic
def seconds
@@ -37,13 +37,13 @@ class Numeric
def minutes
ActiveSupport::Duration.new(self * 60, [[:seconds, self * 60]])
end
- alias :minute :minutes
-
+ alias :minute :minutes
+
def hours
ActiveSupport::Duration.new(self * 3600, [[:seconds, self * 3600]])
end
alias :hour :hours
-
+
def days
ActiveSupport::Duration.new(self * 24.hours, [[:days, self]])
end
@@ -53,14 +53,14 @@ class Numeric
ActiveSupport::Duration.new(self * 7.days, [[:days, self * 7]])
end
alias :week :weeks
-
+
def fortnights
ActiveSupport::Duration.new(self * 2.weeks, [[:days, self * 14]])
end
alias :fortnight :fortnights
-
+
# Reads best without arguments: 10.minutes.ago
- def ago(time = ::Time.now)
+ def ago(time = ::Time.current)
time - self
end
@@ -68,7 +68,7 @@ class Numeric
alias :until :ago
# Reads best with argument: 10.minutes.since(time)
- def since(time = ::Time.now)
+ def since(time = ::Time.current)
time + self
end
diff --git a/activesupport/lib/active_support/core_ext/object.rb b/activesupport/lib/active_support/core_ext/object.rb
index d671da6711..790a26f5c1 100644
--- a/activesupport/lib/active_support/core_ext/object.rb
+++ b/activesupport/lib/active_support/core_ext/object.rb
@@ -2,7 +2,6 @@ require 'active_support/core_ext/object/acts_like'
require 'active_support/core_ext/object/blank'
require 'active_support/core_ext/object/duplicable'
require 'active_support/core_ext/object/try'
-require 'active_support/core_ext/object/returning'
require 'active_support/core_ext/object/conversions'
require 'active_support/core_ext/object/instance_variables'
diff --git a/activesupport/lib/active_support/core_ext/object/blank.rb b/activesupport/lib/active_support/core_ext/object/blank.rb
index eb99bb1a36..d0c1ea8326 100644
--- a/activesupport/lib/active_support/core_ext/object/blank.rb
+++ b/activesupport/lib/active_support/core_ext/object/blank.rb
@@ -13,11 +13,11 @@ class Object
respond_to?(:empty?) ? empty? : !self
end
- # An object is present if it's not blank.
+ # An object is present if it's not <tt>blank?</tt>.
def present?
!blank?
end
-
+
# Returns object if it's #present? otherwise returns nil.
# object.presence is equivalent to object.present? ? object : nil.
#
diff --git a/activesupport/lib/active_support/core_ext/object/instance_variables.rb b/activesupport/lib/active_support/core_ext/object/instance_variables.rb
index 866317b17a..eda9694614 100644
--- a/activesupport/lib/active_support/core_ext/object/instance_variables.rb
+++ b/activesupport/lib/active_support/core_ext/object/instance_variables.rb
@@ -7,13 +7,10 @@ class Object
# @x, @y = x, y
# end
# end
- #
+ #
# C.new(0, 1).instance_values # => {"x" => 0, "y" => 1}
def instance_values #:nodoc:
- instance_variables.inject({}) do |values, name|
- values[name.to_s[1..-1]] = instance_variable_get(name)
- values
- end
+ Hash[instance_variables.map { |name| [name.to_s[1..-1], instance_variable_get(name)] }]
end
# Returns an array of instance variable names including "@". They are strings
@@ -24,7 +21,7 @@ class Object
# @x, @y = x, y
# end
# end
- #
+ #
# C.new(0, 1).instance_variable_names # => ["@y", "@x"]
if RUBY_VERSION >= '1.9'
def instance_variable_names
@@ -33,35 +30,4 @@ class Object
else
alias_method :instance_variable_names, :instance_variables
end
-
- # Copies the instance variables of +object+ into +self+.
- #
- # Instance variable names in the +exclude+ array are ignored. If +object+
- # responds to <tt>protected_instance_variables</tt> the ones returned are
- # also ignored. For example, Rails controllers implement that method.
- #
- # In both cases strings and symbols are understood, and they have to include
- # the at sign.
- #
- # class C
- # def initialize(x, y, z)
- # @x, @y, @z = x, y, z
- # end
- #
- # def protected_instance_variables
- # %w(@z)
- # end
- # end
- #
- # a = C.new(0, 1, 2)
- # b = C.new(3, 4, 5)
- #
- # a.copy_instance_variables_from(b, [:@y])
- # # a is now: @x = 3, @y = 1, @z = 2
- def copy_instance_variables_from(object, exclude = []) #:nodoc:
- exclude += object.protected_instance_variables if object.respond_to? :protected_instance_variables
-
- vars = object.instance_variables.map(&:to_s) - exclude.map(&:to_s)
- vars.each { |name| instance_variable_set(name, object.instance_variable_get(name)) }
- end
end
diff --git a/activesupport/lib/active_support/core_ext/object/returning.rb b/activesupport/lib/active_support/core_ext/object/returning.rb
deleted file mode 100644
index 07250b2a27..0000000000
--- a/activesupport/lib/active_support/core_ext/object/returning.rb
+++ /dev/null
@@ -1,43 +0,0 @@
-class Object
- # Returns +value+ after yielding +value+ to the block. This simplifies the
- # process of constructing an object, performing work on the object, and then
- # returning the object from a method. It is a Ruby-ized realization of the K
- # combinator, courtesy of Mikael Brockman.
- #
- # ==== Examples
- #
- # # Without returning
- # def foo
- # values = []
- # values << "bar"
- # values << "baz"
- # return values
- # end
- #
- # foo # => ['bar', 'baz']
- #
- # # returning with a local variable
- # def foo
- # returning values = [] do
- # values << 'bar'
- # values << 'baz'
- # end
- # end
- #
- # foo # => ['bar', 'baz']
- #
- # # returning with a block argument
- # def foo
- # returning [] do |values|
- # values << 'bar'
- # values << 'baz'
- # end
- # end
- #
- # foo # => ['bar', 'baz']
- def returning(value)
- ActiveSupport::Deprecation.warn('Object#returning has been deprecated in favor of Object#tap.', caller)
- yield(value)
- value
- end
-end \ No newline at end of file
diff --git a/activesupport/lib/active_support/core_ext/object/to_param.rb b/activesupport/lib/active_support/core_ext/object/to_param.rb
index f2e7c2351e..e5f81078ee 100644
--- a/activesupport/lib/active_support/core_ext/object/to_param.rb
+++ b/activesupport/lib/active_support/core_ext/object/to_param.rb
@@ -1,5 +1,3 @@
-
-
class Object
# Alias of <tt>to_s</tt>.
def to_param
@@ -34,16 +32,24 @@ class Array
end
class Hash
- # Converts a hash into a string suitable for use as a URL query string. An optional <tt>namespace</tt> can be
- # passed to enclose the param names (see example below).
+ # Returns a string representation of the receiver suitable for use as a URL
+ # query string:
+ #
+ # {:name => 'David', :nationality => 'Danish'}.to_param
+ # # => "name=David&nationality=Danish"
+ #
+ # An optional namespace can be passed to enclose the param names:
+ #
+ # {:name => 'David', :nationality => 'Danish'}.to_param('user')
+ # # => "user[name]=David&user[nationality]=Danish"
#
- # ==== Examples
- # { :name => 'David', :nationality => 'Danish' }.to_param # => "name=David&nationality=Danish"
+ # The string pairs "key=value" that conform the query string
+ # are sorted lexicographically in ascending order.
#
- # { :name => 'David', :nationality => 'Danish' }.to_param('user') # => "user[name]=David&user[nationality]=Danish"
+ # This method is also aliased as +to_query+.
def to_param(namespace = nil)
collect do |key, value|
value.to_query(namespace ? "#{namespace}[#{key}]" : key)
- end * '&'
+ end.sort * '&'
end
end
diff --git a/activesupport/lib/active_support/core_ext/object/to_query.rb b/activesupport/lib/active_support/core_ext/object/to_query.rb
index c9981895b4..3f1540f685 100644
--- a/activesupport/lib/active_support/core_ext/object/to_query.rb
+++ b/activesupport/lib/active_support/core_ext/object/to_query.rb
@@ -7,7 +7,7 @@ class Object
# Note: This method is defined as a default implementation for all Objects for Hash#to_query to work.
def to_query(key)
require 'cgi' unless defined?(CGI) && defined?(CGI::escape)
- "#{CGI.escape(key.to_s).gsub(/%(5B|5D)/n) { [$1].pack('H*') }}=#{CGI.escape(to_param.to_s)}"
+ "#{CGI.escape(key.to_s)}=#{CGI.escape(to_param.to_s)}"
end
end
@@ -15,7 +15,7 @@ class Array
# Converts an array into a string suitable for use as a URL query string,
# using the given +key+ as the param name.
#
- # ['Rails', 'coding'].to_query('hobbies') # => "hobbies[]=Rails&hobbies[]=coding"
+ # ['Rails', 'coding'].to_query('hobbies') # => "hobbies%5B%5D=Rails&hobbies%5B%5D=coding"
def to_query(key)
prefix = "#{key}[]"
collect { |value| value.to_query(prefix) }.join '&'
diff --git a/activesupport/lib/active_support/core_ext/object/try.rb b/activesupport/lib/active_support/core_ext/object/try.rb
index a1c63a0e54..04619124a1 100644
--- a/activesupport/lib/active_support/core_ext/object/try.rb
+++ b/activesupport/lib/active_support/core_ext/object/try.rb
@@ -5,6 +5,8 @@ class Object
# *Unlike* that method however, a +NoMethodError+ exception will *not* be raised
# and +nil+ will be returned instead, if the receiving object is a +nil+ object or NilClass.
#
+ # If try is called without a method to call, it will yield any given block with the object.
+ #
# ==== Examples
#
# Without try
@@ -18,15 +20,18 @@ class Object
# +try+ also accepts arguments and/or a block, for the method it is trying
# Person.try(:find, 1)
# @people.try(:collect) {|p| p.name}
+ #
+ # Without a method argument try will yield to the block unless the receiver is nil.
+ # @person.try { |p| "#{p.first_name} #{p.last_name}" }
#--
- # This method definition below is for rdoc purposes only. The alias_method call
- # below overrides it as an optimization since +try+ behaves like +Object#send+,
- # unless called on +NilClass+.
- def try(method, *args, &block)
- send(method, *args, &block)
+ # +try+ behaves like +Object#send+, unless called on +NilClass+.
+ def try(*a, &b)
+ if a.empty? && block_given?
+ yield self
+ else
+ __send__(*a, &b)
+ end
end
- remove_method :try
- alias_method :try, :__send__
end
class NilClass #:nodoc:
diff --git a/activesupport/lib/active_support/core_ext/object/with_options.rb b/activesupport/lib/active_support/core_ext/object/with_options.rb
index 3209cf7f11..c23afabfdb 100644
--- a/activesupport/lib/active_support/core_ext/object/with_options.rb
+++ b/activesupport/lib/active_support/core_ext/object/with_options.rb
@@ -7,13 +7,27 @@ class Object
# provided. Each method called on the block variable must take an options
# hash as its final argument.
#
- # with_options :order => 'created_at', :class_name => 'Comment' do |post|
- # post.has_many :comments, :conditions => ['approved = ?', true], :dependent => :delete_all
- # post.has_many :unapproved_comments, :conditions => ['approved = ?', false]
- # post.has_many :all_comments
+ # Without with_options, this code contains duplication:
+ #
+ # class Account < ActiveRecord::Base
+ # has_many :customers, :dependent => :destroy
+ # has_many :products, :dependent => :destroy
+ # has_many :invoices, :dependent => :destroy
+ # has_many :expenses, :dependent => :destroy
+ # end
+ #
+ # Using with_options, we can remove the duplication:
+ #
+ # class Account < ActiveRecord::Base
+ # with_options :dependent => :destroy do |assoc|
+ # assoc.has_many :customers
+ # assoc.has_many :products
+ # assoc.has_many :invoices
+ # assoc.has_many :expenses
+ # end
# end
#
- # Can also be used with an explicit receiver:
+ # It can also be used with an explicit receiver:
#
# map.with_options :controller => "people" do |people|
# people.connect "/people", :action => "index"
diff --git a/activesupport/lib/active_support/core_ext/range.rb b/activesupport/lib/active_support/core_ext/range.rb
index c0736f3a44..2428a02242 100644
--- a/activesupport/lib/active_support/core_ext/range.rb
+++ b/activesupport/lib/active_support/core_ext/range.rb
@@ -2,3 +2,4 @@ require 'active_support/core_ext/range/blockless_step'
require 'active_support/core_ext/range/conversions'
require 'active_support/core_ext/range/include_range'
require 'active_support/core_ext/range/overlaps'
+require 'active_support/core_ext/range/cover'
diff --git a/activesupport/lib/active_support/core_ext/range/conversions.rb b/activesupport/lib/active_support/core_ext/range/conversions.rb
index 11a7ff66de..544e63132d 100644
--- a/activesupport/lib/active_support/core_ext/range/conversions.rb
+++ b/activesupport/lib/active_support/core_ext/range/conversions.rb
@@ -6,7 +6,7 @@ class Range
# Gives a human readable format of the range.
#
# ==== Example
- #
+ #
# [1..100].to_formatted_s # => "1..100"
def to_formatted_s(format = :default)
if formatter = RANGE_FORMATS[format]
diff --git a/activesupport/lib/active_support/core_ext/range/cover.rb b/activesupport/lib/active_support/core_ext/range/cover.rb
new file mode 100644
index 0000000000..3a182cddd2
--- /dev/null
+++ b/activesupport/lib/active_support/core_ext/range/cover.rb
@@ -0,0 +1,3 @@
+class Range
+ alias_method(:cover?, :include?) unless instance_methods.include?(:cover?)
+end
diff --git a/activesupport/lib/active_support/core_ext/string.rb b/activesupport/lib/active_support/core_ext/string.rb
index d8d1f9436e..8fb8c31ade 100644
--- a/activesupport/lib/active_support/core_ext/string.rb
+++ b/activesupport/lib/active_support/core_ext/string.rb
@@ -9,4 +9,5 @@ require 'active_support/core_ext/string/behavior'
require 'active_support/core_ext/string/interpolation'
require 'active_support/core_ext/string/output_safety'
require 'active_support/core_ext/string/exclude'
-require 'active_support/core_ext/string/encoding' \ No newline at end of file
+require 'active_support/core_ext/string/encoding'
+require 'active_support/core_ext/string/strip'
diff --git a/activesupport/lib/active_support/core_ext/string/access.rb b/activesupport/lib/active_support/core_ext/string/access.rb
index 64bc8f6cea..c0d5cdf2d5 100644
--- a/activesupport/lib/active_support/core_ext/string/access.rb
+++ b/activesupport/lib/active_support/core_ext/string/access.rb
@@ -4,27 +4,27 @@ class String
unless '1.9'.respond_to?(:force_encoding)
# Returns the character at the +position+ treating the string as an array (where 0 is the first character).
#
- # Examples:
+ # Examples:
# "hello".at(0) # => "h"
# "hello".at(4) # => "o"
# "hello".at(10) # => ERROR if < 1.9, nil in 1.9
def at(position)
mb_chars[position, 1].to_s
end
-
+
# Returns the remaining of the string from the +position+ treating the string as an array (where 0 is the first character).
#
- # Examples:
+ # Examples:
# "hello".from(0) # => "hello"
# "hello".from(2) # => "llo"
# "hello".from(10) # => "" if < 1.9, nil in 1.9
def from(position)
mb_chars[position..-1].to_s
end
-
+
# Returns the beginning of the string up to the +position+ treating the string as an array (where 0 is the first character).
#
- # Examples:
+ # Examples:
# "hello".to(0) # => "h"
# "hello".to(2) # => "hel"
# "hello".to(10) # => "hello"
@@ -34,7 +34,7 @@ class String
# Returns the first character of the string or the first +limit+ characters.
#
- # Examples:
+ # Examples:
# "hello".first # => "h"
# "hello".first(2) # => "he"
# "hello".first(10) # => "hello"
@@ -50,7 +50,7 @@ class String
# Returns the last character of the string or the last +limit+ characters.
#
- # Examples:
+ # Examples:
# "hello".last # => "o"
# "hello".last(2) # => "lo"
# "hello".last(10) # => "hello"
diff --git a/activesupport/lib/active_support/core_ext/string/filters.rb b/activesupport/lib/active_support/core_ext/string/filters.rb
index e15a1df9c9..d478ee0ef6 100644
--- a/activesupport/lib/active_support/core_ext/string/filters.rb
+++ b/activesupport/lib/active_support/core_ext/string/filters.rb
@@ -25,13 +25,13 @@ class String
# "Once upon a time in a world far far away".truncate(27)
# # => "Once upon a time in a wo..."
#
- # The last characters will be replaced with the <tt>:omission</tt> string (defaults to "...")
- # for a total length not exceeding <tt>:length</tt>:
+ # Pass a <tt>:separator</tt> to truncate +text+ at a natural break:
#
# "Once upon a time in a world far far away".truncate(27, :separator => ' ')
# # => "Once upon a time in a..."
#
- # Pass a <tt>:separator</tt> to truncate +text+ at a natural break:
+ # The last characters will be replaced with the <tt>:omission</tt> string (defaults to "...")
+ # for a total length not exceeding <tt>:length</tt>:
#
# "And they found that many people were sleeping better.".truncate(25, :omission => "... (continued)")
# # => "And they f... (continued)"
diff --git a/activesupport/lib/active_support/core_ext/string/inflections.rb b/activesupport/lib/active_support/core_ext/string/inflections.rb
index 32913a06ad..2f0676f567 100644
--- a/activesupport/lib/active_support/core_ext/string/inflections.rb
+++ b/activesupport/lib/active_support/core_ext/string/inflections.rb
@@ -1,7 +1,9 @@
require 'active_support/inflector/methods'
require 'active_support/inflector/inflections'
+require 'active_support/inflector/transliterate'
+
# String inflections define new methods on the String class to transform names for different purposes.
-# For instance, you can figure out the name of a database from the name of a class.
+# For instance, you can figure out the name of a table from the name of a class.
#
# "ScaleScore".tableize # => "scale_scores"
#
@@ -72,7 +74,7 @@ class String
alias_method :titlecase, :titleize
# The reverse of +camelize+. Makes an underscored, lowercase form from the expression in the string.
- #
+ #
# +underscore+ will also change '::' to '/' to convert namespaces to paths.
#
# "ActiveRecord".underscore # => "active_record"
@@ -97,7 +99,7 @@ class String
end
# Replaces special characters in a string so that it may be used as part of a 'pretty' URL.
- #
+ #
# ==== Examples
#
# class Person
@@ -105,10 +107,10 @@ class String
# "#{id}-#{name.parameterize}"
# end
# end
- #
+ #
# @person = Person.find(1)
# # => #<Person id: 1, name: "Donald E. Knuth">
- #
+ #
# <%= link_to(@person.name, person_path %>
# # => <a href="/person/1-donald-e-knuth">Donald E. Knuth</a>
def parameterize(sep = '-')
@@ -138,11 +140,11 @@ class String
def classify
ActiveSupport::Inflector.classify(self)
end
-
+
# Capitalizes the first word, turns underscores into spaces, and strips '_id'.
# Like +titleize+, this is meant for creating pretty output.
#
- # "employee_salary" # => "Employee salary"
+ # "employee_salary" # => "Employee salary"
# "author_id" # => "Author"
def humanize
ActiveSupport::Inflector.humanize(self)
diff --git a/activesupport/lib/active_support/core_ext/string/multibyte.rb b/activesupport/lib/active_support/core_ext/string/multibyte.rb
index 0b974f5e0a..41de4d6435 100644
--- a/activesupport/lib/active_support/core_ext/string/multibyte.rb
+++ b/activesupport/lib/active_support/core_ext/string/multibyte.rb
@@ -9,7 +9,7 @@ class String
#
# In Ruby 1.8 and older it creates and returns an instance of the ActiveSupport::Multibyte::Chars class which
# encapsulates the original string. A Unicode safe version of all the String methods are defined on this proxy
- # class. If the proxy class doesn't respond to a certain method, it's forwarded to the encapsuled string.
+ # class. If the proxy class doesn't respond to a certain method, it's forwarded to the encapsulated string.
#
# name = 'Claus Müller'
# name.reverse # => "rell??M sualC"
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 b53929c2a3..addd4dab95 100644
--- a/activesupport/lib/active_support/core_ext/string/output_safety.rb
+++ b/activesupport/lib/active_support/core_ext/string/output_safety.rb
@@ -24,6 +24,7 @@ class ERB
end
end
+ # Aliasing twice issues a warning "discarding old...". Remove first to avoid it.
remove_method(:h)
alias h html_escape
@@ -32,15 +33,23 @@ class ERB
singleton_class.send(:remove_method, :html_escape)
module_function :html_escape
- # A utility method for escaping HTML entities in JSON strings.
- # This method is also aliased as <tt>j</tt>.
+ # A utility method for escaping HTML entities in JSON strings
+ # using \uXXXX JavaScript escape sequences for string literals:
+ #
+ # json_escape("is a > 0 & a < 10?")
+ # # => is a \u003E 0 \u0026 a \u003C 10?
+ #
+ # Note that after this operation is performed the output is not
+ # valid JSON. In particular double quotes are removed:
+ #
+ # json_escape('{"name":"john","created_at":"2010-04-28T01:39:31Z","id":1}')
+ # # => {name:john,created_at:2010-04-28T01:39:31Z,id:1}
+ #
+ # This method is also aliased as +j+, and available as a helper
+ # in Rails templates:
#
- # 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
@@ -92,7 +101,13 @@ module ActiveSupport #:nodoc:
self
end
+ def encode_with(coder)
+ coder.represent_scalar nil, to_str
+ end
+
def to_yaml(*args)
+ return super() if defined?(YAML::ENGINE) && !YAML::ENGINE.syck?
+
to_str.to_yaml(*args)
end
end
diff --git a/activesupport/lib/active_support/core_ext/string/strip.rb b/activesupport/lib/active_support/core_ext/string/strip.rb
new file mode 100644
index 0000000000..086c610976
--- /dev/null
+++ b/activesupport/lib/active_support/core_ext/string/strip.rb
@@ -0,0 +1,26 @@
+require 'active_support/core_ext/object/try'
+
+class String
+ # Strips indentation in heredocs.
+ #
+ # For example in
+ #
+ # if options[:usage]
+ # puts <<-USAGE.strip_heredoc
+ # This command does such and such.
+ #
+ # Supported options are:
+ # -h This message
+ # ...
+ # USAGE
+ # end
+ #
+ # the user would see the usage message aligned against the left margin.
+ #
+ # Technically, it looks for the least indented line in the whole string, and removes
+ # that amount of leading whitespace.
+ def strip_heredoc
+ indent = scan(/^[ \t]*(?=\S)/).min.try(:size) || 0
+ gsub(/^[ \t]{#{indent}}/, '')
+ end
+end
diff --git a/activesupport/lib/active_support/core_ext/time/calculations.rb b/activesupport/lib/active_support/core_ext/time/calculations.rb
index 90b6cd3685..7e134db118 100644
--- a/activesupport/lib/active_support/core_ext/time/calculations.rb
+++ b/activesupport/lib/active_support/core_ext/time/calculations.rb
@@ -1,7 +1,4 @@
require 'active_support/duration'
-require 'active_support/core_ext/date/acts_like'
-require 'active_support/core_ext/date/calculations'
-require 'active_support/core_ext/date_time/conversions'
class Time
COMMON_YEAR_DAYS_IN_MONTH = [nil, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
@@ -22,7 +19,7 @@ class Time
# Returns a new Time if requested year can be accommodated by Ruby's Time class
# (i.e., if year is within either 1970..2038 or 1902..2038, depending on system architecture);
- # otherwise returns a DateTime
+ # otherwise returns a DateTime.
def time_with_datetime_fallback(utc_or_local, year, month=1, day=1, hour=0, min=0, sec=0, usec=0)
time = ::Time.send(utc_or_local, year, month, day, hour, min, sec, usec)
# This check is needed because Time.utc(y) returns a time object in the 2000s for 0 <= y <= 138.
@@ -41,9 +38,9 @@ class Time
time_with_datetime_fallback(:local, *args)
end
- # Returns <tt>Time.zone.now</tt> when <tt>config.time_zone</tt> is set, otherwise just returns <tt>Time.now</tt>.
+ # Returns <tt>Time.zone.now</tt> when <tt>Time.zone</tt> or <tt>config.time_zone</tt> are set, otherwise just returns <tt>Time.now</tt>.
def current
- ::Time.zone_default ? ::Time.zone.now : ::Time.now
+ ::Time.zone ? ::Time.zone.now : ::Time.now
end
end
@@ -92,12 +89,12 @@ class Time
options[:weeks], partial_weeks = options[:weeks].divmod(1)
options[:days] = (options[:days] || 0) + 7 * partial_weeks
end
-
+
unless options[:days].nil?
options[:days], partial_days = options[:days].divmod(1)
options[:hours] = (options[:hours] || 0) + 24 * partial_days
end
-
+
d = to_date.advance(options)
time_advanced_by_date = change(:year => d.year, :month => d.month, :day => d.day)
seconds_to_advance = (options[:seconds] || 0) + (options[:minutes] || 0) * 60 + (options[:hours] || 0) * 3600
@@ -117,6 +114,11 @@ class Time
end
alias :in :since
+ # Returns a new Time representing the time a number of specified weeks ago.
+ def weeks_ago(weeks)
+ advance(:weeks => -weeks)
+ end
+
# Returns a new Time representing the time a number of specified months ago
def months_ago(months)
advance(:months => -months)
@@ -172,6 +174,11 @@ class Time
end
alias :at_end_of_week :end_of_week
+ # Returns a new Time representing the start of the given day in the previous week (default is Monday).
+ def prev_week(day = :monday)
+ ago(1.week).beginning_of_week.since(DAYS_INTO_WEEK[day].day).change(:hour => 0)
+ end
+
# Returns a new Time representing the start of the given day in next week (default is Monday).
def next_week(day = :monday)
since(1.week).beginning_of_week.since(DAYS_INTO_WEEK[day].day).change(:hour => 0)
@@ -273,14 +280,8 @@ class Time
# Layers additional behavior on Time#<=> so that DateTime and ActiveSupport::TimeWithZone instances
# can be chronologically compared with a Time
def compare_with_coercion(other)
- # if other is an ActiveSupport::TimeWithZone, coerce a Time instance from it so we can do <=> comparison
- other = other.comparable_time if other.respond_to?(:comparable_time)
- if other.acts_like?(:date)
- # other is a Date/DateTime, so coerce self #to_datetime and hand off to DateTime#<=>
- to_datetime.compare_without_coercion(other)
- else
- compare_without_coercion(other)
- end
+ # we're avoiding Time#to_datetime cause it's expensive
+ other.is_a?(Time) ? compare_without_coercion(other.to_time) : to_datetime <=> other
end
alias_method :compare_without_coercion, :<=>
alias_method :<=>, :compare_with_coercion
diff --git a/activesupport/lib/active_support/core_ext/time/conversions.rb b/activesupport/lib/active_support/core_ext/time/conversions.rb
index 86103ebce2..d9d5e02778 100644
--- a/activesupport/lib/active_support/core_ext/time/conversions.rb
+++ b/activesupport/lib/active_support/core_ext/time/conversions.rb
@@ -1,4 +1,4 @@
-require 'active_support/inflector'
+require 'active_support/inflector/methods'
require 'active_support/core_ext/time/publicize_conversion_methods'
require 'active_support/values/time_zone'
@@ -19,8 +19,8 @@ class Time
#
# time = Time.now # => Thu Jan 18 06:10:17 CST 2007
#
- # time.to_formatted_s(:time) # => "06:10:17"
- # time.to_s(:time) # => "06:10:17"
+ # time.to_formatted_s(:time) # => "06:10"
+ # time.to_s(:time) # => "06:10"
#
# time.to_formatted_s(:db) # => "2007-01-18 06:10:17"
# time.to_formatted_s(:number) # => "20070118061017"
@@ -46,7 +46,7 @@ class Time
end
alias_method :to_default_s, :to_s
alias_method :to_s, :to_formatted_s
-
+
# Returns the UTC offset as an +HH:MM formatted string.
#
# Time.local(2000).formatted_offset # => "-06:00"
@@ -55,31 +55,9 @@ class Time
utc? && alternate_utc_string || ActiveSupport::TimeZone.seconds_to_utc_offset(utc_offset, colon)
end
- # Converts a Time object to a Date, dropping hour, minute, and second precision.
- #
- # my_time = Time.now # => Mon Nov 12 22:59:51 -0500 2007
- # my_time.to_date # => Mon, 12 Nov 2007
- #
- # your_time = Time.parse("1/13/2009 1:13:03 P.M.") # => Tue Jan 13 13:13:03 -0500 2009
- # your_time.to_date # => Tue, 13 Jan 2009
- def to_date
- ::Date.new(year, month, day)
- end unless method_defined?(:to_date)
-
# A method to keep Time, Date and DateTime instances interchangeable on conversions.
# In this case, it simply returns +self+.
def to_time
self
end unless method_defined?(:to_time)
-
- # Converts a Time instance to a Ruby DateTime instance, preserving UTC offset.
- #
- # my_time = Time.now # => Mon Nov 12 23:04:21 -0500 2007
- # my_time.to_datetime # => Mon, 12 Nov 2007 23:04:21 -0500
- #
- # your_time = Time.parse("1/13/2009 1:13:03 P.M.") # => Tue Jan 13 13:13:03 -0500 2009
- # your_time.to_datetime # => Tue, 13 Jan 2009 13:13:03 -0500
- def to_datetime
- ::DateTime.civil(year, month, day, hour, min, sec, Rational(utc_offset, 86400))
- end unless method_defined?(:to_datetime)
end
diff --git a/activesupport/lib/active_support/core_ext/time/zones.rb b/activesupport/lib/active_support/core_ext/time/zones.rb
index 6b9ee84d5c..ff90d7ca58 100644
--- a/activesupport/lib/active_support/core_ext/time/zones.rb
+++ b/activesupport/lib/active_support/core_ext/time/zones.rb
@@ -4,13 +4,13 @@ class Time
class << self
attr_accessor :zone_default
- # Returns the TimeZone for the current request, if this has been set (via Time.zone=).
+ # Returns the TimeZone for the current request, if this has been set (via Time.zone=).
# If <tt>Time.zone</tt> has not been set for the current request, returns the TimeZone specified in <tt>config.time_zone</tt>.
def zone
Thread.current[:time_zone] || zone_default
end
- # Sets <tt>Time.zone</tt> to a TimeZone object for the current request/thread.
+ # Sets <tt>Time.zone</tt> to a TimeZone object for the current request/thread.
#
# This method accepts any of the following:
#
@@ -19,14 +19,18 @@ class Time
# * A TZInfo::Timezone object.
# * An identifier for a TZInfo::Timezone object (e.g., "America/New_York").
#
- # Here's an example of how you might set <tt>Time.zone</tt> on a per request basis -- <tt>current_user.time_zone</tt>
- # just needs to return a string identifying the user's preferred TimeZone:
+ # Here's an example of how you might set <tt>Time.zone</tt> on a per request basis and reset it when the request is done.
+ # <tt>current_user.time_zone</tt> just needs to return a string identifying the user's preferred time zone:
#
# class ApplicationController < ActionController::Base
- # before_filter :set_time_zone
+ # around_filter :set_time_zone
#
# def set_time_zone
- # Time.zone = current_user.time_zone
+ # old_time_zone = Time.zone
+ # Time.zone = current_user.time_zone if logged_in?
+ # yield
+ # ensure
+ # Time.zone = old_time_zone
# end
# end
def zone=(time_zone)
@@ -63,7 +67,7 @@ class Time
# This method is similar to Time#localtime, except that it uses <tt>Time.zone</tt> as the local zone
# instead of the operating system's time zone.
#
- # You can also pass in a TimeZone instance or string that identifies a TimeZone as an argument,
+ # You can also pass in a TimeZone instance or string that identifies a TimeZone as an argument,
# and the conversion will be based on that zone instead of <tt>Time.zone</tt>.
#
# Time.utc(2000).in_time_zone('Alaska') # => Fri, 31 Dec 1999 15:00:00 AKST -09:00
diff --git a/activesupport/lib/active_support/core_ext/uri.rb b/activesupport/lib/active_support/core_ext/uri.rb
index b7fe0a6209..ee991e3439 100644
--- a/activesupport/lib/active_support/core_ext/uri.rb
+++ b/activesupport/lib/active_support/core_ext/uri.rb
@@ -20,3 +20,11 @@ if RUBY_VERSION >= '1.9'
end
end
end
+
+module URI
+ class << self
+ def parser
+ @parser ||= URI.const_defined?(:Parser) ? URI::Parser.new : URI
+ end
+ end
+end
diff --git a/activesupport/lib/active_support/dependencies.rb b/activesupport/lib/active_support/dependencies.rb
index 2b80bd214f..dc10f78104 100644
--- a/activesupport/lib/active_support/dependencies.rb
+++ b/activesupport/lib/active_support/dependencies.rb
@@ -5,6 +5,7 @@ require 'active_support/core_ext/module/aliasing'
require 'active_support/core_ext/module/attribute_accessors'
require 'active_support/core_ext/module/introspection'
require 'active_support/core_ext/module/anonymous'
+require 'active_support/core_ext/module/deprecation'
require 'active_support/core_ext/object/blank'
require 'active_support/core_ext/load_error'
require 'active_support/core_ext/name_error'
@@ -47,9 +48,6 @@ module ActiveSupport #:nodoc:
mattr_accessor :autoloaded_constants
self.autoloaded_constants = []
- mattr_accessor :references
- self.references = {}
-
# An array of constant names that need to be unloaded on every request. Used
# to allow arbitrary constants to be marked for unloading.
mattr_accessor :explicitly_unloadable_constants
@@ -63,58 +61,78 @@ module ActiveSupport #:nodoc:
mattr_accessor :log_activity
self.log_activity = false
- class WatchStack < Array
+ # The WatchStack keeps a stack of the modules being watched as files are loaded.
+ # If a file in the process of being loaded (parent.rb) triggers the load of
+ # another file (child.rb) the stack will ensure that child.rb handles the new
+ # constants.
+ #
+ # If child.rb is being autoloaded, its constants will be added to
+ # autoloaded_constants. If it was being `require`d, they will be discarded.
+ #
+ # This is handled by walking back up the watch stack and adding the constants
+ # found by child.rb to the list of original constants in parent.rb
+ class WatchStack < Hash
+ # @watching is a stack of lists of constants being watched. For instance,
+ # if parent.rb is autoloaded, the stack will look like [[Object]]. If parent.rb
+ # then requires namespace/child.rb, the stack will look like [[Object], [Namespace]].
+
def initialize
- @mutex = Mutex.new
+ @watching = []
+ super { |h,k| h[k] = [] }
end
- def self.locked(*methods)
- methods.each { |m| class_eval "def #{m}(*) lock { super } end", __FILE__, __LINE__ }
- end
+ # return a list of new constants found since the last call to watch_namespaces
+ def new_constants
+ constants = []
- locked :concat, :each, :delete_if, :<<
+ # Grab the list of namespaces that we're looking for new constants under
+ @watching.last.each do |namespace|
+ # Retrieve the constants that were present under the namespace when watch_namespaces
+ # was originally called
+ original_constants = self[namespace].last
- def new_constants_for(frames)
- constants = []
- frames.each do |mod_name, prior_constants|
- mod = Inflector.constantize(mod_name) if Dependencies.qualified_const_defined?(mod_name)
+ mod = Inflector.constantize(namespace) if Dependencies.qualified_const_defined?(namespace)
next unless mod.is_a?(Module)
- new_constants = mod.local_constant_names - prior_constants
-
- # If we are checking for constants under, say, :Object, nested under something
- # else that is checking for constants also under :Object, make sure the
- # parent knows that we have found, and taken care of, the constant.
- #
- # In particular, this means that since Kernel.require discards the constants
- # it finds, parents will be notified that about those constants, and not
- # consider them "new". As a result, they will not be added to the
- # autoloaded_constants list.
- each do |key, value|
- value.concat(new_constants) if key == mod_name
+ # Get a list of the constants that were added
+ new_constants = mod.local_constant_names - original_constants
+
+ # self[namespace] returns an Array of the constants that are being evaluated
+ # for that namespace. For instance, if parent.rb requires child.rb, the first
+ # element of self[Object] will be an Array of the constants that were present
+ # before parent.rb was required. The second element will be an Array of the
+ # constants that were present before child.rb was required.
+ self[namespace].each do |namespace_constants|
+ namespace_constants.concat(new_constants)
end
+ # Normalize the list of new constants, and add them to the list we will return
new_constants.each do |suffix|
- constants << ([mod_name, suffix] - ["Object"]).join("::")
+ constants << ([namespace, suffix] - ["Object"]).join("::")
end
end
constants
+ ensure
+ # A call to new_constants is always called after a call to watch_namespaces
+ pop_modules(@watching.pop)
end
# Add a set of modules to the watch stack, remembering the initial constants
- def add_modules(modules)
- list = modules.map do |desc|
- name = Dependencies.to_constant_name(desc)
- consts = Dependencies.qualified_const_defined?(name) ?
- Inflector.constantize(name).local_constant_names : []
- [name, consts]
+ def watch_namespaces(namespaces)
+ watching = []
+ namespaces.map do |namespace|
+ module_name = Dependencies.to_constant_name(namespace)
+ original_constants = Dependencies.qualified_const_defined?(module_name) ?
+ Inflector.constantize(module_name).local_constant_names : []
+
+ watching << module_name
+ self[module_name] << original_constants
end
- concat(list)
- list
+ @watching << watching
end
- def lock
- @mutex.synchronize { yield self }
+ def pop_modules(modules)
+ modules.each { |mod| self[mod].pop }
end
end
@@ -146,7 +164,7 @@ module ActiveSupport #:nodoc:
def const_missing(const_name, nesting = nil)
klass_name = name.presence || "Object"
- if !nesting
+ unless nesting
# We'll assume that the nesting of Foo::Bar is ["Foo::Bar", "Foo"]
# even though it might not be, such as in the case of
# class Foo::Bar; Baz; end
@@ -311,7 +329,7 @@ module ActiveSupport #:nodoc:
if load?
log "loading #{file_name}"
- # Enable warnings iff this file has not been loaded before and
+ # Enable warnings if this file has not been loaded before and
# warnings_on_first_load is set.
load_args = ["#{file_name}.rb"]
load_args << const_path unless const_path.nil?
@@ -491,7 +509,12 @@ module ActiveSupport #:nodoc:
end
# Remove the constants that have been autoloaded, and those that have been
- # marked for unloading.
+ # marked for unloading. Before each constant is removed a callback is sent
+ # to its class/module if it implements +before_remove_const+.
+ #
+ # The callback implementation should be restricted to cleaning up caches, etc.
+ # as the environment will be in an inconsistent state, e.g. other constants
+ # may have already been unloaded and not accessible.
def remove_unloadable_constants!
autoloaded_constants.each { |const| remove_constant const }
autoloaded_constants.clear
@@ -499,31 +522,76 @@ module ActiveSupport #:nodoc:
explicitly_unloadable_constants.each { |const| remove_constant const }
end
- class Reference
- @@constants = Hash.new { |h, k| h[k] = Inflector.constantize(k) }
+ class ClassCache
+ def initialize
+ @store = Hash.new { |h, k| h[k] = Inflector.constantize(k) }
+ end
- attr_reader :name
+ def empty?
+ @store.empty?
+ end
- def initialize(name)
- @name = name.to_s
- @@constants[@name] = name if name.respond_to?(:name)
+ def key?(key)
+ @store.key?(key)
end
- def get
- @@constants[@name]
+ def []=(key, value)
+ return unless key.respond_to?(:name)
+
+ raise(ArgumentError, 'anonymous classes cannot be cached') if key.name.blank?
+
+ @store[key.name] = value
end
- def self.clear!
- @@constants.clear
+ def [](key)
+ key = key.name if key.respond_to?(:name)
+
+ @store[key]
+ end
+ alias :get :[]
+
+ class Getter # :nodoc:
+ def initialize(name)
+ @name = name
+ end
+
+ def get
+ Reference.get @name
+ end
+ deprecate :get
+ end
+
+ def new(name)
+ self[name] = name
+ Getter.new(name)
+ end
+ deprecate :new
+
+ def store(name)
+ self[name] = name
+ self
+ end
+
+ def clear!
+ @store.clear
end
end
+ Reference = ClassCache.new
+
def ref(name)
- references[name] ||= Reference.new(name)
+ Reference.new(name)
+ end
+ deprecate :ref
+
+ # Store a reference to a class +klass+.
+ def reference(klass)
+ Reference.store klass
end
+ # Get the reference for class named +name+.
def constantize(name)
- ref(name).get
+ Reference.get(name)
end
# Determine if the given constant has been automatically loaded.
@@ -563,14 +631,15 @@ module ActiveSupport #:nodoc:
# and will be removed immediately.
def new_constants_in(*descs)
log_call(*descs)
- watch_frames = constant_watch_stack.add_modules(descs)
+ constant_watch_stack.watch_namespaces(descs)
aborting = true
+
begin
yield # Now yield to the code that is to define new constants.
aborting = false
ensure
- new_constants = constant_watch_stack.new_constants_for(watch_frames)
+ new_constants = constant_watch_stack.new_constants
log "New constants: #{new_constants * ', '}"
return new_constants unless aborting
@@ -580,9 +649,6 @@ module ActiveSupport #:nodoc:
end
return []
- ensure
- # Remove the stack frames that we added.
- watch_frames.each {|f| constant_watch_stack.delete(f) } if watch_frames.present?
end
class LoadingModule #:nodoc:
@@ -618,6 +684,8 @@ module ActiveSupport #:nodoc:
parent = Inflector.constantize(names * '::')
log "removing constant #{const}"
+ constantized = constantize(const)
+ constantized.before_remove_const if constantized.respond_to?(:before_remove_const)
parent.instance_eval { remove_const to_remove }
return true
@@ -625,7 +693,7 @@ module ActiveSupport #:nodoc:
protected
def log_call(*args)
- if logger && log_activity
+ if log_activity?
arg_str = args.collect { |arg| arg.inspect } * ', '
/in `([a-z_\?\!]+)'/ =~ caller(1).first
selector = $1 || '<unknown>'
@@ -634,9 +702,11 @@ module ActiveSupport #:nodoc:
end
def log(msg)
- if logger && log_activity
- logger.debug "Dependencies: #{msg}"
- end
+ logger.debug "Dependencies: #{msg}" if log_activity?
+ end
+
+ def log_activity?
+ logger && log_activity
end
end
end
diff --git a/activesupport/lib/active_support/deprecation.rb b/activesupport/lib/active_support/deprecation.rb
index e1b8211d68..ce0775a690 100644
--- a/activesupport/lib/active_support/deprecation.rb
+++ b/activesupport/lib/active_support/deprecation.rb
@@ -4,12 +4,12 @@ require 'active_support/deprecation/method_wrappers'
require 'active_support/deprecation/proxy_wrappers'
module ActiveSupport
- module Deprecation #:nodoc:
+ module Deprecation
class << self
# The version the deprecated behavior will be removed, by default.
attr_accessor :deprecation_horizon
end
- self.deprecation_horizon = '3.0'
+ self.deprecation_horizon = '3.1'
# By default, warnings are not silenced and debugging is off.
self.silenced = false
diff --git a/activesupport/lib/active_support/deprecation/behaviors.rb b/activesupport/lib/active_support/deprecation/behaviors.rb
index f54f65dcf0..da4af339fc 100644
--- a/activesupport/lib/active_support/deprecation/behaviors.rb
+++ b/activesupport/lib/active_support/deprecation/behaviors.rb
@@ -7,10 +7,17 @@ module ActiveSupport
# Whether to print a backtrace along with the warning.
attr_accessor :debug
+ # Returns the set behaviour or if one isn't set, defaults to +:stderr+
def behavior
@behavior ||= [DEFAULT_BEHAVIORS[:stderr]]
end
+ # Sets the behaviour to the specified value. Can be a single value or an array.
+ #
+ # Examples
+ #
+ # ActiveSupport::Deprecation.behavior = :stderr
+ # ActiveSupport::Deprecation.behavior = [:stderr, :log]
def behavior=(behavior)
@behavior = Array.wrap(behavior).map { |b| DEFAULT_BEHAVIORS[b] || b }
end
diff --git a/activesupport/lib/active_support/deprecation/proxy_wrappers.rb b/activesupport/lib/active_support/deprecation/proxy_wrappers.rb
index deb33ab702..a65fcafb44 100644
--- a/activesupport/lib/active_support/deprecation/proxy_wrappers.rb
+++ b/activesupport/lib/active_support/deprecation/proxy_wrappers.rb
@@ -1,4 +1,4 @@
-require 'active_support/inflector'
+require 'active_support/inflector/methods'
module ActiveSupport
module Deprecation
@@ -58,7 +58,7 @@ module ActiveSupport
end
end
- class DeprecatedConstantProxy < DeprecationProxy #:nodoc:
+ class DeprecatedConstantProxy < DeprecationProxy #:nodoc:all
def initialize(old_const, new_const)
@old_const = old_const
@new_const = new_const
diff --git a/activesupport/lib/active_support/deprecation/reporting.rb b/activesupport/lib/active_support/deprecation/reporting.rb
index 49d58cd3a1..ced08b8783 100644
--- a/activesupport/lib/active_support/deprecation/reporting.rb
+++ b/activesupport/lib/active_support/deprecation/reporting.rb
@@ -3,6 +3,12 @@ module ActiveSupport
class << self
attr_accessor :silenced
+ # Outputs a deprecation warning to the output configured by <tt>ActiveSupport::Deprecation.behavior</tt>
+ #
+ # Example:
+ #
+ # ActiveSupport::Deprecation.warn("something broke!")
+ # #=> "DEPRECATION WARNING: something broke! (called from your_code.rb:1)"
def warn(message = nil, callstack = caller)
return if silenced
deprecation_message(callstack, message).tap do |m|
@@ -46,10 +52,14 @@ module ActiveSupport
end
def extract_callstack(callstack)
- if md = callstack.first.match(/^(.+?):(\d+)(?::in `(.*?)')?/)
- md.captures
- else
- callstack.first
+ rails_gem_root = File.expand_path("../../../../..", __FILE__) + "/"
+ offending_line = callstack.find { |line| !line.start_with?(rails_gem_root) } || callstack.first
+ if offending_line
+ if md = offending_line.match(/^(.+?):(\d+)(?::in `(.*?)')?/)
+ md.captures
+ else
+ offending_line
+ end
end
end
end
diff --git a/activesupport/lib/active_support/duration.rb b/activesupport/lib/active_support/duration.rb
index 7da357730b..00c67a470d 100644
--- a/activesupport/lib/active_support/duration.rb
+++ b/activesupport/lib/active_support/duration.rb
@@ -3,7 +3,7 @@ require 'active_support/core_ext/array/conversions'
require 'active_support/core_ext/object/acts_like'
module ActiveSupport
- # Provides accurate date and time measurements using Date#advance and
+ # Provides accurate date and time measurements using Date#advance and
# Time#advance, respectively. It mainly supports the methods on Numeric.
# Example:
#
@@ -80,6 +80,10 @@ module ActiveSupport
parts.to_sentence(:locale => :en)
end
+ def as_json(options = nil) #:nodoc:
+ to_i
+ end
+
protected
def sum(sign, time = ::Time.current) #:nodoc:
@@ -99,7 +103,7 @@ module ActiveSupport
private
def method_missing(method, *args, &block) #:nodoc:
- value.send(method, *args)
+ value.send(method, *args, &block)
end
end
end
diff --git a/activesupport/lib/active_support/file_update_checker.rb b/activesupport/lib/active_support/file_update_checker.rb
index cd658fe173..a97e9d7daf 100644
--- a/activesupport/lib/active_support/file_update_checker.rb
+++ b/activesupport/lib/active_support/file_update_checker.rb
@@ -8,7 +8,7 @@ module ActiveSupport
# I18n.reload!
# end
#
- # ActionDispatch::Callbacks.to_prepare do
+ # ActionDispatch::Reloader.to_prepare do
# i18n_reloader.execute_if_updated
# end
#
diff --git a/activesupport/lib/active_support/file_watcher.rb b/activesupport/lib/active_support/file_watcher.rb
new file mode 100644
index 0000000000..81e63e76a7
--- /dev/null
+++ b/activesupport/lib/active_support/file_watcher.rb
@@ -0,0 +1,36 @@
+module ActiveSupport
+ class FileWatcher
+ class Backend
+ def initialize(path, watcher)
+ @watcher = watcher
+ @path = path
+ end
+
+ def trigger(files)
+ @watcher.trigger(files)
+ end
+ end
+
+ def initialize
+ @regex_matchers = {}
+ end
+
+ def watch(pattern, &block)
+ @regex_matchers[pattern] = block
+ end
+
+ def trigger(files)
+ trigger_files = Hash.new { |h,k| h[k] = Hash.new { |h2,k2| h2[k2] = [] } }
+
+ files.each do |file, state|
+ @regex_matchers.each do |pattern, block|
+ trigger_files[block][state] << file if pattern === file
+ end
+ end
+
+ trigger_files.each do |block, payload|
+ block.call payload
+ end
+ end
+ end
+end
diff --git a/activesupport/lib/active_support/gzip.rb b/activesupport/lib/active_support/gzip.rb
index 35a50e9a77..62f9c9aa2e 100644
--- a/activesupport/lib/active_support/gzip.rb
+++ b/activesupport/lib/active_support/gzip.rb
@@ -5,6 +5,10 @@ module ActiveSupport
# A convenient wrapper for the zlib standard library that allows compression/decompression of strings with gzip.
module Gzip
class Stream < StringIO
+ def initialize(*)
+ super
+ set_encoding "BINARY" if "".encoding_aware?
+ end
def close; rewind; end
end
@@ -22,4 +26,4 @@ module ActiveSupport
output.string
end
end
-end \ No newline at end of file
+end
diff --git a/activesupport/lib/active_support/hash_with_indifferent_access.rb b/activesupport/lib/active_support/hash_with_indifferent_access.rb
index eec5d4cf47..79a0de7940 100644
--- a/activesupport/lib/active_support/hash_with_indifferent_access.rb
+++ b/activesupport/lib/active_support/hash_with_indifferent_access.rb
@@ -1,8 +1,7 @@
-require 'active_support/core_ext/hash/indifferent_access'
require 'active_support/core_ext/hash/keys'
# This class has dubious semantics and we only have it so that
-# people can write params[:key] instead of params['key']
+# people can write <tt>params[:key]</tt> instead of <tt>params['key']</tt>
# and they get the same value for both keys.
module ActiveSupport
@@ -28,6 +27,12 @@ module ActiveSupport
end
end
+ def self.new_from_hash_copying_default(hash)
+ new(hash).tap do |new_hash|
+ new_hash.default = hash.default
+ end
+ end
+
alias_method :regular_writer, :[]= unless method_defined?(:regular_writer)
alias_method :regular_update, :update unless method_defined?(:regular_update)
@@ -40,6 +45,8 @@ module ActiveSupport
regular_writer(convert_key(key), convert_value(value))
end
+ alias_method :store, :[]=
+
# Updates the instantized hash with values from the second:
#
# hash_1 = HashWithIndifferentAccess.new
@@ -90,7 +97,9 @@ module ActiveSupport
# Returns an exact copy of the hash.
def dup
- HashWithIndifferentAccess.new(self)
+ self.class.new(self).tap do |new_hash|
+ new_hash.default = default
+ end
end
# Merges the instantized and the specified hashes together, giving precedence to the values from the second hash
@@ -100,9 +109,9 @@ module ActiveSupport
end
# Performs the opposite of merge, with the keys and values from the first hash taking precedence over the second.
- # This overloaded definition prevents returning a regular hash, if reverse_merge is called on a HashWithDifferentAccess.
+ # This overloaded definition prevents returning a regular hash, if reverse_merge is called on a <tt>HashWithDifferentAccess</tt>.
def reverse_merge(other_hash)
- super other_hash.with_indifferent_access
+ super self.class.new_from_hash_copying_default(other_hash)
end
def reverse_merge!(other_hash)
@@ -131,11 +140,10 @@ module ActiveSupport
end
def convert_value(value)
- case value
- when Hash
- value.with_indifferent_access
- when Array
- value.collect { |e| e.is_a?(Hash) ? e.with_indifferent_access : e }
+ if value.class == Hash
+ self.class.new_from_hash_copying_default(value)
+ elsif value.is_a?(Array)
+ value.dup.replace(value.map { |e| convert_value(e) })
else
value
end
diff --git a/activesupport/lib/active_support/i18n.rb b/activesupport/lib/active_support/i18n.rb
index 45b9d20c01..00ea8813dd 100644
--- a/activesupport/lib/active_support/i18n.rb
+++ b/activesupport/lib/active_support/i18n.rb
@@ -1,9 +1,9 @@
begin
require 'i18n'
+ require 'active_support/lazy_load_hooks'
rescue LoadError => e
$stderr.puts "You don't have i18n installed in your application. Please add it to your Gemfile and run bundle install"
raise e
end
I18n.load_path << "#{File.dirname(__FILE__)}/locale/en.yml"
-ActiveSupport.run_load_hooks(:i18n)
diff --git a/activesupport/lib/active_support/i18n_railtie.rb b/activesupport/lib/active_support/i18n_railtie.rb
index db09919fd3..a25e951080 100644
--- a/activesupport/lib/active_support/i18n_railtie.rb
+++ b/activesupport/lib/active_support/i18n_railtie.rb
@@ -14,19 +14,34 @@ module I18n
@reloader ||= ActiveSupport::FileUpdateChecker.new([]){ I18n.reload! }
end
- # Add I18n::Railtie.reloader to ActionDispatch callbacks. Since, at this
+ # Add <tt>I18n::Railtie.reloader</tt> to ActionDispatch callbacks. Since, at this
# point, no path was added to the reloader, I18n.reload! is not triggered
# on to_prepare callbacks. This will only happen on the config.after_initialize
# callback below.
initializer "i18n.callbacks" do
- ActionDispatch::Callbacks.to_prepare do
+ ActionDispatch::Reloader.to_prepare do
I18n::Railtie.reloader.execute_if_updated
end
end
- # Set the i18n configuration only after initialization since a lot of
+ # Set the i18n configuration after initialization since a lot of
# configuration is still usually done in application initializers.
config.after_initialize do |app|
+ I18n::Railtie.initialize_i18n(app)
+ end
+
+ # Trigger i18n config before any eager loading has happened
+ # so it's ready if any classes require it when eager loaded
+ config.before_eager_load do |app|
+ I18n::Railtie.initialize_i18n(app)
+ end
+
+ protected
+
+ # Setup i18n configuration
+ def self.initialize_i18n(app)
+ return if @i18n_inited
+
fallbacks = app.config.i18n.delete(:fallbacks)
app.config.i18n.each do |setting, value|
@@ -44,9 +59,9 @@ module I18n
reloader.paths.concat I18n.load_path
reloader.execute_if_updated
- end
- protected
+ @i18n_inited = true
+ end
def self.include_fallbacks_module
I18n.backend.class.send(:include, I18n::Backend::Fallbacks)
@@ -66,7 +81,7 @@ module I18n
I18n.fallbacks = I18n::Locale::Fallbacks.new(*args)
end
-
+
def self.validate_fallbacks(fallbacks)
case fallbacks
when ActiveSupport::OrderedOptions
@@ -78,4 +93,4 @@ module I18n
end
end
end
-end \ No newline at end of file
+end
diff --git a/activesupport/lib/active_support/inflections.rb b/activesupport/lib/active_support/inflections.rb
index e7b5387ed7..06ceccdb22 100644
--- a/activesupport/lib/active_support/inflections.rb
+++ b/activesupport/lib/active_support/inflections.rb
@@ -4,10 +4,12 @@ module ActiveSupport
inflect.plural(/s$/i, 's')
inflect.plural(/(ax|test)is$/i, '\1es')
inflect.plural(/(octop|vir)us$/i, '\1i')
+ inflect.plural(/(octop|vir)i$/i, '\1i')
inflect.plural(/(alias|status)$/i, '\1es')
inflect.plural(/(bu)s$/i, '\1ses')
inflect.plural(/(buffal|tomat)o$/i, '\1oes')
inflect.plural(/([ti])um$/i, '\1a')
+ inflect.plural(/([ti])a$/i, '\1a')
inflect.plural(/sis$/i, 'ses')
inflect.plural(/(?:([^f])fe|([lr])f)$/i, '\1\2ves')
inflect.plural(/(hive)$/i, '\1s')
@@ -15,7 +17,9 @@ module ActiveSupport
inflect.plural(/(x|ch|ss|sh)$/i, '\1es')
inflect.plural(/(matr|vert|ind)(?:ix|ex)$/i, '\1ices')
inflect.plural(/([m|l])ouse$/i, '\1ice')
+ inflect.plural(/([m|l])ice$/i, '\1ice')
inflect.plural(/^(ox)$/i, '\1en')
+ inflect.plural(/^(oxen)$/i, '\1')
inflect.plural(/(quiz)$/i, '\1zes')
inflect.singular(/s$/i, '')
diff --git a/activesupport/lib/active_support/inflector/inflections.rb b/activesupport/lib/active_support/inflector/inflections.rb
index 3caf78bc7d..e136e4c5b3 100644
--- a/activesupport/lib/active_support/inflector/inflections.rb
+++ b/activesupport/lib/active_support/inflector/inflections.rb
@@ -148,7 +148,7 @@ module ActiveSupport
def singularize(word)
result = word.to_s.dup
- if inflections.uncountables.any? { |inflection| result =~ /#{inflection}\Z/i }
+ if inflections.uncountables.any? { |inflection| result =~ /\b(#{inflection})\Z/i }
result
else
inflections.singulars.each { |(rule, replacement)| break if result.gsub!(rule, replacement) }
diff --git a/activesupport/lib/active_support/inflector/transliterate.rb b/activesupport/lib/active_support/inflector/transliterate.rb
index bccc5425a6..40e7a0e389 100644
--- a/activesupport/lib/active_support/inflector/transliterate.rb
+++ b/activesupport/lib/active_support/inflector/transliterate.rb
@@ -1,5 +1,6 @@
# encoding: utf-8
require 'active_support/core_ext/string/multibyte'
+require 'active_support/i18n'
module ActiveSupport
module Inflector
diff --git a/activesupport/lib/active_support/json/backends/jsongem.rb b/activesupport/lib/active_support/json/backends/jsongem.rb
index cfe28d7bb9..533ba25da3 100644
--- a/activesupport/lib/active_support/json/backends/jsongem.rb
+++ b/activesupport/lib/active_support/json/backends/jsongem.rb
@@ -26,7 +26,11 @@ module ActiveSupport
when nil
nil
when DATE_REGEX
- DateTime.parse(data)
+ begin
+ DateTime.parse(data)
+ rescue ArgumentError
+ data
+ end
when Array
data.map! { |d| convert_dates_from(d) }
when Hash
diff --git a/activesupport/lib/active_support/json/backends/yajl.rb b/activesupport/lib/active_support/json/backends/yajl.rb
index 64e50e0d87..58818658c7 100644
--- a/activesupport/lib/active_support/json/backends/yajl.rb
+++ b/activesupport/lib/active_support/json/backends/yajl.rb
@@ -23,7 +23,11 @@ module ActiveSupport
when nil
nil
when DATE_REGEX
- DateTime.parse(data)
+ begin
+ DateTime.parse(data)
+ rescue ArgumentError
+ data
+ end
when Array
data.map! { |d| convert_dates_from(d) }
when Hash
diff --git a/activesupport/lib/active_support/json/backends/yaml.rb b/activesupport/lib/active_support/json/backends/yaml.rb
index 4cb9d01077..e25e29d36b 100644
--- a/activesupport/lib/active_support/json/backends/yaml.rb
+++ b/activesupport/lib/active_support/json/backends/yaml.rb
@@ -7,14 +7,21 @@ module ActiveSupport
ParseError = ::StandardError
extend self
+ EXCEPTIONS = [::ArgumentError] # :nodoc:
+ begin
+ require 'psych'
+ EXCEPTIONS << Psych::SyntaxError
+ rescue LoadError
+ end
+
# Parses a JSON string or IO and converts it into an object
def decode(json)
if json.respond_to?(:read)
json = json.read
end
YAML.load(convert_json_to_yaml(json))
- rescue ArgumentError
- raise ParseError, "Invalid JSON string"
+ rescue *EXCEPTIONS => e
+ raise ParseError, "Invalid JSON string: '%s'" % json
end
protected
@@ -22,21 +29,21 @@ module ActiveSupport
def convert_json_to_yaml(json) #:nodoc:
require 'strscan' unless defined? ::StringScanner
scanner, quoting, marks, pos, times = ::StringScanner.new(json), false, [], nil, []
- while scanner.scan_until(/(\\['"]|['":,\\]|\\.)/)
+ while scanner.scan_until(/(\\['"]|['":,\\]|\\.|[\]])/)
case char = scanner[1]
when '"', "'"
if !quoting
quoting = char
pos = scanner.pos
elsif quoting == char
- if json[pos..scanner.pos-2] =~ DATE_REGEX
+ if valid_date?(json[pos..scanner.pos-2])
# found a date, track the exact positions of the quotes so we can
# overwrite them with spaces later.
- times << pos << scanner.pos
+ times << pos
end
quoting = false
end
- when ":",","
+ when ":",",", "]"
marks << scanner.pos - 1 unless quoting
when "\\"
scanner.skip(/\\/)
@@ -47,7 +54,9 @@ module ActiveSupport
json.gsub(/\\([\\\/]|u[[:xdigit:]]{4})/) do
ustr = $1
if ustr.start_with?('u')
- [ustr[1..-1].to_i(16)].pack("U")
+ char = [ustr[1..-1].to_i(16)].pack("U")
+ # "\n" needs extra escaping due to yaml formatting
+ char == "\n" ? "\\n" : char
elsif ustr == '\\'
'\\\\'
else
@@ -61,14 +70,18 @@ module ActiveSupport
left_pos.each_with_index do |left, i|
scanner.pos = left.succ
chunk = scanner.peek(right_pos[i] - scanner.pos + 1)
- # overwrite the quotes found around the dates with spaces
- while times.size > 0 && times[0] <= right_pos[i]
- chunk[times.shift - scanner.pos - 1] = ' '
+ if ActiveSupport.parse_json_times
+ # overwrite the quotes found around the dates with spaces
+ while times.size > 0 && times[0] <= right_pos[i]
+ chunk.insert(times.shift - scanner.pos - 1, '! ')
+ end
end
chunk.gsub!(/\\([\\\/]|u[[:xdigit:]]{4})/) do
ustr = $1
if ustr.start_with?('u')
- [ustr[1..-1].to_i(16)].pack("U")
+ char = [ustr[1..-1].to_i(16)].pack("U")
+ # "\n" needs extra escaping due to yaml formatting
+ char == "\n" ? "\\n" : char
elsif ustr == '\\'
'\\\\'
else
@@ -83,6 +96,16 @@ module ActiveSupport
output
end
end
+
+ private
+ def valid_date?(date_string)
+ begin
+ date_string =~ DATE_REGEX && DateTime.parse(date_string)
+ rescue ArgumentError
+ false
+ end
+ end
+
end
end
end
diff --git a/activesupport/lib/active_support/json/encoding.rb b/activesupport/lib/active_support/json/encoding.rb
index 2f9588e0f4..82b8a7e148 100644
--- a/activesupport/lib/active_support/json/encoding.rb
+++ b/activesupport/lib/active_support/json/encoding.rb
@@ -23,7 +23,7 @@ module ActiveSupport
module JSON
# matches YAML-formatted dates
- DATE_REGEX = /^(?:\d{4}-\d{2}-\d{2}|\d{4}-\d{1,2}-\d{1,2}[ \t]+\d{1,2}:\d{2}:\d{2}(\.[0-9]*)?(([ \t]*)Z|[-+]\d{2}?(:\d{2})?))$/
+ DATE_REGEX = /^(?:\d{4}-\d{2}-\d{2}|\d{4}-\d{1,2}-\d{1,2}[T \t]+\d{1,2}:\d{2}:\d{2}(\.[0-9]*)?(([ \t]*)Z|[-+]\d{2}?(:\d{2})?))$/
# Dumps object in JSON (JavaScript Object Notation). See www.json.org for more info.
def self.encode(value, options = nil)
@@ -41,9 +41,26 @@ module ActiveSupport
@seen = []
end
- def encode(value)
+ def encode(value, use_options = true)
check_for_circular_references(value) do
- value.as_json(options).encode_json(self)
+ jsonified = use_options ? value.as_json(options_for(value)) : value.as_json
+ jsonified.encode_json(self)
+ end
+ end
+
+ # like encode, but only calls as_json, without encoding to string
+ def as_json(value)
+ check_for_circular_references(value) do
+ value.as_json(options_for(value))
+ end
+ end
+
+ def options_for(value)
+ if value.is_a?(Array) || value.is_a?(Hash)
+ # hashes and arrays need to get encoder in the options, so that they can detect circular references
+ (options || {}).merge(:encoder => self)
+ else
+ options
end
end
@@ -136,6 +153,12 @@ class Object
end
end
+class Struct
+ def as_json(options = nil) #:nodoc:
+ Hash[members.zip(values)]
+ end
+end
+
class TrueClass
AS_JSON = ActiveSupport::JSON::Variable.new('true').freeze
def as_json(options = nil) AS_JSON end #:nodoc:
@@ -186,13 +209,22 @@ module Enumerable
end
class Array
- def as_json(options = nil) self end #:nodoc:
- def encode_json(encoder) "[#{map { |v| encoder.encode(v) } * ','}]" end #:nodoc:
+ def as_json(options = nil) #:nodoc:
+ # use encoder as a proxy to call as_json on all elements, to protect from circular references
+ encoder = options && options[:encoder] || ActiveSupport::JSON::Encoding::Encoder.new(options)
+ map { |v| encoder.as_json(v) }
+ end
+
+ def encode_json(encoder) #:nodoc:
+ # we assume here that the encoder has already run as_json on self and the elements, so we run encode_json directly
+ "[#{map { |v| v.encode_json(encoder) } * ','}]"
+ end
end
class Hash
def as_json(options = nil) #:nodoc:
- if options
+ # create a subset of the hash by applying :only or :except
+ subset = if options
if attrs = options[:only]
slice(*Array.wrap(attrs))
elsif attrs = options[:except]
@@ -203,10 +235,21 @@ class Hash
else
self
end
+
+ # use encoder as a proxy to call as_json on all values in the subset, to protect from circular references
+ encoder = options && options[:encoder] || ActiveSupport::JSON::Encoding::Encoder.new(options)
+ result = self.is_a?(ActiveSupport::OrderedHash) ? ActiveSupport::OrderedHash : Hash
+ result[subset.map { |k, v| [k.to_s, encoder.as_json(v)] }]
end
def encode_json(encoder)
- "{#{map { |k,v| "#{encoder.encode(k.to_s)}:#{encoder.encode(v)}" } * ','}}"
+ # values are encoded with use_options = false, because we don't want hash representations from ActiveModel to be
+ # processed once again with as_json with options, as this could cause unexpected results (i.e. missing fields);
+
+ # on the other hand, we need to run as_json on the elements, because the model representation may contain fields
+ # like Time/Date in their original (not jsonified) form, etc.
+
+ "{#{map { |k,v| "#{encoder.encode(k.to_s)}:#{encoder.encode(v, false)}" } * ','}}"
end
end
diff --git a/activesupport/lib/active_support/lazy_load_hooks.rb b/activesupport/lib/active_support/lazy_load_hooks.rb
index ef43fc0431..82507c1e03 100644
--- a/activesupport/lib/active_support/lazy_load_hooks.rb
+++ b/activesupport/lib/active_support/lazy_load_hooks.rb
@@ -1,21 +1,21 @@
-# lazy_load_hooks allows rails to lazily load a lot of components and thus making the app boot faster. Because of
+# lazy_load_hooks allows rails to lazily load a lot of components and thus making the app boot faster. Because of
# this feature now there is no need to require <tt>ActiveRecord::Base</tt> at boot time purely to apply configuration. Instead
# a hook is registered that applies configuration once <tt>ActiveRecord::Base</tt> is loaded. Here <tt>ActiveRecord::Base</tt> is used
# as example but this feature can be applied elsewhere too.
#
# Here is an example where +on_load+ method is called to register a hook.
#
-# initializer "active_record.initialize_timezone" do
-# ActiveSupport.on_load(:active_record) do
-# self.time_zone_aware_attributes = true
-# self.default_timezone = :utc
-# end
-# end
+# initializer "active_record.initialize_timezone" do
+# ActiveSupport.on_load(:active_record) do
+# self.time_zone_aware_attributes = true
+# self.default_timezone = :utc
+# end
+# end
#
-# When the entirety of +activerecord/lib/active_record/base.rb+ has been evaluated then +run_load_hooks+ is invoked.
+# When the entirety of +activerecord/lib/active_record/base.rb+ has been evaluated then +run_load_hooks+ is invoked.
# The very last line of +activerecord/lib/active_record/base.rb+ is:
#
-# ActiveSupport.run_load_hooks(:active_record, ActiveRecord::Base)
+# ActiveSupport.run_load_hooks(:active_record, ActiveRecord::Base)
#
module ActiveSupport
@load_hooks = Hash.new {|h,k| h[k] = [] }
diff --git a/activesupport/lib/active_support/locale/en.yml b/activesupport/lib/active_support/locale/en.yml
index 8f08f37a70..a1499bcc90 100644
--- a/activesupport/lib/active_support/locale/en.yml
+++ b/activesupport/lib/active_support/locale/en.yml
@@ -7,10 +7,10 @@ en:
default: "%Y-%m-%d"
short: "%b %d"
long: "%B %d, %Y"
-
+
day_names: [Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday]
abbr_day_names: [Sun, Mon, Tue, Wed, Thu, Fri, Sat]
-
+
# Don't forget the nil at the beginning; there's no such thing as a 0th month
month_names: [~, January, February, March, April, May, June, July, August, September, October, November, December]
abbr_month_names: [~, Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec]
@@ -27,7 +27,7 @@ en:
long: "%B %d, %Y %H:%M"
am: "am"
pm: "pm"
-
+
# Used in array.to_sentence.
support:
array:
diff --git a/activesupport/lib/active_support/log_subscriber.rb b/activesupport/lib/active_support/log_subscriber.rb
index 83930b3f0d..10675edac5 100644
--- a/activesupport/lib/active_support/log_subscriber.rb
+++ b/activesupport/lib/active_support/log_subscriber.rb
@@ -4,7 +4,7 @@ require 'active_support/core_ext/class/attribute'
module ActiveSupport
# ActiveSupport::LogSubscriber is an object set to consume ActiveSupport::Notifications
# with solely purpose of logging. The log subscriber dispatches notifications to a
- # regirested object based on its given namespace.
+ # registered object based on its given namespace.
#
# An example would be Active Record log subscriber responsible for logging queries:
#
@@ -16,12 +16,12 @@ module ActiveSupport
# end
# end
#
- # And it's finally registed as:
+ # And it's finally registered as:
#
# ActiveRecord::LogSubscriber.attach_to :active_record
#
# Since we need to know all instance methods before attaching the log subscriber,
- # the line above should be called after your ActiveRecord::LogSubscriber definition.
+ # the line above should be called after your <tt>ActiveRecord::LogSubscriber</tt> definition.
#
# After configured, whenever a "sql.active_record" notification is published,
# it will properly dispatch the event (ActiveSupport::Notifications::Event) to
@@ -31,23 +31,10 @@ module ActiveSupport
# all logs when the request finishes (via action_dispatch.callback notification) in
# a Rails environment.
class LogSubscriber
- mattr_accessor :colorize_logging
- self.colorize_logging = true
-
- class_attribute :logger
-
- class << self
- remove_method :logger
- end
-
- def self.logger
- @logger ||= Rails.logger if defined?(Rails)
- end
-
# Embed in a String to clear all previous ANSI sequences.
CLEAR = "\e[0m"
BOLD = "\e[1m"
-
+
# Colors
BLACK = "\e[30m"
RED = "\e[31m"
@@ -58,32 +45,44 @@ module ActiveSupport
CYAN = "\e[36m"
WHITE = "\e[37m"
- def self.attach_to(namespace, log_subscriber=new, notifier=ActiveSupport::Notifications)
- log_subscribers << log_subscriber
- @@flushable_loggers = nil
+ mattr_accessor :colorize_logging
+ self.colorize_logging = true
+
+ class_attribute :logger
+
+ class << self
+ remove_method :logger
+ def logger
+ @logger ||= Rails.logger if defined?(Rails)
+ end
+
+ def attach_to(namespace, log_subscriber=new, notifier=ActiveSupport::Notifications)
+ log_subscribers << log_subscriber
+ @@flushable_loggers = nil
- log_subscriber.public_methods(false).each do |event|
- next if 'call' == event.to_s
+ log_subscriber.public_methods(false).each do |event|
+ next if 'call' == event.to_s
- notifier.subscribe("#{event}.#{namespace}", log_subscriber)
+ notifier.subscribe("#{event}.#{namespace}", log_subscriber)
+ end
end
- end
- def self.log_subscribers
- @@log_subscribers ||= []
- end
+ def log_subscribers
+ @@log_subscribers ||= []
+ end
- def self.flushable_loggers
- @@flushable_loggers ||= begin
- loggers = log_subscribers.map(&:logger)
- loggers.uniq!
- loggers.select { |l| l.respond_to?(:flush) }
+ def flushable_loggers
+ @@flushable_loggers ||= begin
+ loggers = log_subscribers.map(&:logger)
+ loggers.uniq!
+ loggers.select { |l| l.respond_to?(:flush) }
+ end
end
- end
- # Flush all log_subscribers' logger.
- def self.flush_all!
- flushable_loggers.each(&:flush)
+ # Flush all log_subscribers' logger.
+ def flush_all!
+ flushable_loggers.each(&:flush)
+ end
end
def call(message, *args)
diff --git a/activesupport/lib/active_support/log_subscriber/test_helper.rb b/activesupport/lib/active_support/log_subscriber/test_helper.rb
index 9e52cb97a9..392e33edbc 100644
--- a/activesupport/lib/active_support/log_subscriber/test_helper.rb
+++ b/activesupport/lib/active_support/log_subscriber/test_helper.rb
@@ -12,7 +12,7 @@ module ActiveSupport
# def setup
# ActiveRecord::LogSubscriber.attach_to(:active_record)
# end
- #
+ #
# def test_basic_query_logging
# Developer.all
# wait
@@ -23,11 +23,11 @@ module ActiveSupport
# end
#
# All you need to do is to ensure that your log subscriber is added to Rails::Subscriber,
- # as in the second line of the code above. The test helpers is reponsible for setting
+ # as in the second line of the code above. The test helpers are responsible for setting
# up the queue, subscriptions and turning colors in logs off.
#
# The messages are available in the @logger instance, which is a logger with limited
- # powers (it actually do not send anything to your output), and you can collect them
+ # powers (it actually does not send anything to your output), and you can collect them
# doing @logger.logged(level), where level is the level used in logging, like info,
# debug, warn and so on.
#
@@ -38,13 +38,14 @@ module ActiveSupport
ActiveSupport::LogSubscriber.colorize_logging = false
+ @old_notifier = ActiveSupport::Notifications.notifier
set_logger(@logger)
ActiveSupport::Notifications.notifier = @notifier
end
def teardown
set_logger(nil)
- ActiveSupport::Notifications.notifier = nil
+ ActiveSupport::Notifications.notifier = @old_notifier
end
class MockLogger
diff --git a/activesupport/lib/active_support/memoizable.rb b/activesupport/lib/active_support/memoizable.rb
index 9fb506fea1..0a7bcd5bb8 100644
--- a/activesupport/lib/active_support/memoizable.rb
+++ b/activesupport/lib/active_support/memoizable.rb
@@ -95,6 +95,8 @@ module ActiveSupport
#
if private_method_defined?(#{original_method.inspect}) # if private_method_defined?(:_unmemoized_mime_type)
private #{symbol.inspect} # private :mime_type
+ elsif protected_method_defined?(#{original_method.inspect}) # elsif protected_method_defined?(:_unmemoized_mime_type)
+ protected #{symbol.inspect} # protected :mime_type
end # end
EOS
end
diff --git a/activesupport/lib/active_support/message_encryptor.rb b/activesupport/lib/active_support/message_encryptor.rb
index 51fa626b45..4f7cd12d48 100644
--- a/activesupport/lib/active_support/message_encryptor.rb
+++ b/activesupport/lib/active_support/message_encryptor.rb
@@ -2,12 +2,12 @@ require 'openssl'
require 'active_support/base64'
module ActiveSupport
- # MessageEncryptor is a simple way to encrypt values which get stored somewhere
+ # MessageEncryptor is a simple way to encrypt values which get stored somewhere
# you don't trust.
- #
+ #
# The cipher text and initialization vector are base64 encoded and returned to you.
#
- # This can be used in situations similar to the MessageVerifier, but where you don't
+ # This can be used in situations similar to the <tt>MessageVerifier</tt>, but where you don't
# want users to be able to determine the value of the payload.
class MessageEncryptor
class InvalidMessage < StandardError; end
@@ -17,53 +17,53 @@ module ActiveSupport
@secret = secret
@cipher = cipher
end
-
+
def encrypt(value)
cipher = new_cipher
# Rely on OpenSSL for the initialization vector
iv = cipher.random_iv
-
- cipher.encrypt
+
+ cipher.encrypt
cipher.key = @secret
cipher.iv = iv
-
- encrypted_data = cipher.update(Marshal.dump(value))
+
+ encrypted_data = cipher.update(Marshal.dump(value))
encrypted_data << cipher.final
[encrypted_data, iv].map {|v| ActiveSupport::Base64.encode64s(v)}.join("--")
end
-
+
def decrypt(encrypted_message)
cipher = new_cipher
encrypted_data, iv = encrypted_message.split("--").map {|v| ActiveSupport::Base64.decode64(v)}
-
+
cipher.decrypt
cipher.key = @secret
cipher.iv = iv
decrypted_data = cipher.update(encrypted_data)
decrypted_data << cipher.final
-
+
Marshal.load(decrypted_data)
rescue OpenSSLCipherError, TypeError
raise InvalidMessage
end
-
+
def encrypt_and_sign(value)
verifier.generate(encrypt(value))
end
-
+
def decrypt_and_verify(value)
decrypt(verifier.verify(value))
end
-
-
-
- private
+
+
+
+ private
def new_cipher
OpenSSL::Cipher::Cipher.new(@cipher)
end
-
+
def verifier
MessageVerifier.new(@secret)
end
diff --git a/activesupport/lib/active_support/message_verifier.rb b/activesupport/lib/active_support/message_verifier.rb
index 6c46b68eaf..8f3946325a 100644
--- a/activesupport/lib/active_support/message_verifier.rb
+++ b/activesupport/lib/active_support/message_verifier.rb
@@ -2,30 +2,30 @@ require 'active_support/base64'
require 'active_support/core_ext/object/blank'
module ActiveSupport
- # MessageVerifier makes it easy to generate and verify messages which are signed
+ # +MessageVerifier+ makes it easy to generate and verify messages which are signed
# to prevent tampering.
- #
+ #
# This is useful for cases like remember-me tokens and auto-unsubscribe links where the
# session store isn't suitable or available.
#
# Remember Me:
# cookies[:remember_me] = @verifier.generate([@user.id, 2.weeks.from_now])
- #
+ #
# In the authentication filter:
#
# id, time = @verifier.verify(cookies[:remember_me])
# if time < Time.now
# self.current_user = User.find(id)
# end
- #
+ #
class MessageVerifier
class InvalidSignature < StandardError; end
-
+
def initialize(secret, digest = 'SHA1')
@secret = secret
@digest = digest
end
-
+
def verify(signed_message)
raise InvalidSignature if signed_message.blank?
@@ -36,12 +36,12 @@ module ActiveSupport
raise InvalidSignature
end
end
-
+
def generate(value)
data = ActiveSupport::Base64.encode64s(Marshal.dump(value))
"#{data}--#{generate_digest(data)}"
end
-
+
private
# constant-time comparison algorithm to prevent timing attacks
def secure_compare(a, b)
diff --git a/activesupport/lib/active_support/multibyte.rb b/activesupport/lib/active_support/multibyte.rb
index 8ffdf5a1bf..57e8e24bf4 100644
--- a/activesupport/lib/active_support/multibyte.rb
+++ b/activesupport/lib/active_support/multibyte.rb
@@ -6,7 +6,7 @@ module ActiveSupport #:nodoc:
autoload :EncodingError, 'active_support/multibyte/exceptions'
autoload :Chars, 'active_support/multibyte/chars'
autoload :Unicode, 'active_support/multibyte/unicode'
-
+
# The proxy class returned when calling mb_chars. You can use this accessor to configure your own proxy
# class so you can support other encodings. See the ActiveSupport::Multibyte::Chars implementation for
# an example how to do this.
diff --git a/activesupport/lib/active_support/multibyte/chars.rb b/activesupport/lib/active_support/multibyte/chars.rb
index 019fb2df06..f9607f1aaf 100644
--- a/activesupport/lib/active_support/multibyte/chars.rb
+++ b/activesupport/lib/active_support/multibyte/chars.rb
@@ -64,7 +64,7 @@ module ActiveSupport #:nodoc:
# Returns +true+ if _obj_ responds to the given method. Private methods are included in the search
# only if the optional second parameter evaluates to +true+.
def respond_to?(method, include_private=false)
- super || @wrapped_string.respond_to?(method, include_private) || false
+ super || @wrapped_string.respond_to?(method, include_private)
end
# Enable more predictable duck-typing on String-like classes. See Object#acts_like?.
@@ -270,13 +270,14 @@ module ActiveSupport #:nodoc:
@wrapped_string[*args] = replace_by
else
result = Unicode.u_unpack(@wrapped_string)
- if args[0].is_a?(Fixnum)
+ case args.first
+ when Fixnum
raise IndexError, "index #{args[0]} out of string" if args[0] >= result.length
min = args[0]
max = args[1].nil? ? min : (min + args[1] - 1)
range = Range.new(min, max)
replace_by = [replace_by].pack('U') if replace_by.is_a?(Fixnum)
- elsif args.first.is_a?(Range)
+ when Range
raise RangeError, "#{args[0]} out of range" if args[0].min >= result.length
range = args[0]
else
@@ -437,7 +438,7 @@ module ActiveSupport #:nodoc:
begin
@wrapped_string[0...byte_offset].unpack('U*').length
- rescue ArgumentError => e
+ rescue ArgumentError
byte_offset -= 1
retry
end
diff --git a/activesupport/lib/active_support/multibyte/unicode.rb b/activesupport/lib/active_support/multibyte/unicode.rb
index 1139783b65..513f83e445 100644
--- a/activesupport/lib/active_support/multibyte/unicode.rb
+++ b/activesupport/lib/active_support/multibyte/unicode.rb
@@ -247,7 +247,7 @@ module ActiveSupport
if is_unused || is_restricted
bytes[i] = tidy_byte(byte)
elsif is_cont
- # Not expecting contination byte? Clean up. Otherwise, now expect one less.
+ # Not expecting continuation byte? Clean up. Otherwise, now expect one less.
conts_expected == 0 ? bytes[i] = tidy_byte(byte) : conts_expected -= 1
else
if conts_expected > 0
diff --git a/activesupport/lib/active_support/notifications.rb b/activesupport/lib/active_support/notifications.rb
index fd79188ba4..77696eb1db 100644
--- a/activesupport/lib/active_support/notifications.rb
+++ b/activesupport/lib/active_support/notifications.rb
@@ -44,8 +44,11 @@ module ActiveSupport
@instrumenters = Hash.new { |h,k| h[k] = notifier.listening?(k) }
class << self
- attr_writer :notifier
- delegate :publish, :to => :notifier
+ attr_accessor :notifier
+
+ def publish(name, *args)
+ notifier.publish(name, *args)
+ end
def instrument(name, payload = {})
if @instrumenters[name]
@@ -61,18 +64,16 @@ module ActiveSupport
end
end
- def unsubscribe(*args)
- notifier.unsubscribe(*args)
+ def unsubscribe(args)
+ notifier.unsubscribe(args)
@instrumenters.clear
end
- def notifier
- @notifier ||= Fanout.new
- end
-
def instrumenter
Thread.current[:"instrumentation_#{notifier.object_id}"] ||= Instrumenter.new(notifier)
end
end
+
+ self.notifier = Fanout.new
end
end
diff --git a/activesupport/lib/active_support/ordered_hash.rb b/activesupport/lib/active_support/ordered_hash.rb
index 2e8d538d0b..fbc40d1b69 100644
--- a/activesupport/lib/active_support/ordered_hash.rb
+++ b/activesupport/lib/active_support/ordered_hash.rb
@@ -1,3 +1,8 @@
+begin
+ require 'psych'
+rescue LoadError
+end
+
require 'yaml'
YAML.add_builtin_type("omap") do |type, val|
@@ -8,21 +13,29 @@ module ActiveSupport
# The order of iteration over hashes in Ruby 1.8 is undefined. For example, you do not know the
# order in which +keys+ will return keys, or +each+ yield pairs. <tt>ActiveSupport::OrderedHash</tt>
# implements a hash that preserves insertion order, as in Ruby 1.9:
- #
+ #
# oh = ActiveSupport::OrderedHash.new
# oh[:a] = 1
# oh[:b] = 2
# oh.keys # => [:a, :b], this order is guaranteed
- #
+ #
# <tt>ActiveSupport::OrderedHash</tt> is namespaced to prevent conflicts with other implementations.
class OrderedHash < ::Hash #:nodoc:
def to_yaml_type
"!tag:yaml.org,2002:omap"
end
+ def encode_with(coder)
+ coder.represent_seq '!omap', map { |k,v| { k => v } }
+ end
+
def to_yaml(opts = {})
+ if YAML.const_defined?(:ENGINE) && !YAML::ENGINE.syck?
+ return super
+ end
+
YAML.quick_emit(self, opts) do |out|
- out.seq(taguri, to_yaml_style) do |seq|
+ out.seq(taguri) do |seq|
each do |k, v|
seq.add(k => v)
end
@@ -79,7 +92,7 @@ module ActiveSupport
end
def []=(key, value)
- @keys << key if !has_key?(key)
+ @keys << key unless has_key?(key)
super
end
@@ -124,19 +137,27 @@ module ActiveSupport
end
def each_key
+ return to_enum(:each_key) unless block_given?
@keys.each { |key| yield key }
+ self
end
def each_value
+ return to_enum(:each_value) unless block_given?
@keys.each { |key| yield self[key]}
+ self
end
def each
+ return to_enum(:each) unless block_given?
@keys.each {|key| yield [key, self[key]]}
+ self
end
alias_method :each_pair, :each
+ alias_method :select, :find_all
+
def clear
super
@keys.clear
diff --git a/activesupport/lib/active_support/ordered_options.rb b/activesupport/lib/active_support/ordered_options.rb
index 7fc2b45b51..8d8e6ebc58 100644
--- a/activesupport/lib/active_support/ordered_options.rb
+++ b/activesupport/lib/active_support/ordered_options.rb
@@ -1,23 +1,26 @@
require 'active_support/ordered_hash'
# Usually key value pairs are handled something like this:
-#
-# h = ActiveSupport::OrderedOptions.new
+#
+# h = {}
# h[:boy] = 'John'
# h[:girl] = 'Mary'
# h[:boy] # => 'John'
# h[:girl] # => 'Mary'
-#
-# Using <tt>OrderedOptions</tt> above code could be reduced to:
+#
+# Using <tt>OrderedOptions</tt>, the above code could be reduced to:
#
# h = ActiveSupport::OrderedOptions.new
# h.boy = 'John'
# h.girl = 'Mary'
# h.boy # => 'John'
# h.girl # => 'Mary'
-#
+#
module ActiveSupport #:nodoc:
class OrderedOptions < OrderedHash
+ alias_method :_get, :[] # preserve the original #[] method
+ protected :_get # make it protected
+
def []=(key, value)
super(key.to_sym, value)
end
@@ -28,7 +31,7 @@ module ActiveSupport #:nodoc:
def method_missing(name, *args)
if name.to_s =~ /(.*)=$/
- self[$1.to_sym] = args.first
+ self[$1] = args.first
else
self[name]
end
@@ -36,8 +39,19 @@ module ActiveSupport #:nodoc:
end
class InheritableOptions < OrderedOptions
- def initialize(parent)
- super() { |h,k| parent[k] }
+ def initialize(parent = nil)
+ if parent.kind_of?(OrderedOptions)
+ # use the faster _get when dealing with OrderedOptions
+ super() { |h,k| parent._get(k) }
+ elsif parent
+ super() { |h,k| parent[k] }
+ else
+ super()
+ end
+ end
+
+ def inheritable_copy
+ self.class.new(self)
end
end
end
diff --git a/activesupport/lib/active_support/rescuable.rb b/activesupport/lib/active_support/rescuable.rb
index cd6f92cdfe..0f4a06468a 100644
--- a/activesupport/lib/active_support/rescuable.rb
+++ b/activesupport/lib/active_support/rescuable.rb
@@ -47,6 +47,7 @@ module ActiveSupport
# exception.record.new_record? ? ...
# end
# end
+ #
def rescue_from(*klasses, &block)
options = klasses.extract_options!
diff --git a/activesupport/lib/active_support/secure_random.rb b/activesupport/lib/active_support/secure_random.rb
index 73344498cb..368954907f 100644
--- a/activesupport/lib/active_support/secure_random.rb
+++ b/activesupport/lib/active_support/secure_random.rb
@@ -46,8 +46,10 @@ module ActiveSupport
# p SecureRandom.random_bytes(10) # => "\016\t{\370g\310pbr\301"
# p SecureRandom.random_bytes(10) # => "\323U\030TO\234\357\020\a\337"
# ...
+ #
module SecureRandom
- # SecureRandom.random_bytes generates a random binary string.
+
+ # Generates a random binary string.
#
# The argument n specifies the length of the result string.
#
@@ -56,6 +58,7 @@ module ActiveSupport
#
# If secure random number generator is not available,
# NotImplementedError is raised.
+ #
def self.random_bytes(n=nil)
n ||= 16
@@ -92,7 +95,7 @@ module ActiveSupport
end
end
- if !defined?(@has_win32)
+ unless defined?(@has_win32)
begin
require 'Win32API'
@@ -124,7 +127,7 @@ module ActiveSupport
raise NotImplementedError, "No random device"
end
- # SecureRandom.hex generates a random hex string.
+ # Generates a random hex string.
#
# The argument n specifies the length of the random length.
# The length of the result string is twice of n.
@@ -134,11 +137,12 @@ module ActiveSupport
#
# If secure random number generator is not available,
# NotImplementedError is raised.
+ #
def self.hex(n=nil)
random_bytes(n).unpack("H*")[0]
end
- # SecureRandom.base64 generates a random base64 string.
+ # Generates a random base64 string.
#
# The argument n specifies the length of the random length.
# The length of the result string is about 4/3 of n.
@@ -148,11 +152,12 @@ module ActiveSupport
#
# If secure random number generator is not available,
# NotImplementedError is raised.
+ #
def self.base64(n=nil)
[random_bytes(n)].pack("m*").delete("\n")
end
- # SecureRandom.random_number generates a random number.
+ # Generates a random number.
#
# If an positive integer is given as n,
# SecureRandom.random_number returns an integer:
@@ -161,6 +166,7 @@ module ActiveSupport
# If 0 is given or an argument is not given,
# SecureRandom.random_number returns an float:
# 0.0 <= SecureRandom.random_number() < 1.0.
+ #
def self.random_number(n=0)
if 0 < n
hex = n.to_s(16)
diff --git a/activesupport/lib/active_support/test_case.rb b/activesupport/lib/active_support/test_case.rb
index ed8c02ba3e..fb52fc7083 100644
--- a/activesupport/lib/active_support/test_case.rb
+++ b/activesupport/lib/active_support/test_case.rb
@@ -24,8 +24,7 @@ module ActiveSupport
else
Assertion = Test::Unit::AssertionFailedError
- require 'active_support/testing/default'
- include ActiveSupport::Testing::Default
+ undef :default_test
end
$tags = {}
diff --git a/activesupport/lib/active_support/testing/assertions.rb b/activesupport/lib/active_support/testing/assertions.rb
index 33793f0688..a4e0361a32 100644
--- a/activesupport/lib/active_support/testing/assertions.rb
+++ b/activesupport/lib/active_support/testing/assertions.rb
@@ -63,19 +63,21 @@ module ActiveSupport
def assert_no_difference(expression, message = nil, &block)
assert_difference expression, 0, message, &block
end
-
+
# Test if an expression is blank. Passes if object.blank? is true.
#
# assert_blank [] # => true
- def assert_blank(object)
- assert object.blank?, "#{object.inspect} is not blank"
+ def assert_blank(object, message=nil)
+ message ||= "#{object.inspect} is not blank"
+ assert object.blank?, message
end
-
+
# Test if an expression is not blank. Passes if object.present? is true.
#
# assert_present {:data => 'x' } # => true
- def assert_present(object)
- assert object.present?, "#{object.inspect} is blank"
+ def assert_present(object, message=nil)
+ message ||= "#{object.inspect} is blank"
+ assert object.present?, message
end
end
end
diff --git a/activesupport/lib/active_support/testing/declarative.rb b/activesupport/lib/active_support/testing/declarative.rb
index 70a6c2ca60..1c05d45888 100644
--- a/activesupport/lib/active_support/testing/declarative.rb
+++ b/activesupport/lib/active_support/testing/declarative.rb
@@ -1,10 +1,10 @@
module ActiveSupport
module Testing
module Declarative
-
+
def self.extended(klass)
klass.class_eval do
-
+
unless method_defined?(:describe)
def self.describe(text)
class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
@@ -14,9 +14,9 @@ module ActiveSupport
RUBY_EVAL
end
end
-
+
end
- end
+ end
unless defined?(Spec)
# test "verify something" do
diff --git a/activesupport/lib/active_support/testing/default.rb b/activesupport/lib/active_support/testing/default.rb
deleted file mode 100644
index a0bd6303c7..0000000000
--- a/activesupport/lib/active_support/testing/default.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-module ActiveSupport
- module Testing
- module Default #:nodoc:
- # Placeholder so test/unit ignores test cases without any tests.
- def default_test
- end
- end
- end
-end
diff --git a/activesupport/lib/active_support/testing/isolation.rb b/activesupport/lib/active_support/testing/isolation.rb
index d629f6f2b7..6b29ba4c10 100644
--- a/activesupport/lib/active_support/testing/isolation.rb
+++ b/activesupport/lib/active_support/testing/isolation.rb
@@ -34,7 +34,7 @@ module ActiveSupport
module Isolation
def self.forking_env?
- !ENV["NO_FORK"] && ((Config::CONFIG['host_os'] !~ /mswin|mingw/) && (RUBY_PLATFORM !~ /java/))
+ !ENV["NO_FORK"] && ((RbConfig::CONFIG['host_os'] !~ /mswin|mingw/) && (RUBY_PLATFORM !~ /java/))
end
def self.included(base)
diff --git a/activesupport/lib/active_support/testing/pending.rb b/activesupport/lib/active_support/testing/pending.rb
index 21134ff9e2..3d119e2fba 100644
--- a/activesupport/lib/active_support/testing/pending.rb
+++ b/activesupport/lib/active_support/testing/pending.rb
@@ -1,5 +1,5 @@
# Some code from jeremymcanally's "pending"
-# http://github.com/jeremymcanally/pending/tree/master
+# https://github.com/jeremymcanally/pending/tree/master
module ActiveSupport
module Testing
@@ -25,13 +25,13 @@ module ActiveSupport
failed = true
end
- flunk("<#{description}> did not fail.") unless failed
+ flunk("<#{description}> did not fail.") unless failed
end
caller[0] =~ (/(.*):(.*):in `(.*)'/)
@@pending_cases << "#{$3} at #{$1}, line #{$2}"
print "P"
-
+
@@at_exit ||= begin
at_exit do
puts "\nPending Cases:"
@@ -42,7 +42,7 @@ module ActiveSupport
end
end
end
-
+
end
end
-end \ No newline at end of file
+end
diff --git a/activesupport/lib/active_support/testing/performance.rb b/activesupport/lib/active_support/testing/performance.rb
index f7ddf6421d..8c91a061fb 100644
--- a/activesupport/lib/active_support/testing/performance.rb
+++ b/activesupport/lib/active_support/testing/performance.rb
@@ -58,16 +58,16 @@ begin
metric.send(mode) { __send__ @method_name }
rescue ::Test::Unit::AssertionFailedError => e
add_failure(e.message, e.backtrace)
- rescue StandardError, ScriptError
- add_error($!)
+ rescue StandardError, ScriptError => e
+ add_error(e)
ensure
begin
teardown
run_callbacks :teardown, :enumerator => :reverse_each
rescue ::Test::Unit::AssertionFailedError => e
add_failure(e.message, e.backtrace)
- rescue StandardError, ScriptError
- add_error($!)
+ rescue StandardError, ScriptError => e
+ add_error(e)
end
end
@@ -401,7 +401,7 @@ begin
Mode = RubyProf::GC_TIME if RubyProf.const_defined?(:GC_TIME)
# Ruby 1.9 with GC::Profiler
- if GC.respond_to?(:total_time)
+ if defined?(GC::Profiler) && GC::Profiler.respond_to?(:total_time)
def measure
GC::Profiler.total_time
end
diff --git a/activesupport/lib/active_support/testing/setup_and_teardown.rb b/activesupport/lib/active_support/testing/setup_and_teardown.rb
index b2d9ddfeb7..22e41fa905 100644
--- a/activesupport/lib/active_support/testing/setup_and_teardown.rb
+++ b/activesupport/lib/active_support/testing/setup_and_teardown.rb
@@ -31,14 +31,14 @@ module ActiveSupport
def run(runner)
result = '.'
begin
- _run_setup_callbacks do
+ run_callbacks :setup do
result = super
end
rescue Exception => e
result = runner.puke(self.class, method_name, e)
ensure
begin
- _run_teardown_callbacks
+ run_callbacks :teardown
rescue Exception => e
result = runner.puke(self.class, method_name, e)
end
@@ -62,7 +62,7 @@ module ActiveSupport
begin
begin
- _run_setup_callbacks do
+ run_callbacks :setup do
setup
__send__(@method_name)
mocha_verify(mocha_counter) if mocha_counter
@@ -77,7 +77,7 @@ module ActiveSupport
ensure
begin
teardown
- _run_teardown_callbacks
+ run_callbacks :teardown
rescue Test::Unit::AssertionFailedError => e
add_failure(e.message, e.backtrace)
rescue Exception => e
diff --git a/activesupport/lib/active_support/time_with_zone.rb b/activesupport/lib/active_support/time_with_zone.rb
index ad6c3de1f5..c66aa78ce8 100644
--- a/activesupport/lib/active_support/time_with_zone.rb
+++ b/activesupport/lib/active_support/time_with_zone.rb
@@ -18,7 +18,7 @@ module ActiveSupport
#
# See Time and TimeZone for further documentation of these methods.
#
- # TimeWithZone instances implement the same API as Ruby Time instances, so that Time and TimeWithZone instances are interchangeable.
+ # TimeWithZone instances implement the same API as Ruby Time instances, so that Time and TimeWithZone instances are interchangeable.
# Examples:
#
# t = Time.zone.now # => Sun, 18 May 2008 13:27:25 EDT -04:00
@@ -32,11 +32,12 @@ module ActiveSupport
# t > Time.utc(1999) # => true
# t.is_a?(Time) # => true
# t.is_a?(ActiveSupport::TimeWithZone) # => true
+ #
class TimeWithZone
def self.name
'Time' # Report class name as 'Time' to thwart type checking
end
-
+
include Comparable
attr_reader :time_zone
@@ -72,7 +73,7 @@ module ActiveSupport
# Returns a <tt>Time.local()</tt> instance of the simultaneous time in your system's <tt>ENV['TZ']</tt> zone
def localtime
- utc.getlocal
+ utc.respond_to?(:getlocal) ? utc.getlocal : utc.to_time.getlocal
end
alias_method :getlocal, :localtime
@@ -127,6 +128,7 @@ module ActiveSupport
# # With ActiveSupport::JSON::Encoding.use_standard_json_time_format = false
# Time.utc(2005,2,1,15,15,10).in_time_zone.to_json
# # => "2005/02/01 15:15:10 +0000"
+ #
def as_json(options = nil)
if ActiveSupport::JSON::Encoding.use_standard_json_time_format
xmlschema
@@ -135,14 +137,20 @@ module ActiveSupport
end
end
- def to_yaml(options = {})
- if options.kind_of?(YAML::Emitter)
- utc.to_yaml(options)
+ def encode_with(coder)
+ if coder.respond_to?(:represent_object)
+ coder.represent_object(nil, utc)
else
- time.to_yaml(options).gsub('Z', formatted_offset(true, 'Z'))
+ coder.represent_scalar(nil, utc.strftime("%Y-%m-%d %H:%M:%S.%9NZ"))
end
end
+ def to_yaml(options = {})
+ return super if defined?(YAML::ENGINE) && !YAML::ENGINE.syck?
+
+ utc.to_yaml(options)
+ end
+
def httpdate
utc.httpdate
end
@@ -273,7 +281,7 @@ module ActiveSupport
# A TimeWithZone acts like a Time, so just return +self+.
def to_time
- self
+ utc
end
def to_datetime
diff --git a/activesupport/lib/active_support/version.rb b/activesupport/lib/active_support/version.rb
index 9d2cf13260..690fc7f0fc 100644
--- a/activesupport/lib/active_support/version.rb
+++ b/activesupport/lib/active_support/version.rb
@@ -1,10 +1,10 @@
module ActiveSupport
module VERSION #:nodoc:
MAJOR = 3
- MINOR = 0
+ MINOR = 1
TINY = 0
- BUILD = "rc"
+ PRE = "beta"
- STRING = [MAJOR, MINOR, TINY, BUILD].join('.')
+ STRING = [MAJOR, MINOR, TINY, PRE].compact.join('.')
end
end
diff --git a/activesupport/lib/active_support/whiny_nil.rb b/activesupport/lib/active_support/whiny_nil.rb
index 91ddef2619..bcedbfd57a 100644
--- a/activesupport/lib/active_support/whiny_nil.rb
+++ b/activesupport/lib/active_support/whiny_nil.rb
@@ -37,7 +37,7 @@ class NilClass
# Raises a RuntimeError when you attempt to call +id+ on +nil+.
def id
- raise RuntimeError, "Called id for nil, which would mistakenly be 4 -- if you really wanted the id of nil, use object_id", caller
+ raise RuntimeError, "Called id for nil, which would mistakenly be #{object_id} -- if you really wanted the id of nil, use object_id", caller
end
private
diff --git a/activesupport/lib/active_support/xml_mini.rb b/activesupport/lib/active_support/xml_mini.rb
index 352172027b..cddfcddb57 100644
--- a/activesupport/lib/active_support/xml_mini.rb
+++ b/activesupport/lib/active_support/xml_mini.rb
@@ -25,7 +25,7 @@ module ActiveSupport
DEFAULT_ENCODINGS = {
"binary" => "base64"
- } unless defined?(TYPE_NAMES)
+ } unless defined?(DEFAULT_ENCODINGS)
TYPE_NAMES = {
"Symbol" => "symbol",
@@ -126,9 +126,11 @@ module ActiveSupport
end
def rename_key(key, options = {})
- camelize = options.has_key?(:camelize) && options[:camelize]
+ camelize = options[:camelize]
dasherize = !options.has_key?(:dasherize) || options[:dasherize]
- key = key.camelize if camelize
+ if camelize
+ key = true == camelize ? key.camelize : key.camelize(camelize)
+ end
key = _dasherize(key) if dasherize
key
end
diff --git a/activesupport/lib/active_support/xml_mini/libxml.rb b/activesupport/lib/active_support/xml_mini/libxml.rb
index 7fdcb11465..16570c6aea 100644
--- a/activesupport/lib/active_support/xml_mini/libxml.rb
+++ b/activesupport/lib/active_support/xml_mini/libxml.rb
@@ -1,5 +1,6 @@
require 'libxml'
require 'active_support/core_ext/object/blank'
+require 'stringio'
# = XmlMini LibXML implementation
module ActiveSupport
diff --git a/activesupport/lib/active_support/xml_mini/libxmlsax.rb b/activesupport/lib/active_support/xml_mini/libxmlsax.rb
index fe2c1b9349..2536b1f33e 100644
--- a/activesupport/lib/active_support/xml_mini/libxmlsax.rb
+++ b/activesupport/lib/active_support/xml_mini/libxmlsax.rb
@@ -1,5 +1,6 @@
require 'libxml'
require 'active_support/core_ext/object/blank'
+require 'stringio'
# = XmlMini LibXML implementation using a SAX-based parser
module ActiveSupport
@@ -82,4 +83,4 @@ module ActiveSupport
end
end
end
-end \ No newline at end of file
+end
diff --git a/activesupport/lib/active_support/xml_mini/nokogiri.rb b/activesupport/lib/active_support/xml_mini/nokogiri.rb
index e03a744257..04ec9e8ab8 100644
--- a/activesupport/lib/active_support/xml_mini/nokogiri.rb
+++ b/activesupport/lib/active_support/xml_mini/nokogiri.rb
@@ -5,6 +5,7 @@ rescue LoadError => e
raise e
end
require 'active_support/core_ext/object/blank'
+require 'stringio'
# = XmlMini Nokogiri implementation
module ActiveSupport
diff --git a/activesupport/lib/active_support/xml_mini/nokogirisax.rb b/activesupport/lib/active_support/xml_mini/nokogirisax.rb
index 38c8685390..93fd3dfe57 100644
--- a/activesupport/lib/active_support/xml_mini/nokogirisax.rb
+++ b/activesupport/lib/active_support/xml_mini/nokogirisax.rb
@@ -5,6 +5,7 @@ rescue LoadError => e
raise e
end
require 'active_support/core_ext/object/blank'
+require 'stringio'
# = XmlMini Nokogiri implementation using a SAX-based parser
module ActiveSupport
@@ -38,8 +39,7 @@ module ActiveSupport
end
def start_element(name, attrs = [])
- new_hash = { CONTENT_KEY => '' }
- new_hash[attrs.shift] = attrs.shift while attrs.length > 0
+ new_hash = { CONTENT_KEY => '' }.merge(Hash[attrs])
new_hash[HASH_SIZE_KEY] = new_hash.size + 1
case current_hash[name]
diff --git a/activesupport/lib/active_support/xml_mini/rexml.rb b/activesupport/lib/active_support/xml_mini/rexml.rb
index a58f22ee5d..a13ad10118 100644
--- a/activesupport/lib/active_support/xml_mini/rexml.rb
+++ b/activesupport/lib/active_support/xml_mini/rexml.rb
@@ -1,5 +1,6 @@
require 'active_support/core_ext/kernel/reporting'
require 'active_support/core_ext/object/blank'
+require 'stringio'
# = XmlMini ReXML implementation
module ActiveSupport
@@ -19,7 +20,7 @@ module ActiveSupport
if !data.respond_to?(:read)
data = StringIO.new(data || '')
end
-
+
char = data.getc
if char.nil?
{}
diff --git a/activesupport/test/abstract_unit.rb b/activesupport/test/abstract_unit.rb
index 6db21f9e12..0382739871 100644
--- a/activesupport/test/abstract_unit.rb
+++ b/activesupport/test/abstract_unit.rb
@@ -10,8 +10,19 @@ end
lib = File.expand_path("#{File.dirname(__FILE__)}/../lib")
$:.unshift(lib) unless $:.include?('lib') || $:.include?(lib)
-require 'test/unit'
require 'active_support/core_ext/kernel/reporting'
+
+require 'active_support/core_ext/string/encoding'
+if "ruby".encoding_aware?
+ # These are the normal settings that will be set up by Railties
+ # TODO: Have these tests support other combinations of these values
+ silence_warnings do
+ Encoding.default_internal = "UTF-8"
+ Encoding.default_external = "UTF-8"
+ end
+end
+
+require 'test/unit'
require 'empty_bool'
silence_warnings { require 'mocha' }
diff --git a/activesupport/test/autoloading_fixtures/class_folder/nested_class.rb b/activesupport/test/autoloading_fixtures/class_folder/nested_class.rb
index 77ea230d2c..57a13d89ea 100644
--- a/activesupport/test/autoloading_fixtures/class_folder/nested_class.rb
+++ b/activesupport/test/autoloading_fixtures/class_folder/nested_class.rb
@@ -1,7 +1,7 @@
class ClassFolder
class NestedClass
end
-
+
class SiblingClass
end
end
diff --git a/activesupport/test/buffered_logger_test.rb b/activesupport/test/buffered_logger_test.rb
index 97c0ef14db..8d1b1c02c6 100644
--- a/activesupport/test/buffered_logger_test.rb
+++ b/activesupport/test/buffered_logger_test.rb
@@ -115,11 +115,9 @@ class BufferedLoggerTest < Test::Unit::TestCase
def test_should_create_the_log_directory_if_it_doesnt_exist
tmp_directory = File.join(File.dirname(__FILE__), "tmp")
log_file = File.join(tmp_directory, "development.log")
- assert !File.exist?(tmp_directory)
+ FileUtils.rm_rf(tmp_directory)
@logger = Logger.new(log_file)
assert File.exist?(tmp_directory)
- ensure
- FileUtils.rm_rf(tmp_directory)
end
def test_logger_should_maintain_separate_buffers_for_each_thread
diff --git a/activesupport/test/caching_test.rb b/activesupport/test/caching_test.rb
index b79a7bbaec..e5668e29d7 100644
--- a/activesupport/test/caching_test.rb
+++ b/activesupport/test/caching_test.rb
@@ -356,9 +356,13 @@ module CacheDeleteMatchedBehavior
def test_delete_matched
@cache.write("foo", "bar")
@cache.write("fu", "baz")
+ @cache.write("foo/bar", "baz")
+ @cache.write("fu/baz", "bar")
@cache.delete_matched(/oo/)
assert_equal false, @cache.exist?("foo")
assert_equal true, @cache.exist?("fu")
+ assert_equal false, @cache.exist?("foo/bar")
+ assert_equal true, @cache.exist?("fu/baz")
end
end
@@ -509,6 +513,11 @@ class FileStoreTest < ActiveSupport::TestCase
assert_nil old_cache.read('foo')
end
end
+
+ def test_key_transformation
+ key = @cache.send(:key_file_path, "views/index?id=1")
+ assert_equal "views/index?id=1", @cache.send(:file_path_key, key)
+ end
end
class MemoryStoreTest < ActiveSupport::TestCase
@@ -649,12 +658,12 @@ class CacheStoreLoggerTest < ActiveSupport::TestCase
def test_logging
@cache.fetch('foo') { 'bar' }
- assert @buffer.string.present?
+ assert_present @buffer.string
end
def test_mute_logging
@cache.mute { @cache.fetch('foo') { 'bar' } }
- assert @buffer.string.blank?
+ assert_blank @buffer.string
end
end
@@ -670,12 +679,12 @@ class CacheEntryTest < ActiveSupport::TestCase
def test_expired
entry = ActiveSupport::Cache::Entry.new("value")
- assert_equal false, entry.expired?
+ assert !entry.expired?, 'entry not expired'
entry = ActiveSupport::Cache::Entry.new("value", :expires_in => 60)
- assert_equal false, entry.expired?
+ assert !entry.expired?, 'entry not expired'
time = Time.now + 61
Time.stubs(:now).returns(time)
- assert_equal true, entry.expired?
+ assert entry.expired?, 'entry is expired'
end
def test_compress_values
diff --git a/activesupport/test/callback_inheritance_test.rb b/activesupport/test/callback_inheritance_test.rb
index 8caf000c5d..d569cbb4fb 100644
--- a/activesupport/test/callback_inheritance_test.rb
+++ b/activesupport/test/callback_inheritance_test.rb
@@ -70,7 +70,7 @@ class EmptyParent
end
def dispatch
- _run_dispatch_callbacks
+ run_callbacks :dispatch
self
end
end
@@ -82,6 +82,30 @@ class EmptyChild < EmptyParent
end
end
+class CountingParent
+ include ActiveSupport::Callbacks
+
+ attr_reader :count
+
+ define_callbacks :dispatch
+
+ def initialize
+ @count = 0
+ end
+
+ def count!
+ @count += 1
+ end
+
+ def dispatch
+ run_callbacks(:dispatch)
+ self
+ end
+end
+
+class CountingChild < CountingParent
+end
+
class BasicCallbacksTest < Test::Unit::TestCase
def setup
@index = GrandParent.new("index").dispatch
@@ -147,4 +171,10 @@ class DynamicInheritedCallbacks < Test::Unit::TestCase
child = EmptyChild.new.dispatch
assert child.performed?
end
+
+ def test_callbacks_should_be_performed_once_in_child_class
+ CountingParent.set_callback(:dispatch, :before) { count! }
+ child = CountingChild.new.dispatch
+ assert_equal 1, child.count
+ end
end
diff --git a/activesupport/test/callbacks_test.rb b/activesupport/test/callbacks_test.rb
index 70a2950f9b..816dcad968 100644
--- a/activesupport/test/callbacks_test.rb
+++ b/activesupport/test/callbacks_test.rb
@@ -3,6 +3,27 @@ require 'test/unit'
require 'active_support'
module CallbacksTest
+ class Phone
+ include ActiveSupport::Callbacks
+ define_callbacks :save, :rescuable => true
+
+ set_callback :save, :before, :before_save1
+ set_callback :save, :after, :after_save1
+
+ def before_save1; self.history << :before; end
+ def after_save1; self.history << :after; end
+
+ def save
+ run_callbacks :save do
+ raise 'boom'
+ end
+ end
+
+ def history
+ @history ||= []
+ end
+ end
+
class Record
include ActiveSupport::Callbacks
@@ -149,6 +170,27 @@ module CallbacksTest
end
end
+ class AfterSaveConditionalPerson < Record
+ after_save Proc.new { |r| r.history << [:after_save, :string1] }
+ after_save Proc.new { |r| r.history << [:after_save, :string2] }
+ def save
+ run_callbacks :save
+ end
+ end
+
+ class AfterSaveConditionalPersonCallbackTest < Test::Unit::TestCase
+ def test_after_save_runs_in_the_reverse_order
+ person = AfterSaveConditionalPerson.new
+ person.save
+ assert_equal [
+ [:after_save, :string2],
+ [:after_save, :string1]
+ ], person.history
+ end
+ end
+
+
+
class ConditionalPerson < Record
# proc
before_save Proc.new { |r| r.history << [:before_save, :proc] }, :if => Proc.new { |r| true }
@@ -257,6 +299,32 @@ module CallbacksTest
end
end
end
+
+ class AroundPersonResult < MySuper
+ attr_reader :result
+
+ set_callback :save, :after, :tweedle_1
+ set_callback :save, :around, :tweedle_dum
+ set_callback :save, :after, :tweedle_2
+
+ def tweedle_dum
+ @result = yield
+ end
+
+ def tweedle_1
+ :tweedle_1
+ end
+
+ def tweedle_2
+ :tweedle_2
+ end
+
+ def save
+ run_callbacks :save do
+ :running
+ end
+ end
+ end
class HyphenatedCallbacks
include ActiveSupport::Callbacks
@@ -296,6 +364,14 @@ module CallbacksTest
], around.history
end
end
+
+ class AroundCallbackResultTest < Test::Unit::TestCase
+ def test_save_around
+ around = AroundPersonResult.new
+ around.save
+ assert_equal :running, around.result
+ end
+ end
class SkipCallbacksTest < Test::Unit::TestCase
def test_skip_person
@@ -317,6 +393,14 @@ module CallbacksTest
end
class CallbacksTest < Test::Unit::TestCase
+ def test_save_phone
+ phone = Phone.new
+ assert_raise RuntimeError do
+ phone.save
+ end
+ assert_equal [:before, :after], phone.history
+ end
+
def test_save_person
person = Person.new
assert_equal [], person.history
@@ -352,6 +436,8 @@ module CallbacksTest
end
end
+
+
class ResetCallbackTest < Test::Unit::TestCase
def test_save_conditional_person
person = CleanPerson.new
@@ -524,4 +610,31 @@ module CallbacksTest
assert_equal "ACTION", obj.stuff
end
end
+
+ class WriterSkipper < Person
+ attr_accessor :age
+ skip_callback :save, :before, :before_save_method, :if => lambda {self.age > 21}
+ end
+
+ class WriterCallbacksTest < Test::Unit::TestCase
+ def test_skip_writer
+ writer = WriterSkipper.new
+ writer.age = 18
+ assert_equal [], writer.history
+ writer.save
+ assert_equal [
+ [:before_save, :symbol],
+ [:before_save, :string],
+ [:before_save, :proc],
+ [:before_save, :object],
+ [:before_save, :block],
+ [:after_save, :block],
+ [:after_save, :object],
+ [:after_save, :proc],
+ [:after_save, :string],
+ [:after_save, :symbol]
+ ], writer.history
+ end
+ end
+
end
diff --git a/activesupport/test/class_cache_test.rb b/activesupport/test/class_cache_test.rb
new file mode 100644
index 0000000000..8445af8d25
--- /dev/null
+++ b/activesupport/test/class_cache_test.rb
@@ -0,0 +1,108 @@
+require 'abstract_unit'
+require 'active_support/dependencies'
+
+module ActiveSupport
+ module Dependencies
+ class ClassCacheTest < ActiveSupport::TestCase
+ def setup
+ @cache = ClassCache.new
+ end
+
+ def test_empty?
+ assert @cache.empty?
+ @cache[ClassCacheTest] = ClassCacheTest
+ assert !@cache.empty?
+ end
+
+ def test_clear!
+ assert @cache.empty?
+ @cache[ClassCacheTest] = ClassCacheTest
+ assert !@cache.empty?
+ @cache.clear!
+ assert @cache.empty?
+ end
+
+ def test_set_key
+ @cache[ClassCacheTest] = ClassCacheTest
+ assert @cache.key?(ClassCacheTest.name)
+ end
+
+ def test_set_rejects_strings
+ @cache[ClassCacheTest.name] = ClassCacheTest
+ assert @cache.empty?
+ end
+
+ def test_get_with_class
+ @cache[ClassCacheTest] = ClassCacheTest
+ assert_equal ClassCacheTest, @cache[ClassCacheTest]
+ end
+
+ def test_get_with_name
+ @cache[ClassCacheTest] = ClassCacheTest
+ assert_equal ClassCacheTest, @cache[ClassCacheTest.name]
+ end
+
+ def test_get_constantizes
+ assert @cache.empty?
+ assert_equal ClassCacheTest, @cache[ClassCacheTest.name]
+ end
+
+ def test_get_is_an_alias
+ assert_equal @cache[ClassCacheTest], @cache.get(ClassCacheTest.name)
+ end
+
+ def test_new
+ assert_deprecated do
+ @cache.new ClassCacheTest
+ end
+ assert @cache.key?(ClassCacheTest.name)
+ end
+
+ def test_new_rejects_strings
+ assert_deprecated do
+ @cache.new ClassCacheTest.name
+ end
+ assert !@cache.key?(ClassCacheTest.name)
+ end
+
+ def test_new_rejects_strings
+ @cache.store ClassCacheTest.name
+ assert !@cache.key?(ClassCacheTest.name)
+ end
+
+ def test_store_returns_self
+ x = @cache.store ClassCacheTest
+ assert_equal @cache, x
+ end
+
+ def test_new_returns_proxy
+ v = nil
+ assert_deprecated do
+ v = @cache.new ClassCacheTest.name
+ end
+
+ assert_deprecated do
+ assert_equal ClassCacheTest, v.get
+ end
+ end
+
+ def test_anonymous_class_fail
+ assert_raises(ArgumentError) do
+ assert_deprecated do
+ @cache.new Class.new
+ end
+ end
+
+ assert_raises(ArgumentError) do
+ x = Class.new
+ @cache[x] = x
+ end
+
+ assert_raises(ArgumentError) do
+ x = Class.new
+ @cache.store x
+ end
+ end
+ end
+ end
+end
diff --git a/activesupport/test/clean_backtrace_test.rb b/activesupport/test/clean_backtrace_test.rb
index 86838a7f9a..32e346bb48 100644
--- a/activesupport/test/clean_backtrace_test.rb
+++ b/activesupport/test/clean_backtrace_test.rb
@@ -5,7 +5,7 @@ class BacktraceCleanerFilterTest < ActiveSupport::TestCase
@bc = ActiveSupport::BacktraceCleaner.new
@bc.add_filter { |line| line.gsub("/my/prefix", '') }
end
-
+
test "backtrace should not contain prefix when it has been filtered out" do
assert_equal "/my/class.rb", @bc.clean([ "/my/prefix/my/class.rb" ]).first
end
@@ -14,14 +14,14 @@ class BacktraceCleanerFilterTest < ActiveSupport::TestCase
@bc.remove_filters!
assert_equal "/my/prefix/my/class.rb", @bc.clean(["/my/prefix/my/class.rb"]).first
end
-
+
test "backtrace should contain unaltered lines if they dont match a filter" do
assert_equal "/my/other_prefix/my/class.rb", @bc.clean([ "/my/other_prefix/my/class.rb" ]).first
end
-
+
test "backtrace should filter all lines in a backtrace" do
assert_equal \
- ["/my/class.rb", "/my/module.rb"],
+ ["/my/class.rb", "/my/module.rb"],
@bc.clean([ "/my/prefix/my/class.rb", "/my/prefix/my/module.rb" ])
end
end
@@ -31,10 +31,10 @@ class BacktraceCleanerSilencerTest < ActiveSupport::TestCase
@bc = ActiveSupport::BacktraceCleaner.new
@bc.add_silencer { |line| line =~ /mongrel/ }
end
-
+
test "backtrace should not contain lines that match the silencer" do
assert_equal \
- [ "/other/class.rb" ],
+ [ "/other/class.rb" ],
@bc.clean([ "/mongrel/class.rb", "/other/class.rb", "/mongrel/stuff.rb" ])
end
end
@@ -45,7 +45,7 @@ class BacktraceCleanerFilterAndSilencerTest < ActiveSupport::TestCase
@bc.add_filter { |line| line.gsub("/mongrel", "") }
@bc.add_silencer { |line| line =~ /mongrel/ }
end
-
+
test "backtrace should not silence lines that has first had their silence hook filtered out" do
assert_equal [ "/class.rb" ], @bc.clean([ "/mongrel/class.rb" ])
end
diff --git a/activesupport/test/clean_logger_test.rb b/activesupport/test/clean_logger_test.rb
index 6c4ec5ac46..2cc46904b4 100644
--- a/activesupport/test/clean_logger_test.rb
+++ b/activesupport/test/clean_logger_test.rb
@@ -41,7 +41,7 @@ class CleanLoggerTest < Test::Unit::TestCase
assert_equal "error\nfatal\nerror\nfatal\nunsilenced\n", @out.string
end
-
+
def test_datetime_format
@logger.formatter = Logger::Formatter.new
@logger.datetime_format = "%Y-%m-%d"
@@ -49,7 +49,7 @@ class CleanLoggerTest < Test::Unit::TestCase
assert_equal "%Y-%m-%d", @logger.datetime_format
assert_match(/D, \[\d\d\d\d-\d\d-\d\d#\d+\] DEBUG -- : debug/, @out.string)
end
-
+
def test_nonstring_formatting
an_object = [1, 2, 3, 4, 5]
@logger.debug an_object
diff --git a/activesupport/test/configurable_test.rb b/activesupport/test/configurable_test.rb
index cef67e3cf9..2b28e61815 100644
--- a/activesupport/test/configurable_test.rb
+++ b/activesupport/test/configurable_test.rb
@@ -21,6 +21,12 @@ class ConfigurableActiveSupport < ActiveSupport::TestCase
assert_equal({ :foo => :bar }, Parent.config)
end
+ test "adds a configuration hash to a module as well" do
+ mixin = Module.new { include ActiveSupport::Configurable }
+ mixin.config.foo = :bar
+ assert_equal({ :foo => :bar }, mixin.config)
+ end
+
test "configuration hash is inheritable" do
assert_equal :bar, Child.config.foo
assert_equal :bar, Parent.config.foo
@@ -39,4 +45,22 @@ class ConfigurableActiveSupport < ActiveSupport::TestCase
assert_equal :baz, instance.config.foo
assert_equal :bar, Parent.config.foo
end
-end \ No newline at end of file
+
+ test "configuration is crystalizeable" do
+ parent = Class.new { include ActiveSupport::Configurable }
+ child = Class.new(parent)
+
+ parent.config.bar = :foo
+ assert !parent.config.respond_to?(:bar)
+ assert !child.config.respond_to?(:bar)
+ assert !child.new.config.respond_to?(:bar)
+
+ parent.config.compile_methods!
+ assert_equal :foo, parent.config.bar
+ assert_equal :foo, child.new.config.bar
+
+ assert_respond_to parent.config, :bar
+ assert_respond_to child.config, :bar
+ assert_respond_to child.new.config, :bar
+ end
+end
diff --git a/activesupport/test/core_ext/array_ext_test.rb b/activesupport/test/core_ext/array_ext_test.rb
index 009a254c64..d7ab3ce605 100644
--- a/activesupport/test/core_ext/array_ext_test.rb
+++ b/activesupport/test/core_ext/array_ext_test.rb
@@ -18,10 +18,10 @@ class ArrayExtAccessTests < Test::Unit::TestCase
assert_equal %w( a b c ), %w( a b c d ).to(2)
assert_equal %w( a b c d ), %w( a b c d ).to(10)
end
-
+
def test_second_through_tenth
array = (1..42).to_a
-
+
assert_equal array[1], array.second
assert_equal array[2], array.third
assert_equal array[3], array.fourth
@@ -82,6 +82,11 @@ class ArrayExtToSentenceTests < Test::Unit::TestCase
assert_equal "one", ['one'].to_sentence
end
+ def test_one_element_not_same_object
+ elements = ["one"]
+ assert_not_equal elements[0].object_id, elements.to_sentence.object_id
+ end
+
def test_one_non_string_element
assert_equal '1', [1].to_sentence
end
@@ -319,7 +324,7 @@ class ArrayExtractOptionsTests < Test::Unit::TestCase
assert_equal({}, options)
assert_equal [hash], array
end
-
+
def test_extract_options_extracts_extractable_subclass
hash = ExtractableHashSubclass.new
hash[:foo] = 1
@@ -370,14 +375,14 @@ class ArrayExtRandomTests < ActiveSupport::TestCase
assert_equal 2, s.size
assert_equal 1, (a-s).size
assert_equal [], a-(0..20).sum{a.sample(2)}
-
+
o = Object.new
def o.to_int; 1; end
assert_equal [0], [0].sample(o)
-
+
o = Object.new
assert_raises(TypeError) { [0].sample(o) }
-
+
o = Object.new
def o.to_int; ''; end
assert_raises(TypeError) { [0].sample(o) }
diff --git a/activesupport/test/core_ext/bigdecimal.rb b/activesupport/test/core_ext/bigdecimal.rb
deleted file mode 100644
index 9faad9146f..0000000000
--- a/activesupport/test/core_ext/bigdecimal.rb
+++ /dev/null
@@ -1,10 +0,0 @@
-require 'abstract_unit'
-
-class BigDecimalTest < Test::Unit::TestCase
- def test_to_yaml
- assert_equal("--- 100000.30020320320000000000000000000000000000001\n", BigDecimal.new('100000.30020320320000000000000000000000000000001').to_yaml)
- assert_equal("--- .Inf\n", BigDecimal.new('Infinity').to_yaml)
- assert_equal("--- .NaN\n", BigDecimal.new('NaN').to_yaml)
- assert_equal("--- -.Inf\n", BigDecimal.new('-Infinity').to_yaml)
- end
-end \ No newline at end of file
diff --git a/activesupport/test/core_ext/bigdecimal_test.rb b/activesupport/test/core_ext/bigdecimal_test.rb
new file mode 100644
index 0000000000..b38e08a9f4
--- /dev/null
+++ b/activesupport/test/core_ext/bigdecimal_test.rb
@@ -0,0 +1,17 @@
+require 'abstract_unit'
+require 'bigdecimal'
+require 'active_support/core_ext/big_decimal'
+
+class BigDecimalTest < Test::Unit::TestCase
+ def test_to_yaml
+ assert_match("--- 100000.30020320320000000000000000000000000000001\n", BigDecimal.new('100000.30020320320000000000000000000000000000001').to_yaml)
+ assert_match("--- .Inf\n", BigDecimal.new('Infinity').to_yaml)
+ assert_match("--- .NaN\n", BigDecimal.new('NaN').to_yaml)
+ assert_match("--- -.Inf\n", BigDecimal.new('-Infinity').to_yaml)
+ end
+
+ def test_to_d
+ bd = BigDecimal.new '10'
+ assert_equal bd, bd.to_d
+ end
+end
diff --git a/activesupport/test/core_ext/cgi_ext_test.rb b/activesupport/test/core_ext/cgi_ext_test.rb
deleted file mode 100644
index c80362e382..0000000000
--- a/activesupport/test/core_ext/cgi_ext_test.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-require 'abstract_unit'
-require 'active_support/core_ext/cgi'
-
-class EscapeSkippingSlashesTest < Test::Unit::TestCase
- def test_array
- assert_equal 'hello/world', CGI.escape_skipping_slashes(%w(hello world))
- assert_equal 'hello+world/how/are/you', CGI.escape_skipping_slashes(['hello world', 'how', 'are', 'you'])
- end
-
- def test_typical
- assert_equal 'hi', CGI.escape_skipping_slashes('hi')
- assert_equal 'hi/world', CGI.escape_skipping_slashes('hi/world')
- assert_equal 'hi/world+you+funky+thing', CGI.escape_skipping_slashes('hi/world you funky thing')
- end
-end
diff --git a/activesupport/test/core_ext/class/attribute_accessor_test.rb b/activesupport/test/core_ext/class/attribute_accessor_test.rb
index 2c896d0cdb..456f4b7948 100644
--- a/activesupport/test/core_ext/class/attribute_accessor_test.rb
+++ b/activesupport/test/core_ext/class/attribute_accessor_test.rb
@@ -10,27 +10,27 @@ class ClassAttributeAccessorTest < Test::Unit::TestCase
end
@object = @class.new
end
-
+
def test_should_use_mattr_default
assert_nil @class.foo
assert_nil @object.foo
end
-
+
def test_should_set_mattr_value
@class.foo = :test
assert_equal :test, @object.foo
-
+
@object.foo = :test2
assert_equal :test2, @class.foo
end
-
+
def test_should_not_create_instance_writer
assert_respond_to @class, :foo
assert_respond_to @class, :foo=
assert_respond_to @object, :bar
assert !@object.respond_to?(:bar=)
end
-
+
def test_should_not_create_instance_reader
assert_respond_to @class, :shaq
assert !@object.respond_to?(:shaq)
diff --git a/activesupport/test/core_ext/class/attribute_test.rb b/activesupport/test/core_ext/class/attribute_test.rb
index 24aa5c0eba..d58b60482b 100644
--- a/activesupport/test/core_ext/class/attribute_test.rb
+++ b/activesupport/test/core_ext/class/attribute_test.rb
@@ -65,4 +65,9 @@ class ClassAttributeTest < ActiveSupport::TestCase
object.singleton_class.setting = 'foo'
assert_equal 'foo', object.setting
end
+
+ test 'setter returns set value' do
+ val = @klass.send(:setting=, 1)
+ assert_equal 1, val
+ end
end
diff --git a/activesupport/test/core_ext/class/class_inheritable_attributes_test.rb b/activesupport/test/core_ext/class/class_inheritable_attributes_test.rb
index 63ea46b564..020dfce56a 100644
--- a/activesupport/test/core_ext/class/class_inheritable_attributes_test.rb
+++ b/activesupport/test/core_ext/class/class_inheritable_attributes_test.rb
@@ -3,9 +3,14 @@ require 'active_support/core_ext/class/inheritable_attributes'
class ClassInheritableAttributesTest < Test::Unit::TestCase
def setup
+ ActiveSupport::Deprecation.silenced = true
@klass = Class.new
end
+ def teardown
+ ActiveSupport::Deprecation.silenced = false
+ end
+
def test_reader_declaration
assert_nothing_raised do
@klass.class_inheritable_reader :a
@@ -21,7 +26,7 @@ class ClassInheritableAttributesTest < Test::Unit::TestCase
assert_respond_to @klass.new, :a=
end
end
-
+
def test_writer_declaration_without_instance_writer
assert_nothing_raised do
@klass.class_inheritable_writer :a, :instance_writer => false
@@ -39,7 +44,7 @@ class ClassInheritableAttributesTest < Test::Unit::TestCase
assert_respond_to @klass.new, :a=
end
end
-
+
def test_accessor_declaration_without_instance_writer
assert_nothing_raised do
@klass.class_inheritable_accessor :a, :instance_writer => false
@@ -176,37 +181,37 @@ class ClassInheritableAttributesTest < Test::Unit::TestCase
assert_equal 'b', @klass.b
assert_equal 'B', @sub.b
end
-
+
def test_array_inheritance
@klass.class_inheritable_accessor :a
@klass.a = []
@sub = eval("class SubbyArray < @klass; end; SubbyArray")
-
+
assert_equal [], @klass.a
assert_equal [], @sub.a
-
+
@sub.a << :first
-
+
assert_equal [:first], @sub.a
assert_equal [], @klass.a
end
-
+
def test_array_inheritance_
@klass.class_inheritable_accessor :a
@klass.a = {}
@sub = eval("class SubbyHash < @klass; end; SubbyHash")
-
+
assert_equal Hash.new, @klass.a
assert_equal Hash.new, @sub.a
-
+
@sub.a[:first] = :first
-
+
assert_equal 1, @sub.a.keys.size
assert_equal 0, @klass.a.keys.size
end
-
+
def test_reset_inheritable_attributes
@klass.class_inheritable_accessor :a
@klass.a = 'a'
diff --git a/activesupport/test/core_ext/date_ext_test.rb b/activesupport/test/core_ext/date_ext_test.rb
index 59c168d33d..d81693209f 100644
--- a/activesupport/test/core_ext/date_ext_test.rb
+++ b/activesupport/test/core_ext/date_ext_test.rb
@@ -26,7 +26,7 @@ class DateExtCalculationsTest < ActiveSupport::TestCase
assert_equal year, Date.new(year).to_time(format).year
end
end
- end
+ end
end
def test_to_datetime
@@ -110,6 +110,14 @@ class DateExtCalculationsTest < ActiveSupport::TestCase
assert_equal Date.new(2005,1,1).to_s, Date.new(2005,2,22).beginning_of_year.to_s
end
+ def test_weeks_ago
+ assert_equal Date.new(2005,5,10), Date.new(2005,5,17).weeks_ago(1)
+ assert_equal Date.new(2005,5,10), Date.new(2005,5,24).weeks_ago(2)
+ assert_equal Date.new(2005,5,10), Date.new(2005,5,31).weeks_ago(3)
+ assert_equal Date.new(2005,5,10), Date.new(2005,6,7).weeks_ago(4)
+ assert_equal Date.new(2006,12,31), Date.new(2007,2,4).weeks_ago(5)
+ end
+
def test_months_ago
assert_equal Date.new(2005,5,5), Date.new(2005,6,5).months_ago(1)
assert_equal Date.new(2004,11,5), Date.new(2005,6,5).months_ago(7)
@@ -219,6 +227,14 @@ class DateExtCalculationsTest < ActiveSupport::TestCase
end
end
+ def test_prev_week
+ assert_equal Date.new(2005,5,9), Date.new(2005,5,17).prev_week
+ assert_equal Date.new(2006,12,25), Date.new(2007,1,7).prev_week
+ assert_equal Date.new(2010,2,12), Date.new(2010,2,19).prev_week(:friday)
+ assert_equal Date.new(2010,2,13), Date.new(2010,2,19).prev_week(:saturday)
+ assert_equal Date.new(2010,2,27), Date.new(2010,3,4).prev_week(:saturday)
+ end
+
def test_next_week
assert_equal Date.new(2005,2,28), Date.new(2005,2,22).next_week
assert_equal Date.new(2005,3,4), Date.new(2005,2,22).next_week(:friday)
@@ -242,17 +258,16 @@ class DateExtCalculationsTest < ActiveSupport::TestCase
def test_yesterday_constructor
assert_equal Date.current - 1, Date.yesterday
end
-
- def test_yesterday_constructor_when_zone_default_is_not_set
+
+ def test_yesterday_constructor_when_zone_is_not_set
with_env_tz 'UTC' do
with_tz_default do
- Time.stubs(:now).returns Time.local(2000, 1, 1)
- assert_equal Date.new(1999, 12, 31), Date.yesterday
+ assert_equal(Date.today - 1, Date.yesterday)
end
end
end
- def test_yesterday_constructor_when_zone_default_is_set
+ def test_yesterday_constructor_when_zone_is_set
with_env_tz 'UTC' do
with_tz_default ActiveSupport::TimeZone['Eastern Time (US & Canada)'] do # UTC -5
Time.stubs(:now).returns Time.local(2000, 1, 1)
@@ -265,16 +280,15 @@ class DateExtCalculationsTest < ActiveSupport::TestCase
assert_equal Date.current + 1, Date.tomorrow
end
- def test_tomorrow_constructor_when_zone_default_is_not_set
+ def test_tomorrow_constructor_when_zone_is_not_set
with_env_tz 'UTC' do
with_tz_default do
- Time.stubs(:now).returns Time.local(1999, 12, 31)
- assert_equal Date.new(2000, 1, 1), Date.tomorrow
+ assert_equal(Date.today + 1, Date.tomorrow)
end
end
end
- def test_tomorrow_constructor_when_zone_default_is_set
+ def test_tomorrow_constructor_when_zone_is_set
with_env_tz 'UTC' do
with_tz_default ActiveSupport::TimeZone['Europe/Paris'] do # UTC +1
Time.stubs(:now).returns Time.local(1999, 12, 31, 23)
@@ -286,8 +300,8 @@ class DateExtCalculationsTest < ActiveSupport::TestCase
def test_since
assert_equal Time.local(2005,2,21,0,0,45), Date.new(2005,2,21).since(45)
end
-
- def test_since_when_zone_default_is_set
+
+ def test_since_when_zone_is_set
zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)']
with_env_tz 'UTC' do
with_tz_default zone do
@@ -300,8 +314,8 @@ class DateExtCalculationsTest < ActiveSupport::TestCase
def test_ago
assert_equal Time.local(2005,2,20,23,59,15), Date.new(2005,2,21).ago(45)
end
-
- def test_ago_when_zone_default_is_set
+
+ def test_ago_when_zone_is_set
zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)']
with_env_tz 'UTC' do
with_tz_default zone do
@@ -314,8 +328,8 @@ class DateExtCalculationsTest < ActiveSupport::TestCase
def test_beginning_of_day
assert_equal Time.local(2005,2,21,0,0,0), Date.new(2005,2,21).beginning_of_day
end
-
- def test_beginning_of_day_when_zone_default_is_set
+
+ def test_beginning_of_day_when_zone_is_set
zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)']
with_env_tz 'UTC' do
with_tz_default zone do
@@ -328,8 +342,8 @@ class DateExtCalculationsTest < ActiveSupport::TestCase
def test_end_of_day
assert_equal Time.local(2005,2,21,23,59,59,999999.999), Date.new(2005,2,21).end_of_day
end
-
- def test_end_of_day_when_zone_default_is_set
+
+ def test_end_of_day_when_zone_is_set
zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)']
with_env_tz 'UTC' do
with_tz_default zone do
@@ -338,7 +352,7 @@ class DateExtCalculationsTest < ActiveSupport::TestCase
end
end
end
-
+
def test_xmlschema
with_env_tz 'US/Eastern' do
assert_match(/^1980-02-28T00:00:00-05:?00$/, Date.new(1980, 2, 28).xmlschema)
@@ -350,8 +364,8 @@ class DateExtCalculationsTest < ActiveSupport::TestCase
end
end
end
-
- def test_xmlschema_when_zone_default_is_set
+
+ def test_xmlschema_when_zone_is_set
with_env_tz 'UTC' do
with_tz_default ActiveSupport::TimeZone['Eastern Time (US & Canada)'] do # UTC -5
assert_match(/^1980-02-28T00:00:00-05:?00$/, Date.new(1980, 2, 28).xmlschema)
@@ -360,6 +374,16 @@ class DateExtCalculationsTest < ActiveSupport::TestCase
end
end
+ if RUBY_VERSION < '1.9'
+ def test_rfc3339
+ assert_equal('1980-02-28', Date.new(1980, 2, 28).rfc3339)
+ end
+
+ def test_iso8601
+ assert_equal('1980-02-28', Date.new(1980, 2, 28).iso8601)
+ end
+ end
+
def test_today
Date.stubs(:current).returns(Date.new(2000, 1, 1))
assert_equal false, Date.new(1999, 12, 31).today?
@@ -381,23 +405,20 @@ class DateExtCalculationsTest < ActiveSupport::TestCase
assert_equal true, Date.new(2000,1,2).future?
end
- def test_current_returns_date_today_when_zone_default_not_set
+ def test_current_returns_date_today_when_zone_not_set
with_env_tz 'US/Central' do
Time.stubs(:now).returns Time.local(1999, 12, 31, 23)
- assert_equal Date.new(1999, 12, 31), Date.today
- assert_equal Date.new(1999, 12, 31), Date.current
+ assert_equal Date.today, Date.current
end
end
- def test_current_returns_time_zone_today_when_zone_default_set
- Time.zone_default = ActiveSupport::TimeZone['Eastern Time (US & Canada)']
+ def test_current_returns_time_zone_today_when_zone_is_set
+ Time.zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)']
with_env_tz 'US/Central' do
- Time.stubs(:now).returns Time.local(1999, 12, 31, 23)
- assert_equal Date.new(1999, 12, 31), Date.today
- assert_equal Date.new(2000, 1, 1), Date.current
+ assert_equal ::Time.zone.today, Date.current
end
ensure
- Time.zone_default = nil
+ Time.zone = nil
end
def test_date_advance_should_not_change_passed_options_hash
@@ -415,11 +436,11 @@ class DateExtCalculationsTest < ActiveSupport::TestCase
end
def with_tz_default(tz = nil)
- old_tz = Time.zone_default
- Time.zone_default = tz
+ old_tz = Time.zone
+ Time.zone = tz
yield
ensure
- Time.zone_default = old_tz
+ Time.zone = old_tz
end
end
diff --git a/activesupport/test/core_ext/date_time_ext_test.rb b/activesupport/test/core_ext/date_time_ext_test.rb
index e8506f5222..456736cbad 100644
--- a/activesupport/test/core_ext/date_time_ext_test.rb
+++ b/activesupport/test/core_ext/date_time_ext_test.rb
@@ -38,6 +38,8 @@ class DateTimeExtCalculationsTest < Test::Unit::TestCase
assert_equal Time.utc_time(2039, 2, 21, 10, 11, 12), DateTime.new(2039, 2, 21, 10, 11, 12, 0, 0).to_time
# DateTimes with offsets other than 0 are returned unaltered
assert_equal DateTime.new(2005, 2, 21, 10, 11, 12, Rational(-5, 24)), DateTime.new(2005, 2, 21, 10, 11, 12, Rational(-5, 24)).to_time
+ # Fractional seconds are preserved
+ assert_equal Time.utc(2005, 2, 21, 10, 11, 12, 256), DateTime.new(2005, 2, 21, 10, 11, 12 + Rational(256, 1000000), 0).to_time
end
def test_civil_from_format
@@ -92,6 +94,14 @@ class DateTimeExtCalculationsTest < Test::Unit::TestCase
assert_equal DateTime.civil(2005,1,1,0,0,0), DateTime.civil(2005,2,22,10,10,10).beginning_of_year
end
+ def test_weeks_ago
+ assert_equal DateTime.civil(2005,5,29,10), DateTime.civil(2005,6,5,10,0,0).weeks_ago(1)
+ assert_equal DateTime.civil(2005,5,1,10), DateTime.civil(2005,6,5,10,0,0).weeks_ago(5)
+ assert_equal DateTime.civil(2005,4,24,10), DateTime.civil(2005,6,5,10,0,0).weeks_ago(6)
+ assert_equal DateTime.civil(2005,2,27,10), DateTime.civil(2005,6,5,10,0,0).weeks_ago(14)
+ assert_equal DateTime.civil(2004,12,25,10), DateTime.civil(2005,1,1,10,0,0).weeks_ago(1)
+ end
+
def test_months_ago
assert_equal DateTime.civil(2005,5,5,10), DateTime.civil(2005,6,5,10,0,0).months_ago(1)
assert_equal DateTime.civil(2004,11,5,10), DateTime.civil(2005,6,5,10,0,0).months_ago(7)
@@ -196,6 +206,14 @@ class DateTimeExtCalculationsTest < Test::Unit::TestCase
assert_equal DateTime.civil(2010, 3, 29), DateTime.civil(2010, 2, 28, 22, 58, 59).advance(:months => 1, :hours => 1, :minutes => 1, :seconds => 1)
end
+ def test_prev_week
+ assert_equal DateTime.civil(2005,2,21), DateTime.civil(2005,3,1,15,15,10).prev_week
+ assert_equal DateTime.civil(2005,2,22), DateTime.civil(2005,3,1,15,15,10).prev_week(:tuesday)
+ assert_equal DateTime.civil(2005,2,25), DateTime.civil(2005,3,1,15,15,10).prev_week(:friday)
+ assert_equal DateTime.civil(2006,10,30), DateTime.civil(2006,11,6,0,0,0).prev_week
+ assert_equal DateTime.civil(2006,11,15), DateTime.civil(2006,11,23,0,0,0).prev_week(:wednesday)
+ end
+
def test_next_week
assert_equal DateTime.civil(2005,2,28), DateTime.civil(2005,2,22,15,15,10).next_week
assert_equal DateTime.civil(2005,3,4), DateTime.civil(2005,2,22,15,15,10).next_week(:friday)
@@ -242,7 +260,7 @@ class DateTimeExtCalculationsTest < Test::Unit::TestCase
assert_equal false, DateTime.civil(2005,2,10,15,30,45, Rational(-18000, 86400)).past?
assert_equal false, DateTime.civil(2005,2,10,15,30,46, Rational(-18000, 86400)).past?
end
-
+
def test_past_without_offset
DateTime.stubs(:current).returns(DateTime.civil(2005,2,10,15,30,45, Rational(-18000, 86400)))
assert_equal true, DateTime.civil(2005,2,10,20,30,44).past?
@@ -264,21 +282,21 @@ class DateTimeExtCalculationsTest < Test::Unit::TestCase
assert_equal true, DateTime.civil(2005,2,10,20,30,46).future?
end
- def test_current_returns_date_today_when_zone_default_not_set
+ def test_current_returns_date_today_when_zone_is_not_set
with_env_tz 'US/Eastern' do
Time.stubs(:now).returns Time.local(1999, 12, 31, 23, 59, 59)
assert_equal DateTime.new(1999, 12, 31, 23, 59, 59, Rational(-18000, 86400)), DateTime.current
end
end
- def test_current_returns_time_zone_today_when_zone_default_set
- Time.zone_default = ActiveSupport::TimeZone['Eastern Time (US & Canada)']
+ def test_current_returns_time_zone_today_when_zone_is_set
+ Time.zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)']
with_env_tz 'US/Eastern' do
Time.stubs(:now).returns Time.local(1999, 12, 31, 23, 59, 59)
assert_equal DateTime.new(1999, 12, 31, 23, 59, 59, Rational(-18000, 86400)), DateTime.current
end
ensure
- Time.zone_default = nil
+ Time.zone = nil
end
def test_current_without_time_zone
diff --git a/activesupport/test/core_ext/duration_test.rb b/activesupport/test/core_ext/duration_test.rb
index 710c221fac..c0b529d9f8 100644
--- a/activesupport/test/core_ext/duration_test.rb
+++ b/activesupport/test/core_ext/duration_test.rb
@@ -1,5 +1,6 @@
require 'abstract_unit'
require 'active_support/time'
+require 'active_support/json'
class DurationTest < ActiveSupport::TestCase
def test_is_a
@@ -53,8 +54,8 @@ class DurationTest < ActiveSupport::TestCase
flunk("no exception was raised")
rescue ArgumentError => e
assert_equal 'expected a time or date, got ""', e.message, "ensure ArgumentError is not being raised by dependencies.rb"
- rescue Exception
- flunk("ArgumentError should be raised, but we got #{$!.class} instead")
+ rescue Exception => e
+ flunk("ArgumentError should be raised, but we got #{e.class} instead")
end
end
@@ -88,8 +89,8 @@ class DurationTest < ActiveSupport::TestCase
assert_in_delta((7 * 24 * 1.7).hours.ago(t), 1.7.weeks.ago(t), 1)
end
- def test_since_and_ago_anchored_to_time_now_when_time_zone_default_not_set
- Time.zone_default = nil
+ def test_since_and_ago_anchored_to_time_now_when_time_zone_is_not_set
+ Time.zone = nil
with_env_tz 'US/Eastern' do
Time.stubs(:now).returns Time.local(2000)
# since
@@ -101,8 +102,8 @@ class DurationTest < ActiveSupport::TestCase
end
end
- def test_since_and_ago_anchored_to_time_zone_now_when_time_zone_default_set
- Time.zone_default = ActiveSupport::TimeZone['Eastern Time (US & Canada)']
+ def test_since_and_ago_anchored_to_time_zone_now_when_time_zone_is_set
+ Time.zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)']
with_env_tz 'US/Eastern' do
Time.stubs(:now).returns Time.local(2000)
# since
@@ -115,20 +116,32 @@ class DurationTest < ActiveSupport::TestCase
assert_equal 'Eastern Time (US & Canada)', 5.seconds.ago.time_zone.name
end
ensure
- Time.zone_default = nil
+ Time.zone = nil
end
-
+
def test_adding_hours_across_dst_boundary
with_env_tz 'CET' do
assert_equal Time.local(2009,3,29,0,0,0) + 24.hours, Time.local(2009,3,30,1,0,0)
end
end
-
+
def test_adding_day_across_dst_boundary
with_env_tz 'CET' do
assert_equal Time.local(2009,3,29,0,0,0) + 1.day, Time.local(2009,3,30,0,0,0)
end
end
+
+ def test_delegation_with_block_works
+ counter = 0
+ assert_nothing_raised do
+ 1.minute.times {counter += 1}
+ end
+ assert_equal counter, 60
+ end
+
+ def test_to_json
+ assert_equal '172800', 2.days.to_json
+ end
protected
def with_env_tz(new_tz = 'US/Eastern')
diff --git a/activesupport/test/core_ext/enumerable_test.rb b/activesupport/test/core_ext/enumerable_test.rb
index 4650b796b6..4655bfe519 100644
--- a/activesupport/test/core_ext/enumerable_test.rb
+++ b/activesupport/test/core_ext/enumerable_test.rb
@@ -89,7 +89,7 @@ class EnumerableTests < Test::Unit::TestCase
assert ![ 1, 2 ].many? {|x| x > 1 }
assert [ 1, 2, 2 ].many? {|x| x > 1 }
end
-
+
def test_exclude?
assert [ 1 ].exclude?(2)
assert ![ 1 ].exclude?(1)
diff --git a/activesupport/test/core_ext/hash_ext_test.rb b/activesupport/test/core_ext/hash_ext_test.rb
index 5d9846a216..a0479d45ac 100644
--- a/activesupport/test/core_ext/hash_ext_test.rb
+++ b/activesupport/test/core_ext/hash_ext_test.rb
@@ -4,8 +4,18 @@ require 'bigdecimal'
require 'active_support/core_ext/string/access'
require 'active_support/ordered_hash'
require 'active_support/core_ext/object/conversions'
+require 'active_support/inflections'
class HashExtTest < Test::Unit::TestCase
+ class IndifferentHash < HashWithIndifferentAccess
+ end
+
+ class SubclassingArray < Array
+ end
+
+ class SubclassingHash < Hash
+ end
+
def setup
@strings = { 'a' => 1, 'b' => 2 }
@symbols = { :a => 1, :b => 2 }
@@ -99,6 +109,11 @@ class HashExtTest < Test::Unit::TestCase
assert_equal @strings, @mixed.with_indifferent_access.dup.stringify_keys!
end
+ def test_hash_subclass
+ flash = { "foo" => SubclassingHash.new.tap { |h| h["bar"] = "baz" } }.with_indifferent_access
+ assert_kind_of SubclassingHash, flash["foo"]
+ end
+
def test_indifferent_assorted
@strings = @strings.with_indifferent_access
@symbols = @symbols.with_indifferent_access
@@ -248,6 +263,20 @@ class HashExtTest < Test::Unit::TestCase
hash = { "urls" => { "url" => [ { "address" => "1" }, { "address" => "2" } ] }}.with_indifferent_access
assert_equal "1", hash[:urls][:url].first[:address]
end
+
+ def test_should_preserve_array_subclass_when_value_is_array
+ array = SubclassingArray.new
+ array << { "address" => "1" }
+ hash = { "urls" => { "url" => array }}.with_indifferent_access
+ assert_equal SubclassingArray, hash[:urls][:url].class
+ end
+
+ def test_should_preserve_array_class_when_hash_value_is_frozen_array
+ array = SubclassingArray.new
+ array << { "address" => "1" }
+ hash = { "urls" => { "url" => array.freeze }}.with_indifferent_access
+ assert_equal SubclassingArray, hash[:urls][:url].class
+ end
def test_stringify_and_symbolize_keys_on_indifferent_preserves_hash
h = HashWithIndifferentAccess.new
@@ -267,7 +296,6 @@ class HashExtTest < Test::Unit::TestCase
assert_equal 1, h['first']
end
-
def test_indifferent_subhashes
h = {'user' => {'id' => 5}}.with_indifferent_access
['user', :user].each {|user| [:id, 'id'].each {|id| assert_equal 5, h[user][id], "h[#{user.inspect}][#{id.inspect}] should be 5"}}
@@ -276,13 +304,24 @@ class HashExtTest < Test::Unit::TestCase
['user', :user].each {|user| [:id, 'id'].each {|id| assert_equal 5, h[user][id], "h[#{user.inspect}][#{id.inspect}] should be 5"}}
end
+ def test_indifferent_duplication
+ # Should preserve default value
+ h = HashWithIndifferentAccess.new
+ h.default = '1234'
+ assert_equal h.default, h.dup.default
+
+ # Should preserve class for subclasses
+ h = IndifferentHash.new
+ assert_equal h.class, h.dup.class
+ end
+
def test_assert_valid_keys
assert_nothing_raised do
{ :failure => "stuff", :funny => "business" }.assert_valid_keys([ :failure, :funny ])
{ :failure => "stuff", :funny => "business" }.assert_valid_keys(:failure, :funny)
end
- assert_raise(ArgumentError, "Unknown key(s): failore") do
+ assert_raise(ArgumentError, "Unknown key: failore") do
{ :failore => "stuff", :funny => "business" }.assert_valid_keys([ :failure, :funny ])
{ :failore => "stuff", :funny => "business" }.assert_valid_keys(:failure, :funny)
end
@@ -316,6 +355,31 @@ class HashExtTest < Test::Unit::TestCase
assert_equal expected, hash_1
end
+ def test_deep_dup
+ hash = { :a => { :b => 'b' } }
+ dup = hash.deep_dup
+ dup[:a][:c] = 'c'
+ assert_equal nil, hash[:a][:c]
+ assert_equal 'c', dup[:a][:c]
+ end
+
+ def test_deep_dup_initialize
+ zero_hash = Hash.new 0
+ hash = { :a => zero_hash }
+ dup = hash.deep_dup
+ assert_equal 0, dup[:a][44]
+ end
+
+ def test_store_on_indifferent_access
+ hash = HashWithIndifferentAccess.new
+ hash.store(:test1, 1)
+ hash.store('test1', 11)
+ hash[:test2] = 2
+ hash['test2'] = 22
+ expected = { "test1" => 11, "test2" => 22 }
+ assert_equal expected, hash
+ end
+
def test_reverse_merge
defaults = { :a => "x", :b => "y", :c => 10 }.freeze
options = { :a => 1, :b => 2 }
@@ -462,20 +526,24 @@ class HashExtToParamTests < Test::Unit::TestCase
assert_equal '', {}.to_param
assert_equal 'hello=world', { :hello => "world" }.to_param
assert_equal 'hello=10', { "hello" => 10 }.to_param
- assert_equal 'hello=world&say_bye=true', ActiveSupport::OrderedHash[:hello, "world", "say_bye", true].to_param
+ assert_equal 'hello=world&say_bye=true', {:hello => "world", "say_bye" => true}.to_param
end
def test_number_hash
- assert_equal '10=20&30=40&50=60', ActiveSupport::OrderedHash[10, 20, 30, 40, 50, 60].to_param
+ assert_equal '10=20&30=40&50=60', {10 => 20, 30 => 40, 50 => 60}.to_param
end
def test_to_param_hash
- assert_equal 'custom=param-1&custom2=param2-1', ActiveSupport::OrderedHash[ToParam.new('custom'), ToParam.new('param'), ToParam.new('custom2'), ToParam.new('param2')].to_param
+ assert_equal 'custom2=param2-1&custom=param-1', {ToParam.new('custom') => ToParam.new('param'), ToParam.new('custom2') => ToParam.new('param2')}.to_param
end
def test_to_param_hash_escapes_its_keys_and_values
assert_equal 'param+1=A+string+with+%2F+characters+%26+that+should+be+%3F+escaped', { 'param 1' => 'A string with / characters & that should be ? escaped' }.to_param
end
+
+ def test_to_param_orders_by_key_in_ascending_order
+ assert_equal 'a=2&b=1&c=0', ActiveSupport::OrderedHash[*%w(b 1 c 0 a 2)].to_param
+ end
end
class HashToXmlTest < Test::Unit::TestCase
@@ -511,6 +579,13 @@ class HashToXmlTest < Test::Unit::TestCase
assert xml.include?(%(<Name>David</Name>))
end
+ def test_one_level_camelize_lower
+ xml = { :name => "David", :street_name => "Paulina" }.to_xml(@xml_options.merge(:camelize => :lower))
+ assert_equal "<person>", xml.first(8)
+ assert xml.include?(%(<streetName>Paulina</streetName>))
+ assert xml.include?(%(<name>David</name>))
+ end
+
def test_one_level_with_types
xml = { :name => "David", :street => "Paulina", :age => 26, :age_in_millis => 820497600000, :moved_on => Date.new(2005, 11, 15), :resident => :yes }.to_xml(@xml_options)
assert_equal "<person>", xml.first(8)
@@ -640,12 +715,12 @@ class HashToXmlTest < Test::Unit::TestCase
EOT
expected_topic_hash = {
- :title => nil,
+ :title => nil,
:id => nil,
:approved => nil,
:written_on => nil,
:viewed_at => nil,
- :content => nil,
+ :content => nil,
:parent_id => nil
}.stringify_keys
@@ -723,7 +798,7 @@ class HashToXmlTest < Test::Unit::TestCase
assert_equal expected_topic_hash, Hash.from_xml(topic_xml)["rsp"]["photos"]["photo"]
end
-
+
def test_all_caps_key_from_xml
test_xml = <<-EOT
<ABC3XYZ>
@@ -839,13 +914,13 @@ class HashToXmlTest < Test::Unit::TestCase
assert_equal expected_bacon_hash, Hash.from_xml(bacon_xml)["bacon"]
end
-
+
def test_type_trickles_through_when_unknown
product_xml = <<-EOT
<product>
<weight type="double">0.5</weight>
<image type="ProductImage"><filename>image.gif</filename></image>
-
+
</product>
EOT
@@ -854,7 +929,7 @@ class HashToXmlTest < Test::Unit::TestCase
:image => {'type' => 'ProductImage', 'filename' => 'image.gif' },
}.stringify_keys
- assert_equal expected_product_hash, Hash.from_xml(product_xml)["product"]
+ assert_equal expected_product_hash, Hash.from_xml(product_xml)["product"]
end
def test_should_use_default_value_for_unknown_key
@@ -888,41 +963,41 @@ class HashToXmlTest < Test::Unit::TestCase
assert_equal expected, hash.to_xml(@xml_options)
end
end
-
- def test_empty_string_works_for_typecast_xml_value
+
+ def test_empty_string_works_for_typecast_xml_value
assert_nothing_raised do
Hash.__send__(:typecast_xml_value, "")
end
end
-
+
def test_escaping_to_xml
- hash = {
- :bare_string => 'First & Last Name',
+ hash = {
+ :bare_string => 'First & Last Name',
:pre_escaped_string => 'First &amp; Last Name'
}.stringify_keys
-
+
expected_xml = '<person><bare-string>First &amp; Last Name</bare-string><pre-escaped-string>First &amp;amp; Last Name</pre-escaped-string></person>'
assert_equal expected_xml, hash.to_xml(@xml_options)
end
-
+
def test_unescaping_from_xml
xml_string = '<person><bare-string>First &amp; Last Name</bare-string><pre-escaped-string>First &amp;amp; Last Name</pre-escaped-string></person>'
- expected_hash = {
- :bare_string => 'First & Last Name',
+ expected_hash = {
+ :bare_string => 'First & Last Name',
:pre_escaped_string => 'First &amp; Last Name'
}.stringify_keys
assert_equal expected_hash, Hash.from_xml(xml_string)['person']
end
-
+
def test_roundtrip_to_xml_from_xml
- hash = {
- :bare_string => 'First & Last Name',
+ hash = {
+ :bare_string => 'First & Last Name',
:pre_escaped_string => 'First &amp; Last Name'
}.stringify_keys
assert_equal hash, Hash.from_xml(hash.to_xml(@xml_options))['person']
end
-
+
def test_datetime_xml_type_with_utc_time
alert_xml = <<-XML
<alert>
@@ -933,7 +1008,7 @@ class HashToXmlTest < Test::Unit::TestCase
assert alert_at.utc?
assert_equal Time.utc(2008, 2, 10, 15, 30, 45), alert_at
end
-
+
def test_datetime_xml_type_with_non_utc_time
alert_xml = <<-XML
<alert>
@@ -944,7 +1019,7 @@ class HashToXmlTest < Test::Unit::TestCase
assert alert_at.utc?
assert_equal Time.utc(2008, 2, 10, 15, 30, 45), alert_at
end
-
+
def test_datetime_xml_type_with_far_future_date
alert_xml = <<-XML
<alert>
diff --git a/activesupport/test/core_ext/kernel_test.rb b/activesupport/test/core_ext/kernel_test.rb
index c22af89918..ede9b0a6aa 100644
--- a/activesupport/test/core_ext/kernel_test.rb
+++ b/activesupport/test/core_ext/kernel_test.rb
@@ -46,22 +46,27 @@ class KernelTest < Test::Unit::TestCase
o = Object.new
assert_equal class << o; self end, o.singleton_class
end
-
+
def test_class_eval
o = Object.new
class << o; @x = 1; end
assert_equal 1, o.class_eval { @x }
end
+
+ def test_capture
+ assert_equal 'STDERR', capture(:stderr) {$stderr.print 'STDERR'}
+ assert_equal 'STDOUT', capture(:stdout) {print 'STDOUT'}
+ end
end
-class KernelSupressTest < Test::Unit::TestCase
+class KernelSuppressTest < Test::Unit::TestCase
def test_reraise
assert_raise(LoadError) do
suppress(ArgumentError) { raise LoadError }
end
end
- def test_supression
+ def test_suppression
suppress(ArgumentError) { raise ArgumentError }
suppress(LoadError) { raise LoadError }
suppress(LoadError, ArgumentError) { raise LoadError }
diff --git a/activesupport/test/core_ext/module/anonymous_test.rb b/activesupport/test/core_ext/module/anonymous_test.rb
index 7a78a3b012..cb556af772 100644
--- a/activesupport/test/core_ext/module/anonymous_test.rb
+++ b/activesupport/test/core_ext/module/anonymous_test.rb
@@ -6,7 +6,7 @@ class AnonymousTest < ActiveSupport::TestCase
assert Module.new.anonymous?
assert Class.new.anonymous?
end
-
+
test "a named class or module are not anonymous" do
assert !Kernel.anonymous?
assert !Object.anonymous?
diff --git a/activesupport/test/core_ext/module/attr_accessor_with_default_test.rb b/activesupport/test/core_ext/module/attr_accessor_with_default_test.rb
index 7c0d0bb242..b9b60c4d6d 100644
--- a/activesupport/test/core_ext/module/attr_accessor_with_default_test.rb
+++ b/activesupport/test/core_ext/module/attr_accessor_with_default_test.rb
@@ -7,25 +7,25 @@ class AttrAccessorWithDefaultTest < Test::Unit::TestCase
def helper
'helper'
end
- end
+ end
@instance = @target.new
end
-
+
def test_default_arg
@target.attr_accessor_with_default :foo, :bar
assert_equal(:bar, @instance.foo)
@instance.foo = nil
assert_nil(@instance.foo)
end
-
+
def test_default_proc
@target.attr_accessor_with_default(:foo) {helper.upcase}
assert_equal('HELPER', @instance.foo)
@instance.foo = nil
assert_nil(@instance.foo)
end
-
+
def test_invalid_args
- assert_raise(RuntimeError) {@target.attr_accessor_with_default :foo}
+ assert_raise(ArgumentError) {@target.attr_accessor_with_default :foo}
end
end
diff --git a/activesupport/test/core_ext/module/attribute_accessor_test.rb b/activesupport/test/core_ext/module/attribute_accessor_test.rb
index 67fcd437d0..118fb070a0 100644
--- a/activesupport/test/core_ext/module/attribute_accessor_test.rb
+++ b/activesupport/test/core_ext/module/attribute_accessor_test.rb
@@ -32,7 +32,7 @@ class ModuleAttributeAccessorTest < Test::Unit::TestCase
assert_respond_to @object, :bar
assert !@object.respond_to?(:bar=)
end
-
+
def test_should_not_create_instance_reader
assert_respond_to @module, :shaq
assert !@object.respond_to?(:shaq)
diff --git a/activesupport/test/core_ext/module/attribute_aliasing_test.rb b/activesupport/test/core_ext/module/attribute_aliasing_test.rb
index f17d031662..065c3531e0 100644
--- a/activesupport/test/core_ext/module/attribute_aliasing_test.rb
+++ b/activesupport/test/core_ext/module/attribute_aliasing_test.rb
@@ -44,14 +44,14 @@ class AttributeAliasingTest < Test::Unit::TestCase
# upper-case attributes, and when people want to alias those names
# to more sensible ones, everything goes *foof*.
e = AttributeAliasing::Email.new
-
+
assert !e.body?
assert !e.Data?
-
+
e.body = "No, really, this is not a joke."
assert_equal "No, really, this is not a joke.", e.Data
assert e.Data?
-
+
e.Data = "Uppercased methods are teh suck"
assert_equal "Uppercased methods are teh suck", e.body
assert e.body?
diff --git a/activesupport/test/core_ext/module/reachable_test.rb b/activesupport/test/core_ext/module/reachable_test.rb
index 72892b77d5..80eb31a5c4 100644
--- a/activesupport/test/core_ext/module/reachable_test.rb
+++ b/activesupport/test/core_ext/module/reachable_test.rb
@@ -6,33 +6,33 @@ class AnonymousTest < ActiveSupport::TestCase
assert !Module.new.reachable?
assert !Class.new.reachable?
end
-
+
test "ordinary named classes or modules are reachable" do
assert Kernel.reachable?
assert Object.reachable?
end
-
+
test "a named class or module whose constant has gone is not reachable" do
c = eval "class C; end; C"
m = eval "module M; end; M"
-
+
self.class.send(:remove_const, :C)
self.class.send(:remove_const, :M)
-
+
assert !c.reachable?
assert !m.reachable?
end
-
+
test "a named class or module whose constants store different objects are not reachable" do
c = eval "class C; end; C"
m = eval "module M; end; M"
-
+
self.class.send(:remove_const, :C)
- self.class.send(:remove_const, :M)
+ self.class.send(:remove_const, :M)
eval "class C; end"
eval "module M; end"
-
+
assert C.reachable?
assert M.reachable?
assert !c.reachable?
diff --git a/activesupport/test/core_ext/module/synchronization_test.rb b/activesupport/test/core_ext/module/synchronization_test.rb
index eb850893f0..6c407e2260 100644
--- a/activesupport/test/core_ext/module/synchronization_test.rb
+++ b/activesupport/test/core_ext/module/synchronization_test.rb
@@ -1,3 +1,4 @@
+require 'thread'
require 'abstract_unit'
require 'active_support/core_ext/class/attribute_accessors'
diff --git a/activesupport/test/core_ext/module_test.rb b/activesupport/test/core_ext/module_test.rb
index 5d9cdf22c2..a95cf1591f 100644
--- a/activesupport/test/core_ext/module_test.rb
+++ b/activesupport/test/core_ext/module_test.rb
@@ -26,14 +26,10 @@ module Yz
end
end
-class De
-end
-
Somewhere = Struct.new(:street, :city)
Someone = Struct.new(:name, :place) do
delegate :street, :city, :to_f, :to => :place
- delegate :state, :to => :@place
delegate :upcase, :to => "place.city"
end
@@ -47,6 +43,14 @@ Project = Struct.new(:description, :person) do
delegate :to_f, :to => :description, :allow_nil => true
end
+Developer = Struct.new(:client) do
+ delegate :name, :to => :client, :prefix => nil
+end
+
+Tester = Struct.new(:client) do
+ delegate :name, :to => :client, :prefix => false
+end
+
class Name
delegate :upcase, :to => :@full_name
@@ -97,6 +101,11 @@ class ModuleTest < Test::Unit::TestCase
assert_equal invoice.customer_city, "Chicago"
end
+ def test_delegation_prefix_with_nil_or_false
+ assert_equal Developer.new(@david).name, "David"
+ assert_equal Tester.new(@david).name, "David"
+ end
+
def test_delegation_prefix_with_instance_variable
assert_raise ArgumentError do
Class.new do
diff --git a/activesupport/test/core_ext/numeric_ext_test.rb b/activesupport/test/core_ext/numeric_ext_test.rb
index 992ec60302..3a2452b4b0 100644
--- a/activesupport/test/core_ext/numeric_ext_test.rb
+++ b/activesupport/test/core_ext/numeric_ext_test.rb
@@ -38,7 +38,7 @@ class NumericExtTimeAndDateTimeTest < Test::Unit::TestCase
assert seconds.from_now >= now + seconds
end
end
-
+
def test_irregular_durations
assert_equal @now.advance(:days => 3000), 3000.days.since(@now)
assert_equal @now.advance(:months => 1), 1.month.since(@now)
@@ -49,16 +49,16 @@ class NumericExtTimeAndDateTimeTest < Test::Unit::TestCase
assert_equal @dtnow.advance(:months => -1), 1.month.until(@dtnow)
assert_equal @dtnow.advance(:years => 20), 20.years.since(@dtnow)
end
-
+
def test_duration_addition
assert_equal @now.advance(:days => 1).advance(:months => 1), (1.day + 1.month).since(@now)
assert_equal @now.advance(:days => 7), (1.week + 5.seconds - 5.seconds).since(@now)
assert_equal @now.advance(:years => 2), (4.years - 2.years).since(@now)
assert_equal @dtnow.advance(:days => 1).advance(:months => 1), (1.day + 1.month).since(@dtnow)
assert_equal @dtnow.advance(:days => 7), (1.week + 5.seconds - 5.seconds).since(@dtnow)
- assert_equal @dtnow.advance(:years => 2), (4.years - 2.years).since(@dtnow)
+ assert_equal @dtnow.advance(:years => 2), (4.years - 2.years).since(@dtnow)
end
-
+
def test_time_plus_duration
assert_equal @now + 8, @now + 8.seconds
assert_equal @now + 22.9, @now + 22.9.seconds
@@ -69,25 +69,63 @@ class NumericExtTimeAndDateTimeTest < Test::Unit::TestCase
assert_equal @dtnow.advance(:days => 15), @dtnow + 15.days
assert_equal @dtnow.advance(:months => 1), @dtnow + 1.month
end
-
+
def test_chaining_duration_operations
assert_equal @now.advance(:days => 2).advance(:months => -3), @now + 2.days - 3.months
assert_equal @now.advance(:days => 1).advance(:months => 2), @now + 1.day + 2.months
assert_equal @dtnow.advance(:days => 2).advance(:months => -3), @dtnow + 2.days - 3.months
- assert_equal @dtnow.advance(:days => 1).advance(:months => 2), @dtnow + 1.day + 2.months
+ assert_equal @dtnow.advance(:days => 1).advance(:months => 2), @dtnow + 1.day + 2.months
end
-
+
def test_duration_after_convertion_is_no_longer_accurate
assert_equal 30.days.to_i.since(@now), 1.month.to_i.since(@now)
assert_equal 365.25.days.to_f.since(@now), 1.year.to_f.since(@now)
assert_equal 30.days.to_i.since(@dtnow), 1.month.to_i.since(@dtnow)
- assert_equal 365.25.days.to_f.since(@dtnow), 1.year.to_f.since(@dtnow)
+ assert_equal 365.25.days.to_f.since(@dtnow), 1.year.to_f.since(@dtnow)
end
-
+
def test_add_one_year_to_leap_day
assert_equal Time.utc(2005,2,28,15,15,10), Time.utc(2004,2,29,15,15,10) + 1.year
assert_equal DateTime.civil(2005,2,28,15,15,10), DateTime.civil(2004,2,29,15,15,10) + 1.year
end
+
+ def test_since_and_ago_anchored_to_time_now_when_time_zone_is_not_set
+ Time.zone = nil
+ with_env_tz 'US/Eastern' do
+ Time.stubs(:now).returns Time.local(2000)
+ # since
+ assert_equal false, 5.since.is_a?(ActiveSupport::TimeWithZone)
+ assert_equal Time.local(2000,1,1,0,0,5), 5.since
+ # ago
+ assert_equal false, 5.ago.is_a?(ActiveSupport::TimeWithZone)
+ assert_equal Time.local(1999,12,31,23,59,55), 5.ago
+ end
+ end
+
+ def test_since_and_ago_anchored_to_time_zone_now_when_time_zone_is_set
+ Time.zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)']
+ with_env_tz 'US/Eastern' do
+ Time.stubs(:now).returns Time.local(2000)
+ # since
+ assert_equal true, 5.since.is_a?(ActiveSupport::TimeWithZone)
+ assert_equal Time.utc(2000,1,1,0,0,5), 5.since.time
+ assert_equal 'Eastern Time (US & Canada)', 5.since.time_zone.name
+ # ago
+ assert_equal true, 5.ago.is_a?(ActiveSupport::TimeWithZone)
+ assert_equal Time.utc(1999,12,31,23,59,55), 5.ago.time
+ assert_equal 'Eastern Time (US & Canada)', 5.ago.time_zone.name
+ end
+ ensure
+ Time.zone = nil
+ end
+
+ protected
+ def with_env_tz(new_tz = 'US/Eastern')
+ old_tz, ENV['TZ'] = ENV['TZ'], new_tz
+ yield
+ ensure
+ old_tz ? ENV['TZ'] = old_tz : ENV.delete('TZ')
+ end
end
class NumericExtDateTest < Test::Unit::TestCase
@@ -102,12 +140,12 @@ class NumericExtDateTest < Test::Unit::TestCase
assert_equal @today.to_time.since(60), @today + 1.minute
assert_equal @today.to_time.since(60*60), @today + 1.hour
end
-
+
def test_chaining_duration_operations
assert_equal @today.advance(:days => 2).advance(:months => -3), @today + 2.days - 3.months
assert_equal @today.advance(:days => 1).advance(:months => 2), @today + 1.day + 2.months
end
-
+
def test_add_one_year_to_leap_day
assert_equal Date.new(2005,2,28), Date.new(2004,2,29) + 1.year
end
@@ -132,7 +170,7 @@ class NumericExtSizeTest < Test::Unit::TestCase
assert_equal right, left
end
end
-
+
def test_units_as_bytes_independently
assert_equal 3145728, 3.megabytes
assert_equal 3145728, 3.megabyte
diff --git a/activesupport/test/core_ext/object/to_query_test.rb b/activesupport/test/core_ext/object/to_query_test.rb
index e28b4cd493..84da52f4bf 100644
--- a/activesupport/test/core_ext/object/to_query_test.rb
+++ b/activesupport/test/core_ext/object/to_query_test.rb
@@ -18,22 +18,22 @@ class ToQueryTest < Test::Unit::TestCase
end
def test_nested_conversion
- assert_query_equal 'person[login]=seckar&person[name]=Nicholas',
+ assert_query_equal 'person%5Blogin%5D=seckar&person%5Bname%5D=Nicholas',
:person => ActiveSupport::OrderedHash[:login, 'seckar', :name, 'Nicholas']
end
def test_multiple_nested
- assert_query_equal 'account[person][id]=20&person[id]=10',
+ assert_query_equal 'account%5Bperson%5D%5Bid%5D=20&person%5Bid%5D=10',
ActiveSupport::OrderedHash[:account, {:person => {:id => 20}}, :person, {:id => 10}]
end
def test_array_values
- assert_query_equal 'person[id][]=10&person[id][]=20',
+ assert_query_equal 'person%5Bid%5D%5B%5D=10&person%5Bid%5D%5B%5D=20',
:person => {:id => [10, 20]}
end
def test_array_values_are_not_sorted
- assert_query_equal 'person[id][]=20&person[id][]=10',
+ assert_query_equal 'person%5Bid%5D%5B%5D=20&person%5Bid%5D%5B%5D=10',
:person => {:id => [20, 10]}
end
diff --git a/activesupport/test/core_ext/object_and_class_ext_test.rb b/activesupport/test/core_ext/object_and_class_ext_test.rb
index 6588f2e345..5d68b198f2 100644
--- a/activesupport/test/core_ext/object_and_class_ext_test.rb
+++ b/activesupport/test/core_ext/object_and_class_ext_test.rb
@@ -28,18 +28,6 @@ module Nested
end
end
-module Bar
- def bar; end
-end
-
-module Baz
- def baz; end
-end
-
-class Foo
- include Bar
-end
-
class ObjectTests < ActiveSupport::TestCase
class DuckTime
def acts_like_time?
@@ -82,37 +70,6 @@ class ObjectInstanceVariableTest < Test::Unit::TestCase
assert_equal %w(@bar @baz), @source.instance_variable_names.sort
end
- def test_copy_instance_variables_from_without_explicit_excludes
- assert_equal [], @dest.instance_variables
- @dest.copy_instance_variables_from(@source)
-
- assert_equal %w(@bar @baz), @dest.instance_variables.sort.map(&:to_s)
- %w(@bar @baz).each do |name|
- assert_equal @source.instance_variable_get(name).object_id,
- @dest.instance_variable_get(name).object_id
- end
- end
-
- def test_copy_instance_variables_from_with_explicit_excludes
- @dest.copy_instance_variables_from(@source, ['@baz'])
- assert !@dest.instance_variable_defined?('@baz')
- assert_equal 'bar', @dest.instance_variable_get('@bar')
- end
-
- def test_copy_instance_variables_automatically_excludes_protected_instance_variables
- @source.instance_variable_set(:@quux, 'quux')
- class << @source
- def protected_instance_variables
- ['@bar', :@quux]
- end
- end
-
- @dest.copy_instance_variables_from(@source)
- assert !@dest.instance_variable_defined?('@bar')
- assert !@dest.instance_variable_defined?('@quux')
- assert_equal 'baz', @dest.instance_variable_get('@baz')
- end
-
def test_instance_values
object = Object.new
object.instance_variable_set :@a, 1
@@ -144,7 +101,7 @@ class ObjectTryTest < Test::Unit::TestCase
assert !@string.respond_to?(method)
assert_raise(NoMethodError) { @string.try(method) }
end
-
+
def test_valid_method
assert_equal 5, @string.try(:size)
end
@@ -165,4 +122,14 @@ class ObjectTryTest < Test::Unit::TestCase
def test_false_try
assert_equal 'false', false.try(:to_s)
end
+
+ def test_try_only_block
+ assert_equal @string.reverse, @string.try { |s| s.reverse }
+ end
+
+ def test_try_only_block_nil
+ ran = false
+ nil.try { ran = true }
+ assert_equal false, ran
+ end
end
diff --git a/activesupport/test/core_ext/range_ext_test.rb b/activesupport/test/core_ext/range_ext_test.rb
index 5701eeef28..1424fa4aca 100644
--- a/activesupport/test/core_ext/range_ext_test.rb
+++ b/activesupport/test/core_ext/range_ext_test.rb
@@ -62,4 +62,16 @@ class RangeTest < Test::Unit::TestCase
(1..10).step(2) {|i| array << i }
assert_equal [1,3,5,7,9], array
end
+
+ if RUBY_VERSION < '1.9'
+ def test_cover
+ assert((1..3).cover?(2))
+ assert !(1..3).cover?(4)
+ end
+ else
+ def test_cover_is_not_override
+ range = (1..3)
+ assert range.method(:include?) != range.method(:cover?)
+ end
+ end
end
diff --git a/activesupport/test/core_ext/string_ext_test.rb b/activesupport/test/core_ext/string_ext_test.rb
index affa1b5e18..bb865cae91 100644
--- a/activesupport/test/core_ext/string_ext_test.rb
+++ b/activesupport/test/core_ext/string_ext_test.rb
@@ -6,10 +6,42 @@ require 'inflector_test_cases'
require 'active_support/core_ext/string'
require 'active_support/time'
require 'active_support/core_ext/kernel/reporting'
+require 'active_support/core_ext/string/strip'
class StringInflectionsTest < Test::Unit::TestCase
include InflectorTestCases
+ def test_strip_heredoc_on_an_empty_string
+ assert_equal '', ''.strip_heredoc
+ end
+
+ def test_strip_heredoc_on_a_string_with_no_lines
+ assert_equal 'x', 'x'.strip_heredoc
+ assert_equal 'x', ' x'.strip_heredoc
+ end
+
+ def test_strip_heredoc_on_a_heredoc_with_no_margin
+ assert_equal "foo\nbar", "foo\nbar".strip_heredoc
+ assert_equal "foo\n bar", "foo\n bar".strip_heredoc
+ end
+
+ def test_strip_heredoc_on_a_regular_indented_heredoc
+ assert_equal "foo\n bar\nbaz\n", <<-EOS.strip_heredoc
+ foo
+ bar
+ baz
+ EOS
+ end
+
+ def test_strip_heredoc_on_a_regular_indented_heredoc_with_blank_lines
+ assert_equal "foo\n bar\n\nbaz\n", <<-EOS.strip_heredoc
+ foo
+ bar
+
+ baz
+ EOS
+ end
+
def test_pluralize
SingularToPlural.each do |singular, plural|
assert_equal(plural, singular.pluralize)
@@ -218,7 +250,7 @@ class StringInflectionsTest < Test::Unit::TestCase
# And changes the original string:
assert_equal original, expected
end
-
+
def test_truncate
assert_equal "Hello World!", "Hello World!".truncate(12)
assert_equal "Hello Wor...", "Hello World!!".truncate(12)
@@ -289,75 +321,6 @@ class CoreExtStringMultibyteTest < ActiveSupport::TestCase
end
end
-=begin
- string.rb - Interpolation for String.
-
- Copyright (C) 2005-2009 Masao Mutoh
-
- You may redistribute it and/or modify it under the same
- license terms as Ruby.
-=end
-class TestGetTextString < Test::Unit::TestCase
- def test_sprintf
- assert_equal("foo is a number", "%{msg} is a number" % {:msg => "foo"})
- assert_equal("bar is a number", "%s is a number" % ["bar"])
- assert_equal("bar is a number", "%s is a number" % "bar")
- assert_equal("1, test", "%{num}, %{record}" % {:num => 1, :record => "test"})
- assert_equal("test, 1", "%{record}, %{num}" % {:num => 1, :record => "test"})
- assert_equal("1, test", "%d, %s" % [1, "test"])
- assert_equal("test, 1", "%2$s, %1$d" % [1, "test"])
- assert_raise(ArgumentError) { "%-%" % [1] }
- end
-
- def test_percent
- assert_equal("% 1", "%% %<num>d" % {:num => 1.0})
- assert_equal("%{num} %<num>d 1", "%%{num} %%<num>d %<num>d" % {:num => 1})
- end
-
- def test_sprintf_percent_in_replacement
- assert_equal("%<not_translated>s", "%{msg}" % { :msg => '%<not_translated>s', :not_translated => 'should not happen' })
- end
-
- def test_sprintf_lack_argument
- assert_raises(KeyError) { "%{num}, %{record}" % {:record => "test"} }
- assert_raises(KeyError) { "%{record}" % {:num => 1} }
- end
-
- def test_no_placeholder
- # Causes a "too many arguments for format string" warning
- # on 1.8.7 and 1.9 but we still want to make sure the behavior works
- silence_warnings do
- assert_equal("aaa", "aaa" % {:num => 1})
- assert_equal("bbb", "bbb" % [1])
- end
- end
-
- def test_sprintf_ruby19_style
- assert_equal("1", "%<num>d" % {:num => 1})
- assert_equal("0b1", "%<num>#b" % {:num => 1})
- assert_equal("foo", "%<msg>s" % {:msg => "foo"})
- assert_equal("1.000000", "%<num>f" % {:num => 1.0})
- assert_equal(" 1", "%<num>3.0f" % {:num => 1.0})
- assert_equal("100.00", "%<num>2.2f" % {:num => 100.0})
- assert_equal("0x64", "%<num>#x" % {:num => 100.0})
- assert_raise(ArgumentError) { "%<num>,d" % {:num => 100} }
- assert_raise(ArgumentError) { "%<num>/d" % {:num => 100} }
- end
-
- def test_sprintf_old_style
- assert_equal("foo 1.000000", "%s %f" % ["foo", 1.0])
- end
-
- def test_sprintf_mix_unformatted_and_formatted_named_placeholders
- assert_equal("foo 1.000000", "%{name} %<num>f" % {:name => "foo", :num => 1.0})
- end
-
- def test_string_interpolation_raises_an_argument_error_when_mixing_named_and_unnamed_placeholders
- assert_raises(ArgumentError) { "%{name} %f" % [1.0] }
- assert_raises(ArgumentError) { "%{name} %f" % [1.0, 2.0] }
- end
-end
-
class OutputSafetyTest < ActiveSupport::TestCase
def setup
@string = "hello"
diff --git a/activesupport/test/core_ext/time_ext_test.rb b/activesupport/test/core_ext/time_ext_test.rb
index 1cf84df386..53d497013a 100644
--- a/activesupport/test/core_ext/time_ext_test.rb
+++ b/activesupport/test/core_ext/time_ext_test.rb
@@ -130,6 +130,14 @@ class TimeExtCalculationsTest < ActiveSupport::TestCase
assert_equal Time.local(2005,1,1,0,0,0), Time.local(2005,2,22,10,10,10).beginning_of_year
end
+ def test_weeks_ago
+ assert_equal Time.local(2005,5,29,10), Time.local(2005,6,5,10,0,0).weeks_ago(1)
+ assert_equal Time.local(2005,5,1,10), Time.local(2005,6,5,10,0,0).weeks_ago(5)
+ assert_equal Time.local(2005,4,24,10), Time.local(2005,6,5,10,0,0).weeks_ago(6)
+ assert_equal Time.local(2005,2,27,10), Time.local(2005,6,5,10,0,0).weeks_ago(14)
+ assert_equal Time.local(2004,12,25,10), Time.local(2005,1,1,10,0,0).weeks_ago(1)
+ end
+
def test_months_ago
assert_equal Time.local(2005,5,5,10), Time.local(2005,6,5,10,0,0).months_ago(1)
assert_equal Time.local(2004,11,5,10), Time.local(2005,6,5,10,0,0).months_ago(7)
@@ -187,7 +195,7 @@ class TimeExtCalculationsTest < ActiveSupport::TestCase
assert_equal Time.local(2005,4,2,3,18,0), Time.local(2005,4,3,4,18,0).ago(24.hours), 'dt-24.hours=>st'
assert_equal Time.local(2005,4,2,3,18,0), Time.local(2005,4,3,4,18,0).ago(86400), 'dt-86400=>st'
assert_equal Time.local(2005,4,2,3,18,0), Time.local(2005,4,3,4,18,0).ago(86400.seconds), 'dt-86400.seconds=>st'
-
+
assert_equal Time.local(2005,4,1,4,18,0), Time.local(2005,4,2,4,18,0).ago(24.hours), 'st-24.hours=>st'
assert_equal Time.local(2005,4,1,4,18,0), Time.local(2005,4,2,4,18,0).ago(86400), 'st-86400=>st'
assert_equal Time.local(2005,4,1,4,18,0), Time.local(2005,4,2,4,18,0).ago(86400.seconds), 'st-86400.seconds=>st'
@@ -197,7 +205,7 @@ class TimeExtCalculationsTest < ActiveSupport::TestCase
assert_equal Time.local(2006,9,30,3,18,0), Time.local(2006,10,1,4,18,0).ago(24.hours), 'dt-24.hours=>st'
assert_equal Time.local(2006,9,30,3,18,0), Time.local(2006,10,1,4,18,0).ago(86400), 'dt-86400=>st'
assert_equal Time.local(2006,9,30,3,18,0), Time.local(2006,10,1,4,18,0).ago(86400.seconds), 'dt-86400.seconds=>st'
-
+
assert_equal Time.local(2006,9,29,4,18,0), Time.local(2006,9,30,4,18,0).ago(24.hours), 'st-24.hours=>st'
assert_equal Time.local(2006,9,29,4,18,0), Time.local(2006,9,30,4,18,0).ago(86400), 'st-86400=>st'
assert_equal Time.local(2006,9,29,4,18,0), Time.local(2006,9,30,4,18,0).ago(86400.seconds), 'st-86400.seconds=>st'
@@ -210,7 +218,7 @@ class TimeExtCalculationsTest < ActiveSupport::TestCase
assert_equal Time.local(2005,10,29,5,3), Time.local(2005,10,30,4,3,0).ago(24.hours), 'st-24.hours=>dt'
assert_equal Time.local(2005,10,29,5,3), Time.local(2005,10,30,4,3,0).ago(86400), 'st-86400=>dt'
assert_equal Time.local(2005,10,29,5,3), Time.local(2005,10,30,4,3,0).ago(86400.seconds), 'st-86400.seconds=>dt'
-
+
assert_equal Time.local(2005,10,28,4,3), Time.local(2005,10,29,4,3,0).ago(24.hours), 'dt-24.hours=>dt'
assert_equal Time.local(2005,10,28,4,3), Time.local(2005,10,29,4,3,0).ago(86400), 'dt-86400=>dt'
assert_equal Time.local(2005,10,28,4,3), Time.local(2005,10,29,4,3,0).ago(86400.seconds), 'dt-86400.seconds=>dt'
@@ -220,7 +228,7 @@ class TimeExtCalculationsTest < ActiveSupport::TestCase
assert_equal Time.local(2006,3,18,5,3), Time.local(2006,3,19,4,3,0).ago(24.hours), 'st-24.hours=>dt'
assert_equal Time.local(2006,3,18,5,3), Time.local(2006,3,19,4,3,0).ago(86400), 'st-86400=>dt'
assert_equal Time.local(2006,3,18,5,3), Time.local(2006,3,19,4,3,0).ago(86400.seconds), 'st-86400.seconds=>dt'
-
+
assert_equal Time.local(2006,3,17,4,3), Time.local(2006,3,18,4,3,0).ago(24.hours), 'dt-24.hours=>dt'
assert_equal Time.local(2006,3,17,4,3), Time.local(2006,3,18,4,3,0).ago(86400), 'dt-86400=>dt'
assert_equal Time.local(2006,3,17,4,3), Time.local(2006,3,18,4,3,0).ago(86400.seconds), 'dt-86400.seconds=>dt'
@@ -252,7 +260,7 @@ class TimeExtCalculationsTest < ActiveSupport::TestCase
assert_equal Time.local(2006,3,17,4,3), Time.local(2006,3,18,4,3,0).ago(1.day), 'dt-1.day=>dt'
end
end
-
+
def test_since
assert_equal Time.local(2005,2,22,10,10,11), Time.local(2005,2,22,10,10,10).since(1)
assert_equal Time.local(2005,2,22,11,10,10), Time.local(2005,2,22,10,10,10).since(3600)
@@ -268,7 +276,7 @@ class TimeExtCalculationsTest < ActiveSupport::TestCase
assert_equal Time.local(2005,4,3,20,27,0), Time.local(2005,4,2,19,27,0).since(24.hours), 'st+24.hours=>dt'
assert_equal Time.local(2005,4,3,20,27,0), Time.local(2005,4,2,19,27,0).since(86400), 'st+86400=>dt'
assert_equal Time.local(2005,4,3,20,27,0), Time.local(2005,4,2,19,27,0).since(86400.seconds), 'st+86400.seconds=>dt'
-
+
assert_equal Time.local(2005,4,4,19,27,0), Time.local(2005,4,3,19,27,0).since(24.hours), 'dt+24.hours=>dt'
assert_equal Time.local(2005,4,4,19,27,0), Time.local(2005,4,3,19,27,0).since(86400), 'dt+86400=>dt'
assert_equal Time.local(2005,4,4,19,27,0), Time.local(2005,4,3,19,27,0).since(86400.seconds), 'dt+86400.seconds=>dt'
@@ -278,7 +286,7 @@ class TimeExtCalculationsTest < ActiveSupport::TestCase
assert_equal Time.local(2006,10,1,20,27,0), Time.local(2006,9,30,19,27,0).since(24.hours), 'st+24.hours=>dt'
assert_equal Time.local(2006,10,1,20,27,0), Time.local(2006,9,30,19,27,0).since(86400), 'st+86400=>dt'
assert_equal Time.local(2006,10,1,20,27,0), Time.local(2006,9,30,19,27,0).since(86400.seconds), 'st+86400.seconds=>dt'
-
+
assert_equal Time.local(2006,10,2,19,27,0), Time.local(2006,10,1,19,27,0).since(24.hours), 'dt+24.hours=>dt'
assert_equal Time.local(2006,10,2,19,27,0), Time.local(2006,10,1,19,27,0).since(86400), 'dt+86400=>dt'
assert_equal Time.local(2006,10,2,19,27,0), Time.local(2006,10,1,19,27,0).since(86400.seconds), 'dt+86400.seconds=>dt'
@@ -330,7 +338,7 @@ class TimeExtCalculationsTest < ActiveSupport::TestCase
assert_equal Time.local(2005,10,30,23,45,0), Time.local(2005,10,30,0,45,0).since(24.hours), 'dt+24.hours=>st'
assert_equal Time.local(2005,10,30,23,45,0), Time.local(2005,10,30,0,45,0).since(86400), 'dt+86400=>st'
assert_equal Time.local(2005,10,30,23,45,0), Time.local(2005,10,30,0,45,0).since(86400.seconds), 'dt+86400.seconds=>st'
-
+
assert_equal Time.local(2005,11, 1,0,45,0), Time.local(2005,10,31,0,45,0).since(24.hours), 'st+24.hours=>st'
assert_equal Time.local(2005,11, 1,0,45,0), Time.local(2005,10,31,0,45,0).since(86400), 'st+86400=>st'
assert_equal Time.local(2005,11, 1,0,45,0), Time.local(2005,10,31,0,45,0).since(86400.seconds), 'st+86400.seconds=>st'
@@ -340,7 +348,7 @@ class TimeExtCalculationsTest < ActiveSupport::TestCase
assert_equal Time.local(2006,3,20,0,45,0), Time.local(2006,3,19,1,45,0).since(24.hours), 'dt+24.hours=>st'
assert_equal Time.local(2006,3,20,0,45,0), Time.local(2006,3,19,1,45,0).since(86400), 'dt+86400=>st'
assert_equal Time.local(2006,3,20,0,45,0), Time.local(2006,3,19,1,45,0).since(86400.seconds), 'dt+86400.seconds=>st'
-
+
assert_equal Time.local(2006,3,21,1,45,0), Time.local(2006,3,20,1,45,0).since(24.hours), 'st+24.hours=>st'
assert_equal Time.local(2006,3,21,1,45,0), Time.local(2006,3,20,1,45,0).since(86400), 'st+86400=>st'
assert_equal Time.local(2006,3,21,1,45,0), Time.local(2006,3,20,1,45,0).since(86400.seconds), 'st+86400.seconds=>st'
@@ -463,6 +471,16 @@ class TimeExtCalculationsTest < ActiveSupport::TestCase
assert_equal Time.utc(2013,10,17,20,22,19), Time.utc(2005,2,28,15,15,10).advance(:years => 7, :months => 19, :weeks => 2, :days => 5, :hours => 5, :minutes => 7, :seconds => 9)
end
+ def test_prev_week
+ with_env_tz 'US/Eastern' do
+ assert_equal Time.local(2005,2,21), Time.local(2005,3,1,15,15,10).prev_week
+ assert_equal Time.local(2005,2,22), Time.local(2005,3,1,15,15,10).prev_week(:tuesday)
+ assert_equal Time.local(2005,2,25), Time.local(2005,3,1,15,15,10).prev_week(:friday)
+ assert_equal Time.local(2006,10,30), Time.local(2006,11,6,0,0,0).prev_week
+ assert_equal Time.local(2006,11,15), Time.local(2006,11,23,0,0,0).prev_week(:wednesday)
+ end
+ end
+
def test_next_week
with_env_tz 'US/Eastern' do
assert_equal Time.local(2005,2,28), Time.local(2005,2,22,15,15,10).next_week
@@ -729,7 +747,7 @@ class TimeExtCalculationsTest < ActiveSupport::TestCase
def test_minus_with_time_with_zone
assert_equal 86_400.0, Time.utc(2000, 1, 2) - ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 1), ActiveSupport::TimeZone['UTC'] )
end
-
+
def test_minus_with_datetime
assert_equal 86_400.0, Time.utc(2000, 1, 2) - DateTime.civil(2000, 1, 1)
end
diff --git a/activesupport/test/core_ext/time_with_zone_test.rb b/activesupport/test/core_ext/time_with_zone_test.rb
index 5ce4277672..bafa335a09 100644
--- a/activesupport/test/core_ext/time_with_zone_test.rb
+++ b/activesupport/test/core_ext/time_with_zone_test.rb
@@ -36,6 +36,10 @@ class TimeWithZoneTest < Test::Unit::TestCase
assert_equal @twz.object_id, @twz.in_time_zone(ActiveSupport::TimeZone['Eastern Time (US & Canada)']).object_id
end
+ def test_localtime
+ assert_equal @twz.localtime, @twz.utc.getlocal
+ end
+
def test_utc?
assert_equal false, @twz.utc?
assert_equal true, ActiveSupport::TimeWithZone.new(Time.utc(2000), ActiveSupport::TimeZone['UTC']).utc?
@@ -102,11 +106,11 @@ class TimeWithZoneTest < Test::Unit::TestCase
end
def test_to_yaml
- assert_equal "--- 1999-12-31 19:00:00 -05:00\n", @twz.to_yaml
+ assert_match(/^--- 2000-01-01 00:00:00(\.0+)?\s*Z\n/, @twz.to_yaml)
end
def test_ruby_to_yaml
- assert_equal "--- \n:twz: 2000-01-01 00:00:00 Z\n", {:twz => @twz}.to_yaml
+ assert_match(/---\s*\n:twz: 2000-01-01 00:00:00(\.0+)?\s*Z\n/, {:twz => @twz}.to_yaml)
end
def test_httpdate
@@ -287,7 +291,7 @@ class TimeWithZoneTest < Test::Unit::TestCase
assert_equal 946684800, result
assert_kind_of Integer, result
end
-
+
def test_to_i_with_wrapped_datetime
datetime = DateTime.civil(2000, 1, 1, 0)
twz = ActiveSupport::TimeWithZone.new(datetime, @time_zone)
@@ -328,7 +332,7 @@ class TimeWithZoneTest < Test::Unit::TestCase
assert_kind_of Time, @twz
assert_kind_of ActiveSupport::TimeWithZone, @twz
end
-
+
def test_class_name
assert_equal 'Time', ActiveSupport::TimeWithZone.name
end
@@ -703,7 +707,7 @@ class TimeWithZoneTest < Test::Unit::TestCase
assert_equal "Sun, 15 Jul 2007 10:30:00 EDT -04:00", twz.years_ago(1).inspect
assert_equal "Sun, 15 Jul 2007 10:30:00 EDT -04:00", (twz - 1.year).inspect
end
-
+
protected
def with_env_tz(new_tz = 'US/Eastern')
old_tz, ENV['TZ'] = ENV['TZ'], new_tz
@@ -763,6 +767,13 @@ class TimeWithZoneMethodsForTimeAndDateTimeTest < Test::Unit::TestCase
end
end
+ def test_localtime
+ Time.zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)']
+ assert_equal @dt.in_time_zone.localtime, @dt.in_time_zone.utc.to_time.getlocal
+ ensure
+ Time.zone = nil
+ end
+
def test_use_zone
Time.zone = 'Alaska'
Time.use_zone 'Hawaii' do
@@ -790,7 +801,7 @@ class TimeWithZoneMethodsForTimeAndDateTimeTest < Test::Unit::TestCase
assert_equal nil, Time.zone
end
- def test_time_zone_getter_and_setter_with_zone_default
+ def test_time_zone_getter_and_setter_with_zone_default_set
Time.zone_default = ActiveSupport::TimeZone['Alaska']
assert_equal ActiveSupport::TimeZone['Alaska'], Time.zone
Time.zone = ActiveSupport::TimeZone['Hawaii']
@@ -798,6 +809,7 @@ class TimeWithZoneMethodsForTimeAndDateTimeTest < Test::Unit::TestCase
Time.zone = nil
assert_equal ActiveSupport::TimeZone['Alaska'], Time.zone
ensure
+ Time.zone = nil
Time.zone_default = nil
end
@@ -838,7 +850,7 @@ class TimeWithZoneMethodsForTimeAndDateTimeTest < Test::Unit::TestCase
assert_nil Time.zone
end
- def test_current_returns_time_now_when_zone_default_not_set
+ def test_current_returns_time_now_when_zone_not_set
with_env_tz 'US/Eastern' do
Time.stubs(:now).returns Time.local(2000)
assert_equal false, Time.current.is_a?(ActiveSupport::TimeWithZone)
@@ -846,8 +858,8 @@ class TimeWithZoneMethodsForTimeAndDateTimeTest < Test::Unit::TestCase
end
end
- def test_current_returns_time_zone_now_when_zone_default_set
- Time.zone_default = ActiveSupport::TimeZone['Eastern Time (US & Canada)']
+ def test_current_returns_time_zone_now_when_zone_set
+ Time.zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)']
with_env_tz 'US/Eastern' do
Time.stubs(:now).returns Time.local(2000)
assert_equal true, Time.current.is_a?(ActiveSupport::TimeWithZone)
@@ -855,7 +867,7 @@ class TimeWithZoneMethodsForTimeAndDateTimeTest < Test::Unit::TestCase
assert_equal Time.utc(2000), Time.current.time
end
ensure
- Time.zone_default = nil
+ Time.zone = nil
end
protected
diff --git a/activesupport/test/dependencies_test.rb b/activesupport/test/dependencies_test.rb
index f98d823f00..ef017d7436 100644
--- a/activesupport/test/dependencies_test.rb
+++ b/activesupport/test/dependencies_test.rb
@@ -477,15 +477,15 @@ class DependenciesTest < Test::Unit::TestCase
def test_references_should_work
with_loading 'dependencies' do
- c = ActiveSupport::Dependencies.ref("ServiceOne")
+ c = ActiveSupport::Dependencies.reference("ServiceOne")
service_one_first = ServiceOne
- assert_equal service_one_first, c.get
+ assert_equal service_one_first, c.get("ServiceOne")
ActiveSupport::Dependencies.clear
assert ! defined?(ServiceOne)
service_one_second = ServiceOne
- assert_not_equal service_one_first, c.get
- assert_equal service_one_second, c.get
+ assert_not_equal service_one_first, c.get("ServiceOne")
+ assert_equal service_one_second, c.get("ServiceOne")
end
end
@@ -574,16 +574,27 @@ class DependenciesTest < Test::Unit::TestCase
end
end
+ def test_unloadable_constants_should_receive_callback
+ Object.const_set :C, Class.new
+ C.unloadable
+ C.expects(:before_remove_const).once
+ assert C.respond_to?(:before_remove_const)
+ ActiveSupport::Dependencies.clear
+ assert !defined?(C)
+ ensure
+ Object.class_eval { remove_const :C } if defined?(C)
+ end
+
def test_new_contants_in_without_constants
assert_equal [], (ActiveSupport::Dependencies.new_constants_in(Object) { })
- assert ActiveSupport::Dependencies.constant_watch_stack.empty?
+ assert ActiveSupport::Dependencies.constant_watch_stack.all? {|k,v| v.empty? }
end
def test_new_constants_in_with_a_single_constant
assert_equal ["Hello"], ActiveSupport::Dependencies.new_constants_in(Object) {
Object.const_set :Hello, 10
}.map(&:to_s)
- assert ActiveSupport::Dependencies.constant_watch_stack.empty?
+ assert ActiveSupport::Dependencies.constant_watch_stack.all? {|k,v| v.empty? }
ensure
Object.class_eval { remove_const :Hello }
end
@@ -600,7 +611,7 @@ class DependenciesTest < Test::Unit::TestCase
end
assert_equal ["OuterAfter", "OuterBefore"], outer.sort.map(&:to_s)
- assert ActiveSupport::Dependencies.constant_watch_stack.empty?
+ assert ActiveSupport::Dependencies.constant_watch_stack.all? {|k,v| v.empty? }
ensure
%w(OuterBefore Inner OuterAfter).each do |name|
Object.class_eval { remove_const name if const_defined?(name) }
@@ -621,7 +632,7 @@ class DependenciesTest < Test::Unit::TestCase
M.const_set :OuterAfter, 30
end
assert_equal ["M::OuterAfter", "M::OuterBefore"], outer.sort
- assert ActiveSupport::Dependencies.constant_watch_stack.empty?
+ assert ActiveSupport::Dependencies.constant_watch_stack.all? {|k,v| v.empty? }
ensure
Object.class_eval { remove_const :M }
end
@@ -639,7 +650,7 @@ class DependenciesTest < Test::Unit::TestCase
M.const_set :OuterAfter, 30
end
assert_equal ["M::OuterAfter", "M::OuterBefore"], outer.sort
- assert ActiveSupport::Dependencies.constant_watch_stack.empty?
+ assert ActiveSupport::Dependencies.constant_watch_stack.all? {|k,v| v.empty? }
ensure
Object.class_eval { remove_const :M }
end
diff --git a/activesupport/test/file_watcher_test.rb b/activesupport/test/file_watcher_test.rb
new file mode 100644
index 0000000000..7b4d4be24f
--- /dev/null
+++ b/activesupport/test/file_watcher_test.rb
@@ -0,0 +1,233 @@
+require 'abstract_unit'
+require 'fssm'
+require "fileutils"
+require "timeout"
+
+
+class FileWatcherTest < ActiveSupport::TestCase
+ class DumbBackend < ActiveSupport::FileWatcher::Backend
+ end
+
+ def setup
+ @watcher = ActiveSupport::FileWatcher.new
+
+ # In real life, the backend would take the path and use it to observe the file
+ # system. In our case, we will manually trigger the events for unit testing,
+ # so we can pass any path.
+ @backend = DumbBackend.new("RAILS_WOOT", @watcher)
+
+ @payload = []
+ @watcher.watch %r{^app/assets/.*\.scss$} do |pay|
+ pay.each do |status, files|
+ files.sort!
+ end
+ @payload << pay
+ end
+ end
+
+ def test_use_triple_equals
+ fw = ActiveSupport::FileWatcher.new
+ called = []
+ fw.watch("some_arbitrary_file.rb") do |file|
+ called << "omg"
+ end
+ fw.trigger(%w{ some_arbitrary_file.rb })
+ assert_equal ['omg'], called
+ end
+
+ def test_one_change
+ @backend.trigger("app/assets/main.scss" => :changed)
+ assert_equal({:changed => ["app/assets/main.scss"]}, @payload.first)
+ end
+
+ def test_multiple_changes
+ @backend.trigger("app/assets/main.scss" => :changed, "app/assets/javascripts/foo.coffee" => :changed)
+ assert_equal([{:changed => ["app/assets/main.scss"]}], @payload)
+ end
+
+ def test_multiple_changes_match
+ @backend.trigger("app/assets/main.scss" => :changed, "app/assets/print.scss" => :changed, "app/assets/javascripts/foo.coffee" => :changed)
+ assert_equal([{:changed => ["app/assets/main.scss", "app/assets/print.scss"]}], @payload)
+ end
+
+ def test_multiple_state_changes
+ @backend.trigger("app/assets/main.scss" => :created, "app/assets/print.scss" => :changed)
+ assert_equal([{:changed => ["app/assets/print.scss"], :created => ["app/assets/main.scss"]}], @payload)
+ end
+
+ def test_more_blocks
+ payload = []
+ @watcher.watch %r{^config/routes\.rb$} do |pay|
+ payload << pay
+ end
+
+ @backend.trigger "config/routes.rb" => :changed
+ assert_equal [:changed => ["config/routes.rb"]], payload
+ assert_equal [], @payload
+ end
+
+ def test_overlapping_watchers
+ payload = []
+ @watcher.watch %r{^app/assets/main\.scss$} do |pay|
+ payload << pay
+ end
+
+ @backend.trigger "app/assets/print.scss" => :changed, "app/assets/main.scss" => :changed
+ assert_equal [:changed => ["app/assets/main.scss"]], payload
+ assert_equal [:changed => ["app/assets/main.scss", "app/assets/print.scss"]], @payload
+ end
+end
+
+module FSSM::Backends
+ class Polling
+ def initialize_with_low_latency(options={})
+ initialize_without_low_latency(options.merge(:latency => 0.1))
+ end
+ alias_method_chain :initialize, :low_latency
+ end
+end
+
+class FSSMFileWatcherTest < ActiveSupport::TestCase
+ class FSSMBackend < ActiveSupport::FileWatcher::Backend
+ def initialize(path, watcher)
+ super
+
+ monitor = FSSM::Monitor.new
+ monitor.path(path, '**/*') do |p|
+ p.update { |base, relative| trigger relative => :changed }
+ p.delete { |base, relative| trigger relative => :deleted }
+ p.create { |base, relative| trigger relative => :created }
+ end
+
+ @thread = Thread.new do
+ monitor.run
+ end
+ end
+
+ def stop
+ @thread.kill
+ end
+ end
+
+ def setup
+ Thread.abort_on_exception = true
+
+ @payload = []
+ @triggered = false
+
+ @watcher = ActiveSupport::FileWatcher.new
+
+ @path = path = File.expand_path("../tmp", __FILE__)
+ FileUtils.rm_rf path
+
+ create "app/assets/main.scss", true
+ create "app/assets/javascripts/foo.coffee", true
+ create "app/assets/print.scss", true
+ create "app/assets/videos.scss", true
+
+ @backend = FSSMBackend.new(path, @watcher)
+
+ @watcher.watch %r{^app/assets/.*\.scss$} do |pay|
+ pay.each do |status, files|
+ files.sort!
+ end
+ @payload << pay
+ trigger
+ end
+ end
+
+ def teardown
+ @backend.stop
+ Thread.abort_on_exception = false
+ end
+
+ def create(path, past = false)
+ wait(past) do
+ path = File.join(@path, path)
+ FileUtils.mkdir_p(File.dirname(path))
+
+ FileUtils.touch(path)
+ File.utime(Time.now - 100, Time.now - 100, path) if past
+ end
+ end
+
+ def change(path)
+ wait do
+ FileUtils.touch(File.join(@path, path))
+ end
+ end
+
+ def delete(path)
+ wait do
+ FileUtils.rm(File.join(@path, path))
+ end
+ end
+
+ def wait(past = false)
+ yield
+ return if past
+
+ begin
+ Timeout.timeout(1) do
+ sleep 0.05 until @triggered
+ end
+ rescue Timeout::Error
+ end
+
+ @triggered = false
+ end
+
+ def trigger
+ @triggered = true
+ end
+
+ def test_one_change
+ change "app/assets/main.scss"
+ assert_equal({:changed => ["app/assets/main.scss"]}, @payload.first)
+ end
+
+ def test_multiple_changes
+ change "app/assets/main.scss"
+ change "app/assets/javascripts/foo.coffee"
+ assert_equal([{:changed => ["app/assets/main.scss"]}], @payload)
+ end
+
+ def test_multiple_changes_match
+ change "app/assets/main.scss"
+ change "app/assets/print.scss"
+ change "app/assets/javascripts/foo.coffee"
+ assert_equal([{:changed => ["app/assets/main.scss"]}, {:changed => ["app/assets/print.scss"]}], @payload)
+ end
+
+ def test_multiple_state_changes
+ create "app/assets/new.scss"
+ change "app/assets/print.scss"
+ delete "app/assets/videos.scss"
+ assert_equal([{:created => ["app/assets/new.scss"]}, {:changed => ["app/assets/print.scss"]}, {:deleted => ["app/assets/videos.scss"]}], @payload)
+ end
+
+ def test_more_blocks
+ payload = []
+ @watcher.watch %r{^config/routes\.rb$} do |pay|
+ payload << pay
+ trigger
+ end
+
+ create "config/routes.rb"
+ assert_equal [{:created => ["config/routes.rb"]}], payload
+ assert_equal [], @payload
+ end
+
+ def test_overlapping_watchers
+ payload = []
+ @watcher.watch %r{^app/assets/main\.scss$} do |pay|
+ payload << pay
+ trigger
+ end
+
+ change "app/assets/main.scss"
+ change "app/assets/print.scss"
+ assert_equal [{:changed => ["app/assets/main.scss"]}], payload
+ assert_equal [{:changed => ["app/assets/main.scss"]}, {:changed => ["app/assets/print.scss"]}], @payload
+ end
+end
diff --git a/activesupport/test/gzip_test.rb b/activesupport/test/gzip_test.rb
index 2a24c0bd0d..f564e63f29 100644
--- a/activesupport/test/gzip_test.rb
+++ b/activesupport/test/gzip_test.rb
@@ -1,7 +1,18 @@
require 'abstract_unit'
+require 'active_support/core_ext/object/blank'
class GzipTest < Test::Unit::TestCase
def test_compress_should_decompress_to_the_same_value
assert_equal "Hello World", ActiveSupport::Gzip.decompress(ActiveSupport::Gzip.compress("Hello World"))
end
-end \ No newline at end of file
+
+ def test_compress_should_return_a_binary_string
+ compressed = ActiveSupport::Gzip.compress('')
+
+ if "".encoding_aware?
+ assert_equal Encoding.find('binary'), compressed.encoding
+ end
+
+ assert !compressed.blank?, "a compressed blank string should not be blank"
+ end
+end
diff --git a/activesupport/test/i18n_test.rb b/activesupport/test/i18n_test.rb
index dfcd4f822d..34825c9b8f 100644
--- a/activesupport/test/i18n_test.rb
+++ b/activesupport/test/i18n_test.rb
@@ -7,68 +7,68 @@ class I18nTest < Test::Unit::TestCase
@date = Date.parse("2008-7-2")
@time = Time.utc(2008, 7, 2, 16, 47, 1)
end
-
+
def test_time_zone_localization_with_default_format
now = Time.local(2000)
assert_equal now.strftime("%a, %d %b %Y %H:%M:%S %z"), I18n.localize(now)
end
-
+
def test_date_localization_should_use_default_format
assert_equal @date.strftime("%Y-%m-%d"), I18n.localize(@date)
end
-
+
def test_date_localization_with_default_format
assert_equal @date.strftime("%Y-%m-%d"), I18n.localize(@date, :format => :default)
end
-
+
def test_date_localization_with_short_format
assert_equal @date.strftime("%b %d"), I18n.localize(@date, :format => :short)
end
-
+
def test_date_localization_with_long_format
assert_equal @date.strftime("%B %d, %Y"), I18n.localize(@date, :format => :long)
end
-
- def test_time_localization_should_use_default_format
+
+ def test_time_localization_should_use_default_format
assert_equal @time.strftime("%a, %d %b %Y %H:%M:%S %z"), I18n.localize(@time)
end
-
+
def test_time_localization_with_default_format
assert_equal @time.strftime("%a, %d %b %Y %H:%M:%S %z"), I18n.localize(@time, :format => :default)
end
-
+
def test_time_localization_with_short_format
assert_equal @time.strftime("%d %b %H:%M"), I18n.localize(@time, :format => :short)
end
-
+
def test_time_localization_with_long_format
assert_equal @time.strftime("%B %d, %Y %H:%M"), I18n.localize(@time, :format => :long)
end
-
+
def test_day_names
assert_equal Date::DAYNAMES, I18n.translate(:'date.day_names')
end
-
+
def test_abbr_day_names
assert_equal Date::ABBR_DAYNAMES, I18n.translate(:'date.abbr_day_names')
end
-
+
def test_month_names
assert_equal Date::MONTHNAMES, I18n.translate(:'date.month_names')
end
-
+
def test_abbr_month_names
assert_equal Date::ABBR_MONTHNAMES, I18n.translate(:'date.abbr_month_names')
end
-
+
def test_date_order
assert_equal [:year, :month, :day], I18n.translate(:'date.order')
end
-
+
def test_time_am
assert_equal 'am', I18n.translate(:'time.am')
end
-
+
def test_time_pm
assert_equal 'pm', I18n.translate(:'time.pm')
end
diff --git a/activesupport/test/inflector_test.rb b/activesupport/test/inflector_test.rb
index 2990177bed..1670d9ee7d 100644
--- a/activesupport/test/inflector_test.rb
+++ b/activesupport/test/inflector_test.rb
@@ -22,20 +22,55 @@ class InflectorTest < Test::Unit::TestCase
assert_equal "", ActiveSupport::Inflector.pluralize("")
end
+ ActiveSupport::Inflector.inflections.uncountable.each do |word|
+ define_method "test_uncountability_of_#{word}" do
+ assert_equal word, ActiveSupport::Inflector.singularize(word)
+ assert_equal word, ActiveSupport::Inflector.pluralize(word)
+ assert_equal ActiveSupport::Inflector.pluralize(word), ActiveSupport::Inflector.singularize(word)
+ end
+ end
+
+ def test_uncountable_word_is_not_greedy
+ uncountable_word = "ors"
+ countable_word = "sponsor"
+
+ cached_uncountables = ActiveSupport::Inflector.inflections.uncountables
+
+ ActiveSupport::Inflector.inflections.uncountable << uncountable_word
+
+ assert_equal uncountable_word, ActiveSupport::Inflector.singularize(uncountable_word)
+ assert_equal uncountable_word, ActiveSupport::Inflector.pluralize(uncountable_word)
+ assert_equal ActiveSupport::Inflector.pluralize(uncountable_word), ActiveSupport::Inflector.singularize(uncountable_word)
+
+ assert_equal "sponsor", ActiveSupport::Inflector.singularize(countable_word)
+ assert_equal "sponsors", ActiveSupport::Inflector.pluralize(countable_word)
+ assert_equal "sponsor", ActiveSupport::Inflector.singularize(ActiveSupport::Inflector.pluralize(countable_word))
+
+ ensure
+ ActiveSupport::Inflector.inflections.instance_variable_set :@uncountables, cached_uncountables
+ end
+
SingularToPlural.each do |singular, plural|
- define_method "test_pluralize_#{singular}" do
+ define_method "test_pluralize_singular_#{singular}" do
assert_equal(plural, ActiveSupport::Inflector.pluralize(singular))
assert_equal(plural.capitalize, ActiveSupport::Inflector.pluralize(singular.capitalize))
end
end
SingularToPlural.each do |singular, plural|
- define_method "test_singularize_#{plural}" do
+ define_method "test_singularize_plural_#{plural}" do
assert_equal(singular, ActiveSupport::Inflector.singularize(plural))
assert_equal(singular.capitalize, ActiveSupport::Inflector.singularize(plural.capitalize))
end
end
+ SingularToPlural.each do |singular, plural|
+ define_method "test_pluralize_plural_#{plural}" do
+ assert_equal(plural, ActiveSupport::Inflector.pluralize(plural))
+ assert_equal(plural.capitalize, ActiveSupport::Inflector.pluralize(plural.capitalize))
+ end
+ end
+
def test_overwrite_previous_inflectors
assert_equal("series", ActiveSupport::Inflector.singularize("series"))
ActiveSupport::Inflector.inflections.singular "series", "serie"
diff --git a/activesupport/test/inflector_test_cases.rb b/activesupport/test/inflector_test_cases.rb
index 59515dad32..2b144e5931 100644
--- a/activesupport/test/inflector_test_cases.rb
+++ b/activesupport/test/inflector_test_cases.rb
@@ -44,6 +44,7 @@ module InflectorTestCases
"datum" => "data",
"medium" => "media",
+ "stadium" => "stadia",
"analysis" => "analyses",
"node_child" => "node_children",
diff --git a/activesupport/test/json/decoding_test.rb b/activesupport/test/json/decoding_test.rb
index d2e3efaa6b..88cf97de7e 100644
--- a/activesupport/test/json/decoding_test.rb
+++ b/activesupport/test/json/decoding_test.rb
@@ -17,8 +17,16 @@ class TestJSONDecoding < ActiveSupport::TestCase
%({"matzue": "松江", "asakusa": "浅草"}) => {"matzue" => "松江", "asakusa" => "浅草"},
%({"a": "2007-01-01"}) => {'a' => Date.new(2007, 1, 1)},
%({"a": "2007-01-01 01:12:34 Z"}) => {'a' => Time.utc(2007, 1, 1, 1, 12, 34)},
+ %(["2007-01-01 01:12:34 Z"]) => [Time.utc(2007, 1, 1, 1, 12, 34)],
+ %(["2007-01-01 01:12:34 Z", "2007-01-01 01:12:35 Z"]) => [Time.utc(2007, 1, 1, 1, 12, 34), Time.utc(2007, 1, 1, 1, 12, 35)],
# no time zone
%({"a": "2007-01-01 01:12:34"}) => {'a' => "2007-01-01 01:12:34"},
+ # invalid date
+ %({"a": "1089-10-40"}) => {'a' => "1089-10-40"},
+ # xmlschema date notation
+ %({"a": "2009-08-10T19:01:02Z"}) => {'a' => Time.utc(2009, 8, 10, 19, 1, 2)},
+ %({"a": "2009-08-10T19:01:02+02:00"}) => {'a' => Time.utc(2009, 8, 10, 17, 1, 2)},
+ %({"a": "2009-08-10T19:01:02-05:00"}) => {'a' => Time.utc(2009, 8, 11, 00, 1, 2)},
# needs to be *exact*
%({"a": " 2007-01-01 01:12:34 Z "}) => {'a' => " 2007-01-01 01:12:34 Z "},
%({"a": "2007-01-01 : it's your birthday"}) => {'a' => "2007-01-01 : it's your birthday"},
@@ -41,7 +49,11 @@ class TestJSONDecoding < ActiveSupport::TestCase
[{'d' => Date.new(1970, 1, 1), 's' => ' escape'},{'d' => Date.new(1970, 1, 1), 's' => ' escape'}],
%q([{"d":"1970-01-01","s":"http:\/\/example.com"},{"d":"1970-01-01","s":"http:\/\/example.com"}]) =>
[{'d' => Date.new(1970, 1, 1), 's' => 'http://example.com'},
- {'d' => Date.new(1970, 1, 1), 's' => 'http://example.com'}]
+ {'d' => Date.new(1970, 1, 1), 's' => 'http://example.com'}],
+ # tests escaping of "\n" char with Yaml backend
+ %q({"a":"\n"}) => {"a"=>"\n"},
+ %q({"a":"\u000a"}) => {"a"=>"\n"},
+ %q({"a":"Line1\u000aLine2"}) => {"a"=>"Line1\nLine2"}
}
# load the default JSON backend
@@ -57,20 +69,16 @@ class TestJSONDecoding < ActiveSupport::TestCase
ActiveSupport.parse_json_times = true
silence_warnings do
ActiveSupport::JSON.with_backend backend do
- assert_nothing_raised do
- assert_equal expected, ActiveSupport::JSON.decode(json)
- end
+ assert_equal expected, ActiveSupport::JSON.decode(json)
end
end
end
end
- end
- if backends.include?("JSONGem")
- test "json decodes time json with time parsing disabled" do
+ test "json decodes time json with time parsing disabled with the #{backend} backend" do
ActiveSupport.parse_json_times = false
expected = {"a" => "2007-01-01 01:12:34 Z"}
- ActiveSupport::JSON.with_backend "JSONGem" do
+ ActiveSupport::JSON.with_backend backend do
assert_equal expected, ActiveSupport::JSON.decode(%({"a": "2007-01-01 01:12:34 Z"}))
end
end
diff --git a/activesupport/test/json/encoding_test.rb b/activesupport/test/json/encoding_test.rb
index 1527d02d16..d5fcbf15b7 100644
--- a/activesupport/test/json/encoding_test.rb
+++ b/activesupport/test/json/encoding_test.rb
@@ -1,5 +1,6 @@
# encoding: utf-8
require 'abstract_unit'
+require 'active_support/core_ext/string/inflections'
require 'active_support/json'
class TestJSONEncoding < Test::Unit::TestCase
@@ -108,12 +109,24 @@ class TestJSONEncoding < Test::Unit::TestCase
end
end
- def test_exception_raised_when_encoding_circular_reference
+ def test_exception_raised_when_encoding_circular_reference_in_array
a = [1]
a << a
assert_raise(ActiveSupport::JSON::Encoding::CircularReferenceError) { ActiveSupport::JSON.encode(a) }
end
+ def test_exception_raised_when_encoding_circular_reference_in_hash
+ a = { :name => 'foo' }
+ a[:next] = a
+ assert_raise(ActiveSupport::JSON::Encoding::CircularReferenceError) { ActiveSupport::JSON.encode(a) }
+ end
+
+ def test_exception_raised_when_encoding_circular_reference_in_hash_inside_array
+ a = { :name => 'foo', :sub => [] }
+ a[:sub] << a
+ assert_raise(ActiveSupport::JSON::Encoding::CircularReferenceError) { ActiveSupport::JSON.encode(a) }
+ end
+
def test_hash_key_identifiers_are_always_quoted
values = {0 => 0, 1 => 1, :_ => :_, "$" => "$", "a" => "a", :A => :A, :A0 => :A0, "A0B" => "A0B"}
assert_equal %w( "$" "A" "A0" "A0B" "_" "a" "0" "1" ).sort, object_keys(ActiveSupport::JSON.encode(values))
@@ -152,6 +165,87 @@ class TestJSONEncoding < Test::Unit::TestCase
end
end
+ def test_hash_should_pass_encoding_options_to_children_in_as_json
+ person = {
+ :name => 'John',
+ :address => {
+ :city => 'London',
+ :country => 'UK'
+ }
+ }
+ json = person.as_json :only => [:address, :city]
+
+ assert_equal({ 'address' => { 'city' => 'London' }}, json)
+ end
+
+ def test_hash_should_pass_encoding_options_to_children_in_to_json
+ person = {
+ :name => 'John',
+ :address => {
+ :city => 'London',
+ :country => 'UK'
+ }
+ }
+ json = person.to_json :only => [:address, :city]
+
+ assert_equal(%({"address":{"city":"London"}}), json)
+ end
+
+ def test_array_should_pass_encoding_options_to_children_in_as_json
+ people = [
+ { :name => 'John', :address => { :city => 'London', :country => 'UK' }},
+ { :name => 'Jean', :address => { :city => 'Paris' , :country => 'France' }}
+ ]
+ json = people.as_json :only => [:address, :city]
+ expected = [
+ { 'address' => { 'city' => 'London' }},
+ { 'address' => { 'city' => 'Paris' }}
+ ]
+
+ assert_equal(expected, json)
+ end
+
+ def test_array_should_pass_encoding_options_to_children_in_to_json
+ people = [
+ { :name => 'John', :address => { :city => 'London', :country => 'UK' }},
+ { :name => 'Jean', :address => { :city => 'Paris' , :country => 'France' }}
+ ]
+ json = people.to_json :only => [:address, :city]
+
+ assert_equal(%([{"address":{"city":"London"}},{"address":{"city":"Paris"}}]), json)
+ end
+
+ def test_struct_encoding
+ Struct.new('UserNameAndEmail', :name, :email)
+ Struct.new('UserNameAndDate', :name, :date)
+ Struct.new('Custom', :name, :sub)
+ user_email = Struct::UserNameAndEmail.new 'David', 'sample@example.com'
+ user_birthday = Struct::UserNameAndDate.new 'David', Date.new(2010, 01, 01)
+ custom = Struct::Custom.new 'David', user_birthday
+
+
+ json_strings = ""
+ json_string_and_date = ""
+ json_custom = ""
+
+ assert_nothing_raised do
+ json_strings = user_email.to_json
+ json_string_and_date = user_birthday.to_json
+ json_custom = custom.to_json
+ end
+
+ assert_equal({"name" => "David",
+ "sub" => {
+ "name" => "David",
+ "date" => "2010/01/01" }}, JSON.parse(json_custom))
+
+ assert_equal({"name" => "David", "email" => "sample@example.com"},
+ JSON.parse(json_strings))
+
+ assert_equal({"name" => "David", "date" => "2010/01/01"},
+ JSON.parse(json_string_and_date))
+ end
+
protected
def object_keys(json_object)
diff --git a/activesupport/test/memoizable_test.rb b/activesupport/test/memoizable_test.rb
index b11fa8d346..bceac1315b 100644
--- a/activesupport/test/memoizable_test.rb
+++ b/activesupport/test/memoizable_test.rb
@@ -36,6 +36,13 @@ class MemoizableTest < ActiveSupport::TestCase
memoize :name, :age
+ protected
+
+ def memoize_protected_test
+ 'protected'
+ end
+ memoize :memoize_protected_test
+
private
def is_developer?
@@ -237,6 +244,13 @@ class MemoizableTest < ActiveSupport::TestCase
assert_raise(RuntimeError) { company.memoize :name }
end
+ def test_protected_method_memoization
+ person = Person.new
+
+ assert_raise(NoMethodError) { person.memoize_protected_test }
+ assert_equal "protected", person.send(:memoize_protected_test)
+ end
+
def test_private_method_memoization
person = Person.new
diff --git a/activesupport/test/message_encryptor_test.rb b/activesupport/test/message_encryptor_test.rb
index 684b931176..419ac14283 100644
--- a/activesupport/test/message_encryptor_test.rb
+++ b/activesupport/test/message_encryptor_test.rb
@@ -14,18 +14,18 @@ class MessageEncryptorTest < Test::Unit::TestCase
@encryptor = ActiveSupport::MessageEncryptor.new(ActiveSupport::SecureRandom.hex(64))
@data = { :some => "data", :now => Time.local(2010) }
end
-
+
def test_simple_round_tripping
message = @encryptor.encrypt(@data)
assert_equal @data, @encryptor.decrypt(message)
end
-
+
def test_encrypting_twice_yields_differing_cipher_text
first_messqage = @encryptor.encrypt(@data)
second_message = @encryptor.encrypt(@data)
assert_not_equal first_messqage, second_message
end
-
+
def test_messing_with_either_value_causes_failure
text, iv = @encryptor.encrypt(@data).split("--")
assert_not_decrypted([iv, text] * "--")
@@ -33,20 +33,20 @@ class MessageEncryptorTest < Test::Unit::TestCase
assert_not_decrypted([munge(text), iv] * "--")
assert_not_decrypted([munge(text), munge(iv)] * "--")
end
-
+
def test_signed_round_tripping
message = @encryptor.encrypt_and_sign(@data)
assert_equal @data, @encryptor.decrypt_and_verify(message)
end
-
-
+
+
private
def assert_not_decrypted(value)
assert_raise(ActiveSupport::MessageEncryptor::InvalidMessage) do
@encryptor.decrypt(value)
end
end
-
+
def munge(base64_string)
bits = ActiveSupport::Base64.decode64(base64_string)
bits.reverse!
diff --git a/activesupport/test/multibyte_conformance.rb b/activesupport/test/multibyte_conformance.rb
index 6ec9a839af..b3b477bb75 100644
--- a/activesupport/test/multibyte_conformance.rb
+++ b/activesupport/test/multibyte_conformance.rb
@@ -27,21 +27,21 @@ end
class MultibyteConformanceTest < Test::Unit::TestCase
include MultibyteTestHelpers
-
+
UNIDATA_URL = "http://www.unicode.org/Public/#{ActiveSupport::Multibyte::Unicode::UNICODE_VERSION}/ucd"
UNIDATA_FILE = '/NormalizationTest.txt'
CACHE_DIR = File.join(Dir.tmpdir, 'cache')
-
+
def setup
FileUtils.mkdir_p(CACHE_DIR)
Downloader.download(UNIDATA_URL + UNIDATA_FILE, CACHE_DIR + UNIDATA_FILE)
@proxy = ActiveSupport::Multibyte::Chars
end
-
+
def test_normalizations_C
each_line_of_norm_tests do |*cols|
col1, col2, col3, col4, col5, comment = *cols
-
+
# CONFORMANCE:
# 1. The following invariants must be true for all conformant implementations
#
@@ -56,7 +56,7 @@ class MultibyteConformanceTest < Test::Unit::TestCase
assert_equal_codepoints col4, @proxy.new(col5).normalize(:c), "Form C - Col 4 has to be C(5) - #{comment}"
end
end
-
+
def test_normalizations_D
each_line_of_norm_tests do |*cols|
col1, col2, col3, col4, col5, comment = *cols
@@ -71,10 +71,10 @@ class MultibyteConformanceTest < Test::Unit::TestCase
assert_equal_codepoints col5, @proxy.new(col5).normalize(:d), "Form D - Col 5 has to be NFD(5) - #{comment}"
end
end
-
+
def test_normalizations_KC
each_line_of_norm_tests do | *cols |
- col1, col2, col3, col4, col5, comment = *cols
+ col1, col2, col3, col4, col5, comment = *cols
#
# NFKC
# c4 == NFKC(c1) == NFKC(c2) == NFKC(c3) == NFKC(c4) == NFKC(c5)
@@ -85,10 +85,10 @@ class MultibyteConformanceTest < Test::Unit::TestCase
assert_equal_codepoints col4, @proxy.new(col5).normalize(:kc), "Form D - Col 4 has to be NFKC(5) - #{comment}"
end
end
-
+
def test_normalizations_KD
each_line_of_norm_tests do | *cols |
- col1, col2, col3, col4, col5, comment = *cols
+ col1, col2, col3, col4, col5, comment = *cols
#
# NFKD
# c5 == NFKD(c1) == NFKD(c2) == NFKD(c3) == NFKD(c4) == NFKD(c5)
@@ -99,7 +99,7 @@ class MultibyteConformanceTest < Test::Unit::TestCase
assert_equal_codepoints col5, @proxy.new(col5).normalize(:kd), "Form KD - Col 5 has to be NFKD(5) - #{comment}"
end
end
-
+
protected
def each_line_of_norm_tests(&block)
lines = 0
@@ -108,21 +108,21 @@ class MultibyteConformanceTest < Test::Unit::TestCase
until f.eof? || (max_test_lines > 38 and lines > max_test_lines)
lines += 1
line = f.gets.chomp!
- next if (line.empty? || line =~ /^\#/)
-
+ next if (line.empty? || line =~ /^\#/)
+
cols, comment = line.split("#")
cols = cols.split(";").map{|e| e.strip}.reject{|e| e.empty? }
next unless cols.length == 5
-
+
# codepoints are in hex in the test suite, pack wants them as integers
cols.map!{|c| c.split.map{|codepoint| codepoint.to_i(16)}.pack("U*") }
cols << comment
-
+
yield(*cols)
end
end
end
-
+
def inspect_codepoints(str)
str.to_s.unpack("U*").map{|cp| cp.to_s(16) }.join(' ')
end
diff --git a/activesupport/test/notifications_test.rb b/activesupport/test/notifications_test.rb
index 9faa11efbc..7b48b3f85b 100644
--- a/activesupport/test/notifications_test.rb
+++ b/activesupport/test/notifications_test.rb
@@ -3,14 +3,19 @@ require 'abstract_unit'
module Notifications
class TestCase < ActiveSupport::TestCase
def setup
- ActiveSupport::Notifications.notifier = nil
- @notifier = ActiveSupport::Notifications.notifier
+ @old_notifier = ActiveSupport::Notifications.notifier
+ @notifier = ActiveSupport::Notifications::Fanout.new
+ ActiveSupport::Notifications.notifier = @notifier
@events = []
@named_events = []
@subscription = @notifier.subscribe { |*args| @events << event(*args) }
@named_subscription = @notifier.subscribe("named.subscription") { |*args| @named_events << event(*args) }
end
+ def teardown
+ ActiveSupport::Notifications.notifier = @old_notifier
+ end
+
private
def event(*args)
diff --git a/activesupport/test/option_merger_test.rb b/activesupport/test/option_merger_test.rb
index 33e3e69666..5b2e16a212 100644
--- a/activesupport/test/option_merger_test.rb
+++ b/activesupport/test/option_merger_test.rb
@@ -65,7 +65,7 @@ class OptionMergerTest < Test::Unit::TestCase
end
end
end
-
+
def test_nested_method_with_options_using_lamdba
local_lamdba = lambda { { :lambda => true } }
with_options(@options) do |o|
diff --git a/activesupport/test/ordered_hash_test.rb b/activesupport/test/ordered_hash_test.rb
index f47e896487..50168fa78f 100644
--- a/activesupport/test/ordered_hash_test.rb
+++ b/activesupport/test/ordered_hash_test.rb
@@ -78,20 +78,26 @@ class OrderedHashTest < Test::Unit::TestCase
def test_each_key
keys = []
- @ordered_hash.each_key { |k| keys << k }
+ assert_equal @ordered_hash, @ordered_hash.each_key { |k| keys << k }
assert_equal @keys, keys
+ expected_class = RUBY_VERSION < '1.9' ? Enumerable::Enumerator : Enumerator
+ assert_kind_of expected_class, @ordered_hash.each_key
end
def test_each_value
values = []
- @ordered_hash.each_value { |v| values << v }
+ assert_equal @ordered_hash, @ordered_hash.each_value { |v| values << v }
assert_equal @values, values
+ expected_class = RUBY_VERSION < '1.9' ? Enumerable::Enumerator : Enumerator
+ assert_kind_of expected_class, @ordered_hash.each_value
end
def test_each
values = []
- @ordered_hash.each {|key, value| values << value}
+ assert_equal @ordered_hash, @ordered_hash.each {|key, value| values << value}
assert_equal @values, values
+ expected_class = RUBY_VERSION < '1.9' ? Enumerable::Enumerator : Enumerator
+ assert_kind_of expected_class, @ordered_hash.each
end
def test_each_with_index
@@ -109,6 +115,14 @@ class OrderedHashTest < Test::Unit::TestCase
assert_equal @keys, keys
end
+ def test_find_all
+ assert_equal @keys, @ordered_hash.find_all { true }.map(&:first)
+ end
+
+ def test_select
+ assert_equal @keys, @ordered_hash.select { true }.map(&:first)
+ end
+
def test_delete_if
copy = @ordered_hash.dup
copy.delete('pink')
@@ -217,8 +231,8 @@ class OrderedHashTest < Test::Unit::TestCase
ActiveSupport::OrderedHash[1,2,3,4,5]
flunk "Hash::[] should have raised an exception on initialization " +
"with an odd number of parameters"
- rescue
- assert_equal "odd number of arguments for Hash", $!.message
+ rescue ArgumentError => e
+ assert_equal "odd number of arguments for Hash", e.message
end
end
@@ -231,14 +245,14 @@ class OrderedHashTest < Test::Unit::TestCase
def test_each_after_yaml_serialization
values = []
- @deserialized_ordered_hash = YAML::load(YAML::dump(@ordered_hash))
+ @deserialized_ordered_hash = YAML.load(YAML.dump(@ordered_hash))
@deserialized_ordered_hash.each {|key, value| values << value}
assert_equal @values, values
end
def test_order_after_yaml_serialization
- @deserialized_ordered_hash = YAML::load(YAML::dump(@ordered_hash))
+ @deserialized_ordered_hash = YAML.load(YAML.dump(@ordered_hash))
assert_equal @keys, @deserialized_ordered_hash.keys
assert_equal @values, @deserialized_ordered_hash.values
@@ -247,12 +261,34 @@ class OrderedHashTest < Test::Unit::TestCase
def test_order_after_yaml_serialization_with_nested_arrays
@ordered_hash[:array] = %w(a b c)
- @deserialized_ordered_hash = YAML::load(YAML::dump(@ordered_hash))
+ @deserialized_ordered_hash = YAML.load(YAML.dump(@ordered_hash))
assert_equal @ordered_hash.keys, @deserialized_ordered_hash.keys
assert_equal @ordered_hash.values, @deserialized_ordered_hash.values
end
+ begin
+ require 'psych'
+
+ def test_psych_serialize
+ @deserialized_ordered_hash = Psych.load(Psych.dump(@ordered_hash))
+
+ values = @deserialized_ordered_hash.map { |_, value| value }
+ assert_equal @values, values
+ end
+
+ def test_psych_serialize_tag
+ yaml = Psych.dump(@ordered_hash)
+ assert_match '!omap', yaml
+ end
+ rescue LoadError
+ end
+
+ def test_has_yaml_tag
+ @ordered_hash[:array] = %w(a b c)
+ assert_match '!omap', YAML.dump(@ordered_hash)
+ end
+
def test_update_sets_keys
@updated_ordered_hash = ActiveSupport::OrderedHash.new
@updated_ordered_hash.update(:name => "Bob")
diff --git a/activesupport/test/rescuable_test.rb b/activesupport/test/rescuable_test.rb
index 1c74ce8b2a..bf4f5265ef 100644
--- a/activesupport/test/rescuable_test.rb
+++ b/activesupport/test/rescuable_test.rb
@@ -24,7 +24,7 @@ class Stargate
rescue_from NuclearExplosion do
@result = 'alldead'
end
-
+
rescue_from MadRonon do |e|
@result = e.message
end
@@ -80,16 +80,16 @@ class RescueableTest < Test::Unit::TestCase
@stargate.dispatch :attack
assert_equal 'killed', @stargate.result
end
-
+
def test_rescue_from_with_block
@stargate.dispatch :nuke
assert_equal 'alldead', @stargate.result
end
-
+
def test_rescue_from_with_block_with_args
@stargate.dispatch :ronanize
assert_equal 'dex', @stargate.result
- end
+ end
def test_rescues_defined_later_are_added_at_end_of_the_rescue_handlers_array
expected = ["WraithAttack", "WraithAttack", "NuclearExplosion", "MadRonon"]
diff --git a/activesupport/test/safe_buffer_test.rb b/activesupport/test/safe_buffer_test.rb
index bf61f9e58c..a4e2acbb32 100644
--- a/activesupport/test/safe_buffer_test.rb
+++ b/activesupport/test/safe_buffer_test.rb
@@ -1,4 +1,10 @@
require 'abstract_unit'
+begin
+ require 'psych'
+rescue LoadError
+end
+
+require 'yaml'
class SafeBufferTest < ActiveSupport::TestCase
def setup
@@ -38,4 +44,20 @@ class SafeBufferTest < ActiveSupport::TestCase
new_buffer = @buffer.to_s
assert_equal ActiveSupport::SafeBuffer, new_buffer.class
end
+
+ def test_to_yaml
+ str = 'hello!'
+ buf = ActiveSupport::SafeBuffer.new str
+ yaml = buf.to_yaml
+
+ assert_match(/^--- #{str}/, yaml)
+ assert_equal 'hello!', YAML.load(yaml)
+ end
+
+ def test_nested
+ str = 'hello!'
+ data = { 'str' => ActiveSupport::SafeBuffer.new(str) }
+ yaml = YAML.dump data
+ assert_equal({'str' => str}, YAML.load(yaml))
+ end
end
diff --git a/activesupport/test/test_case_test.rb b/activesupport/test/test_case_test.rb
new file mode 100644
index 0000000000..756d21b3e4
--- /dev/null
+++ b/activesupport/test/test_case_test.rb
@@ -0,0 +1,61 @@
+require 'abstract_unit'
+
+module ActiveSupport
+ class TestCaseTest < ActiveSupport::TestCase
+ class FakeRunner
+ attr_reader :puked
+
+ def initialize
+ @puked = []
+ end
+
+ def puke(klass, name, e)
+ @puked << [klass, name, e]
+ end
+
+ def options
+ nil
+ end
+ end
+
+ if defined?(MiniTest::Assertions) && TestCase < MiniTest::Assertions
+ def test_callback_with_exception
+ tc = Class.new(TestCase) do
+ setup :bad_callback
+ def bad_callback; raise 'oh noes' end
+ def test_true; assert true end
+ end
+
+ test_name = 'test_true'
+ fr = FakeRunner.new
+
+ test = tc.new test_name
+ test.run fr
+ klass, name, exception = *fr.puked.first
+
+ assert_equal tc, klass
+ assert_equal test_name, name
+ assert_equal 'oh noes', exception.message
+ end
+
+ def test_teardown_callback_with_exception
+ tc = Class.new(TestCase) do
+ teardown :bad_callback
+ def bad_callback; raise 'oh noes' end
+ def test_true; assert true end
+ end
+
+ test_name = 'test_true'
+ fr = FakeRunner.new
+
+ test = tc.new test_name
+ test.run fr
+ klass, name, exception = *fr.puked.first
+
+ assert_equal tc, klass
+ assert_equal test_name, name
+ assert_equal 'oh noes', exception.message
+ end
+ end
+ end
+end
diff --git a/activesupport/test/test_test.rb b/activesupport/test/test_test.rb
index 633d3b212b..ee5a20c789 100644
--- a/activesupport/test/test_test.rb
+++ b/activesupport/test/test_test.rb
@@ -89,19 +89,19 @@ end
class AssertBlankTest < ActiveSupport::TestCase
BLANK = [ EmptyTrue.new, nil, false, '', ' ', " \n\t \r ", [], {} ]
NOT_BLANK = [ EmptyFalse.new, Object.new, true, 0, 1, 'x', [nil], { nil => 0 } ]
-
+
def test_assert_blank_true
BLANK.each { |v| assert_blank v }
end
-
+
def test_assert_blank_false
NOT_BLANK.each { |v|
- begin
+ begin
assert_blank v
fail 'should not get to here'
rescue Exception => e
- assert_match(/is not blank/, e.message)
- end
+ assert_match(/is not blank/, e.message)
+ end
}
end
end
@@ -109,30 +109,23 @@ end
class AssertPresentTest < ActiveSupport::TestCase
BLANK = [ EmptyTrue.new, nil, false, '', ' ', " \n\t \r ", [], {} ]
NOT_BLANK = [ EmptyFalse.new, Object.new, true, 0, 1, 'x', [nil], { nil => 0 } ]
-
+
def test_assert_blank_true
NOT_BLANK.each { |v| assert_present v }
end
-
+
def test_assert_blank_false
BLANK.each { |v|
- begin
+ begin
assert_present v
fail 'should not get to here'
rescue Exception => e
- assert_match(/is blank/, e.message)
- end
+ assert_match(/is blank/, e.message)
+ end
}
end
end
-# These should always pass
-if ActiveSupport::Testing.const_defined?(:Default)
- class NotTestingThingsTest < Test::Unit::TestCase
- include ActiveSupport::Testing::Default
- end
-end
-
class AlsoDoingNothingTest < ActiveSupport::TestCase
end
diff --git a/activesupport/test/test_xml_mini.rb b/activesupport/test/test_xml_mini.rb
index 585eb15c6e..6dbcd1f40b 100644
--- a/activesupport/test/test_xml_mini.rb
+++ b/activesupport/test/test_xml_mini.rb
@@ -1,49 +1,100 @@
require 'abstract_unit'
require 'active_support/xml_mini'
+require 'active_support/builder'
-class XmlMiniTest < Test::Unit::TestCase
- def test_rename_key_dasherizes_by_default
- assert_equal "my-key", ActiveSupport::XmlMini.rename_key("my_key")
- end
+module XmlMiniTest
+ class RenameKeyTest < Test::Unit::TestCase
+ def test_rename_key_dasherizes_by_default
+ assert_equal "my-key", ActiveSupport::XmlMini.rename_key("my_key")
+ end
- def test_rename_key_does_nothing_with_dasherize_true
- assert_equal "my-key", ActiveSupport::XmlMini.rename_key("my_key", :dasherize => true)
- end
+ def test_rename_key_does_nothing_with_dasherize_true
+ assert_equal "my-key", ActiveSupport::XmlMini.rename_key("my_key", :dasherize => true)
+ end
- def test_rename_key_does_nothing_with_dasherize_false
- assert_equal "my_key", ActiveSupport::XmlMini.rename_key("my_key", :dasherize => false)
- end
+ def test_rename_key_does_nothing_with_dasherize_false
+ assert_equal "my_key", ActiveSupport::XmlMini.rename_key("my_key", :dasherize => false)
+ end
- def test_rename_key_camelizes_with_camelize_true
- assert_equal "MyKey", ActiveSupport::XmlMini.rename_key("my_key", :camelize => true)
- end
+ def test_rename_key_camelizes_with_camelize_false
+ assert_equal "my_key", ActiveSupport::XmlMini.rename_key("my_key", :camelize => false)
+ end
- def test_rename_key_camelizes_with_camelize_true
- assert_equal "MyKey", ActiveSupport::XmlMini.rename_key("my_key", :camelize => true)
- end
+ def test_rename_key_camelizes_with_camelize_nil
+ assert_equal "my_key", ActiveSupport::XmlMini.rename_key("my_key", :camelize => nil)
+ end
- def test_rename_key_does_not_dasherize_leading_underscores
- assert_equal "_id", ActiveSupport::XmlMini.rename_key("_id")
- end
+ def test_rename_key_camelizes_with_camelize_true
+ assert_equal "MyKey", ActiveSupport::XmlMini.rename_key("my_key", :camelize => true)
+ end
- def test_rename_key_with_leading_underscore_dasherizes_interior_underscores
- assert_equal "_my-key", ActiveSupport::XmlMini.rename_key("_my_key")
- end
+ def test_rename_key_lower_camelizes_with_camelize_lower
+ assert_equal "myKey", ActiveSupport::XmlMini.rename_key("my_key", :camelize => :lower)
+ end
- def test_rename_key_does_not_dasherize_trailing_underscores
- assert_equal "id_", ActiveSupport::XmlMini.rename_key("id_")
- end
+ def test_rename_key_lower_camelizes_with_camelize_upper
+ assert_equal "MyKey", ActiveSupport::XmlMini.rename_key("my_key", :camelize => :upper)
+ end
- def test_rename_key_with_trailing_underscore_dasherizes_interior_underscores
- assert_equal "my-key_", ActiveSupport::XmlMini.rename_key("my_key_")
- end
+ def test_rename_key_does_not_dasherize_leading_underscores
+ assert_equal "_id", ActiveSupport::XmlMini.rename_key("_id")
+ end
- def test_rename_key_does_not_dasherize_multiple_leading_underscores
- assert_equal "__id", ActiveSupport::XmlMini.rename_key("__id")
- end
+ def test_rename_key_with_leading_underscore_dasherizes_interior_underscores
+ assert_equal "_my-key", ActiveSupport::XmlMini.rename_key("_my_key")
+ end
+
+ def test_rename_key_does_not_dasherize_trailing_underscores
+ assert_equal "id_", ActiveSupport::XmlMini.rename_key("id_")
+ end
- def test_rename_key_does_not_dasherize_multiple_leading_underscores
- assert_equal "id__", ActiveSupport::XmlMini.rename_key("id__")
+ def test_rename_key_with_trailing_underscore_dasherizes_interior_underscores
+ assert_equal "my-key_", ActiveSupport::XmlMini.rename_key("my_key_")
+ end
+
+ def test_rename_key_does_not_dasherize_multiple_leading_underscores
+ assert_equal "__id", ActiveSupport::XmlMini.rename_key("__id")
+ end
+
+ def test_rename_key_does_not_dasherize_multiple_leading_underscores
+ assert_equal "id__", ActiveSupport::XmlMini.rename_key("id__")
+ end
end
+ class ToTagTest < ActiveSupport::TestCase
+ def assert_xml(xml)
+ assert_equal xml, @options[:builder].target!
+ end
+
+ setup do
+ @xml = ActiveSupport::XmlMini
+ @options = {:skip_instruct => true, :builder => Builder::XmlMarkup.new}
+ end
+
+ test "#to_tag accepts a callable object and passes options with the builder" do
+ @xml.to_tag(:some_tag, lambda {|o| o[:builder].br }, @options)
+ assert_xml "<br/>"
+ end
+
+ test "#to_tag accepts a callable object and passes options and tag name" do
+ @xml.to_tag(:tag, lambda {|o, t| o[:builder].b(t) }, @options)
+ assert_xml "<b>tag</b>"
+ end
+
+ test "#to_tag accepts an object responding to #to_xml and passes the options, where :root is key" do
+ obj = Object.new
+ obj.instance_eval do
+ def to_xml(options) options[:builder].yo(options[:root].to_s) end
+ end
+
+ @xml.to_tag(:tag, obj, @options)
+ assert_xml "<yo>tag</yo>"
+ end
+
+ test "#to_tag accepts arbitrary objects responding to #to_str" do
+ @xml.to_tag(:b, "Howdy", @options)
+ assert_xml "<b>Howdy</b>"
+ end
+ # TODO: test the remaining functions hidden in #to_tag.
+ end
end
diff --git a/activesupport/test/time_zone_test.rb b/activesupport/test/time_zone_test.rb
index af6eee69e5..49cefc6e82 100644
--- a/activesupport/test/time_zone_test.rb
+++ b/activesupport/test/time_zone_test.rb
@@ -216,7 +216,7 @@ class TimeZoneTest < Test::Unit::TestCase
assert_equal "+0000", ActiveSupport::TimeZone.seconds_to_utc_offset(0, false)
assert_equal "+0500", ActiveSupport::TimeZone.seconds_to_utc_offset(18_000, false)
end
-
+
def test_seconds_to_utc_offset_with_negative_offset
assert_equal "-01:00", ActiveSupport::TimeZone.seconds_to_utc_offset(-3_600)
assert_equal "-00:59", ActiveSupport::TimeZone.seconds_to_utc_offset(-3_599)
diff --git a/activesupport/test/whiny_nil_test.rb b/activesupport/test/whiny_nil_test.rb
index 4b9f06dead..ec3ca99ee6 100644
--- a/activesupport/test/whiny_nil_test.rb
+++ b/activesupport/test/whiny_nil_test.rb
@@ -33,9 +33,11 @@ class WhinyNilTest < Test::Unit::TestCase
end
def test_id
+ nil.stubs(:object_id).returns(999)
nil.id
rescue RuntimeError => nme
assert_no_match(/nil:NilClass/, nme.message)
+ assert_match(/999/, nme.message)
end
def test_no_to_ary_coercion