From 45d41f0dadd9fa171f306ff356770c4492726f30 Mon Sep 17 00:00:00 2001 From: Sven Fuchs Date: Thu, 19 Jun 2008 16:25:27 +0200 Subject: integrating I18n into Rails --- .../lib/active_support/core_ext/array/conversions.rb | 14 ++++++++++---- activesupport/lib/active_support/vendor.rb | 7 +++++++ activesupport/lib/active_support/vendor/i18n-0.0.1 | 1 + 3 files changed, 18 insertions(+), 4 deletions(-) create mode 160000 activesupport/lib/active_support/vendor/i18n-0.0.1 (limited to 'activesupport/lib') diff --git a/activesupport/lib/active_support/core_ext/array/conversions.rb b/activesupport/lib/active_support/core_ext/array/conversions.rb index a9882828ca..08e608d346 100644 --- a/activesupport/lib/active_support/core_ext/array/conversions.rb +++ b/activesupport/lib/active_support/core_ext/array/conversions.rb @@ -6,10 +6,15 @@ module ActiveSupport #:nodoc: module Conversions # Converts the array to a comma-separated sentence where the last element is joined by the connector word. Options: # * :connector - The word used to join the last element in arrays with two or more elements (default: "and") - # * :skip_last_comma - Set to true to return "a, b and c" instead of "a, b, and c". - def to_sentence(options = {}) - options.assert_valid_keys(:connector, :skip_last_comma) - options.reverse_merge! :connector => 'and', :skip_last_comma => false + # * :skip_last_comma - Set to true to return "a, b and c" instead of "a, b, and c". + def to_sentence(options = {}) + options.assert_valid_keys(:connector, :skip_last_comma, :locale) + + locale = options[:locale] + locale ||= request.locale if respond_to?(:request) + + default = :'support.array.sentence_connector'.t(locale) + options.reverse_merge! :connector => default, :skip_last_comma => false options[:connector] = "#{options[:connector]} " unless options[:connector].nil? || options[:connector].strip == '' case length @@ -23,6 +28,7 @@ module ActiveSupport #:nodoc: "#{self[0...-1].join(', ')}#{options[:skip_last_comma] ? '' : ','} #{options[:connector]}#{self[-1]}" end end + # Calls to_param on all its elements and joins the result with # slashes. This is used by url_for in Action Pack. diff --git a/activesupport/lib/active_support/vendor.rb b/activesupport/lib/active_support/vendor.rb index a02e42f791..bca2664fa4 100644 --- a/activesupport/lib/active_support/vendor.rb +++ b/activesupport/lib/active_support/vendor.rb @@ -23,4 +23,11 @@ begin gem 'tzinfo', '~> 0.3.9' rescue Gem::LoadError $:.unshift "#{File.dirname(__FILE__)}/vendor/tzinfo-0.3.9" +end + +begin + gem 'i18n', '~> 0.3.9' +rescue Gem::LoadError + $:.unshift "#{File.dirname(__FILE__)}/vendor/i18n-0.0.1/lib" # TODO + require 'i18n' end \ No newline at end of file diff --git a/activesupport/lib/active_support/vendor/i18n-0.0.1 b/activesupport/lib/active_support/vendor/i18n-0.0.1 new file mode 160000 index 0000000000..70ab0f3cc5 --- /dev/null +++ b/activesupport/lib/active_support/vendor/i18n-0.0.1 @@ -0,0 +1 @@ +Subproject commit 70ab0f3cc5921cc67e09741939a08b2582d707cb -- cgit v1.2.3 From 4a8486a1b1aa28d4cab5571b55301917221870e9 Mon Sep 17 00:00:00 2001 From: Sven Fuchs Date: Thu, 19 Jun 2008 16:43:30 +0200 Subject: add lang file for active_support --- activesupport/lib/active_support.rb | 1 + activesupport/lib/active_support/lang/en-US.rb | 7 +++++++ 2 files changed, 8 insertions(+) create mode 100644 activesupport/lib/active_support/lang/en-US.rb (limited to 'activesupport/lib') diff --git a/activesupport/lib/active_support.rb b/activesupport/lib/active_support.rb index 1a8603e892..acdb3056d2 100644 --- a/activesupport/lib/active_support.rb +++ b/activesupport/lib/active_support.rb @@ -55,6 +55,7 @@ require 'active_support/multibyte' require 'active_support/base64' require 'active_support/time_with_zone' +require 'active_support/lang/en-US.rb' Inflector = ActiveSupport::Deprecation::DeprecatedConstantProxy.new('Inflector', 'ActiveSupport::Inflector') Dependencies = ActiveSupport::Deprecation::DeprecatedConstantProxy.new('Dependencies', 'ActiveSupport::Dependencies') diff --git a/activesupport/lib/active_support/lang/en-US.rb b/activesupport/lib/active_support/lang/en-US.rb new file mode 100644 index 0000000000..8732927f48 --- /dev/null +++ b/activesupport/lib/active_support/lang/en-US.rb @@ -0,0 +1,7 @@ +I18n.backend.add_translations :'en-US', { + :support => { + :array => { + :sentence_connector => 'and' + } + } +} \ No newline at end of file -- cgit v1.2.3 From fdb5f810dc41f54f8cdb9c51154ff8987362c13a Mon Sep 17 00:00:00 2001 From: Sven Fuchs Date: Thu, 19 Jun 2008 16:55:47 +0200 Subject: I18n has not been released as a gem, yet --- activesupport/lib/active_support/vendor.rb | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'activesupport/lib') diff --git a/activesupport/lib/active_support/vendor.rb b/activesupport/lib/active_support/vendor.rb index bca2664fa4..381471b833 100644 --- a/activesupport/lib/active_support/vendor.rb +++ b/activesupport/lib/active_support/vendor.rb @@ -25,9 +25,10 @@ rescue Gem::LoadError $:.unshift "#{File.dirname(__FILE__)}/vendor/tzinfo-0.3.9" end -begin - gem 'i18n', '~> 0.3.9' -rescue Gem::LoadError - $:.unshift "#{File.dirname(__FILE__)}/vendor/i18n-0.0.1/lib" # TODO +# TODO I18n gem has not been released yet +# begin +# gem 'i18n', '~> 0.0.1' +# rescue Gem::LoadError + $:.unshift "#{File.dirname(__FILE__)}/vendor/i18n-0.0.1/lib" require 'i18n' -end \ No newline at end of file +# end \ No newline at end of file -- cgit v1.2.3 From 585c8c17c303fc46fcf014a644a541eae6cb5ffd Mon Sep 17 00:00:00 2001 From: Sven Fuchs Date: Fri, 20 Jun 2008 09:13:20 +0200 Subject: rename Backend::Simple#add_translations to set_translations because it overwrites existing translations --- activesupport/lib/active_support/lang/en-US.rb | 2 +- activesupport/lib/active_support/vendor/i18n-0.0.1 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'activesupport/lib') diff --git a/activesupport/lib/active_support/lang/en-US.rb b/activesupport/lib/active_support/lang/en-US.rb index 8732927f48..5b8e04363e 100644 --- a/activesupport/lib/active_support/lang/en-US.rb +++ b/activesupport/lib/active_support/lang/en-US.rb @@ -1,4 +1,4 @@ -I18n.backend.add_translations :'en-US', { +I18n.backend.set_translations :'en-US', { :support => { :array => { :sentence_connector => 'and' diff --git a/activesupport/lib/active_support/vendor/i18n-0.0.1 b/activesupport/lib/active_support/vendor/i18n-0.0.1 index 70ab0f3cc5..1af3435539 160000 --- a/activesupport/lib/active_support/vendor/i18n-0.0.1 +++ b/activesupport/lib/active_support/vendor/i18n-0.0.1 @@ -1 +1 @@ -Subproject commit 70ab0f3cc5921cc67e09741939a08b2582d707cb +Subproject commit 1af3435539b4a0729c13d21c5df037a635fe98c1 -- cgit v1.2.3 From c1e2506494107892a0962b8491cd234f77949c08 Mon Sep 17 00:00:00 2001 From: Sven Fuchs Date: Sat, 21 Jun 2008 11:27:19 +0200 Subject: Changed process of storing translations from the client libraries to the backend: clients now can pass a block to backend#populate which can contain code to load and register translations. This makes sense for backends that persist their translations (e.g. to db) so the repeated loading and passing of translations throughout the server startup would be wasted resources. --- activesupport/lib/active_support.rb | 5 ++++- activesupport/lib/active_support/lang/en-US.rb | 2 +- activesupport/lib/active_support/vendor/i18n-0.0.1 | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) (limited to 'activesupport/lib') diff --git a/activesupport/lib/active_support.rb b/activesupport/lib/active_support.rb index acdb3056d2..0de948dda9 100644 --- a/activesupport/lib/active_support.rb +++ b/activesupport/lib/active_support.rb @@ -55,7 +55,10 @@ require 'active_support/multibyte' require 'active_support/base64' require 'active_support/time_with_zone' -require 'active_support/lang/en-US.rb' + +I18n.backend.populate do + require 'active_support/lang/en-US.rb' +end Inflector = ActiveSupport::Deprecation::DeprecatedConstantProxy.new('Inflector', 'ActiveSupport::Inflector') Dependencies = ActiveSupport::Deprecation::DeprecatedConstantProxy.new('Dependencies', 'ActiveSupport::Dependencies') diff --git a/activesupport/lib/active_support/lang/en-US.rb b/activesupport/lib/active_support/lang/en-US.rb index 5b8e04363e..aa06fe14bd 100644 --- a/activesupport/lib/active_support/lang/en-US.rb +++ b/activesupport/lib/active_support/lang/en-US.rb @@ -1,4 +1,4 @@ -I18n.backend.set_translations :'en-US', { +I18n.backend.store_translations :'en-US', { :support => { :array => { :sentence_connector => 'and' diff --git a/activesupport/lib/active_support/vendor/i18n-0.0.1 b/activesupport/lib/active_support/vendor/i18n-0.0.1 index 1af3435539..8e43afa38a 160000 --- a/activesupport/lib/active_support/vendor/i18n-0.0.1 +++ b/activesupport/lib/active_support/vendor/i18n-0.0.1 @@ -1 +1 @@ -Subproject commit 1af3435539b4a0729c13d21c5df037a635fe98c1 +Subproject commit 8e43afa38aa007d1de6d6acf44d43143c403d13f -- cgit v1.2.3 From 428aa24d24032d382dc3d9ccf131e0c874043dbd Mon Sep 17 00:00:00 2001 From: Sven Fuchs Date: Sat, 21 Jun 2008 11:35:02 +0200 Subject: Renamed lang/ to locale/ because that's what we seem to standarize on. Also, in future this place can be used for data/code that's not literally translations but conceptually belongs to the locale (like custom pluralization algorithms etc.). --- activesupport/lib/active_support.rb | 2 +- activesupport/lib/active_support/lang/en-US.rb | 7 ------- activesupport/lib/active_support/locale/en-US.rb | 7 +++++++ 3 files changed, 8 insertions(+), 8 deletions(-) delete mode 100644 activesupport/lib/active_support/lang/en-US.rb create mode 100644 activesupport/lib/active_support/locale/en-US.rb (limited to 'activesupport/lib') diff --git a/activesupport/lib/active_support.rb b/activesupport/lib/active_support.rb index 0de948dda9..de50aafe16 100644 --- a/activesupport/lib/active_support.rb +++ b/activesupport/lib/active_support.rb @@ -57,7 +57,7 @@ require 'active_support/base64' require 'active_support/time_with_zone' I18n.backend.populate do - require 'active_support/lang/en-US.rb' + require 'active_support/locale/en-US.rb' end Inflector = ActiveSupport::Deprecation::DeprecatedConstantProxy.new('Inflector', 'ActiveSupport::Inflector') diff --git a/activesupport/lib/active_support/lang/en-US.rb b/activesupport/lib/active_support/lang/en-US.rb deleted file mode 100644 index aa06fe14bd..0000000000 --- a/activesupport/lib/active_support/lang/en-US.rb +++ /dev/null @@ -1,7 +0,0 @@ -I18n.backend.store_translations :'en-US', { - :support => { - :array => { - :sentence_connector => 'and' - } - } -} \ No newline at end of file diff --git a/activesupport/lib/active_support/locale/en-US.rb b/activesupport/lib/active_support/locale/en-US.rb new file mode 100644 index 0000000000..aa06fe14bd --- /dev/null +++ b/activesupport/lib/active_support/locale/en-US.rb @@ -0,0 +1,7 @@ +I18n.backend.store_translations :'en-US', { + :support => { + :array => { + :sentence_connector => 'and' + } + } +} \ No newline at end of file -- cgit v1.2.3 From 8bfdabbd8b5137f91d8bcddc8c3d18961c8e316b Mon Sep 17 00:00:00 2001 From: Sven Fuchs Date: Sat, 21 Jun 2008 17:50:37 +0200 Subject: incorporate #translate usage with several default keys (use first default key that resolves to a translation). this might, depending on the backend implementation save some expensive lookups (like db lookups) --- activesupport/lib/active_support/vendor/i18n-0.0.1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'activesupport/lib') diff --git a/activesupport/lib/active_support/vendor/i18n-0.0.1 b/activesupport/lib/active_support/vendor/i18n-0.0.1 index 8e43afa38a..20c331666b 160000 --- a/activesupport/lib/active_support/vendor/i18n-0.0.1 +++ b/activesupport/lib/active_support/vendor/i18n-0.0.1 @@ -1 +1 @@ -Subproject commit 8e43afa38aa007d1de6d6acf44d43143c403d13f +Subproject commit 20c331666b3b6a21791d4cded53c3d8654fba714 -- cgit v1.2.3 From 55e2e2e8b4efbe6fdb0a921c19cd8be5650eab0a Mon Sep 17 00:00:00 2001 From: Sven Fuchs Date: Sat, 21 Jun 2008 18:12:59 +0200 Subject: experimental DeprecatedConstantToMethodProxy --- activesupport/lib/active_support/deprecation.rb | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'activesupport/lib') diff --git a/activesupport/lib/active_support/deprecation.rb b/activesupport/lib/active_support/deprecation.rb index ebdaf86146..36933b007d 100644 --- a/activesupport/lib/active_support/deprecation.rb +++ b/activesupport/lib/active_support/deprecation.rb @@ -194,6 +194,23 @@ module ActiveSupport ActiveSupport::Deprecation.warn("#{@old_const} is deprecated! Use #{@new_const} instead.", callstack) end end + + class DeprecatedConstantToMethodProxy < DeprecationProxy #:nodoc: + def initialize(old_const, new_target, new_method) + @old_const = old_const + @new_target = new_target + @new_method = new_method + end + + private + def target + @new_target.__send__(@new_method) + end + + def warn(callstack, called, args) + ActiveSupport::Deprecation.warn("#{@old_const} is deprecated! Use #{@new_target.inspect}.#{@new_method} instead.", callstack) + end + end end end -- cgit v1.2.3 From d897acfbb11aaa2d7f3138e1f9772546ecb6f981 Mon Sep 17 00:00:00 2001 From: Sven Fuchs Date: Sun, 22 Jun 2008 11:39:10 +0200 Subject: remove DeprecatedConstantToMethodProxy again --- activesupport/lib/active_support/deprecation.rb | 17 ----------------- 1 file changed, 17 deletions(-) (limited to 'activesupport/lib') diff --git a/activesupport/lib/active_support/deprecation.rb b/activesupport/lib/active_support/deprecation.rb index 36933b007d..ebdaf86146 100644 --- a/activesupport/lib/active_support/deprecation.rb +++ b/activesupport/lib/active_support/deprecation.rb @@ -194,23 +194,6 @@ module ActiveSupport ActiveSupport::Deprecation.warn("#{@old_const} is deprecated! Use #{@new_const} instead.", callstack) end end - - class DeprecatedConstantToMethodProxy < DeprecationProxy #:nodoc: - def initialize(old_const, new_target, new_method) - @old_const = old_const - @new_target = new_target - @new_method = new_method - end - - private - def target - @new_target.__send__(@new_method) - end - - def warn(callstack, called, args) - ActiveSupport::Deprecation.warn("#{@old_const} is deprecated! Use #{@new_target.inspect}.#{@new_method} instead.", callstack) - end - end end end -- cgit v1.2.3 From 67fce4671e8bcfe2aa670a89195b20837546183a Mon Sep 17 00:00:00 2001 From: Sven Fuchs Date: Sun, 22 Jun 2008 13:49:08 +0200 Subject: crap, an array never has a request, stupid. --- activesupport/lib/active_support/core_ext/array/conversions.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'activesupport/lib') diff --git a/activesupport/lib/active_support/core_ext/array/conversions.rb b/activesupport/lib/active_support/core_ext/array/conversions.rb index 08e608d346..80d91a6cbd 100644 --- a/activesupport/lib/active_support/core_ext/array/conversions.rb +++ b/activesupport/lib/active_support/core_ext/array/conversions.rb @@ -11,7 +11,7 @@ module ActiveSupport #:nodoc: options.assert_valid_keys(:connector, :skip_last_comma, :locale) locale = options[:locale] - locale ||= request.locale if respond_to?(:request) + locale ||= self.locale if respond_to?(:locale) default = :'support.array.sentence_connector'.t(locale) options.reverse_merge! :connector => default, :skip_last_comma => false -- cgit v1.2.3 From 7403c825a05af320e20f1b7e20b0c565081ede89 Mon Sep 17 00:00:00 2001 From: Luca Guidi Date: Wed, 2 Jul 2008 17:51:34 +0200 Subject: Fixed Date and Time localization for ActiveSupport --- activesupport/lib/active_support/locale/en-US.rb | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'activesupport/lib') diff --git a/activesupport/lib/active_support/locale/en-US.rb b/activesupport/lib/active_support/locale/en-US.rb index aa06fe14bd..51324a90bf 100644 --- a/activesupport/lib/active_support/locale/en-US.rb +++ b/activesupport/lib/active_support/locale/en-US.rb @@ -3,5 +3,26 @@ I18n.backend.store_translations :'en-US', { :array => { :sentence_connector => 'and' } + }, + :date => { + :formats => { + :default => "%Y-%m-%d", + :short => "%b %d", + :long => "%B %d, %Y", + }, + :day_names => Date::DAYNAMES, + :abbr_day_names => Date::ABBR_DAYNAMES, + :month_names => Date::MONTHNAMES, + :abbr_month_names => Date::ABBR_MONTHNAMES, + :order => [:year, :month, :day] + }, + :time => { + :formats => { + :default => "%a, %d %b %Y %H:%M:%S %z", + :short => "%d %b %H:%M", + :long => "%B %d, %Y %H:%M", + }, + :am => 'am', + :pm => 'pm' } } \ No newline at end of file -- cgit v1.2.3 From 8f74ba96c47e77e18ce363c8e7cd2fc9196faf7a Mon Sep 17 00:00:00 2001 From: Sven Fuchs Date: Wed, 2 Jul 2008 19:21:07 +0200 Subject: remove core extensions in favor of I18n#translate and I18n#localize --- activesupport/lib/active_support/core_ext/array/conversions.rb | 2 +- activesupport/lib/active_support/vendor/i18n-0.0.1 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'activesupport/lib') diff --git a/activesupport/lib/active_support/core_ext/array/conversions.rb b/activesupport/lib/active_support/core_ext/array/conversions.rb index 80d91a6cbd..80bf1404de 100644 --- a/activesupport/lib/active_support/core_ext/array/conversions.rb +++ b/activesupport/lib/active_support/core_ext/array/conversions.rb @@ -13,7 +13,7 @@ module ActiveSupport #:nodoc: locale = options[:locale] locale ||= self.locale if respond_to?(:locale) - default = :'support.array.sentence_connector'.t(locale) + default = I18n.translate(:'support.array.sentence_connector', locale) options.reverse_merge! :connector => default, :skip_last_comma => false options[:connector] = "#{options[:connector]} " unless options[:connector].nil? || options[:connector].strip == '' diff --git a/activesupport/lib/active_support/vendor/i18n-0.0.1 b/activesupport/lib/active_support/vendor/i18n-0.0.1 index 20c331666b..970bc7ab5f 160000 --- a/activesupport/lib/active_support/vendor/i18n-0.0.1 +++ b/activesupport/lib/active_support/vendor/i18n-0.0.1 @@ -1 +1 @@ -Subproject commit 20c331666b3b6a21791d4cded53c3d8654fba714 +Subproject commit 970bc7ab5faa94e41ee4a56bc8913c144c1cdd19 -- cgit v1.2.3 From 84816ae981a8598e5e401eb1b9b805de840fefc9 Mon Sep 17 00:00:00 2001 From: Sven Fuchs Date: Sun, 6 Jul 2008 21:20:02 +0200 Subject: align with changes in i18n --- activesupport/lib/active_support/core_ext/array/conversions.rb | 5 +---- activesupport/lib/active_support/vendor/i18n-0.0.1 | 2 +- 2 files changed, 2 insertions(+), 5 deletions(-) (limited to 'activesupport/lib') diff --git a/activesupport/lib/active_support/core_ext/array/conversions.rb b/activesupport/lib/active_support/core_ext/array/conversions.rb index 80bf1404de..59dc96754f 100644 --- a/activesupport/lib/active_support/core_ext/array/conversions.rb +++ b/activesupport/lib/active_support/core_ext/array/conversions.rb @@ -10,10 +10,7 @@ module ActiveSupport #:nodoc: def to_sentence(options = {}) options.assert_valid_keys(:connector, :skip_last_comma, :locale) - locale = options[:locale] - locale ||= self.locale if respond_to?(:locale) - - default = I18n.translate(:'support.array.sentence_connector', locale) + default = I18n.translate(:'support.array.sentence_connector', :locale => options[:locale]) options.reverse_merge! :connector => default, :skip_last_comma => false options[:connector] = "#{options[:connector]} " unless options[:connector].nil? || options[:connector].strip == '' diff --git a/activesupport/lib/active_support/vendor/i18n-0.0.1 b/activesupport/lib/active_support/vendor/i18n-0.0.1 index 970bc7ab5f..46aad28993 160000 --- a/activesupport/lib/active_support/vendor/i18n-0.0.1 +++ b/activesupport/lib/active_support/vendor/i18n-0.0.1 @@ -1 +1 @@ -Subproject commit 970bc7ab5faa94e41ee4a56bc8913c144c1cdd19 +Subproject commit 46aad289935eaf059c429acb5f3bfa0946f2d99f -- cgit v1.2.3 From 731fca8cf68ddb6d6b9670538a4686ada6b14b26 Mon Sep 17 00:00:00 2001 From: Sven Fuchs Date: Wed, 16 Jul 2008 04:15:31 +0200 Subject: remove i18n lib subproject --- activesupport/lib/active_support/vendor/i18n-0.0.1 | 1 - 1 file changed, 1 deletion(-) delete mode 160000 activesupport/lib/active_support/vendor/i18n-0.0.1 (limited to 'activesupport/lib') diff --git a/activesupport/lib/active_support/vendor/i18n-0.0.1 b/activesupport/lib/active_support/vendor/i18n-0.0.1 deleted file mode 160000 index 46aad28993..0000000000 --- a/activesupport/lib/active_support/vendor/i18n-0.0.1 +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 46aad289935eaf059c429acb5f3bfa0946f2d99f -- cgit v1.2.3 From fbe1823117c6170e26b328ce192a2fc0945af533 Mon Sep 17 00:00:00 2001 From: Sven Fuchs Date: Wed, 16 Jul 2008 04:16:08 +0200 Subject: add i18n lib files --- .../active_support/vendor/i18n-0.0.1/MIT-LICENSE | 20 ++ .../vendor/i18n-0.0.1/README.textile | 18 + .../active_support/vendor/i18n-0.0.1/i18n.gemspec | 24 ++ .../active_support/vendor/i18n-0.0.1/lib/i18n.rb | 182 ++++++++++ .../vendor/i18n-0.0.1/lib/i18n/backend/simple.rb | 154 +++++++++ .../vendor/i18n-0.0.1/lib/i18n/exceptions.rb | 45 +++ .../active_support/vendor/i18n-0.0.1/test/all.rb | 4 + .../vendor/i18n-0.0.1/test/i18n_exceptions_test.rb | 100 ++++++ .../vendor/i18n-0.0.1/test/i18n_test.rb | 141 ++++++++ .../vendor/i18n-0.0.1/test/simple_backend_test.rb | 376 +++++++++++++++++++++ 10 files changed, 1064 insertions(+) create mode 100755 activesupport/lib/active_support/vendor/i18n-0.0.1/MIT-LICENSE create mode 100644 activesupport/lib/active_support/vendor/i18n-0.0.1/README.textile create mode 100644 activesupport/lib/active_support/vendor/i18n-0.0.1/i18n.gemspec create mode 100755 activesupport/lib/active_support/vendor/i18n-0.0.1/lib/i18n.rb create mode 100644 activesupport/lib/active_support/vendor/i18n-0.0.1/lib/i18n/backend/simple.rb create mode 100644 activesupport/lib/active_support/vendor/i18n-0.0.1/lib/i18n/exceptions.rb create mode 100644 activesupport/lib/active_support/vendor/i18n-0.0.1/test/all.rb create mode 100644 activesupport/lib/active_support/vendor/i18n-0.0.1/test/i18n_exceptions_test.rb create mode 100644 activesupport/lib/active_support/vendor/i18n-0.0.1/test/i18n_test.rb create mode 100644 activesupport/lib/active_support/vendor/i18n-0.0.1/test/simple_backend_test.rb (limited to 'activesupport/lib') diff --git a/activesupport/lib/active_support/vendor/i18n-0.0.1/MIT-LICENSE b/activesupport/lib/active_support/vendor/i18n-0.0.1/MIT-LICENSE new file mode 100755 index 0000000000..ed8e9ee66d --- /dev/null +++ b/activesupport/lib/active_support/vendor/i18n-0.0.1/MIT-LICENSE @@ -0,0 +1,20 @@ +Copyright (c) 2008 The Ruby I18n team + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/activesupport/lib/active_support/vendor/i18n-0.0.1/README.textile b/activesupport/lib/active_support/vendor/i18n-0.0.1/README.textile new file mode 100644 index 0000000000..2b14a99c0f --- /dev/null +++ b/activesupport/lib/active_support/vendor/i18n-0.0.1/README.textile @@ -0,0 +1,18 @@ +h1. Ruby I18n gem + +I18n and localization solution for Ruby. + +h2. Authors + +* "Matt Aimonetti":http://railsontherun.com +* "Sven Fuchs":http://www.artweb-design.de +* "Joshua Harvey":http://www.workingwithrails.com/person/759-joshua-harvey +* "Saimon Moore":http://saimonmoore.net +* "Stephan Soller":http://www.arkanis-development.de + +h2. License + +MIT License. See the included MIT-LICENCE file. + + + diff --git a/activesupport/lib/active_support/vendor/i18n-0.0.1/i18n.gemspec b/activesupport/lib/active_support/vendor/i18n-0.0.1/i18n.gemspec new file mode 100644 index 0000000000..81ad0b598d --- /dev/null +++ b/activesupport/lib/active_support/vendor/i18n-0.0.1/i18n.gemspec @@ -0,0 +1,24 @@ +Gem::Specification.new do |s| + s.name = "i18n" + s.version = "0.0.1" + s.date = "2008-06-13" + s.summary = "Internationalization for Ruby" + s.email = "rails-patch-i18n@googlegroups.com" + s.homepage = "http://groups.google.com/group/rails-patch-i18n" + s.description = "Add Internationalization to your Ruby application." + s.has_rdoc = false + s.authors = ['Sven Fuchs', 'Matt Aimonetti', 'Stephan Soller', 'Saimon Moore'] + s.files = [ + "lib/i18n/backend/minimal.rb", + "lib/i18n/core_ext.rb", + "lib/i18n/localization.rb", + "lib/i18n/translation.rb", + "lib/i18n.rb", + "LICENSE", + "README", + "spec/core_ext_spec.rb", + "spec/i18n_spec.rb", + "spec/spec.opts", + "spec/spec_helper.rb" + ] +end \ No newline at end of file diff --git a/activesupport/lib/active_support/vendor/i18n-0.0.1/lib/i18n.rb b/activesupport/lib/active_support/vendor/i18n-0.0.1/lib/i18n.rb new file mode 100755 index 0000000000..2185194da9 --- /dev/null +++ b/activesupport/lib/active_support/vendor/i18n-0.0.1/lib/i18n.rb @@ -0,0 +1,182 @@ +# Authors:: Matt Aimonetti (http://railsontherun.com/), +# Sven Fuchs (http://www.artweb-design.de), +# Joshua Harvey (http://www.workingwithrails.com/person/759-joshua-harvey), +# Saimon Moore (http://saimonmoore.net), +# Stephan Soller (http://www.arkanis-development.de/) +# Copyright:: Copyright (c) 2008 The Ruby i18n Team +# License:: MIT +require 'i18n/backend/simple' +require 'i18n/exceptions' + +module I18n + @@backend = Backend::Simple + @@default_locale = 'en-US' + @@exception_handler = :default_exception_handler + + class << self + # Returns the current backend. Defaults to +Backend::Simple+. + def backend + @@backend + end + + # Sets the current backend. Used to set a custom backend. + def backend=(backend) + @@backend = backend + end + + # Returns the current default locale. Defaults to 'en-US' + def default_locale + @@default_locale + end + + # Sets the current default locale. Used to set a custom default locale. + def default_locale=(locale) + @@default_locale = locale + end + + # Returns the current locale. Defaults to I18n.default_locale. + def locale + Thread.current[:locale] ||= default_locale + end + + # Sets the current locale pseudo-globally, i.e. in the Thread.current hash. + def locale=(locale) + Thread.current[:locale] = locale + end + + # Sets the exception handler. + def exception_handler=(exception_handler) + @@exception_handler = exception_handler + end + + # Allow client libraries to pass a block that populates the translation + # storage. Decoupled for backends like a db backend that persist their + # translations, so the backend can decide whether/when to yield or not. + def populate(&block) + backend.populate &block + end + + # Stores translations for the given locale in the backend. + def store_translations(locale, data) + backend.store_translations locale, data + end + + # Translates, pluralizes and interpolates a given key using a given locale, + # scope, and default, as well as interpolation values. + # + # *LOOKUP* + # + # Translation data is organized as a nested hash using the upper-level keys + # as namespaces. E.g., ActionView ships with the translation: + # :date => {:formats => {:short => "%b %d"}}. + # + # Translations can be looked up at any level of this hash using the key argument + # and the scope option. E.g., in this example I18n.t :date + # returns the whole translations hash {:formats => {:short => "%b %d"}}. + # + # Key can be either a single key or a dot-separated key (both Strings and Symbols + # work). E.g., the short format can be looked up using both: + # I18n.t 'date.formats.short' + # I18n.t :'date.formats.short' + # + # Scope can be either a single key, a dot-separated key or an array of keys + # or dot-separated keys. Keys and scopes can be combined freely. So these + # examples will all look up the same short date format: + # I18n.t 'date.formats.short' + # I18n.t 'formats.short', :scope => 'date' + # I18n.t 'short', :scope => 'date.formats' + # I18n.t 'short', :scope => %w(date formats) + # + # *INTERPOLATION* + # + # Translations can contain interpolation variables which will be replaced by + # values passed to #translate as part of the options hash, with the keys matching + # the interpolation variable names. + # + # E.g., with a translation :foo => "foo {{bar}}" the option + # value for the key +bar+ will be interpolated into the translation: + # I18n.t :foo, :bar => 'baz' # => 'foo baz' + # + # *PLURALIZATION* + # + # Translation data can contain pluralized translations. Pluralized translations + # are arrays of singluar/plural versions of translations like ['Foo', 'Foos']. + # + # Note that I18n::Backend::Simple only supports an algorithm for English + # pluralization rules. Other algorithms can be supported by custom backends. + # + # This returns the singular version of a pluralized translation: + # I18n.t :foo, :count => 1 # => 'Foo' + # + # These both return the plural version of a pluralized translation: + # I18n.t :foo, :count => 0 # => 'Foos' + # I18n.t :foo, :count => 2 # => 'Foos' + # + # The :count option can be used both for pluralization and interpolation. + # E.g., with the translation + # :foo => ['{{count}} foo', '{{count}} foos'], count will + # be interpolated to the pluralized translation: + # I18n.t :foo, :count => 1 # => '1 foo' + # + # *DEFAULTS* + # + # This returns the translation for :foo or default if no translation was found: + # I18n.t :foo, :default => 'default' + # + # This returns the translation for :foo or the translation for :bar if no + # translation for :foo was found: + # I18n.t :foo, :default => :bar + # + # Returns the translation for :foo or the translation for :bar + # or default if no translations for :foo and :bar were found. + # I18n.t :foo, :default => [:bar, 'default'] + # + # BULK LOOKUP + # + # This returns an array with the translations for :foo and :bar. + # I18n.t [:foo, :bar] + # + # Can be used with dot-separated nested keys: + # I18n.t [:'baz.foo', :'baz.bar'] + # + # Which is the same as using a scope option: + # I18n.t [:foo, :bar], :scope => :baz + def translate(key, options = {}) + locale = options.delete(:locale) || I18n.locale + backend.translate locale, key, options + rescue I18n::ArgumentError => e + raise e if options[:raise] + send @@exception_handler, e, locale, key, options + end + alias :t :translate + + # Localizes certain objects, such as dates and numbers to local formatting. + def localize(object, options = {}) + locale = options[:locale] || I18n.locale + format = options[:format] || :default + backend.localize(locale, object, format) + end + alias :l :localize + + protected + # Handles exceptions raised in the backend. All exceptions except for + # MissingTranslationData exceptions are re-raised. When a MissingTranslationData + # was caught and the option :raise is not set the handler returns an error + # message string containing the key/scope. + def default_exception_handler(exception, locale, key, options) + return exception.message if MissingTranslationData === exception + raise exception + end + + # Merges the given locale, key and scope into a single array of keys. + # Splits keys that contain dots into multiple keys. Makes sure all + # keys are Symbols. + def normalize_translation_keys(locale, key, scope) + keys = [locale] + Array(scope) + [key] + keys = keys.map{|key| key.to_s.split(/\./) } + keys.flatten.map{|key| key.to_sym} + end + end +end + + diff --git a/activesupport/lib/active_support/vendor/i18n-0.0.1/lib/i18n/backend/simple.rb b/activesupport/lib/active_support/vendor/i18n-0.0.1/lib/i18n/backend/simple.rb new file mode 100644 index 0000000000..284f2bfcbd --- /dev/null +++ b/activesupport/lib/active_support/vendor/i18n-0.0.1/lib/i18n/backend/simple.rb @@ -0,0 +1,154 @@ +require 'strscan' + +module I18n + module Backend + module Simple + @@translations = {} + + class << self + # Allow client libraries to pass a block that populates the translation + # storage. Decoupled for backends like a db backend that persist their + # translations, so the backend can decide whether/when to yield or not. + def populate(&block) + yield + end + + # Stores translations for the given locale in memory. + # This uses a deep merge for the translations hash, so existing + # translations will be overwritten by new ones only at the deepest + # level of the hash. + def store_translations(locale, data) + merge_translations(locale, data) + end + + def translate(locale, key, options = {}) + raise InvalidLocale.new(locale) if locale.nil? + return key.map{|key| translate locale, key, options } if key.is_a? Array + + reserved = :scope, :default + count, scope, default = options.values_at(:count, *reserved) + options.delete(:default) + values = options.reject{|name, value| reserved.include? name } + + entry = lookup(locale, key, scope) || default(locale, default, options) || raise(I18n::MissingTranslationData.new(locale, key, options)) + entry = pluralize entry, count + entry = interpolate entry, values + entry + end + + # Acts the same as +strftime+, but returns a localized version of the + # formatted date string. Takes a key from the date/time formats + # translations as a format argument (e.g., :short in :'date.formats'). + def localize(locale, object, format = :default) + raise ArgumentError, "Object must be a Date, DateTime or Time object. #{object.inspect} given." unless object.respond_to?(:strftime) + + type = object.respond_to?(:sec) ? 'time' : 'date' + formats = translate(locale, :"#{type}.formats") + format = formats[format.to_sym] if formats && formats[format.to_sym] + # TODO raise exception unless format found? + format = format.to_s.dup + + format.gsub!(/%a/, translate(locale, :"date.abbr_day_names")[object.wday]) + format.gsub!(/%A/, translate(locale, :"date.day_names")[object.wday]) + format.gsub!(/%b/, translate(locale, :"date.abbr_month_names")[object.mon]) + format.gsub!(/%B/, translate(locale, :"date.month_names")[object.mon]) + format.gsub!(/%p/, translate(locale, :"time.#{object.hour < 12 ? :am : :pm}")) if object.respond_to? :hour + object.strftime(format) + end + + protected + + # Looks up a translation from the translations hash. Returns nil if + # eiher key is nil, or locale, scope or key do not exist as a key in the + # nested translations hash. Splits keys or scopes containing dots + # into multiple keys, i.e. currency.format is regarded the same as + # %w(currency format). + def lookup(locale, key, scope = []) + return unless key + keys = I18n.send :normalize_translation_keys, locale, key, scope + keys.inject(@@translations){|result, key| result[key.to_sym] or return nil } + end + + # Evaluates a default translation. + # If the given default is a String it is used literally. If it is a Symbol + # it will be translated with the given options. If it is an Array the first + # translation yielded will be returned. + # + # I.e., default(locale, [:foo, 'default']) will return +default+ if + # translate(locale, :foo) does not yield a result. + def default(locale, default, options = {}) + case default + when String then default + when Symbol then translate locale, default, options + when Array then default.each do |obj| + result = default(locale, obj, options.dup) and return result + end + end + rescue MissingTranslationData + nil + end + + # Picks a translation from an array according to English pluralization + # rules. It will pick the first translation if count is not equal to 1 + # and the second translation if it is equal to 1. Other backends can + # implement more flexible or complex pluralization rules. + def pluralize(entry, count) + return entry unless entry.is_a?(Array) and count + raise InvalidPluralizationData.new(entry, count) unless entry.size == 2 + entry[count == 1 ? 0 : 1] + end + + # Interpolates values into a given string. + # + # interpolate "file {{file}} opened by \\{{user}}", :file => 'test.txt', :user => 'Mr. X' + # # => "file test.txt opened by {{user}}" + # + # Note that you have to double escape the \\ when you want to escape + # the {{...}} key in a string (once for the string and once for the + # interpolation). + def interpolate(string, values = {}) + return string if !string.is_a?(String) + + map = {'%d' => '{{count}}', '%s' => '{{value}}'} # TODO deprecate this? + string.gsub!(/#{map.keys.join('|')}/){|key| map[key]} + + s = StringScanner.new string.dup + while s.skip_until(/\{\{/) + s.string[s.pos - 3, 1] = '' and next if s.pre_match[-1, 1] == '\\' + start_pos = s.pos - 2 + key = s.scan_until(/\}\}/)[0..-3] + end_pos = s.pos - 1 + + raise ReservedInterpolationKey.new(key, string) if %w(scope default).include?(key) + raise MissingInterpolationArgument.new(key, string) unless values.has_key? key.to_sym + + s.string[start_pos..end_pos] = values[key.to_sym].to_s + s.unscan + end + s.string + end + + # Deep merges the given translations hash with the existing translations + # for the given locale + def merge_translations(locale, data) + locale = locale.to_sym + @@translations[locale] ||= {} + data = deep_symbolize_keys data + + # deep_merge by Stefan Rusterholz, see http://www.ruby-forum.com/topic/142809 + merger = proc{|key, v1, v2| Hash === v1 && Hash === v2 ? v1.merge(v2, &merger) : v2 } + @@translations[locale].merge! data, &merger + end + + # Return a new hash with all keys and nested keys converted to symbols. + def deep_symbolize_keys(hash) + hash.inject({}){|result, (key, value)| + value = deep_symbolize_keys(value) if value.is_a? Hash + result[(key.to_sym rescue key) || key] = value + result + } + end + end + end + end +end diff --git a/activesupport/lib/active_support/vendor/i18n-0.0.1/lib/i18n/exceptions.rb b/activesupport/lib/active_support/vendor/i18n-0.0.1/lib/i18n/exceptions.rb new file mode 100644 index 0000000000..6c1fc6d9b6 --- /dev/null +++ b/activesupport/lib/active_support/vendor/i18n-0.0.1/lib/i18n/exceptions.rb @@ -0,0 +1,45 @@ +module I18n + class ArgumentError < ::ArgumentError; end + + class InvalidLocale < ArgumentError + attr_reader :locale + def initialize(locale) + @locale = locale + super "#{locale.inspect} is not a valid locale" + end + end + + class MissingTranslationData < ArgumentError + attr_reader :locale, :key, :options + def initialize(locale, key, options) + @key, @locale, @options = key, locale, options + keys = I18n.send(:normalize_translation_keys, locale, key, options[:scope]) + keys << 'no key' if keys.size < 2 + super "translation missing: #{keys.join(', ')}" + end + end + + class InvalidPluralizationData < ArgumentError + attr_reader :entry, :count + def initialize(entry, count) + @entry, @count = entry, count + super "translation data #{entry.inspect} can not be used with :count => #{count}" + end + end + + class MissingInterpolationArgument < ArgumentError + attr_reader :key, :string + def initialize(key, string) + @key, @string = key, string + super "interpolation argument #{key} missing in #{string.inspect}" + end + end + + class ReservedInterpolationKey < ArgumentError + attr_reader :key, :string + def initialize(key, string) + @key, @string = key, string + super "reserved key #{key.inspect} used in #{string.inspect}" + end + end +end \ No newline at end of file diff --git a/activesupport/lib/active_support/vendor/i18n-0.0.1/test/all.rb b/activesupport/lib/active_support/vendor/i18n-0.0.1/test/all.rb new file mode 100644 index 0000000000..048b62f8c3 --- /dev/null +++ b/activesupport/lib/active_support/vendor/i18n-0.0.1/test/all.rb @@ -0,0 +1,4 @@ +dir = File.dirname(__FILE__) +require dir + '/i18n_test.rb' +require dir + '/simple_backend_test.rb' +require dir + '/i18n_exceptions_test.rb' diff --git a/activesupport/lib/active_support/vendor/i18n-0.0.1/test/i18n_exceptions_test.rb b/activesupport/lib/active_support/vendor/i18n-0.0.1/test/i18n_exceptions_test.rb new file mode 100644 index 0000000000..1ea1601681 --- /dev/null +++ b/activesupport/lib/active_support/vendor/i18n-0.0.1/test/i18n_exceptions_test.rb @@ -0,0 +1,100 @@ +$:.unshift "lib" + +require 'rubygems' +require 'test/unit' +require 'mocha' +require 'i18n' +require 'active_support' + +class I18nExceptionsTest < Test::Unit::TestCase + def test_invalid_locale_stores_locale + force_invalid_locale + rescue I18n::ArgumentError => e + assert_nil e.locale + end + + def test_invalid_locale_message + force_invalid_locale + rescue I18n::ArgumentError => e + assert_equal 'nil is not a valid locale', e.message + end + + def test_missing_translation_data_stores_locale_key_and_options + force_missing_translation_data + rescue I18n::ArgumentError => e + options = {:scope => :bar} + assert_equal 'de-DE', e.locale + assert_equal :foo, e.key + assert_equal options, e.options + end + + def test_missing_translation_data_message + force_missing_translation_data + rescue I18n::ArgumentError => e + assert_equal 'translation missing: de-DE, bar, foo', e.message + end + + def test_invalid_pluralization_data_stores_entry_and_count + force_invalid_pluralization_data + rescue I18n::ArgumentError => e + assert_equal [:bar], e.entry + assert_equal 1, e.count + end + + def test_invalid_pluralization_data_message + force_invalid_pluralization_data + rescue I18n::ArgumentError => e + assert_equal 'translation data [:bar] can not be used with :count => 1', e.message + end + + def test_missing_interpolation_argument_stores_key_and_string + force_missing_interpolation_argument + rescue I18n::ArgumentError => e + assert_equal 'bar', e.key + assert_equal "{{bar}}", e.string + end + + def test_missing_interpolation_argument_message + force_missing_interpolation_argument + rescue I18n::ArgumentError => e + assert_equal 'interpolation argument bar missing in "{{bar}}"', e.message + end + + def test_reserved_interpolation_key_stores_key_and_string + force_reserved_interpolation_key + rescue I18n::ArgumentError => e + assert_equal 'scope', e.key + assert_equal "{{scope}}", e.string + end + + def test_reserved_interpolation_key_message + force_reserved_interpolation_key + rescue I18n::ArgumentError => e + assert_equal 'reserved key "scope" used in "{{scope}}"', e.message + end + + private + def force_invalid_locale + I18n.backend.translate nil, :foo + end + + def force_missing_translation_data + I18n.store_translations 'de-DE', :bar => nil + I18n.backend.translate 'de-DE', :foo, :scope => :bar + end + + def force_invalid_pluralization_data + I18n.store_translations 'de-DE', :foo => [:bar] + I18n.backend.translate 'de-DE', :foo, :count => 1 + end + + def force_missing_interpolation_argument + I18n.store_translations 'de-DE', :foo => "{{bar}}" + I18n.backend.translate 'de-DE', :foo, :baz => 'baz' + end + + def force_reserved_interpolation_key + I18n.store_translations 'de-DE', :foo => "{{scope}}" + I18n.backend.translate 'de-DE', :foo, :baz => 'baz' + end +end \ No newline at end of file diff --git a/activesupport/lib/active_support/vendor/i18n-0.0.1/test/i18n_test.rb b/activesupport/lib/active_support/vendor/i18n-0.0.1/test/i18n_test.rb new file mode 100644 index 0000000000..bbb1316b49 --- /dev/null +++ b/activesupport/lib/active_support/vendor/i18n-0.0.1/test/i18n_test.rb @@ -0,0 +1,141 @@ +$:.unshift "lib" + +require 'rubygems' +require 'test/unit' +require 'mocha' +require 'i18n' +require 'active_support' + +class I18nTest < Test::Unit::TestCase + def setup + I18n.store_translations :'en-US', { + :currency => { + :format => { + :separator => '.', + :delimiter => ',', + } + } + } + end + + def test_uses_simple_backend_set_by_default + assert_equal I18n::Backend::Simple, I18n.backend + end + + def test_can_set_backend + assert_nothing_raised{ I18n.backend = self } + assert_equal self, I18n.backend + I18n.backend = I18n::Backend::Simple + end + + def test_uses_en_us_as_default_locale_by_default + assert_equal 'en-US', I18n.default_locale + end + + def test_can_set_default_locale + assert_nothing_raised{ I18n.default_locale = 'de-DE' } + assert_equal 'de-DE', I18n.default_locale + I18n.default_locale = 'en-US' + end + + def test_uses_default_locale_as_locale_by_default + assert_equal I18n.default_locale, I18n.locale + end + + def test_can_set_locale_to_thread_current + assert_nothing_raised{ I18n.locale = 'de-DE' } + assert_equal 'de-DE', I18n.locale + assert_equal 'de-DE', Thread.current[:locale] + I18n.locale = 'en-US' + end + + def test_can_set_exception_handler + assert_nothing_raised{ I18n.exception_handler = :custom_exception_handler } + I18n.exception_handler = :default_exception_handler # revert it + end + + def test_uses_custom_exception_handler + I18n.exception_handler = :custom_exception_handler + I18n.expects(:custom_exception_handler) + I18n.translate :bogus + I18n.exception_handler = :default_exception_handler # revert it + end + + def test_delegates_translate_to_backend + I18n.backend.expects(:translate).with 'de-DE', :foo, {} + I18n.translate :foo, :locale => 'de-DE' + end + + def test_delegates_localize_to_backend + I18n.backend.expects(:localize).with 'de-DE', :whatever, :default + I18n.localize :whatever, :locale => 'de-DE' + end + + def test_delegates_store_translations_to_backend + I18n.backend.expects(:store_translations).with 'de-DE', {:foo => :bar} + I18n.store_translations 'de-DE', {:foo => :bar} + end + + def test_delegates_populate_to_backend + I18n.backend.expects(:populate) # can't specify a block here as an expected argument + I18n.populate{ } + end + + def test_populate_yields_the_block + tmp = nil + I18n.populate do tmp = 'yielded' end + assert_equal 'yielded', tmp + end + + def test_translate_given_no_locale_uses_i18n_locale + I18n.backend.expects(:translate).with 'en-US', :foo, {} + I18n.translate :foo + end + + def test_translate_on_nested_symbol_keys_works + assert_equal ".", I18n.t(:'currency.format.separator') + end + + def test_translate_with_nested_string_keys_works + assert_equal ".", I18n.t('currency.format.separator') + end + + def test_translate_with_array_as_scope_works + assert_equal ".", I18n.t(:separator, :scope => ['currency.format']) + end + + def test_translate_with_array_containing_dot_separated_strings_as_scope_works + assert_equal ".", I18n.t(:separator, :scope => ['currency.format']) + end + + def test_translate_with_key_array_and_dot_separated_scope_works + assert_equal [".", ","], I18n.t(%w(separator delimiter), :scope => 'currency.format') + end + + def test_translate_with_dot_separated_key_array_and_scope_works + assert_equal [".", ","], I18n.t(%w(format.separator format.delimiter), :scope => 'currency') + end + + def test_translate_with_options_using_scope_works + I18n.backend.expects(:translate).with('de-DE', :precision, :scope => :"currency.format") + I18n.with_options :locale => 'de-DE', :scope => :'currency.format' do |locale| + locale.t :precision + end + end + + # def test_translate_given_no_args_raises_missing_translation_data + # assert_equal "translation missing: en-US, no key", I18n.t + # end + + def test_translate_given_a_bogus_key_raises_missing_translation_data + assert_equal "translation missing: en-US, bogus", I18n.t(:bogus) + end + + def test_localize_nil_raises_argument_error + assert_raises(I18n::ArgumentError) { I18n.l nil } + end + + def test_localize_object_raises_argument_error + assert_raises(I18n::ArgumentError) { I18n.l Object.new } + end +end diff --git a/activesupport/lib/active_support/vendor/i18n-0.0.1/test/simple_backend_test.rb b/activesupport/lib/active_support/vendor/i18n-0.0.1/test/simple_backend_test.rb new file mode 100644 index 0000000000..c94d742e2d --- /dev/null +++ b/activesupport/lib/active_support/vendor/i18n-0.0.1/test/simple_backend_test.rb @@ -0,0 +1,376 @@ +$:.unshift "lib" + +require 'rubygems' +require 'test/unit' +require 'mocha' +require 'i18n' + +module I18nSimpleBackendTestSetup + def setup_backend + @backend = I18n::Backend::Simple + @backend.send :class_variable_set, :@@translations, {} + @backend.store_translations 'en-US', :foo => {:bar => 'bar', :baz => 'baz'} + end + alias :setup :setup_backend + + def add_datetime_translations + @backend.store_translations :'de-DE', { + :date => { + :formats => { + :default => "%d.%m.%Y", + :short => "%d. %b", + :long => "%d. %B %Y", + }, + :day_names => %w(Sonntag Montag Dienstag Mittwoch Donnerstag Freitag Samstag), + :abbr_day_names => %w(So Mo Di Mi Do Fr Sa), + :month_names => %w(Januar Februar März April Mai Juni Juli August September Oktober November Dezember).unshift(nil), + :abbr_month_names => %w(Jan Feb Mar Apr Mai Jun Jul Aug Sep Okt Nov Dez).unshift(nil), + :order => [:day, :month, :year] + }, + :time => { + :formats => { + :default => "%a, %d. %b %Y %H:%M:%S %z", + :short => "%d. %b %H:%M", + :long => "%d. %B %Y %H:%M", + }, + :am => 'am', + :pm => 'pm' + }, + :datetime => { + :distance_in_words => { + :half_a_minute => 'half a minute', + :less_than_x_seconds => ['less than 1 second', 'less than {{count}} seconds'], + :x_seconds => ['1 second', '{{count}} seconds'], + :less_than_x_minutes => ['less than a minute', 'less than {{count}} minutes'], + :x_minutes => ['1 minute', '{{count}} minutes'], + :about_x_hours => ['about 1 hour', 'about {{count}} hours'], + :x_days => ['1 day', '{{count}} days'], + :about_x_months => ['about 1 month', 'about {{count}} months'], + :x_months => ['1 month', '{{count}} months'], + :about_x_years => ['about 1 year', 'about {{count}} year'], + :over_x_years => ['over 1 year', 'over {{count}} years'] + } + } + } + end +end + +class I18nSimpleBackendTranslationsTest < Test::Unit::TestCase + include I18nSimpleBackendTestSetup + + def test_store_translations_adds_translations # no, really :-) + @backend.store_translations :'en-US', :foo => 'bar' + assert_equal Hash[:'en-US', {:foo => 'bar'}], @backend.send(:class_variable_get, :@@translations) + end + + def test_store_translations_deep_merges_translations + @backend.store_translations :'en-US', :foo => {:bar => 'bar'} + @backend.store_translations :'en-US', :foo => {:baz => 'baz'} + assert_equal Hash[:'en-US', {:foo => {:bar => 'bar', :baz => 'baz'}}], @backend.send(:class_variable_get, :@@translations) + end + + def test_store_translations_forces_locale_to_sym + @backend.store_translations 'en-US', :foo => 'bar' + assert_equal Hash[:'en-US', {:foo => 'bar'}], @backend.send(:class_variable_get, :@@translations) + end + + def test_store_translations_covert_key_symbols + @backend.send :class_variable_set, :@@translations, {} # reset translations + @backend.store_translations :'en-US', 'foo' => {'bar' => 'baz'} + assert_equal Hash[:'en-US', {:foo => {:bar => 'baz'}}], + @backend.send(:class_variable_get, :@@translations) + end +end + +class I18nSimpleBackendTranslateTest < Test::Unit::TestCase + include I18nSimpleBackendTestSetup + + def test_translate_calls_lookup_with_locale_given + @backend.expects(:lookup).with('de-DE', :bar, [:foo]).returns 'bar' + @backend.translate 'de-DE', :bar, :scope => [:foo] + end + + def test_translate_given_a_symbol_as_a_default_translates_the_symbol + assert_equal 'bar', @backend.translate('en-US', nil, :scope => [:foo], :default => :bar) + end + + def test_translate_given_an_array_as_default_uses_the_first_match + assert_equal 'bar', @backend.translate('en-US', :does_not_exist, :scope => [:foo], :default => [:does_not_exist_2, :bar]) + end + + def test_translate_an_array_of_keys_translates_all_of_them + assert_equal %w(bar baz), @backend.translate('en-US', [:bar, :baz], :scope => [:foo]) + end + + def test_translate_calls_pluralize + @backend.expects(:pluralize).with 'bar', 1 + @backend.translate 'en-US', :bar, :scope => [:foo], :count => 1 + end + + def test_translate_calls_interpolate + @backend.expects(:interpolate).with 'bar', {} + @backend.translate 'en-US', :bar, :scope => [:foo] + end + + def test_translate_calls_interpolate_including_count_as_a_value + @backend.expects(:interpolate).with 'bar', {:count => 1} + @backend.translate 'en-US', :bar, :scope => [:foo], :count => 1 + end + + def test_given_no_keys_it_returns_the_default + assert_equal 'default', @backend.translate('en-US', nil, :default => 'default') + end + + def test_translate_given_nil_as_a_locale_raises_an_argument_error + assert_raises(I18n::InvalidLocale){ @backend.translate nil, :bar } + end + + def test_translate_with_a_bogus_key_and_no_default_raises_missing_translation_data + assert_raises(I18n::MissingTranslationData){ @backend.translate 'de-DE', :bogus } + end +end + +class I18nSimpleBackendLookupTest < Test::Unit::TestCase + include I18nSimpleBackendTestSetup + + # useful because this way we can use the backend with no key for interpolation/pluralization + def test_lookup_given_nil_as_a_key_returns_nil + assert_nil @backend.send(:lookup, 'en-US', nil) + end + + def test_lookup_given_nested_keys_looks_up_a_nested_hash_value + assert_equal 'bar', @backend.send(:lookup, 'en-US', :bar, [:foo]) + end +end + +class I18nSimpleBackendPluralizeTest < Test::Unit::TestCase + include I18nSimpleBackendTestSetup + + def test_pluralize_given_nil_returns_the_given_entry + assert_equal ['bar', 'bars'], @backend.send(:pluralize, ['bar', 'bars'], nil) + end + + def test_pluralize_given_0_returns_plural_string + assert_equal 'bars', @backend.send(:pluralize, ['bar', 'bars'], 0) + end + + def test_pluralize_given_1_returns_singular_string + assert_equal 'bar', @backend.send(:pluralize, ['bar', 'bars'], 1) + end + + def test_pluralize_given_2_returns_plural_string + assert_equal 'bars', @backend.send(:pluralize, ['bar', 'bars'], 2) + end + + def test_pluralize_given_3_returns_plural_string + assert_equal 'bars', @backend.send(:pluralize, ['bar', 'bars'], 3) + end + + def test_interpolate_given_invalid_pluralization_data_raises_invalid_pluralization_data + assert_raises(I18n::InvalidPluralizationData){ @backend.send(:pluralize, ['bar'], 2) } + end +end + +class I18nSimpleBackendInterpolateTest < Test::Unit::TestCase + include I18nSimpleBackendTestSetup + + def test_interpolate_given_a_value_hash_interpolates_the_values_to_the_string + assert_equal 'Hi David!', @backend.send(:interpolate, 'Hi {{name}}!', :name => 'David') + end + + def test_interpolate_given_nil_as_a_string_returns_nil + assert_nil @backend.send(:interpolate, nil, :name => 'David') + end + + def test_interpolate_given_an_non_string_as_a_string_returns_nil + assert_equal [], @backend.send(:interpolate, [], :name => 'David') + end + + def test_interpolate_given_a_values_hash_with_nil_values_interpolates_the_string + assert_equal 'Hi !', @backend.send(:interpolate, 'Hi {{name}}!', {:name => nil}) + end + + def test_interpolate_given_an_empty_values_hash_raises_missing_interpolation_argument + assert_raises(I18n::MissingInterpolationArgument) { @backend.send(:interpolate, 'Hi {{name}}!', {}) } + end + + def test_interpolate_given_a_string_containing_a_reserved_key_raises_reserved_interpolation_key + assert_raises(I18n::ReservedInterpolationKey) { @backend.send(:interpolate, '{{default}}', {:default => nil}) } + end +end + +class I18nSimpleBackendLocalizeDateTest < Test::Unit::TestCase + include I18nSimpleBackendTestSetup + + def setup + @backend = I18n::Backend::Simple + add_datetime_translations + @date = Date.new 2008, 1, 1 + end + + def test_translate_given_the_short_format_it_uses_it + assert_equal '01. Jan', @backend.localize('de-DE', @date, :short) + end + + def test_translate_given_the_long_format_it_uses_it + assert_equal '01. Januar 2008', @backend.localize('de-DE', @date, :long) + end + + def test_translate_given_the_default_format_it_uses_it + assert_equal '01.01.2008', @backend.localize('de-DE', @date, :default) + end + + def test_translate_given_a_day_name_format_it_returns_a_day_name + assert_equal 'Dienstag', @backend.localize('de-DE', @date, '%A') + end + + def test_translate_given_an_abbr_day_name_format_it_returns_an_abbrevated_day_name + assert_equal 'Di', @backend.localize('de-DE', @date, '%a') + end + + def test_translate_given_a_month_name_format_it_returns_a_month_name + assert_equal 'Januar', @backend.localize('de-DE', @date, '%B') + end + + def test_translate_given_an_abbr_month_name_format_it_returns_an_abbrevated_month_name + assert_equal 'Jan', @backend.localize('de-DE', @date, '%b') + end + + def test_translate_given_no_format_it_does_not_fail + assert_nothing_raised{ @backend.localize 'de-DE', @date } + end + + def test_translate_given_an_unknown_format_it_does_not_fail + assert_nothing_raised{ @backend.localize 'de-DE', @date, '%x' } + end + + def test_localize_nil_raises_argument_error + assert_raises(I18n::ArgumentError) { @backend.localize 'de-DE', nil } + end + + def test_localize_object_raises_argument_error + assert_raises(I18n::ArgumentError) { @backend.localize 'de-DE', Object.new } + end +end + +class I18nSimpleBackendLocalizeDateTimeTest < Test::Unit::TestCase + include I18nSimpleBackendTestSetup + + def setup + @backend = I18n::Backend::Simple + add_datetime_translations + @morning = DateTime.new 2008, 1, 1, 6 + @evening = DateTime.new 2008, 1, 1, 18 + end + + def test_translate_given_the_short_format_it_uses_it + assert_equal '01. Jan 06:00', @backend.localize('de-DE', @morning, :short) + end + + def test_translate_given_the_long_format_it_uses_it + assert_equal '01. Januar 2008 06:00', @backend.localize('de-DE', @morning, :long) + end + + def test_translate_given_the_default_format_it_uses_it + assert_equal 'Di, 01. Jan 2008 06:00:00 +0000', @backend.localize('de-DE', @morning, :default) + end + + def test_translate_given_a_day_name_format_it_returns_the_correct_day_name + assert_equal 'Dienstag', @backend.localize('de-DE', @morning, '%A') + end + + def test_translate_given_an_abbr_day_name_format_it_returns_the_correct_abbrevated_day_name + assert_equal 'Di', @backend.localize('de-DE', @morning, '%a') + end + + def test_translate_given_a_month_name_format_it_returns_the_correct_month_name + assert_equal 'Januar', @backend.localize('de-DE', @morning, '%B') + end + + def test_translate_given_an_abbr_month_name_format_it_returns_the_correct_abbrevated_month_name + assert_equal 'Jan', @backend.localize('de-DE', @morning, '%b') + end + + def test_translate_given_a_meridian_indicator_format_it_returns_the_correct_meridian_indicator + assert_equal 'am', @backend.localize('de-DE', @morning, '%p') + assert_equal 'pm', @backend.localize('de-DE', @evening, '%p') + end + + def test_translate_given_no_format_it_does_not_fail + assert_nothing_raised{ @backend.localize 'de-DE', @morning } + end + + def test_translate_given_an_unknown_format_it_does_not_fail + assert_nothing_raised{ @backend.localize 'de-DE', @morning, '%x' } + end +end + +class I18nSimpleBackendLocalizeTimeTest < Test::Unit::TestCase + include I18nSimpleBackendTestSetup + + def setup + @old_timezone, ENV['TZ'] = ENV['TZ'], 'UTC' + @backend = I18n::Backend::Simple + add_datetime_translations + @morning = Time.parse '2008-01-01 6:00 UTC' + @evening = Time.parse '2008-01-01 18:00 UTC' + end + + def teardown + ENV['TZ'] = @old_timezone + end + + def test_translate_given_the_short_format_it_uses_it + assert_equal '01. Jan 06:00', @backend.localize('de-DE', @morning, :short) + end + + def test_translate_given_the_long_format_it_uses_it + assert_equal '01. Januar 2008 06:00', @backend.localize('de-DE', @morning, :long) + end + + # TODO Seems to break on Windows because ENV['TZ'] is ignored. What's a better way to do this? + # def test_translate_given_the_default_format_it_uses_it + # assert_equal 'Di, 01. Jan 2008 06:00:00 +0000', @backend.localize('de-DE', @morning, :default) + # end + + def test_translate_given_a_day_name_format_it_returns_the_correct_day_name + assert_equal 'Dienstag', @backend.localize('de-DE', @morning, '%A') + end + + def test_translate_given_an_abbr_day_name_format_it_returns_the_correct_abbrevated_day_name + assert_equal 'Di', @backend.localize('de-DE', @morning, '%a') + end + + def test_translate_given_a_month_name_format_it_returns_the_correct_month_name + assert_equal 'Januar', @backend.localize('de-DE', @morning, '%B') + end + + def test_translate_given_an_abbr_month_name_format_it_returns_the_correct_abbrevated_month_name + assert_equal 'Jan', @backend.localize('de-DE', @morning, '%b') + end + + def test_translate_given_a_meridian_indicator_format_it_returns_the_correct_meridian_indicator + assert_equal 'am', @backend.localize('de-DE', @morning, '%p') + assert_equal 'pm', @backend.localize('de-DE', @evening, '%p') + end + + def test_translate_given_no_format_it_does_not_fail + assert_nothing_raised{ @backend.localize 'de-DE', @morning } + end + + def test_translate_given_an_unknown_format_it_does_not_fail + assert_nothing_raised{ @backend.localize 'de-DE', @morning, '%x' } + end +end + +class I18nSimpleBackendHelperMethodsTest < Test::Unit::TestCase + def setup + @backend = I18n::Backend::Simple + end + + def test_deep_symbolize_keys_works + result = @backend.send :deep_symbolize_keys, 'foo' => {'bar' => {'baz' => 'bar'}} + expected = {:foo => {:bar => {:baz => 'bar'}}} + assert_equal expected, result + end +end -- cgit v1.2.3 From f4f6e57e8c2a446a4a600576f0caf0fb8921ba13 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Tue, 15 Jul 2008 21:24:00 -0500 Subject: Added Object#metaclass --- activesupport/lib/active_support/core_ext/object.rb | 1 + activesupport/lib/active_support/core_ext/object/metaclass.rb | 8 ++++++++ 2 files changed, 9 insertions(+) create mode 100644 activesupport/lib/active_support/core_ext/object/metaclass.rb (limited to 'activesupport/lib') diff --git a/activesupport/lib/active_support/core_ext/object.rb b/activesupport/lib/active_support/core_ext/object.rb index bbc7d81672..0796a7b710 100644 --- a/activesupport/lib/active_support/core_ext/object.rb +++ b/activesupport/lib/active_support/core_ext/object.rb @@ -1,4 +1,5 @@ require 'active_support/core_ext/object/conversions' require 'active_support/core_ext/object/extending' require 'active_support/core_ext/object/instance_variables' +require 'active_support/core_ext/object/metaclass' require 'active_support/core_ext/object/misc' diff --git a/activesupport/lib/active_support/core_ext/object/metaclass.rb b/activesupport/lib/active_support/core_ext/object/metaclass.rb new file mode 100644 index 0000000000..169a76dfb7 --- /dev/null +++ b/activesupport/lib/active_support/core_ext/object/metaclass.rb @@ -0,0 +1,8 @@ +class Object + # Get object's meta (ghost, eigenclass, singleton) class + def metaclass + class << self + self + end + end +end -- cgit v1.2.3 From be078ee162fcae883a5621a30929879cd783a238 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Tue, 15 Jul 2008 21:55:28 -0500 Subject: Run callbacks from object's metaclass [#575 state:resolved] --- activesupport/lib/active_support/callbacks.rb | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'activesupport/lib') diff --git a/activesupport/lib/active_support/callbacks.rb b/activesupport/lib/active_support/callbacks.rb index 9c59b7ac76..f125a56246 100644 --- a/activesupport/lib/active_support/callbacks.rb +++ b/activesupport/lib/active_support/callbacks.rb @@ -269,7 +269,15 @@ module ActiveSupport # pass # stop def run_callbacks(kind, options = {}, &block) - self.class.send("#{kind}_callback_chain").run(self, options, &block) + callback_chain_method = "#{kind}_callback_chain" + + # Meta class inherits Class so we don't have to merge it in 1.9 + if RUBY_VERSION >= '1.9' + metaclass.send(callback_chain_method).run(self, options, &block) + else + callbacks = self.class.send(callback_chain_method) | metaclass.send(callback_chain_method) + callbacks.run(self, options, &block) + end end end end -- cgit v1.2.3 From 0432d151647f2178ddee79979827d552447c251f Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Wed, 16 Jul 2008 13:00:36 +0100 Subject: Merge with docrails. --- .../active_support/core_ext/bigdecimal/conversions.rb | 2 +- .../lib/active_support/core_ext/hash/except.rb | 2 +- .../lib/active_support/core_ext/hash/reverse_merge.rb | 17 ++++++++++++----- .../lib/active_support/core_ext/string/inflections.rb | 4 ++-- .../lib/active_support/core_ext/time/calculations.rb | 2 +- activesupport/lib/active_support/json.rb | 2 +- activesupport/lib/active_support/json/encoders/date.rb | 11 +++++++++-- .../lib/active_support/json/encoders/date_time.rb | 11 +++++++++-- activesupport/lib/active_support/json/encoders/time.rb | 13 ++++++++++--- activesupport/lib/active_support/time_with_zone.rb | 14 +++++++++++++- .../vendor/builder-2.1.2/builder/xmlevents.rb | 2 +- .../vendor/memcache-client-1.5.0/memcache.rb | 4 ++-- .../vendor/tzinfo-0.3.9/tzinfo/data_timezone.rb | 2 +- .../vendor/tzinfo-0.3.9/tzinfo/data_timezone_info.rb | 2 +- .../vendor/tzinfo-0.3.9/tzinfo/linked_timezone.rb | 2 +- .../vendor/tzinfo-0.3.9/tzinfo/timezone.rb | 2 +- .../tzinfo-0.3.9/tzinfo/timezone_transition_info.rb | 2 +- .../vendor/xml-simple-1.0.11/xmlsimple.rb | 6 +++--- 18 files changed, 70 insertions(+), 30 deletions(-) (limited to 'activesupport/lib') diff --git a/activesupport/lib/active_support/core_ext/bigdecimal/conversions.rb b/activesupport/lib/active_support/core_ext/bigdecimal/conversions.rb index d2b01b1b8d..94c7c779f7 100644 --- a/activesupport/lib/active_support/core_ext/bigdecimal/conversions.rb +++ b/activesupport/lib/active_support/core_ext/bigdecimal/conversions.rb @@ -21,7 +21,7 @@ module ActiveSupport #:nodoc: # This emits the number without any scientific notation. # I prefer it to using self.to_f.to_s, which would lose precision. # - # Note that YAML allows that when reconsituting floats + # Note that YAML allows that when reconstituting floats # to native types, some precision may get lost. # There is no full precision real YAML tag that I am aware of. str = self.to_s diff --git a/activesupport/lib/active_support/core_ext/hash/except.rb b/activesupport/lib/active_support/core_ext/hash/except.rb index bc97fa35a6..f26d01553d 100644 --- a/activesupport/lib/active_support/core_ext/hash/except.rb +++ b/activesupport/lib/active_support/core_ext/hash/except.rb @@ -13,7 +13,7 @@ module ActiveSupport #:nodoc: clone.except!(*keys) end - # Replaces the hash without only the given keys. + # Replaces the hash without the given keys. def except!(*keys) keys.map! { |key| convert_key(key) } if respond_to?(:convert_key) keys.each { |key| delete(key) } 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 7af10846e7..546e261cc9 100644 --- a/activesupport/lib/active_support/core_ext/hash/reverse_merge.rb +++ b/activesupport/lib/active_support/core_ext/hash/reverse_merge.rb @@ -1,21 +1,28 @@ module ActiveSupport #:nodoc: module CoreExtensions #:nodoc: module Hash #:nodoc: - # Allows for reverse merging where its the keys in the calling hash that wins over those in the other_hash. - # This is particularly useful for initializing an incoming option hash with default values: + # Allows for reverse merging two hashes where the keys in the calling hash take precedence over those + # in the other_hash. This is particularly useful for initializing an option hash with default values: # # def setup(options = {}) # options.reverse_merge! :size => 25, :velocity => 10 # end # - # The default :size and :velocity is only set if the +options+ passed in doesn't already have those keys set. + # Using merge, the above example would look as follows: + # + # def setup(options = {}) + # { :size => 25, :velocity => 10 }.merge(options) + # end + # + # The default :size and :velocity are only set if the +options+ hash passed in doesn't already + # have the respective key. module ReverseMerge - # Performs the opposite of merge, with the keys and values from the first hash taking precedence over the second. + # Performs the opposite of merge, with the keys and values from the first hash taking precedence over the second. def reverse_merge(other_hash) other_hash.merge(self) end - # Performs the opposite of merge, with the keys and values from the first hash taking precedence over the second. + # Performs the opposite of merge, with the keys and values from the first hash taking precedence over the second. # Modifies the receiver in place. def reverse_merge!(other_hash) replace(reverse_merge(other_hash)) diff --git a/activesupport/lib/active_support/core_ext/string/inflections.rb b/activesupport/lib/active_support/core_ext/string/inflections.rb index a009d7c085..3bbad7dad8 100644 --- a/activesupport/lib/active_support/core_ext/string/inflections.rb +++ b/activesupport/lib/active_support/core_ext/string/inflections.rb @@ -24,8 +24,8 @@ module ActiveSupport #:nodoc: # # "posts".singularize # => "post" # "octopi".singularize # => "octopus" - # "sheep".singluarize # => "sheep" - # "word".singluarize # => "word" + # "sheep".singularize # => "sheep" + # "word".singularize # => "word" # "the blue mailmen".singularize # => "the blue mailman" # "CamelOctopi".singularize # => "CamelOctopus" def singularize diff --git a/activesupport/lib/active_support/core_ext/time/calculations.rb b/activesupport/lib/active_support/core_ext/time/calculations.rb index 2cce782676..cd234c9b89 100644 --- a/activesupport/lib/active_support/core_ext/time/calculations.rb +++ b/activesupport/lib/active_support/core_ext/time/calculations.rb @@ -261,7 +261,7 @@ module ActiveSupport #:nodoc: # 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 <=> comparision + # 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#<=> diff --git a/activesupport/lib/active_support/json.rb b/activesupport/lib/active_support/json.rb index 54a7becd0f..2bdb4a7b11 100644 --- a/activesupport/lib/active_support/json.rb +++ b/activesupport/lib/active_support/json.rb @@ -1,5 +1,5 @@ module ActiveSupport - # If true, use ISO 8601 format for dates and times. Otherwise, fall back to the Active Support legacy format. + # If true, use ISO 8601 format for dates and times. Otherwise, fall back to the Active Support legacy format. mattr_accessor :use_standard_json_time_format class << self diff --git a/activesupport/lib/active_support/json/encoders/date.rb b/activesupport/lib/active_support/json/encoders/date.rb index cb9419d29d..1fc99c466f 100644 --- a/activesupport/lib/active_support/json/encoders/date.rb +++ b/activesupport/lib/active_support/json/encoders/date.rb @@ -1,7 +1,14 @@ class Date - # Returns a JSON string representing the date. + # Returns a JSON string representing the date. If ActiveSupport.use_standard_json_time_format is set to true, the + # ISO 8601 format is used. # - # ==== Example: + # ==== Examples: + # + # # With ActiveSupport.use_standard_json_time_format = true + # Date.new(2005,2,1).to_json + # # => "2005-02-01" + # + # # With ActiveSupport.use_standard_json_time_format = false # Date.new(2005,2,1).to_json # # => "2005/02/01" def to_json(options = nil) diff --git a/activesupport/lib/active_support/json/encoders/date_time.rb b/activesupport/lib/active_support/json/encoders/date_time.rb index a4a5efbfb1..e259930033 100644 --- a/activesupport/lib/active_support/json/encoders/date_time.rb +++ b/activesupport/lib/active_support/json/encoders/date_time.rb @@ -1,7 +1,14 @@ class DateTime - # Returns a JSON string representing the datetime. + # Returns a JSON string representing the datetime. If ActiveSupport.use_standard_json_time_format is set to true, the + # ISO 8601 format is used. # - # ==== Example: + # ==== Examples: + # + # # With ActiveSupport.use_standard_json_time_format = true + # DateTime.civil(2005,2,1,15,15,10).to_json + # # => "2005-02-01T15:15:10+00:00" + # + # # With ActiveSupport.use_standard_json_time_format = false # DateTime.civil(2005,2,1,15,15,10).to_json # # => "2005/02/01 15:15:10 +0000" def to_json(options = nil) diff --git a/activesupport/lib/active_support/json/encoders/time.rb b/activesupport/lib/active_support/json/encoders/time.rb index 57ed3c9e31..09fc614889 100644 --- a/activesupport/lib/active_support/json/encoders/time.rb +++ b/activesupport/lib/active_support/json/encoders/time.rb @@ -1,9 +1,16 @@ class Time - # Returns a JSON string representing the time. + # Returns a JSON string representing the time. If ActiveSupport.use_standard_json_time_format is set to true, the + # ISO 8601 format is used. # - # ==== Example: + # ==== Examples: + # + # # With ActiveSupport.use_standard_json_time_format = true + # Time.utc(2005,2,1,15,15,10).to_json + # # => "2005-02-01T15:15:10Z" + # + # # With ActiveSupport.use_standard_json_time_format = false # Time.utc(2005,2,1,15,15,10).to_json - # # => 2005/02/01 15:15:10 +0000" + # # => "2005/02/01 15:15:10 +0000" def to_json(options = nil) if ActiveSupport.use_standard_json_time_format xmlschema.inspect diff --git a/activesupport/lib/active_support/time_with_zone.rb b/activesupport/lib/active_support/time_with_zone.rb index e85bfe9b2e..4866fa0dc8 100644 --- a/activesupport/lib/active_support/time_with_zone.rb +++ b/activesupport/lib/active_support/time_with_zone.rb @@ -102,7 +102,19 @@ module ActiveSupport "#{time.strftime("%Y-%m-%dT%H:%M:%S")}#{formatted_offset(true, 'Z')}" end alias_method :iso8601, :xmlschema - + + # Returns a JSON string representing the TimeWithZone. If ActiveSupport.use_standard_json_time_format is set to + # true, the ISO 8601 format is used. + # + # ==== Examples: + # + # # With ActiveSupport.use_standard_json_time_format = true + # Time.utc(2005,2,1,15,15,10).in_time_zone.to_json + # # => "2005-02-01T15:15:10Z" + # + # # With ActiveSupport.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 to_json(options = nil) if ActiveSupport.use_standard_json_time_format xmlschema.inspect diff --git a/activesupport/lib/active_support/vendor/builder-2.1.2/builder/xmlevents.rb b/activesupport/lib/active_support/vendor/builder-2.1.2/builder/xmlevents.rb index 91fcd21e13..b373e4da3c 100644 --- a/activesupport/lib/active_support/vendor/builder-2.1.2/builder/xmlevents.rb +++ b/activesupport/lib/active_support/vendor/builder-2.1.2/builder/xmlevents.rb @@ -20,7 +20,7 @@ module Builder # markup. # # Usage: - # xe = Builder::XmlEvents.new(hander) + # xe = Builder::XmlEvents.new(handler) # xe.title("HI") # Sends start_tag/end_tag/text messages to the handler. # # Indentation may also be selected by providing value for the diff --git a/activesupport/lib/active_support/vendor/memcache-client-1.5.0/memcache.rb b/activesupport/lib/active_support/vendor/memcache-client-1.5.0/memcache.rb index dda7f2c30e..30113201a6 100644 --- a/activesupport/lib/active_support/vendor/memcache-client-1.5.0/memcache.rb +++ b/activesupport/lib/active_support/vendor/memcache-client-1.5.0/memcache.rb @@ -119,7 +119,7 @@ class MemCache # Valid options for +opts+ are: # # [:namespace] Prepends this value to all keys added or retrieved. - # [:readonly] Raises an exeception on cache writes when true. + # [:readonly] Raises an exception on cache writes when true. # [:multithread] Wraps cache access in a Mutex for thread safety. # # Other options are ignored. @@ -207,7 +207,7 @@ class MemCache end ## - # Deceremets the value for +key+ by +amount+ and returns the new value. + # Decrements the value for +key+ by +amount+ and returns the new value. # +key+ must already exist. If +key+ is not an integer, it is assumed to be # 0. +key+ can not be decremented below 0. diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/data_timezone.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/data_timezone.rb index 5eccbdf0db..2510e90b5b 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/data_timezone.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/data_timezone.rb @@ -38,7 +38,7 @@ module TZInfo # Returns the set of TimezonePeriod instances that are valid for the given # local time as an array. If you just want a single period, use - # period_for_local instead and specify how abiguities should be resolved. + # period_for_local instead and specify how ambiguities should be resolved. # Raises PeriodNotFound if no periods are found for the given time. def periods_for_local(local) info.periods_for_local(local) diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/data_timezone_info.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/data_timezone_info.rb index a45d94554b..8829ba9cc8 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/data_timezone_info.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/data_timezone_info.rb @@ -66,7 +66,7 @@ module TZInfo # ArgumentError will be raised if a transition is added out of order. # offset_id refers to an id defined with offset. ArgumentError will be # raised if the offset_id cannot be found. numerator_or_time and - # denomiator specify the time the transition occurs as. See + # denominator specify the time the transition occurs as. See # TimezoneTransitionInfo for more detail about specifying times. def transition(year, month, offset_id, numerator_or_time, denominator = nil) offset = @offsets[offset_id] diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/linked_timezone.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/linked_timezone.rb index f8ec4fca87..c757485b84 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/linked_timezone.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/linked_timezone.rb @@ -36,7 +36,7 @@ module TZInfo # Returns the set of TimezonePeriod instances that are valid for the given # local time as an array. If you just want a single period, use - # period_for_local instead and specify how abiguities should be resolved. + # period_for_local instead and specify how ambiguities should be resolved. # Raises PeriodNotFound if no periods are found for the given time. def periods_for_local(local) @linked_timezone.periods_for_local(local) diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/timezone.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/timezone.rb index f87fb6fb70..eeaa772d0f 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/timezone.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/timezone.rb @@ -121,7 +121,7 @@ module TZInfo TimezoneProxy.new(identifier) end - # If identifier is nil calls super(), otherwise calls get. An identfier + # If identifier is nil calls super(), otherwise calls get. An identifier # should always be passed in when called externally. def self.new(identifier = nil) if identifier diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/timezone_transition_info.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/timezone_transition_info.rb index 3fecb24f0d..781764f0b0 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/timezone_transition_info.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/timezone_transition_info.rb @@ -37,7 +37,7 @@ module TZInfo attr_reader :numerator_or_time protected :numerator_or_time - # Either the denominotor of the DateTime if the transition time is defined + # Either the denominator of the DateTime if the transition time is defined # as a DateTime, otherwise nil. attr_reader :denominator protected :denominator diff --git a/activesupport/lib/active_support/vendor/xml-simple-1.0.11/xmlsimple.rb b/activesupport/lib/active_support/vendor/xml-simple-1.0.11/xmlsimple.rb index 0de24c0eff..ec6dab513f 100644 --- a/activesupport/lib/active_support/vendor/xml-simple-1.0.11/xmlsimple.rb +++ b/activesupport/lib/active_support/vendor/xml-simple-1.0.11/xmlsimple.rb @@ -121,7 +121,7 @@ class XmlSimple # Create a "global" cache. @@cache = Cache.new - # Creates and intializes a new XmlSimple object. + # Creates and initializes a new XmlSimple object. # # defaults:: # Default values for options. @@ -497,7 +497,7 @@ class XmlSimple } end - # Fold Hases containing a single anonymous Array up into just the Array. + # Fold Hashes containing a single anonymous Array up into just the Array. if count == 1 anonymoustag = @options['anonymoustag'] if result.has_key?(anonymoustag) && result[anonymoustag].instance_of?(Array) @@ -907,7 +907,7 @@ class XmlSimple # Thanks to Norbert Gawor for a bugfix. # # value:: - # Value to be checked for emptyness. + # Value to be checked for emptiness. def empty(value) case value when Hash -- cgit v1.2.3 From 7ae2105d57d3c08bebde44bd72093dd43c48d613 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Wed, 16 Jul 2008 18:46:04 -0500 Subject: MemCacheStore#decrement should use data instance variable not local variable [#521 state:resolved] --- .../lib/active_support/cache/mem_cache_store.rb | 30 +++++++++++----------- 1 file changed, 15 insertions(+), 15 deletions(-) (limited to 'activesupport/lib') diff --git a/activesupport/lib/active_support/cache/mem_cache_store.rb b/activesupport/lib/active_support/cache/mem_cache_store.rb index b3769b812f..58958dccef 100644 --- a/activesupport/lib/active_support/cache/mem_cache_store.rb +++ b/activesupport/lib/active_support/cache/mem_cache_store.rb @@ -29,8 +29,8 @@ module ActiveSupport nil end - # Set key = value. Pass :unless_exist => true if you don't - # want to update the cache if the key is already set. + # Set key = value. Pass :unless_exist => true if you don't + # want to update the cache if the key is already set. def write(key, value, options = nil) super method = options && options[:unless_exist] ? :add : :set @@ -56,33 +56,33 @@ module ActiveSupport !read(key, options).nil? end - def increment(key, amount = 1) + def increment(key, amount = 1) log("incrementing", key, amount) - - response = @data.incr(key, amount) + + response = @data.incr(key, amount) response == Response::NOT_FOUND ? nil : response - rescue MemCache::MemCacheError + rescue MemCache::MemCacheError nil end def decrement(key, amount = 1) log("decrement", key, amount) - - response = data.decr(key, amount) + + response = @data.decr(key, amount) response == Response::NOT_FOUND ? nil : response - rescue MemCache::MemCacheError + rescue MemCache::MemCacheError nil - end - + end + def delete_matched(matcher, options = nil) super raise "Not supported by Memcache" - end - + end + def clear @data.flush_all - end - + end + def stats @data.stats end -- cgit v1.2.3 From 396f9df8916b71f83aad8d56559cf55fc8501679 Mon Sep 17 00:00:00 2001 From: Josh Owens Date: Wed, 16 Jul 2008 19:31:37 -0500 Subject: Hash#slice supports an array of keys [#613 state:resolved] Signed-off-by: Joshua Peek --- activesupport/lib/active_support/core_ext/hash/slice.rb | 1 + 1 file changed, 1 insertion(+) (limited to 'activesupport/lib') diff --git a/activesupport/lib/active_support/core_ext/hash/slice.rb b/activesupport/lib/active_support/core_ext/hash/slice.rb index be4dec6e53..d3837d2e54 100644 --- a/activesupport/lib/active_support/core_ext/hash/slice.rb +++ b/activesupport/lib/active_support/core_ext/hash/slice.rb @@ -12,6 +12,7 @@ module ActiveSupport #:nodoc: module Slice # Returns a new hash with only the given keys. def slice(*keys) + keys.flatten! keys = keys.map! { |key| convert_key(key) } if respond_to?(:convert_key) hash = {} keys.each { |k| hash[k] = self[k] if has_key?(k) } -- cgit v1.2.3 From 40dbebba28bfa1c55737da7354542c3bdca4e1a1 Mon Sep 17 00:00:00 2001 From: Lawrence Pit Date: Mon, 14 Jul 2008 11:53:41 +1000 Subject: Allow deep merging of hash values for nested with_options. [#490 state:resolved] Signed-off-by: Pratik Naik --- activesupport/lib/active_support/core_ext/hash.rb | 3 ++- .../lib/active_support/core_ext/hash/deep_merge.rb | 23 ++++++++++++++++++++++ activesupport/lib/active_support/option_merger.rb | 10 +--------- 3 files changed, 26 insertions(+), 10 deletions(-) create mode 100644 activesupport/lib/active_support/core_ext/hash/deep_merge.rb (limited to 'activesupport/lib') diff --git a/activesupport/lib/active_support/core_ext/hash.rb b/activesupport/lib/active_support/core_ext/hash.rb index 6cbd9dd378..a6065ab48e 100644 --- a/activesupport/lib/active_support/core_ext/hash.rb +++ b/activesupport/lib/active_support/core_ext/hash.rb @@ -1,10 +1,11 @@ -%w(keys indifferent_access reverse_merge conversions diff slice except).each do |ext| +%w(keys indifferent_access deep_merge reverse_merge conversions diff slice except).each do |ext| require "active_support/core_ext/hash/#{ext}" end class Hash #:nodoc: include ActiveSupport::CoreExtensions::Hash::Keys include ActiveSupport::CoreExtensions::Hash::IndifferentAccess + include ActiveSupport::CoreExtensions::Hash::DeepMerge include ActiveSupport::CoreExtensions::Hash::ReverseMerge include ActiveSupport::CoreExtensions::Hash::Conversions include ActiveSupport::CoreExtensions::Hash::Diff diff --git a/activesupport/lib/active_support/core_ext/hash/deep_merge.rb b/activesupport/lib/active_support/core_ext/hash/deep_merge.rb new file mode 100644 index 0000000000..f8842ba57a --- /dev/null +++ b/activesupport/lib/active_support/core_ext/hash/deep_merge.rb @@ -0,0 +1,23 @@ +module ActiveSupport #:nodoc: + module CoreExtensions #:nodoc: + module Hash #:nodoc: + # Allows for deep merging + module DeepMerge + # Returns a new hash with +self+ and +other_hash+ merged recursively. + def deep_merge(other_hash) + self.merge(other_hash) do |key, oldval, newval| + oldval = oldval.to_hash if oldval.respond_to?(:to_hash) + newval = newval.to_hash if newval.respond_to?(:to_hash) + oldval.class.to_s == 'Hash' && newval.class.to_s == 'Hash' ? oldval.deep_merge(newval) : newval + end + end + + # Returns a new hash with +self+ and +other_hash+ merged recursively. + # Modifies the receiver in place. + def deep_merge!(other_hash) + replace(deep_merge(other_hash)) + end + end + end + end +end diff --git a/activesupport/lib/active_support/option_merger.rb b/activesupport/lib/active_support/option_merger.rb index 1a4ff9db9a..c77bca1ac9 100644 --- a/activesupport/lib/active_support/option_merger.rb +++ b/activesupport/lib/active_support/option_merger.rb @@ -10,16 +10,8 @@ module ActiveSupport private def method_missing(method, *arguments, &block) - merge_argument_options! arguments + arguments << (arguments.last.respond_to?(:to_hash) ? @options.deep_merge(arguments.pop) : @options.dup) @context.send!(method, *arguments, &block) end - - def merge_argument_options!(arguments) - arguments << if arguments.last.respond_to? :to_hash - @options.merge(arguments.pop) - else - @options.dup - end - end end end -- cgit v1.2.3 From d8a72b32c5b0c32abf257f05b89bad7d21f178ec Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Wed, 16 Jul 2008 20:23:44 -0500 Subject: Revert "Run callbacks from object's metaclass" --- activesupport/lib/active_support/callbacks.rb | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) (limited to 'activesupport/lib') diff --git a/activesupport/lib/active_support/callbacks.rb b/activesupport/lib/active_support/callbacks.rb index f125a56246..9c59b7ac76 100644 --- a/activesupport/lib/active_support/callbacks.rb +++ b/activesupport/lib/active_support/callbacks.rb @@ -269,15 +269,7 @@ module ActiveSupport # pass # stop def run_callbacks(kind, options = {}, &block) - callback_chain_method = "#{kind}_callback_chain" - - # Meta class inherits Class so we don't have to merge it in 1.9 - if RUBY_VERSION >= '1.9' - metaclass.send(callback_chain_method).run(self, options, &block) - else - callbacks = self.class.send(callback_chain_method) | metaclass.send(callback_chain_method) - callbacks.run(self, options, &block) - end + self.class.send("#{kind}_callback_chain").run(self, options, &block) end end end -- cgit v1.2.3 From b3a2ee7b87a6b2a4c6ff086644f40a472a676b65 Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Thu, 17 Jul 2008 15:28:02 +0100 Subject: Revert "Hash#slice supports an array of keys [#613 state:resolved]" This reverts commit 396f9df8916b71f83aad8d56559cf55fc8501679. --- activesupport/lib/active_support/core_ext/hash/slice.rb | 1 - 1 file changed, 1 deletion(-) (limited to 'activesupport/lib') diff --git a/activesupport/lib/active_support/core_ext/hash/slice.rb b/activesupport/lib/active_support/core_ext/hash/slice.rb index d3837d2e54..be4dec6e53 100644 --- a/activesupport/lib/active_support/core_ext/hash/slice.rb +++ b/activesupport/lib/active_support/core_ext/hash/slice.rb @@ -12,7 +12,6 @@ module ActiveSupport #:nodoc: module Slice # Returns a new hash with only the given keys. def slice(*keys) - keys.flatten! keys = keys.map! { |key| convert_key(key) } if respond_to?(:convert_key) hash = {} keys.each { |k| hash[k] = self[k] if has_key?(k) } -- cgit v1.2.3 From 7e8aee7e6cbd23c1eb18bec1869465e923915e7a Mon Sep 17 00:00:00 2001 From: MatthewRudy Date: Thu, 17 Jul 2008 13:58:42 +0100 Subject: Add extra tests to ensure Hash#slice works with an array as a key. #613 Signed-off-by: Pratik Naik --- activesupport/lib/active_support/core_ext/hash/slice.rb | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'activesupport/lib') diff --git a/activesupport/lib/active_support/core_ext/hash/slice.rb b/activesupport/lib/active_support/core_ext/hash/slice.rb index be4dec6e53..3f14470f36 100644 --- a/activesupport/lib/active_support/core_ext/hash/slice.rb +++ b/activesupport/lib/active_support/core_ext/hash/slice.rb @@ -9,6 +9,11 @@ module ActiveSupport #:nodoc: # end # # search(options.slice(:mass, :velocity, :time)) + # + # If you have an array of keys you want to limit to, you should splat them: + # + # valid_keys = [:mass, :velocity, :time] + # search(options.slice(*valid_keys)) module Slice # Returns a new hash with only the given keys. def slice(*keys) -- cgit v1.2.3 From 94cf6675d516a0196f0222694f26dcd4c29c49c6 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Thu, 17 Jul 2008 15:29:30 -0500 Subject: Cleanup ActiveSupport::Cache::ThreadSafety module and add test coverage --- activesupport/lib/active_support/cache.rb | 32 +++++++++++-------------------- 1 file changed, 11 insertions(+), 21 deletions(-) (limited to 'activesupport/lib') diff --git a/activesupport/lib/active_support/cache.rb b/activesupport/lib/active_support/cache.rb index 3e3dc18263..57c6a6331d 100644 --- a/activesupport/lib/active_support/cache.rb +++ b/activesupport/lib/active_support/cache.rb @@ -21,7 +21,7 @@ module ActiveSupport expanded_cache_key = namespace ? "#{namespace}/" : "" if ENV["RAILS_CACHE_ID"] || ENV["RAILS_APP_VERSION"] - expanded_cache_key << "#{ENV["RAILS_CACHE_ID"] || ENV["RAILS_APP_VERSION"]}/" + expanded_cache_key << "#{ENV["RAILS_CACHE_ID"] || ENV["RAILS_APP_VERSION"]}/" end expanded_cache_key << case @@ -40,13 +40,8 @@ module ActiveSupport class Store cattr_accessor :logger - def initialize - end - def threadsafe! - @mutex = Mutex.new - self.class.send :include, ThreadSafety - self + extend ThreadSafety end # Pass :force => true to force a cache miss. @@ -110,29 +105,24 @@ module ActiveSupport nil end end - + private def log(operation, key, options) logger.debug("Cache #{operation}: #{key}#{options ? " (#{options.inspect})" : ""}") if logger && !@logger_off end end - module ThreadSafety #:nodoc: - def read(key, options = nil) #:nodoc: - @mutex.synchronize { super } - end - - def write(key, value, options = nil) #:nodoc: - @mutex.synchronize { super } - end - - def delete(key, options = nil) #:nodoc: - @mutex.synchronize { super } + def self.extended(object) #:nodoc: + object.instance_variable_set(:@mutex, Mutex.new) end - def delete_matched(matcher, options = nil) #:nodoc: - @mutex.synchronize { super } + %w(read write delete delete_matched exist? increment decrement).each do |method| + module_eval <<-EOS, __FILE__, __LINE__ + def #{method}(*args) + @mutex.synchronize { super } + end + EOS end end end -- cgit v1.2.3 From 0eef4e554db9b1af47305f5a8c51c90c15ac6c04 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Thu, 17 Jul 2008 16:00:59 -0500 Subject: Allow ActiveSupport::Cache logger to be silenced --- activesupport/lib/active_support/cache.rb | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'activesupport/lib') diff --git a/activesupport/lib/active_support/cache.rb b/activesupport/lib/active_support/cache.rb index 57c6a6331d..5a064f8bea 100644 --- a/activesupport/lib/active_support/cache.rb +++ b/activesupport/lib/active_support/cache.rb @@ -36,7 +36,6 @@ module ActiveSupport expanded_cache_key end - class Store cattr_accessor :logger @@ -44,6 +43,11 @@ module ActiveSupport extend ThreadSafety end + def silence! + @silence = true + self + end + # Pass :force => true to force a cache miss. def fetch(key, options = {}) @logger_off = true @@ -108,7 +112,7 @@ module ActiveSupport private def log(operation, key, options) - logger.debug("Cache #{operation}: #{key}#{options ? " (#{options.inspect})" : ""}") if logger && !@logger_off + logger.debug("Cache #{operation}: #{key}#{options ? " (#{options.inspect})" : ""}") if logger && !@silence && !@logger_off end end -- cgit v1.2.3 From 7430c4168fad07b480dbf80c8ac75ba7db8c634f Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Wed, 16 Jul 2008 22:27:04 -0700 Subject: Decrease default benchmark runs from 10 to 4 --- activesupport/lib/active_support/testing/performance.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'activesupport/lib') diff --git a/activesupport/lib/active_support/testing/performance.rb b/activesupport/lib/active_support/testing/performance.rb index 5f2027eb3b..71d6f4d9c6 100644 --- a/activesupport/lib/active_support/testing/performance.rb +++ b/activesupport/lib/active_support/testing/performance.rb @@ -11,7 +11,7 @@ module ActiveSupport DEFAULTS = if benchmark = ARGV.include?('--benchmark') # HAX for rake test { :benchmark => true, - :runs => 10, + :runs => 4, :metrics => [:process_time, :memory, :objects, :gc_runs, :gc_time], :output => 'tmp/performance' } else -- cgit v1.2.3 From e1f23da53cef20a60e4bf458d959fe2bfe7d52ea Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Fri, 18 Jul 2008 11:18:16 -0500 Subject: Allow memoized methods to be reloaded and allow multiple symbols --- activesupport/lib/active_support/memoizable.rb | 32 ++++++++++++++------------ 1 file changed, 17 insertions(+), 15 deletions(-) (limited to 'activesupport/lib') diff --git a/activesupport/lib/active_support/memoizable.rb b/activesupport/lib/active_support/memoizable.rb index d06250171a..c41feef4c7 100644 --- a/activesupport/lib/active_support/memoizable.rb +++ b/activesupport/lib/active_support/memoizable.rb @@ -5,28 +5,30 @@ module ActiveSupport end module ClassMethods - def memoize(symbol) - original_method = "_unmemoized_#{symbol}" - memoized_ivar = "@_memoized_#{symbol}" - raise "Already memoized #{symbol}" if instance_methods.map(&:to_s).include?(original_method) + def memoize(*symbols) + symbols.each do |symbol| + original_method = "unmemoized_#{symbol}" + memoized_ivar = "@#{symbol}" + raise "Already memoized #{symbol}" if instance_methods.map(&:to_s).include?(original_method) - alias_method original_method, symbol - class_eval <<-EOS, __FILE__, __LINE__ - def #{symbol} - if defined? #{memoized_ivar} - #{memoized_ivar} - else - #{memoized_ivar} = #{original_method} + alias_method original_method, symbol + class_eval <<-EOS, __FILE__, __LINE__ + def #{symbol}(reload = false) + if !reload && defined? #{memoized_ivar} + #{memoized_ivar} + else + #{memoized_ivar} = #{original_method}.freeze + end end - end - EOS + EOS + end end end def freeze methods.each do |method| - if m = method.to_s.match(/\A_unmemoized_(.*)/) - send(m[1]).freeze + if m = method.to_s.match(/\Aunmemoized_(.*)/) + send(m[1]) end end super -- cgit v1.2.3 From ef6f6625c91ea789a033799f649e4388e4a71045 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Fri, 18 Jul 2008 15:32:28 -0500 Subject: Changed ActiveSupport::Memoizable API to extend since it mainly adds the memoize class method --- activesupport/lib/active_support/memoizable.rb | 55 +++++++++++++------------- 1 file changed, 28 insertions(+), 27 deletions(-) (limited to 'activesupport/lib') diff --git a/activesupport/lib/active_support/memoizable.rb b/activesupport/lib/active_support/memoizable.rb index c41feef4c7..59fecbecb1 100644 --- a/activesupport/lib/active_support/memoizable.rb +++ b/activesupport/lib/active_support/memoizable.rb @@ -1,37 +1,38 @@ module ActiveSupport - module Memoizable - def self.included(base) #:nodoc: - base.extend(ClassMethods) - end - - module ClassMethods - def memoize(*symbols) - symbols.each do |symbol| - original_method = "unmemoized_#{symbol}" - memoized_ivar = "@#{symbol}" - raise "Already memoized #{symbol}" if instance_methods.map(&:to_s).include?(original_method) - - alias_method original_method, symbol - class_eval <<-EOS, __FILE__, __LINE__ - def #{symbol}(reload = false) - if !reload && defined? #{memoized_ivar} - #{memoized_ivar} - else - #{memoized_ivar} = #{original_method}.freeze - end + module Memoizable #:nodoc: + def self.extended(obj) + klass = obj.respond_to?(:class_eval) ? obj : obj.metaclass + klass.class_eval do + def freeze + methods.each do |method| + if m = method.to_s.match(/^unmemoized_(.*)/) + send(m[1]) end - EOS + end + super end end end - def freeze - methods.each do |method| - if m = method.to_s.match(/\Aunmemoized_(.*)/) - send(m[1]) - end + def memoize(*symbols) + symbols.each do |symbol| + original_method = "unmemoized_#{symbol}" + memoized_ivar = "@#{symbol}" + + klass = respond_to?(:class_eval) ? self : self.metaclass + raise "Already memoized #{symbol}" if klass.instance_methods.map(&:to_s).include?(original_method) + + klass.class_eval <<-EOS, __FILE__, __LINE__ + alias_method :#{original_method}, :#{symbol} + def #{symbol}(reload = false) + if !reload && defined? #{memoized_ivar} + #{memoized_ivar} + else + #{memoized_ivar} = #{original_method}.freeze + end + end + EOS end - super end end end -- cgit v1.2.3 From c609be45966316bb107e0bad2b0935ac4a0d0c41 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Fri, 18 Jul 2008 23:30:36 -0500 Subject: Ruby 1.9: Ensure Memoizable#freeze is only overriden once to avoid an endless loop --- activesupport/lib/active_support/memoizable.rb | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) (limited to 'activesupport/lib') diff --git a/activesupport/lib/active_support/memoizable.rb b/activesupport/lib/active_support/memoizable.rb index 59fecbecb1..f7cd73d39c 100644 --- a/activesupport/lib/active_support/memoizable.rb +++ b/activesupport/lib/active_support/memoizable.rb @@ -1,19 +1,5 @@ module ActiveSupport module Memoizable #:nodoc: - def self.extended(obj) - klass = obj.respond_to?(:class_eval) ? obj : obj.metaclass - klass.class_eval do - def freeze - methods.each do |method| - if m = method.to_s.match(/^unmemoized_(.*)/) - send(m[1]) - end - end - super - end - end - end - def memoize(*symbols) symbols.each do |symbol| original_method = "unmemoized_#{symbol}" @@ -23,6 +9,18 @@ module ActiveSupport raise "Already memoized #{symbol}" if klass.instance_methods.map(&:to_s).include?(original_method) klass.class_eval <<-EOS, __FILE__, __LINE__ + unless instance_methods.map(&:to_s).include?("freeze_without_memoizable") + alias_method :freeze_without_memoizable, :freeze + def freeze + methods.each do |method| + if m = method.to_s.match(/^unmemoized_(.*)/) + send(m[1]) + end + end + freeze_without_memoizable + end + end + alias_method :#{original_method}, :#{symbol} def #{symbol}(reload = false) if !reload && defined? #{memoized_ivar} -- cgit v1.2.3 From d84d99a8f7dc672b050a6ab891c1680a323a7c97 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Sat, 19 Jul 2008 10:52:30 -0500 Subject: Undefine old run method --- activesupport/lib/active_support/testing/setup_and_teardown.rb | 3 +++ 1 file changed, 3 insertions(+) (limited to 'activesupport/lib') diff --git a/activesupport/lib/active_support/testing/setup_and_teardown.rb b/activesupport/lib/active_support/testing/setup_and_teardown.rb index 21d71eb92a..a514b61fea 100644 --- a/activesupport/lib/active_support/testing/setup_and_teardown.rb +++ b/activesupport/lib/active_support/testing/setup_and_teardown.rb @@ -15,12 +15,15 @@ module ActiveSupport define_callbacks :setup, :teardown if defined?(::Mini) + undef_method :run alias_method :run, :run_with_callbacks_and_miniunit else begin require 'mocha' + undef_method :run alias_method :run, :run_with_callbacks_and_mocha rescue LoadError + undef_method :run alias_method :run, :run_with_callbacks_and_testunit end end -- cgit v1.2.3 From 8c2e839e5a0fb1662ae867c70114c3fc91850a55 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Sat, 19 Jul 2008 11:04:23 -0500 Subject: Fix some warnings in i18n lib --- activesupport/lib/active_support/vendor/i18n-0.0.1/lib/i18n.rb | 6 +++--- .../lib/active_support/vendor/i18n-0.0.1/lib/i18n/backend/simple.rb | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'activesupport/lib') diff --git a/activesupport/lib/active_support/vendor/i18n-0.0.1/lib/i18n.rb b/activesupport/lib/active_support/vendor/i18n-0.0.1/lib/i18n.rb index 2185194da9..1bb65263a3 100755 --- a/activesupport/lib/active_support/vendor/i18n-0.0.1/lib/i18n.rb +++ b/activesupport/lib/active_support/vendor/i18n-0.0.1/lib/i18n.rb @@ -53,7 +53,7 @@ module I18n # storage. Decoupled for backends like a db backend that persist their # translations, so the backend can decide whether/when to yield or not. def populate(&block) - backend.populate &block + backend.populate(&block) end # Stores translations for the given locale in the backend. @@ -173,8 +173,8 @@ module I18n # keys are Symbols. def normalize_translation_keys(locale, key, scope) keys = [locale] + Array(scope) + [key] - keys = keys.map{|key| key.to_s.split(/\./) } - keys.flatten.map{|key| key.to_sym} + keys = keys.map{|k| k.to_s.split(/\./) } + keys.flatten.map{|k| k.to_sym} end end end diff --git a/activesupport/lib/active_support/vendor/i18n-0.0.1/lib/i18n/backend/simple.rb b/activesupport/lib/active_support/vendor/i18n-0.0.1/lib/i18n/backend/simple.rb index 284f2bfcbd..b8be1cecfb 100644 --- a/activesupport/lib/active_support/vendor/i18n-0.0.1/lib/i18n/backend/simple.rb +++ b/activesupport/lib/active_support/vendor/i18n-0.0.1/lib/i18n/backend/simple.rb @@ -23,7 +23,7 @@ module I18n def translate(locale, key, options = {}) raise InvalidLocale.new(locale) if locale.nil? - return key.map{|key| translate locale, key, options } if key.is_a? Array + return key.map{|k| translate locale, k, options } if key.is_a? Array reserved = :scope, :default count, scope, default = options.values_at(:count, *reserved) @@ -66,7 +66,7 @@ module I18n def lookup(locale, key, scope = []) return unless key keys = I18n.send :normalize_translation_keys, locale, key, scope - keys.inject(@@translations){|result, key| result[key.to_sym] or return nil } + keys.inject(@@translations){|result, k| result[k.to_sym] or return nil } end # Evaluates a default translation. -- cgit v1.2.3 From da85251f85420d3a906a1eb949b73bb286122ea9 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Sat, 19 Jul 2008 17:32:22 -0500 Subject: Refactor ActiveSupport::Dependencies injector so it would be possible to disable it --- activesupport/lib/active_support/dependencies.rb | 218 ++++++++++++----------- 1 file changed, 114 insertions(+), 104 deletions(-) (limited to 'activesupport/lib') diff --git a/activesupport/lib/active_support/dependencies.rb b/activesupport/lib/active_support/dependencies.rb index 2f3fa72bb4..e3d4f3d7eb 100644 --- a/activesupport/lib/active_support/dependencies.rb +++ b/activesupport/lib/active_support/dependencies.rb @@ -1,8 +1,3 @@ -require 'set' -require 'active_support/core_ext/module/attribute_accessors' -require 'active_support/core_ext/load_error' -require 'active_support/core_ext/kernel' - module ActiveSupport #:nodoc: module Dependencies #:nodoc: extend self @@ -52,6 +47,119 @@ module ActiveSupport #:nodoc: mattr_accessor :constant_watch_stack self.constant_watch_stack = [] + # Module includes this module + module ModuleConstMissing #:nodoc: + def self.included(base) #:nodoc: + base.class_eval do + # Rename the original handler so we can chain it to the new one + alias_method :rails_original_const_missing, :const_missing + + # Use const_missing to autoload associations so we don't have to + # require_association when using single-table inheritance. + def const_missing(class_id) + ActiveSupport::Dependencies.load_missing_constant self, class_id + end + end + end + + def unloadable(const_desc = self) + super(const_desc) + end + end + + # Class includes this module + module ClassConstMissing #:nodoc: + def const_missing(const_name) + if [Object, Kernel].include?(self) || parent == self + super + else + begin + begin + Dependencies.load_missing_constant self, const_name + rescue NameError + parent.send :const_missing, const_name + end + rescue NameError => e + # Make sure that the name we are missing is the one that caused the error + parent_qualified_name = Dependencies.qualified_name_for parent, const_name + raise unless e.missing_name? parent_qualified_name + qualified_name = Dependencies.qualified_name_for self, const_name + raise NameError.new("uninitialized constant #{qualified_name}").copy_blame!(e) + end + end + end + end + + # Object includes this module + module Loadable #:nodoc: + def load(file, *extras) #:nodoc: + Dependencies.new_constants_in(Object) { super } + rescue Exception => exception # errors from loading file + exception.blame_file! file + raise + end + + def require(file, *extras) #:nodoc: + Dependencies.new_constants_in(Object) { super } + rescue Exception => exception # errors from required file + exception.blame_file! file + raise + end + + # Mark the given constant as unloadable. Unloadable constants are removed each + # time dependencies are cleared. + # + # Note that marking a constant for unloading need only be done once. Setup + # or init scripts may list each unloadable constant that may need unloading; + # each constant will be removed for every subsequent clear, as opposed to for + # the first clear. + # + # The provided constant descriptor may be a (non-anonymous) module or class, + # or a qualified constant name as a string or symbol. + # + # Returns true if the constant was not previously marked for unloading, false + # otherwise. + def unloadable(const_desc) + Dependencies.mark_for_unload const_desc + end + end + + # Exception file-blaming + module Blamable #:nodoc: + def blame_file!(file) + (@blamed_files ||= []).unshift file + end + + def blamed_files + @blamed_files ||= [] + end + + def describe_blame + return nil if blamed_files.empty? + "This error occurred while loading the following files:\n #{blamed_files.join "\n "}" + end + + def copy_blame!(exc) + @blamed_files = exc.blamed_files.clone + self + end + end + + def inject! + Object.instance_eval do + define_method(:require_or_load) { |file_name| Dependencies.require_or_load(file_name) } unless Object.respond_to?(:require_or_load) + define_method(:require_dependency) { |file_name| Dependencies.depend_on(file_name) } unless Object.respond_to?(:require_dependency) + define_method(:require_association) { |file_name| Dependencies.associate_with(file_name) } unless Object.respond_to?(:require_association) + + alias_method :load_without_new_constant_marking, :load + include Loadable + end + + Module.instance_eval { include ModuleConstMissing } + Class.instance_eval { include ClassConstMissing } + Exception.instance_eval { include Blamable } + end + def load? mechanism == :load end @@ -452,102 +560,4 @@ module ActiveSupport #:nodoc: end end -Object.instance_eval do - define_method(:require_or_load) { |file_name| ActiveSupport::Dependencies.require_or_load(file_name) } unless Object.respond_to?(:require_or_load) - define_method(:require_dependency) { |file_name| ActiveSupport::Dependencies.depend_on(file_name) } unless Object.respond_to?(:require_dependency) - define_method(:require_association) { |file_name| ActiveSupport::Dependencies.associate_with(file_name) } unless Object.respond_to?(:require_association) -end - -class Module #:nodoc: - # Rename the original handler so we can chain it to the new one - alias :rails_original_const_missing :const_missing - - # Use const_missing to autoload associations so we don't have to - # require_association when using single-table inheritance. - def const_missing(class_id) - ActiveSupport::Dependencies.load_missing_constant self, class_id - end - - def unloadable(const_desc = self) - super(const_desc) - end - -end - -class Class - def const_missing(const_name) - if [Object, Kernel].include?(self) || parent == self - super - else - begin - begin - ActiveSupport::Dependencies.load_missing_constant self, const_name - rescue NameError - parent.send :const_missing, const_name - end - rescue NameError => e - # Make sure that the name we are missing is the one that caused the error - parent_qualified_name = ActiveSupport::Dependencies.qualified_name_for parent, const_name - raise unless e.missing_name? parent_qualified_name - qualified_name = ActiveSupport::Dependencies.qualified_name_for self, const_name - raise NameError.new("uninitialized constant #{qualified_name}").copy_blame!(e) - end - end - end -end - -class Object - alias_method :load_without_new_constant_marking, :load - - def load(file, *extras) #:nodoc: - ActiveSupport::Dependencies.new_constants_in(Object) { super } - rescue Exception => exception # errors from loading file - exception.blame_file! file - raise - end - - def require(file, *extras) #:nodoc: - ActiveSupport::Dependencies.new_constants_in(Object) { super } - rescue Exception => exception # errors from required file - exception.blame_file! file - raise - end - - # Mark the given constant as unloadable. Unloadable constants are removed each - # time dependencies are cleared. - # - # Note that marking a constant for unloading need only be done once. Setup - # or init scripts may list each unloadable constant that may need unloading; - # each constant will be removed for every subsequent clear, as opposed to for - # the first clear. - # - # The provided constant descriptor may be a (non-anonymous) module or class, - # or a qualified constant name as a string or symbol. - # - # Returns true if the constant was not previously marked for unloading, false - # otherwise. - def unloadable(const_desc) - ActiveSupport::Dependencies.mark_for_unload const_desc - end -end - -# Add file-blaming to exceptions -class Exception #:nodoc: - def blame_file!(file) - (@blamed_files ||= []).unshift file - end - - def blamed_files - @blamed_files ||= [] - end - - def describe_blame - return nil if blamed_files.empty? - "This error occurred while loading the following files:\n #{blamed_files.join "\n "}" - end - - def copy_blame!(exc) - @blamed_files = exc.blamed_files.clone - self - end -end +ActiveSupport::Dependencies.inject! -- cgit v1.2.3 From 8a87d8a6c2c6dfb423bcaf61c750010d80993b16 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Tue, 22 Jul 2008 10:26:44 -0500 Subject: Improved Memoizable test coverage and added support for multiple arguments --- .../active_support/core_ext/object/metaclass.rb | 5 ++ activesupport/lib/active_support/memoizable.rb | 55 +++++++++++++--------- 2 files changed, 38 insertions(+), 22 deletions(-) (limited to 'activesupport/lib') diff --git a/activesupport/lib/active_support/core_ext/object/metaclass.rb b/activesupport/lib/active_support/core_ext/object/metaclass.rb index 169a76dfb7..93fb0ad594 100644 --- a/activesupport/lib/active_support/core_ext/object/metaclass.rb +++ b/activesupport/lib/active_support/core_ext/object/metaclass.rb @@ -5,4 +5,9 @@ class Object self end end + + # If class_eval is called on an object, add those methods to its metaclass + def class_eval(*args, &block) + metaclass.class_eval(*args, &block) + end end diff --git a/activesupport/lib/active_support/memoizable.rb b/activesupport/lib/active_support/memoizable.rb index f7cd73d39c..21636b8af4 100644 --- a/activesupport/lib/active_support/memoizable.rb +++ b/activesupport/lib/active_support/memoizable.rb @@ -1,32 +1,43 @@ module ActiveSupport - module Memoizable #:nodoc: + module Memoizable + module Freezable + def self.included(base) + base.class_eval do + unless base.method_defined?(:freeze_without_memoizable) + alias_method_chain :freeze, :memoizable + end + end + end + + def freeze_with_memoizable + methods.each do |method| + if m = method.to_s.match(/^_unmemoized_(.*)/) + send(m[1]) + end + end + freeze_without_memoizable + end + end + def memoize(*symbols) symbols.each do |symbol| - original_method = "unmemoized_#{symbol}" - memoized_ivar = "@#{symbol}" + original_method = "_unmemoized_#{symbol}" + memoized_ivar = "@_memoized_#{symbol}" - klass = respond_to?(:class_eval) ? self : self.metaclass - raise "Already memoized #{symbol}" if klass.instance_methods.map(&:to_s).include?(original_method) + class_eval <<-EOS, __FILE__, __LINE__ + include Freezable - klass.class_eval <<-EOS, __FILE__, __LINE__ - unless instance_methods.map(&:to_s).include?("freeze_without_memoizable") - alias_method :freeze_without_memoizable, :freeze - def freeze - methods.each do |method| - if m = method.to_s.match(/^unmemoized_(.*)/) - send(m[1]) - end - end - freeze_without_memoizable - end - end + raise "Already memoized #{symbol}" if method_defined?(:#{original_method}) + alias #{original_method} #{symbol} + + def #{symbol}(*args) + #{memoized_ivar} ||= {} + reload = args.pop if args.last == true || args.last == :reload - alias_method :#{original_method}, :#{symbol} - def #{symbol}(reload = false) - if !reload && defined? #{memoized_ivar} - #{memoized_ivar} + if !reload && #{memoized_ivar} && #{memoized_ivar}.has_key?(args) + #{memoized_ivar}[args] else - #{memoized_ivar} = #{original_method}.freeze + #{memoized_ivar}[args] = #{original_method}(*args).freeze end end EOS -- cgit v1.2.3 From 2681685450631238511cfc3c2f0fa044c1f8033a Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Tue, 22 Jul 2008 11:12:16 -0500 Subject: Extract ActiveSupport::TypedArray class to ensure an array is all of the same type [#673 state:resolved] --- activesupport/lib/active_support.rb | 1 + activesupport/lib/active_support/typed_array.rb | 31 +++++++++++++++++++++++++ 2 files changed, 32 insertions(+) create mode 100644 activesupport/lib/active_support/typed_array.rb (limited to 'activesupport/lib') diff --git a/activesupport/lib/active_support.rb b/activesupport/lib/active_support.rb index 1df911a3f2..51067e910e 100644 --- a/activesupport/lib/active_support.rb +++ b/activesupport/lib/active_support.rb @@ -39,6 +39,7 @@ require 'active_support/cache' require 'active_support/dependencies' require 'active_support/deprecation' +require 'active_support/typed_array' require 'active_support/ordered_hash' require 'active_support/ordered_options' require 'active_support/option_merger' diff --git a/activesupport/lib/active_support/typed_array.rb b/activesupport/lib/active_support/typed_array.rb new file mode 100644 index 0000000000..1a4d8a8faf --- /dev/null +++ b/activesupport/lib/active_support/typed_array.rb @@ -0,0 +1,31 @@ +module ActiveSupport + class TypedArray < Array + def self.type_cast(obj) + obj + end + + def initialize(*args) + super(*args).map! { |obj| self.class.type_cast(obj) } + end + + def <<(obj) + super(self.class.type_cast(obj)) + end + + def concat(array) + super(array.map! { |obj| self.class.type_cast(obj) }) + end + + def insert(index, obj) + super(index, self.class.type_cast(obj)) + end + + def push(*objs) + super(*objs.map { |obj| self.class.type_cast(obj) }) + end + + def unshift(*objs) + super(*objs.map { |obj| self.class.type_cast(obj) }) + end + end +end -- cgit v1.2.3 From 3fd9036fc554979e951422a79f0f77f061112bdc Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Thu, 24 Jul 2008 11:58:26 -0500 Subject: Added config.dependency_loading to enable or disable the dependency loader after initialization --- activesupport/lib/active_support/dependencies.rb | 78 ++++++++++++++++++------ 1 file changed, 59 insertions(+), 19 deletions(-) (limited to 'activesupport/lib') diff --git a/activesupport/lib/active_support/dependencies.rb b/activesupport/lib/active_support/dependencies.rb index e3d4f3d7eb..a3f5f799a2 100644 --- a/activesupport/lib/active_support/dependencies.rb +++ b/activesupport/lib/active_support/dependencies.rb @@ -51,17 +51,28 @@ module ActiveSupport #:nodoc: module ModuleConstMissing #:nodoc: def self.included(base) #:nodoc: base.class_eval do - # Rename the original handler so we can chain it to the new one - alias_method :rails_original_const_missing, :const_missing + unless defined? const_missing_without_dependencies + alias_method_chain :const_missing, :dependencies + end + end + end - # Use const_missing to autoload associations so we don't have to - # require_association when using single-table inheritance. - def const_missing(class_id) - ActiveSupport::Dependencies.load_missing_constant self, class_id + def self.excluded(base) #:nodoc: + base.class_eval do + if defined? const_missing_without_dependencies + undef_method :const_missing + alias_method :const_missing, :const_missing_without_dependencies + undef_method :const_missing_without_dependencies end end end + # Use const_missing to autoload associations so we don't have to + # require_association when using single-table inheritance. + def const_missing_with_dependencies(class_id) + ActiveSupport::Dependencies.load_missing_constant self, class_id + end + def unloadable(const_desc = self) super(const_desc) end @@ -92,8 +103,38 @@ module ActiveSupport #:nodoc: # Object includes this module module Loadable #:nodoc: - def load(file, *extras) #:nodoc: - Dependencies.new_constants_in(Object) { super } + def self.included(base) #:nodoc: + base.class_eval do + unless defined? load_without_new_constant_marking + alias_method_chain :load, :new_constant_marking + end + end + end + + def self.excluded(base) #:nodoc: + base.class_eval do + if defined? load_without_new_constant_marking + undef_method :load + alias_method :load, :load_without_new_constant_marking + undef_method :load_without_new_constant_marking + end + end + end + + def require_or_load(file_name) + Dependencies.require_or_load(file_name) + end + + def require_dependency(file_name) + Dependencies.depend_on(file_name) + end + + def require_association(file_name) + Dependencies.associate_with(file_name) + end + + def load_with_new_constant_marking(file, *extras) #:nodoc: + Dependencies.new_constants_in(Object) { load_without_new_constant_marking(file, *extras) } rescue Exception => exception # errors from loading file exception.blame_file! file raise @@ -145,19 +186,18 @@ module ActiveSupport #:nodoc: end end - def inject! - Object.instance_eval do - define_method(:require_or_load) { |file_name| Dependencies.require_or_load(file_name) } unless Object.respond_to?(:require_or_load) - define_method(:require_dependency) { |file_name| Dependencies.depend_on(file_name) } unless Object.respond_to?(:require_dependency) - define_method(:require_association) { |file_name| Dependencies.associate_with(file_name) } unless Object.respond_to?(:require_association) - - alias_method :load_without_new_constant_marking, :load - include Loadable - end - + def hook! + Object.instance_eval { include Loadable } Module.instance_eval { include ModuleConstMissing } Class.instance_eval { include ClassConstMissing } Exception.instance_eval { include Blamable } + true + end + + def unhook! + ModuleConstMissing.excluded(Module) + Loadable.excluded(Object) + true end def load? @@ -560,4 +600,4 @@ module ActiveSupport #:nodoc: end end -ActiveSupport::Dependencies.inject! +ActiveSupport::Dependencies.hook! -- cgit v1.2.3 From 6e754551254a8cc64e034163f5d0dc155b450388 Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Mon, 28 Jul 2008 12:26:59 +0100 Subject: Merge docrails changes --- .../lib/active_support/core_ext/array/access.rb | 20 +++++++++++--------- .../lib/active_support/core_ext/time/conversions.rb | 1 + 2 files changed, 12 insertions(+), 9 deletions(-) (limited to 'activesupport/lib') diff --git a/activesupport/lib/active_support/core_ext/array/access.rb b/activesupport/lib/active_support/core_ext/array/access.rb index 4ac95efdc7..779ca40aea 100644 --- a/activesupport/lib/active_support/core_ext/array/access.rb +++ b/activesupport/lib/active_support/core_ext/array/access.rb @@ -8,6 +8,7 @@ module ActiveSupport #:nodoc: # %w( a b c d ).from(0) # => %w( a b c d ) # %w( a b c d ).from(2) # => %w( c d ) # %w( a b c d ).from(10) # => nil + # %w().from(0) # => nil def from(position) self[position..-1] end @@ -17,51 +18,52 @@ module ActiveSupport #:nodoc: # %w( a b c d ).to(0) # => %w( a ) # %w( a b c d ).to(2) # => %w( a b c ) # %w( a b c d ).to(10) # => %w( a b c d ) + # %w().to(0) # => %w() def to(position) self[0..position] end - # Equal to self[1] + # Equals to self[1]. def second self[1] end - # Equal to self[2] + # Equals to self[2]. def third self[2] end - # Equal to self[3] + # Equals to self[3]. def fourth self[3] end - # Equal to self[4] + # Equals to self[4]. def fifth self[4] end - # Equal to self[5] + # Equals to self[5]. def sixth self[5] end - # Equal to self[6] + # Equals to self[6]. def seventh self[6] end - # Equal to self[7] + # Equals to self[7]. def eighth self[7] end - # Equal to self[8] + # Equals to self[8]. def ninth self[8] end - # Equal to self[9] + # Equals to self[9]. def tenth self[9] end diff --git a/activesupport/lib/active_support/core_ext/time/conversions.rb b/activesupport/lib/active_support/core_ext/time/conversions.rb index 9054008309..f42be46770 100644 --- a/activesupport/lib/active_support/core_ext/time/conversions.rb +++ b/activesupport/lib/active_support/core_ext/time/conversions.rb @@ -30,6 +30,7 @@ module ActiveSupport #:nodoc: # time.to_s(:time) # => "06:10:17" # # time.to_formatted_s(:db) # => "2007-01-18 06:10:17" + # time.to_formatted_s(:number) # => "20070118061017" # time.to_formatted_s(:short) # => "18 Jan 06:10" # time.to_formatted_s(:long) # => "January 18, 2007 06:10" # time.to_formatted_s(:long_ordinal) # => "January 18th, 2007 06:10" -- cgit v1.2.3 From 50bbc87f85e817a2926c56ccd81d3dc498a05e21 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Sun, 27 Jul 2008 21:44:53 -0700 Subject: MacRuby: BasicObject unavailable --- activesupport/lib/active_support/basic_object.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'activesupport/lib') diff --git a/activesupport/lib/active_support/basic_object.rb b/activesupport/lib/active_support/basic_object.rb index e06da79d26..1f77209e7f 100644 --- a/activesupport/lib/active_support/basic_object.rb +++ b/activesupport/lib/active_support/basic_object.rb @@ -7,7 +7,7 @@ # barebones base class that emulates Builder::BlankSlate while still relying on # Ruby 1.9's BasicObject in Ruby 1.9. module ActiveSupport - if RUBY_VERSION >= '1.9' + if defined? ::BasicObject class BasicObject < ::BasicObject undef_method :== undef_method :equal? -- cgit v1.2.3 From ae6105ef01b2a767afa2bf5b64c90d288c752995 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Sun, 27 Jul 2008 21:45:55 -0700 Subject: Don't rememoize if already frozen --- activesupport/lib/active_support/memoizable.rb | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'activesupport/lib') diff --git a/activesupport/lib/active_support/memoizable.rb b/activesupport/lib/active_support/memoizable.rb index 21636b8af4..23dd96e4df 100644 --- a/activesupport/lib/active_support/memoizable.rb +++ b/activesupport/lib/active_support/memoizable.rb @@ -11,10 +11,9 @@ module ActiveSupport def freeze_with_memoizable methods.each do |method| - if m = method.to_s.match(/^_unmemoized_(.*)/) - send(m[1]) - end - end + __send__($1) if method.to_s =~ /^_unmemoized_(.*)/ + end unless frozen? + freeze_without_memoizable end end -- cgit v1.2.3 From 2cf161a384cc361d856aa76639bcb30570d67286 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Sun, 27 Jul 2008 21:46:12 -0700 Subject: Once is enough, mmk --- activesupport/lib/active_support/testing/performance.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'activesupport/lib') diff --git a/activesupport/lib/active_support/testing/performance.rb b/activesupport/lib/active_support/testing/performance.rb index 71d6f4d9c6..70a7f84023 100644 --- a/activesupport/lib/active_support/testing/performance.rb +++ b/activesupport/lib/active_support/testing/performance.rb @@ -72,13 +72,13 @@ module ActiveSupport protected def run_warmup - 5.times { GC.start } + GC.start time = Metrics::Time.new run_test(time, :benchmark) puts "%s (%s warmup)" % [full_test_name, time.format(time.total)] - 5.times { GC.start } + GC.start end def run_profile(metric) -- cgit v1.2.3 From a24398b64757df8c5939b07238c740bddfdab03e Mon Sep 17 00:00:00 2001 From: Michael Koziarski Date: Tue, 29 Jul 2008 19:49:38 +0200 Subject: Guard the logger's internal buffer to prevent major breakage on genuinely threaded environments --- activesupport/lib/active_support/buffered_logger.rb | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) (limited to 'activesupport/lib') diff --git a/activesupport/lib/active_support/buffered_logger.rb b/activesupport/lib/active_support/buffered_logger.rb index 67b0a580ea..aec416a6d6 100644 --- a/activesupport/lib/active_support/buffered_logger.rb +++ b/activesupport/lib/active_support/buffered_logger.rb @@ -40,6 +40,7 @@ module ActiveSupport @buffer = [] @auto_flushing = 1 @no_block = false + @guard = Mutex.new if log.respond_to?(:write) @log = log @@ -66,7 +67,9 @@ module ActiveSupport # If a newline is necessary then create a new message ending with a newline. # Ensures that the original message is not mutated. message = "#{message}\n" unless message[-1] == ?\n - buffer << message + @guard.synchronize do + buffer << message + end auto_flush message end @@ -98,11 +101,16 @@ module ActiveSupport end def flush - unless buffer.empty? - if @no_block - @log.write_nonblock(buffer.slice!(0..-1).join) - else - @log.write(buffer.slice!(0..-1).join) + @guard.synchronize do + unless buffer.empty? + old_buffer = @buffer + @buffer = [] + text_to_write = old_buffer.join + if @no_block + @log.write_nonblock(text_to_write) + else + @log.write(text_to_write) + end end end end -- cgit v1.2.3 From d9452d3ab3063c5e96dfd80cf6056c49192081b3 Mon Sep 17 00:00:00 2001 From: Michael Koziarski Date: Tue, 29 Jul 2008 20:01:25 +0200 Subject: Remove incomplete non-blocking logger functionality --- activesupport/lib/active_support/buffered_logger.rb | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) (limited to 'activesupport/lib') diff --git a/activesupport/lib/active_support/buffered_logger.rb b/activesupport/lib/active_support/buffered_logger.rb index aec416a6d6..cedc1afe7f 100644 --- a/activesupport/lib/active_support/buffered_logger.rb +++ b/activesupport/lib/active_support/buffered_logger.rb @@ -39,7 +39,6 @@ module ActiveSupport @level = level @buffer = [] @auto_flushing = 1 - @no_block = false @guard = Mutex.new if log.respond_to?(:write) @@ -55,12 +54,6 @@ module ActiveSupport end end - def set_non_blocking_io - if !RUBY_PLATFORM.match(/java|mswin/) && !(@log == STDOUT) && @log.respond_to?(:write_nonblock) - @no_block = true - end - end - def add(severity, message = nil, progname = nil, &block) return if @level > severity message = (message || (block && block.call) || progname).to_s @@ -105,12 +98,7 @@ module ActiveSupport unless buffer.empty? old_buffer = @buffer @buffer = [] - text_to_write = old_buffer.join - if @no_block - @log.write_nonblock(text_to_write) - else - @log.write(text_to_write) - end + @log.write(old_buffer.join) end end end -- cgit v1.2.3 From 2617d0dc5ced4b354bff9633bddafdf80ad5a711 Mon Sep 17 00:00:00 2001 From: miloops Date: Tue, 29 Jul 2008 23:14:56 -0300 Subject: Performance: grouping helpers should use yield instead of block as argument. [#723 state:resolved] --- activesupport/lib/active_support/core_ext/array/grouping.rb | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'activesupport/lib') diff --git a/activesupport/lib/active_support/core_ext/array/grouping.rb b/activesupport/lib/active_support/core_ext/array/grouping.rb index df37afb053..dd1484f8fa 100644 --- a/activesupport/lib/active_support/core_ext/array/grouping.rb +++ b/activesupport/lib/active_support/core_ext/array/grouping.rb @@ -19,7 +19,7 @@ module ActiveSupport #:nodoc: # %w(1 2 3).in_groups_of(2, false) {|g| p g} # ["1", "2"] # ["3"] - def in_groups_of(number, fill_with = nil, &block) + def in_groups_of(number, fill_with = nil) if fill_with == false collection = self else @@ -31,7 +31,7 @@ module ActiveSupport #:nodoc: end if block_given? - collection.each_slice(number, &block) + collection.each_slice(number) { |slice| yield(slice) } else returning [] do |groups| collection.each_slice(number) { |group| groups << group } @@ -87,11 +87,11 @@ module ActiveSupport #:nodoc: # # [1, 2, 3, 4, 5].split(3) # => [[1, 2], [4, 5]] # (1..10).to_a.split { |i| i % 3 == 0 } # => [[1, 2], [4, 5], [7, 8], [10]] - def split(value = nil, &block) - block ||= Proc.new { |e| e == value } + def split(value = nil) + using_block = block_given? inject([[]]) do |results, element| - if block.call(element) + if (using_block && yield(element)) || (value == element) results << [] else results.last << element -- cgit v1.2.3 From 656f0e7c6c9a305abaf9f9b7fb80479b6f94efce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tarmo=20T=C3=A4nav?= Date: Thu, 31 Jul 2008 16:36:23 -0500 Subject: Fix file permissions Signed-off-by: Joshua Peek --- activesupport/lib/active_support/multibyte/generators/generate_tables.rb | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 activesupport/lib/active_support/multibyte/generators/generate_tables.rb (limited to 'activesupport/lib') diff --git a/activesupport/lib/active_support/multibyte/generators/generate_tables.rb b/activesupport/lib/active_support/multibyte/generators/generate_tables.rb old mode 100644 new mode 100755 -- cgit v1.2.3 From 73056500f88d569fa497d846dfe6b501a9e03739 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Wed, 6 Aug 2008 14:39:13 -0500 Subject: Make File.atomic_write copy the original permissions or use the directories default. --- activesupport/lib/active_support/core_ext/file.rb | 24 ++--------- .../lib/active_support/core_ext/file/atomic.rb | 46 ++++++++++++++++++++++ 2 files changed, 50 insertions(+), 20 deletions(-) create mode 100644 activesupport/lib/active_support/core_ext/file/atomic.rb (limited to 'activesupport/lib') diff --git a/activesupport/lib/active_support/core_ext/file.rb b/activesupport/lib/active_support/core_ext/file.rb index 45d93b220f..e03f8ac44e 100644 --- a/activesupport/lib/active_support/core_ext/file.rb +++ b/activesupport/lib/active_support/core_ext/file.rb @@ -1,21 +1,5 @@ -require 'tempfile' +require 'active_support/core_ext/file/atomic' -# Write to a file atomically. Useful for situations where you don't -# want other processes or threads to see half-written files. -# -# File.atomic_write("important.file") do |file| -# file.write("hello") -# end -# -# If your temp directory is not on the same filesystem as the file you're -# trying to write, you can provide a different temporary directory. -# -# File.atomic_write("/data/something.important", "/data/tmp") do |f| -# file.write("hello") -# end -def File.atomic_write(file_name, temp_dir = Dir.tmpdir) - temp_file = Tempfile.new(File.basename(file_name), temp_dir) - yield temp_file - temp_file.close - File.rename(temp_file.path, file_name) -end \ No newline at end of file +class File #:nodoc: + extend ActiveSupport::CoreExtensions::File::Atomic +end diff --git a/activesupport/lib/active_support/core_ext/file/atomic.rb b/activesupport/lib/active_support/core_ext/file/atomic.rb new file mode 100644 index 0000000000..4d3cf5423f --- /dev/null +++ b/activesupport/lib/active_support/core_ext/file/atomic.rb @@ -0,0 +1,46 @@ +require 'tempfile' + +module ActiveSupport #:nodoc: + module CoreExtensions #:nodoc: + module File #:nodoc: + module Atomic + # Write to a file atomically. Useful for situations where you don't + # want other processes or threads to see half-written files. + # + # File.atomic_write("important.file") do |file| + # file.write("hello") + # end + # + # If your temp directory is not on the same filesystem as the file you're + # trying to write, you can provide a different temporary directory. + # + # File.atomic_write("/data/something.important", "/data/tmp") do |f| + # file.write("hello") + # end + def atomic_write(file_name, temp_dir = Dir.tmpdir) + temp_file = Tempfile.new(basename(file_name), temp_dir) + yield temp_file + temp_file.close + + begin + # Get original file permissions + old_stat = stat(file_name) + rescue Errno::ENOENT + # No old permissions, write a temp file to determine the defaults + check_name = ".permissions_check.#{Thread.current.object_id}.#{Process.pid}.#{rand(1000000)}" + new(check_name, "w") + old_stat = stat(check_name) + unlink(check_name) + end + + # Overwrite original file with temp file + rename(temp_file.path, file_name) + + # Set correct permissions on new file + chown(old_stat.uid, old_stat.gid, file_name) + chmod(old_stat.mode, file_name) + end + end + end + end +end -- cgit v1.2.3 From e5b1ab7cc39ff57f9789ffda75fb33f72187775d Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Wed, 6 Aug 2008 14:50:02 -0500 Subject: MemoryStore is the only "unsafe" store. Make it threadsafe by default. --- activesupport/lib/active_support/cache.rb | 18 ------- .../lib/active_support/cache/memory_store.rb | 55 +++++++++++++++++----- 2 files changed, 43 insertions(+), 30 deletions(-) (limited to 'activesupport/lib') diff --git a/activesupport/lib/active_support/cache.rb b/activesupport/lib/active_support/cache.rb index 5a064f8bea..95eae3a77e 100644 --- a/activesupport/lib/active_support/cache.rb +++ b/activesupport/lib/active_support/cache.rb @@ -39,10 +39,6 @@ module ActiveSupport class Store cattr_accessor :logger - def threadsafe! - extend ThreadSafety - end - def silence! @silence = true self @@ -115,20 +111,6 @@ module ActiveSupport logger.debug("Cache #{operation}: #{key}#{options ? " (#{options.inspect})" : ""}") if logger && !@silence && !@logger_off end end - - module ThreadSafety #:nodoc: - def self.extended(object) #:nodoc: - object.instance_variable_set(:@mutex, Mutex.new) - end - - %w(read write delete delete_matched exist? increment decrement).each do |method| - module_eval <<-EOS, __FILE__, __LINE__ - def #{method}(*args) - @mutex.synchronize { super } - end - EOS - end - end end end diff --git a/activesupport/lib/active_support/cache/memory_store.rb b/activesupport/lib/active_support/cache/memory_store.rb index 6f114273e4..9332d50f24 100644 --- a/activesupport/lib/active_support/cache/memory_store.rb +++ b/activesupport/lib/active_support/cache/memory_store.rb @@ -3,36 +3,67 @@ module ActiveSupport class MemoryStore < Store def initialize @data = {} + @mutex = Mutex.new + end + + def fetch(key, options = {}) + @mutex.synchronize do + super + end end def read(name, options = nil) - super - @data[name] + @mutex.synchronize do + super + @data[name] + end end def write(name, value, options = nil) - super - @data[name] = value + @mutex.synchronize do + super + @data[name] = value + end end def delete(name, options = nil) - super - @data.delete(name) + @mutex.synchronize do + super + @data.delete(name) + end end def delete_matched(matcher, options = nil) - super - @data.delete_if { |k,v| k =~ matcher } + @mutex.synchronize do + super + @data.delete_if { |k,v| k =~ matcher } + end end def exist?(name,options = nil) - super - @data.has_key?(name) + @mutex.synchronize do + super + @data.has_key?(name) + end + end + + def increment(key, amount = 1) + @mutex.synchronize do + super + end + end + + def decrement(key, amount = 1) + @mutex.synchronize do + super + end end def clear - @data.clear + @mutex.synchronize do + @data.clear + end end end end -end \ No newline at end of file +end -- cgit v1.2.3 From dfc83566b3f52b4b84db52312c01fcc3b8847059 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Wed, 6 Aug 2008 14:52:39 -0500 Subject: Make FileStore use atomic writes --- activesupport/lib/active_support/cache/file_store.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'activesupport/lib') diff --git a/activesupport/lib/active_support/cache/file_store.rb b/activesupport/lib/active_support/cache/file_store.rb index 5b771b1da0..0bdca49388 100644 --- a/activesupport/lib/active_support/cache/file_store.rb +++ b/activesupport/lib/active_support/cache/file_store.rb @@ -15,7 +15,7 @@ module ActiveSupport def write(name, value, options = nil) super ensure_cache_path(File.dirname(real_file_path(name))) - File.open(real_file_path(name), "wb+") { |f| f.write(value) } + File.atomic_write(real_file_path(name)) { |f| f.write(value) } rescue => e RAILS_DEFAULT_LOGGER.error "Couldn't create cache directory: #{name} (#{e.message})" if RAILS_DEFAULT_LOGGER end -- cgit v1.2.3 From fbc6129acd9ecb6b7435931b472d3226985ba4c4 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Wed, 6 Aug 2008 17:03:42 -0500 Subject: Treat single C operations in MemoryStore as atomic --- .../lib/active_support/cache/memory_store.rb | 31 ++++++---------------- 1 file changed, 8 insertions(+), 23 deletions(-) (limited to 'activesupport/lib') diff --git a/activesupport/lib/active_support/cache/memory_store.rb b/activesupport/lib/active_support/cache/memory_store.rb index 9332d50f24..a44f877414 100644 --- a/activesupport/lib/active_support/cache/memory_store.rb +++ b/activesupport/lib/active_support/cache/memory_store.rb @@ -13,38 +13,25 @@ module ActiveSupport end def read(name, options = nil) - @mutex.synchronize do - super - @data[name] - end + super + @data[name] end def write(name, value, options = nil) - @mutex.synchronize do - super - @data[name] = value - end + super + @data[name] = value end def delete(name, options = nil) - @mutex.synchronize do - super - @data.delete(name) - end + @data.delete(name) end def delete_matched(matcher, options = nil) - @mutex.synchronize do - super - @data.delete_if { |k,v| k =~ matcher } - end + @data.delete_if { |k,v| k =~ matcher } end def exist?(name,options = nil) - @mutex.synchronize do - super - @data.has_key?(name) - end + @data.has_key?(name) end def increment(key, amount = 1) @@ -60,9 +47,7 @@ module ActiveSupport end def clear - @mutex.synchronize do - @data.clear - end + @data.clear end end end -- cgit v1.2.3 From c6b7d0f34472ee7ef03d602c8923fd0ba8dab833 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Wed, 6 Aug 2008 17:22:58 -0500 Subject: Ensure file atomic write uses the cache directory as its tmp folder --- activesupport/lib/active_support/cache/file_store.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'activesupport/lib') diff --git a/activesupport/lib/active_support/cache/file_store.rb b/activesupport/lib/active_support/cache/file_store.rb index 0bdca49388..7b6ca39091 100644 --- a/activesupport/lib/active_support/cache/file_store.rb +++ b/activesupport/lib/active_support/cache/file_store.rb @@ -15,7 +15,7 @@ module ActiveSupport def write(name, value, options = nil) super ensure_cache_path(File.dirname(real_file_path(name))) - File.atomic_write(real_file_path(name)) { |f| f.write(value) } + File.atomic_write(real_file_path(name), cache_path) { |f| f.write(value) } rescue => e RAILS_DEFAULT_LOGGER.error "Couldn't create cache directory: #{name} (#{e.message})" if RAILS_DEFAULT_LOGGER end -- cgit v1.2.3 From ed8a882e47e07b470b71cacd8cd50e251dca4d27 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Wed, 6 Aug 2008 17:31:57 -0700 Subject: JRuby: improve constantize performance. [#410 state:resolved] --- activesupport/lib/active_support/inflector.rb | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'activesupport/lib') diff --git a/activesupport/lib/active_support/inflector.rb b/activesupport/lib/active_support/inflector.rb index 6651569d33..c2738b39fc 100644 --- a/activesupport/lib/active_support/inflector.rb +++ b/activesupport/lib/active_support/inflector.rb @@ -291,11 +291,14 @@ module ActiveSupport # NameError is raised when the name is not in CamelCase or the constant is # unknown. def constantize(camel_cased_word) - unless /\A(?:::)?([A-Z]\w*(?:::[A-Z]\w*)*)\z/ =~ camel_cased_word - raise NameError, "#{camel_cased_word.inspect} is not a valid constant name!" - end + names = camel_cased_word.split('::') + names.shift if names.empty? || names.first.empty? - Object.module_eval("::#{$1}", __FILE__, __LINE__) + constant = Object + names.each do |name| + constant = constant.const_defined?(name) ? constant.const_get(name) : constant.const_missing(name) + end + constant end # Turns a number into an ordinal string used to denote the position in an @@ -326,4 +329,4 @@ require 'active_support/inflections' require 'active_support/core_ext/string/inflections' unless String.included_modules.include?(ActiveSupport::CoreExtensions::String::Inflections) String.send :include, ActiveSupport::CoreExtensions::String::Inflections -end \ No newline at end of file +end -- cgit v1.2.3 From be0d235a3b82e72de49592913753a1f291a98f86 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Wed, 6 Aug 2008 20:21:15 -0500 Subject: Optimize memoized method if there are no arguments --- activesupport/lib/active_support/memoizable.rb | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) (limited to 'activesupport/lib') diff --git a/activesupport/lib/active_support/memoizable.rb b/activesupport/lib/active_support/memoizable.rb index 23dd96e4df..7e2e28712c 100644 --- a/activesupport/lib/active_support/memoizable.rb +++ b/activesupport/lib/active_support/memoizable.rb @@ -29,14 +29,24 @@ module ActiveSupport raise "Already memoized #{symbol}" if method_defined?(:#{original_method}) alias #{original_method} #{symbol} - def #{symbol}(*args) - #{memoized_ivar} ||= {} - reload = args.pop if args.last == true || args.last == :reload + if instance_method(:#{symbol}).arity == 0 + def #{symbol}(reload = false) + if !reload && defined? #{memoized_ivar} + #{memoized_ivar} + else + #{memoized_ivar} = #{original_method}.freeze + end + end + else + def #{symbol}(*args) + #{memoized_ivar} ||= {} + reload = args.pop if args.last == true || args.last == :reload - if !reload && #{memoized_ivar} && #{memoized_ivar}.has_key?(args) - #{memoized_ivar}[args] - else - #{memoized_ivar}[args] = #{original_method}(*args).freeze + if !reload && #{memoized_ivar} && #{memoized_ivar}.has_key?(args) + #{memoized_ivar}[args] + else + #{memoized_ivar}[args] = #{original_method}(*args).freeze + end end end EOS -- cgit v1.2.3 From a8057669ff6ba11e228fc73eef7390b826d0de25 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Thu, 7 Aug 2008 14:55:14 -0500 Subject: Fixed memoize with punctuation and freezing memoized methods with arguments Signed-off-by: Joshua Peek --- activesupport/lib/active_support/memoizable.rb | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) (limited to 'activesupport/lib') diff --git a/activesupport/lib/active_support/memoizable.rb b/activesupport/lib/active_support/memoizable.rb index 7e2e28712c..e6049d9496 100644 --- a/activesupport/lib/active_support/memoizable.rb +++ b/activesupport/lib/active_support/memoizable.rb @@ -10,9 +10,16 @@ module ActiveSupport end def freeze_with_memoizable - methods.each do |method| - __send__($1) if method.to_s =~ /^_unmemoized_(.*)/ - end unless frozen? + unless frozen? + methods.each do |method| + if method.to_s =~ /^_unmemoized_(.*)/ + begin + __send__($1) + rescue ArgumentError + end + end + end + end freeze_without_memoizable end @@ -21,7 +28,7 @@ module ActiveSupport def memoize(*symbols) symbols.each do |symbol| original_method = "_unmemoized_#{symbol}" - memoized_ivar = "@_memoized_#{symbol}" + memoized_ivar = "@_memoized_#{symbol.to_s.sub(/\?\Z/, '_query').sub(/!\Z/, '_bang')}" class_eval <<-EOS, __FILE__, __LINE__ include Freezable -- cgit v1.2.3 From 6c70c02c83b3a03c88df4286130be8882f6d201c Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Thu, 7 Aug 2008 23:31:43 -0700 Subject: Freeze memoized results when instance is frozen instead of immediately so you can memoize mutable objects --- activesupport/lib/active_support/memoizable.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'activesupport/lib') diff --git a/activesupport/lib/active_support/memoizable.rb b/activesupport/lib/active_support/memoizable.rb index e6049d9496..b5adc2330c 100644 --- a/activesupport/lib/active_support/memoizable.rb +++ b/activesupport/lib/active_support/memoizable.rb @@ -14,7 +14,7 @@ module ActiveSupport methods.each do |method| if method.to_s =~ /^_unmemoized_(.*)/ begin - __send__($1) + __send__($1).freeze rescue ArgumentError end end @@ -41,7 +41,7 @@ module ActiveSupport if !reload && defined? #{memoized_ivar} #{memoized_ivar} else - #{memoized_ivar} = #{original_method}.freeze + #{memoized_ivar} = #{original_method} end end else @@ -52,7 +52,7 @@ module ActiveSupport if !reload && #{memoized_ivar} && #{memoized_ivar}.has_key?(args) #{memoized_ivar}[args] else - #{memoized_ivar}[args] = #{original_method}(*args).freeze + #{memoized_ivar}[args] = #{original_method}(*args) end end end -- cgit v1.2.3 From 572f73fae62972cc5aebba24bed45a127f2a4cac Mon Sep 17 00:00:00 2001 From: Sven Fuchs Date: Sun, 10 Aug 2008 21:44:35 +0200 Subject: update i18n gem and clean up dir structure within i18n-0.0.1 --- .../active_support/vendor/i18n-0.0.1/MIT-LICENSE | 20 -- .../vendor/i18n-0.0.1/README.textile | 18 - .../active_support/vendor/i18n-0.0.1/i18n.gemspec | 24 -- .../lib/active_support/vendor/i18n-0.0.1/i18n.rb | 186 ++++++++++ .../vendor/i18n-0.0.1/i18n/backend/simple.rb | 178 ++++++++++ .../vendor/i18n-0.0.1/i18n/exceptions.rb | 53 +++ .../active_support/vendor/i18n-0.0.1/lib/i18n.rb | 182 ---------- .../vendor/i18n-0.0.1/lib/i18n/backend/simple.rb | 154 --------- .../vendor/i18n-0.0.1/lib/i18n/exceptions.rb | 45 --- .../active_support/vendor/i18n-0.0.1/test/all.rb | 4 - .../vendor/i18n-0.0.1/test/i18n_exceptions_test.rb | 100 ------ .../vendor/i18n-0.0.1/test/i18n_test.rb | 141 -------- .../vendor/i18n-0.0.1/test/simple_backend_test.rb | 376 --------------------- 13 files changed, 417 insertions(+), 1064 deletions(-) delete mode 100755 activesupport/lib/active_support/vendor/i18n-0.0.1/MIT-LICENSE delete mode 100644 activesupport/lib/active_support/vendor/i18n-0.0.1/README.textile delete mode 100644 activesupport/lib/active_support/vendor/i18n-0.0.1/i18n.gemspec create mode 100755 activesupport/lib/active_support/vendor/i18n-0.0.1/i18n.rb create mode 100644 activesupport/lib/active_support/vendor/i18n-0.0.1/i18n/backend/simple.rb create mode 100644 activesupport/lib/active_support/vendor/i18n-0.0.1/i18n/exceptions.rb delete mode 100755 activesupport/lib/active_support/vendor/i18n-0.0.1/lib/i18n.rb delete mode 100644 activesupport/lib/active_support/vendor/i18n-0.0.1/lib/i18n/backend/simple.rb delete mode 100644 activesupport/lib/active_support/vendor/i18n-0.0.1/lib/i18n/exceptions.rb delete mode 100644 activesupport/lib/active_support/vendor/i18n-0.0.1/test/all.rb delete mode 100644 activesupport/lib/active_support/vendor/i18n-0.0.1/test/i18n_exceptions_test.rb delete mode 100644 activesupport/lib/active_support/vendor/i18n-0.0.1/test/i18n_test.rb delete mode 100644 activesupport/lib/active_support/vendor/i18n-0.0.1/test/simple_backend_test.rb (limited to 'activesupport/lib') diff --git a/activesupport/lib/active_support/vendor/i18n-0.0.1/MIT-LICENSE b/activesupport/lib/active_support/vendor/i18n-0.0.1/MIT-LICENSE deleted file mode 100755 index ed8e9ee66d..0000000000 --- a/activesupport/lib/active_support/vendor/i18n-0.0.1/MIT-LICENSE +++ /dev/null @@ -1,20 +0,0 @@ -Copyright (c) 2008 The Ruby I18n team - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/activesupport/lib/active_support/vendor/i18n-0.0.1/README.textile b/activesupport/lib/active_support/vendor/i18n-0.0.1/README.textile deleted file mode 100644 index 2b14a99c0f..0000000000 --- a/activesupport/lib/active_support/vendor/i18n-0.0.1/README.textile +++ /dev/null @@ -1,18 +0,0 @@ -h1. Ruby I18n gem - -I18n and localization solution for Ruby. - -h2. Authors - -* "Matt Aimonetti":http://railsontherun.com -* "Sven Fuchs":http://www.artweb-design.de -* "Joshua Harvey":http://www.workingwithrails.com/person/759-joshua-harvey -* "Saimon Moore":http://saimonmoore.net -* "Stephan Soller":http://www.arkanis-development.de - -h2. License - -MIT License. See the included MIT-LICENCE file. - - - diff --git a/activesupport/lib/active_support/vendor/i18n-0.0.1/i18n.gemspec b/activesupport/lib/active_support/vendor/i18n-0.0.1/i18n.gemspec deleted file mode 100644 index 81ad0b598d..0000000000 --- a/activesupport/lib/active_support/vendor/i18n-0.0.1/i18n.gemspec +++ /dev/null @@ -1,24 +0,0 @@ -Gem::Specification.new do |s| - s.name = "i18n" - s.version = "0.0.1" - s.date = "2008-06-13" - s.summary = "Internationalization for Ruby" - s.email = "rails-patch-i18n@googlegroups.com" - s.homepage = "http://groups.google.com/group/rails-patch-i18n" - s.description = "Add Internationalization to your Ruby application." - s.has_rdoc = false - s.authors = ['Sven Fuchs', 'Matt Aimonetti', 'Stephan Soller', 'Saimon Moore'] - s.files = [ - "lib/i18n/backend/minimal.rb", - "lib/i18n/core_ext.rb", - "lib/i18n/localization.rb", - "lib/i18n/translation.rb", - "lib/i18n.rb", - "LICENSE", - "README", - "spec/core_ext_spec.rb", - "spec/i18n_spec.rb", - "spec/spec.opts", - "spec/spec_helper.rb" - ] -end \ No newline at end of file diff --git a/activesupport/lib/active_support/vendor/i18n-0.0.1/i18n.rb b/activesupport/lib/active_support/vendor/i18n-0.0.1/i18n.rb new file mode 100755 index 0000000000..86005553c0 --- /dev/null +++ b/activesupport/lib/active_support/vendor/i18n-0.0.1/i18n.rb @@ -0,0 +1,186 @@ +# Authors:: Matt Aimonetti (http://railsontherun.com/), +# Sven Fuchs (http://www.artweb-design.de), +# Joshua Harvey (http://www.workingwithrails.com/person/759-joshua-harvey), +# Saimon Moore (http://saimonmoore.net), +# Stephan Soller (http://www.arkanis-development.de/) +# Copyright:: Copyright (c) 2008 The Ruby i18n Team +# License:: MIT +require 'i18n/backend/simple' +require 'i18n/exceptions' + +module I18n + @@backend = Backend::Simple + @@default_locale = 'en-US' + @@exception_handler = :default_exception_handler + + class << self + # Returns the current backend. Defaults to +Backend::Simple+. + def backend + @@backend + end + + # Sets the current backend. Used to set a custom backend. + def backend=(backend) + @@backend = backend + end + + # Returns the current default locale. Defaults to 'en-US' + def default_locale + @@default_locale + end + + # Sets the current default locale. Used to set a custom default locale. + def default_locale=(locale) + @@default_locale = locale + end + + # Returns the current locale. Defaults to I18n.default_locale. + def locale + Thread.current[:locale] ||= default_locale + end + + # Sets the current locale pseudo-globally, i.e. in the Thread.current hash. + def locale=(locale) + Thread.current[:locale] = locale + end + + # Sets the exception handler. + def exception_handler=(exception_handler) + @@exception_handler = exception_handler + end + + # Allow client libraries to pass a block that populates the translation + # storage. Decoupled for backends like a db backend that persist their + # translations, so the backend can decide whether/when to yield or not. + def populate(&block) + backend.populate(&block) + end + + def load_translations(filename) + backend.load_translations filename + end + + # Stores translations for the given locale in the backend. + def store_translations(locale, data) + backend.store_translations locale, data + end + + # Translates, pluralizes and interpolates a given key using a given locale, + # scope, and default, as well as interpolation values. + # + # *LOOKUP* + # + # Translation data is organized as a nested hash using the upper-level keys + # as namespaces. E.g., ActionView ships with the translation: + # :date => {:formats => {:short => "%b %d"}}. + # + # Translations can be looked up at any level of this hash using the key argument + # and the scope option. E.g., in this example I18n.t :date + # returns the whole translations hash {:formats => {:short => "%b %d"}}. + # + # Key can be either a single key or a dot-separated key (both Strings and Symbols + # work). E.g., the short format can be looked up using both: + # I18n.t 'date.formats.short' + # I18n.t :'date.formats.short' + # + # Scope can be either a single key, a dot-separated key or an array of keys + # or dot-separated keys. Keys and scopes can be combined freely. So these + # examples will all look up the same short date format: + # I18n.t 'date.formats.short' + # I18n.t 'formats.short', :scope => 'date' + # I18n.t 'short', :scope => 'date.formats' + # I18n.t 'short', :scope => %w(date formats) + # + # *INTERPOLATION* + # + # Translations can contain interpolation variables which will be replaced by + # values passed to #translate as part of the options hash, with the keys matching + # the interpolation variable names. + # + # E.g., with a translation :foo => "foo {{bar}}" the option + # value for the key +bar+ will be interpolated into the translation: + # I18n.t :foo, :bar => 'baz' # => 'foo baz' + # + # *PLURALIZATION* + # + # Translation data can contain pluralized translations. Pluralized translations + # are arrays of singluar/plural versions of translations like ['Foo', 'Foos']. + # + # Note that I18n::Backend::Simple only supports an algorithm for English + # pluralization rules. Other algorithms can be supported by custom backends. + # + # This returns the singular version of a pluralized translation: + # I18n.t :foo, :count => 1 # => 'Foo' + # + # These both return the plural version of a pluralized translation: + # I18n.t :foo, :count => 0 # => 'Foos' + # I18n.t :foo, :count => 2 # => 'Foos' + # + # The :count option can be used both for pluralization and interpolation. + # E.g., with the translation + # :foo => ['{{count}} foo', '{{count}} foos'], count will + # be interpolated to the pluralized translation: + # I18n.t :foo, :count => 1 # => '1 foo' + # + # *DEFAULTS* + # + # This returns the translation for :foo or default if no translation was found: + # I18n.t :foo, :default => 'default' + # + # This returns the translation for :foo or the translation for :bar if no + # translation for :foo was found: + # I18n.t :foo, :default => :bar + # + # Returns the translation for :foo or the translation for :bar + # or default if no translations for :foo and :bar were found. + # I18n.t :foo, :default => [:bar, 'default'] + # + # BULK LOOKUP + # + # This returns an array with the translations for :foo and :bar. + # I18n.t [:foo, :bar] + # + # Can be used with dot-separated nested keys: + # I18n.t [:'baz.foo', :'baz.bar'] + # + # Which is the same as using a scope option: + # I18n.t [:foo, :bar], :scope => :baz + def translate(key, options = {}) + locale = options.delete(:locale) || I18n.locale + backend.translate locale, key, options + rescue I18n::ArgumentError => e + raise e if options[:raise] + send @@exception_handler, e, locale, key, options + end + alias :t :translate + + # Localizes certain objects, such as dates and numbers to local formatting. + def localize(object, options = {}) + locale = options[:locale] || I18n.locale + format = options[:format] || :default + backend.localize(locale, object, format) + end + alias :l :localize + + protected + # Handles exceptions raised in the backend. All exceptions except for + # MissingTranslationData exceptions are re-raised. When a MissingTranslationData + # was caught and the option :raise is not set the handler returns an error + # message string containing the key/scope. + def default_exception_handler(exception, locale, key, options) + return exception.message if MissingTranslationData === exception + raise exception + end + + # Merges the given locale, key and scope into a single array of keys. + # Splits keys that contain dots into multiple keys. Makes sure all + # keys are Symbols. + def normalize_translation_keys(locale, key, scope) + keys = [locale] + Array(scope) + [key] + keys = keys.map{|key| key.to_s.split(/\./) } + keys.flatten.map{|key| key.to_sym} + end + end +end + + diff --git a/activesupport/lib/active_support/vendor/i18n-0.0.1/i18n/backend/simple.rb b/activesupport/lib/active_support/vendor/i18n-0.0.1/i18n/backend/simple.rb new file mode 100644 index 0000000000..98c7964b21 --- /dev/null +++ b/activesupport/lib/active_support/vendor/i18n-0.0.1/i18n/backend/simple.rb @@ -0,0 +1,178 @@ +require 'strscan' + +module I18n + module Backend + module Simple + @@translations = {} + + class << self + # Allow client libraries to pass a block that populates the translation + # storage. Decoupled for backends like a db backend that persist their + # translations, so the backend can decide whether/when to yield or not. + def populate(&block) + yield + end + + def load_translations(*filenames) + filenames.each {|filename| load_file filename } + end + + # Stores translations for the given locale in memory. + # This uses a deep merge for the translations hash, so existing + # translations will be overwritten by new ones only at the deepest + # level of the hash. + def store_translations(locale, data) + merge_translations(locale, data) + end + + def translate(locale, key, options = {}) + raise InvalidLocale.new(locale) if locale.nil? + return key.map{|key| translate locale, key, options } if key.is_a? Array + + reserved = :scope, :default + count, scope, default = options.values_at(:count, *reserved) + options.delete(:default) + values = options.reject{|name, value| reserved.include? name } + + entry = lookup(locale, key, scope) || default(locale, default, options) || raise(I18n::MissingTranslationData.new(locale, key, options)) + entry = pluralize locale, entry, count + entry = interpolate locale, entry, values + entry + end + + # Acts the same as +strftime+, but returns a localized version of the + # formatted date string. Takes a key from the date/time formats + # translations as a format argument (e.g., :short in :'date.formats'). + def localize(locale, object, format = :default) + raise ArgumentError, "Object must be a Date, DateTime or Time object. #{object.inspect} given." unless object.respond_to?(:strftime) + + type = object.respond_to?(:sec) ? 'time' : 'date' + formats = translate(locale, :"#{type}.formats") + format = formats[format.to_sym] if formats && formats[format.to_sym] + # TODO raise exception unless format found? + format = format.to_s.dup + + format.gsub!(/%a/, translate(locale, :"date.abbr_day_names")[object.wday]) + format.gsub!(/%A/, translate(locale, :"date.day_names")[object.wday]) + format.gsub!(/%b/, translate(locale, :"date.abbr_month_names")[object.mon]) + format.gsub!(/%B/, translate(locale, :"date.month_names")[object.mon]) + format.gsub!(/%p/, translate(locale, :"time.#{object.hour < 12 ? :am : :pm}")) if object.respond_to? :hour + object.strftime(format) + end + + protected + + # Looks up a translation from the translations hash. Returns nil if + # eiher key is nil, or locale, scope or key do not exist as a key in the + # nested translations hash. Splits keys or scopes containing dots + # into multiple keys, i.e. currency.format is regarded the same as + # %w(currency format). + def lookup(locale, key, scope = []) + return unless key + keys = I18n.send :normalize_translation_keys, locale, key, scope + keys.inject(@@translations){|result, key| result[key.to_sym] or return nil } + end + + # Evaluates a default translation. + # If the given default is a String it is used literally. If it is a Symbol + # it will be translated with the given options. If it is an Array the first + # translation yielded will be returned. + # + # I.e., default(locale, [:foo, 'default']) will return +default+ if + # translate(locale, :foo) does not yield a result. + def default(locale, default, options = {}) + case default + when String then default + when Symbol then translate locale, default, options + when Array then default.each do |obj| + result = default(locale, obj, options.dup) and return result + end + end + rescue MissingTranslationData + nil + end + + # Picks a translation from an array according to English pluralization + # rules. It will pick the first translation if count is not equal to 1 + # and the second translation if it is equal to 1. Other backends can + # implement more flexible or complex pluralization rules. + def pluralize(locale, entry, count) + return entry unless entry.is_a?(Hash) and count + # raise InvalidPluralizationData.new(entry, count) unless entry.is_a?(Hash) + key = :zero if count == 0 && entry.has_key?(:zero) + key ||= count == 1 ? :one : :many + raise InvalidPluralizationData.new(entry, count) unless entry.has_key?(key) + entry[key] + end + + # Interpolates values into a given string. + # + # interpolate "file {{file}} opened by \\{{user}}", :file => 'test.txt', :user => 'Mr. X' + # # => "file test.txt opened by {{user}}" + # + # Note that you have to double escape the \\ when you want to escape + # the {{...}} key in a string (once for the string and once for the + # interpolation). + def interpolate(locale, string, values = {}) + return string if !string.is_a?(String) + + map = {'%d' => '{{count}}', '%s' => '{{value}}'} # TODO deprecate this? + string.gsub!(/#{map.keys.join('|')}/){|key| map[key]} + + s = StringScanner.new string.dup + while s.skip_until(/\{\{/) + s.string[s.pos - 3, 1] = '' and next if s.pre_match[-1, 1] == '\\' + start_pos = s.pos - 2 + key = s.scan_until(/\}\}/)[0..-3] + end_pos = s.pos - 1 + + raise ReservedInterpolationKey.new(key, string) if %w(scope default).include?(key) + raise MissingInterpolationArgument.new(key, string) unless values.has_key? key.to_sym + + s.string[start_pos..end_pos] = values[key.to_sym].to_s + s.unscan + end + s.string + end + + def load_file(filename) + type = File.extname(filename).tr('.', '').downcase + raise UnknownFileType.new(type, filename) unless respond_to? :"load_#{type}" + data = send :"load_#{type}", filename # TODO raise a meaningful exception if this does not yield a Hash + data.each do |locale, data| + merge_translations locale, data + end + end + + def load_rb(filename) + eval IO.read(filename), binding, filename + end + + def load_yml(filename) + YAML::load IO.read(filename) + end + + # Deep merges the given translations hash with the existing translations + # for the given locale + def merge_translations(locale, data) + locale = locale.to_sym + @@translations[locale] ||= {} + data = deep_symbolize_keys data + + # deep_merge by Stefan Rusterholz, see http://www.ruby-forum.com/topic/142809 + merger = proc{|key, v1, v2| Hash === v1 && Hash === v2 ? v1.merge(v2, &merger) : v2 } + @@translations[locale].merge! data, &merger + end + + # Return a new hash with all keys and nested keys converted to symbols. + def deep_symbolize_keys(hash) + hash.inject({}){|result, (key, value)| + value = deep_symbolize_keys(value) if value.is_a? Hash + result[(key.to_sym rescue key) || key] = value + result + } + end + end + end + end +end diff --git a/activesupport/lib/active_support/vendor/i18n-0.0.1/i18n/exceptions.rb b/activesupport/lib/active_support/vendor/i18n-0.0.1/i18n/exceptions.rb new file mode 100644 index 0000000000..0f3eff1071 --- /dev/null +++ b/activesupport/lib/active_support/vendor/i18n-0.0.1/i18n/exceptions.rb @@ -0,0 +1,53 @@ +module I18n + class ArgumentError < ::ArgumentError; end + + class InvalidLocale < ArgumentError + attr_reader :locale + def initialize(locale) + @locale = locale + super "#{locale.inspect} is not a valid locale" + end + end + + class MissingTranslationData < ArgumentError + attr_reader :locale, :key, :options + def initialize(locale, key, options) + @key, @locale, @options = key, locale, options + keys = I18n.send(:normalize_translation_keys, locale, key, options[:scope]) + keys << 'no key' if keys.size < 2 + super "translation missing: #{keys.join(', ')}" + end + end + + class InvalidPluralizationData < ArgumentError + attr_reader :entry, :count + def initialize(entry, count) + @entry, @count = entry, count + super "translation data #{entry.inspect} can not be used with :count => #{count}" + end + end + + class MissingInterpolationArgument < ArgumentError + attr_reader :key, :string + def initialize(key, string) + @key, @string = key, string + super "interpolation argument #{key} missing in #{string.inspect}" + end + end + + class ReservedInterpolationKey < ArgumentError + attr_reader :key, :string + def initialize(key, string) + @key, @string = key, string + super "reserved key #{key.inspect} used in #{string.inspect}" + end + end + + class UnknownFileType < ArgumentError + attr_reader :type, :filename + def initialize(type, filename) + @type, @filename = type, filename + super "can not load translations from #{filename}, the file type #{type} is not known" + end + end +end \ No newline at end of file diff --git a/activesupport/lib/active_support/vendor/i18n-0.0.1/lib/i18n.rb b/activesupport/lib/active_support/vendor/i18n-0.0.1/lib/i18n.rb deleted file mode 100755 index 1bb65263a3..0000000000 --- a/activesupport/lib/active_support/vendor/i18n-0.0.1/lib/i18n.rb +++ /dev/null @@ -1,182 +0,0 @@ -# Authors:: Matt Aimonetti (http://railsontherun.com/), -# Sven Fuchs (http://www.artweb-design.de), -# Joshua Harvey (http://www.workingwithrails.com/person/759-joshua-harvey), -# Saimon Moore (http://saimonmoore.net), -# Stephan Soller (http://www.arkanis-development.de/) -# Copyright:: Copyright (c) 2008 The Ruby i18n Team -# License:: MIT -require 'i18n/backend/simple' -require 'i18n/exceptions' - -module I18n - @@backend = Backend::Simple - @@default_locale = 'en-US' - @@exception_handler = :default_exception_handler - - class << self - # Returns the current backend. Defaults to +Backend::Simple+. - def backend - @@backend - end - - # Sets the current backend. Used to set a custom backend. - def backend=(backend) - @@backend = backend - end - - # Returns the current default locale. Defaults to 'en-US' - def default_locale - @@default_locale - end - - # Sets the current default locale. Used to set a custom default locale. - def default_locale=(locale) - @@default_locale = locale - end - - # Returns the current locale. Defaults to I18n.default_locale. - def locale - Thread.current[:locale] ||= default_locale - end - - # Sets the current locale pseudo-globally, i.e. in the Thread.current hash. - def locale=(locale) - Thread.current[:locale] = locale - end - - # Sets the exception handler. - def exception_handler=(exception_handler) - @@exception_handler = exception_handler - end - - # Allow client libraries to pass a block that populates the translation - # storage. Decoupled for backends like a db backend that persist their - # translations, so the backend can decide whether/when to yield or not. - def populate(&block) - backend.populate(&block) - end - - # Stores translations for the given locale in the backend. - def store_translations(locale, data) - backend.store_translations locale, data - end - - # Translates, pluralizes and interpolates a given key using a given locale, - # scope, and default, as well as interpolation values. - # - # *LOOKUP* - # - # Translation data is organized as a nested hash using the upper-level keys - # as namespaces. E.g., ActionView ships with the translation: - # :date => {:formats => {:short => "%b %d"}}. - # - # Translations can be looked up at any level of this hash using the key argument - # and the scope option. E.g., in this example I18n.t :date - # returns the whole translations hash {:formats => {:short => "%b %d"}}. - # - # Key can be either a single key or a dot-separated key (both Strings and Symbols - # work). E.g., the short format can be looked up using both: - # I18n.t 'date.formats.short' - # I18n.t :'date.formats.short' - # - # Scope can be either a single key, a dot-separated key or an array of keys - # or dot-separated keys. Keys and scopes can be combined freely. So these - # examples will all look up the same short date format: - # I18n.t 'date.formats.short' - # I18n.t 'formats.short', :scope => 'date' - # I18n.t 'short', :scope => 'date.formats' - # I18n.t 'short', :scope => %w(date formats) - # - # *INTERPOLATION* - # - # Translations can contain interpolation variables which will be replaced by - # values passed to #translate as part of the options hash, with the keys matching - # the interpolation variable names. - # - # E.g., with a translation :foo => "foo {{bar}}" the option - # value for the key +bar+ will be interpolated into the translation: - # I18n.t :foo, :bar => 'baz' # => 'foo baz' - # - # *PLURALIZATION* - # - # Translation data can contain pluralized translations. Pluralized translations - # are arrays of singluar/plural versions of translations like ['Foo', 'Foos']. - # - # Note that I18n::Backend::Simple only supports an algorithm for English - # pluralization rules. Other algorithms can be supported by custom backends. - # - # This returns the singular version of a pluralized translation: - # I18n.t :foo, :count => 1 # => 'Foo' - # - # These both return the plural version of a pluralized translation: - # I18n.t :foo, :count => 0 # => 'Foos' - # I18n.t :foo, :count => 2 # => 'Foos' - # - # The :count option can be used both for pluralization and interpolation. - # E.g., with the translation - # :foo => ['{{count}} foo', '{{count}} foos'], count will - # be interpolated to the pluralized translation: - # I18n.t :foo, :count => 1 # => '1 foo' - # - # *DEFAULTS* - # - # This returns the translation for :foo or default if no translation was found: - # I18n.t :foo, :default => 'default' - # - # This returns the translation for :foo or the translation for :bar if no - # translation for :foo was found: - # I18n.t :foo, :default => :bar - # - # Returns the translation for :foo or the translation for :bar - # or default if no translations for :foo and :bar were found. - # I18n.t :foo, :default => [:bar, 'default'] - # - # BULK LOOKUP - # - # This returns an array with the translations for :foo and :bar. - # I18n.t [:foo, :bar] - # - # Can be used with dot-separated nested keys: - # I18n.t [:'baz.foo', :'baz.bar'] - # - # Which is the same as using a scope option: - # I18n.t [:foo, :bar], :scope => :baz - def translate(key, options = {}) - locale = options.delete(:locale) || I18n.locale - backend.translate locale, key, options - rescue I18n::ArgumentError => e - raise e if options[:raise] - send @@exception_handler, e, locale, key, options - end - alias :t :translate - - # Localizes certain objects, such as dates and numbers to local formatting. - def localize(object, options = {}) - locale = options[:locale] || I18n.locale - format = options[:format] || :default - backend.localize(locale, object, format) - end - alias :l :localize - - protected - # Handles exceptions raised in the backend. All exceptions except for - # MissingTranslationData exceptions are re-raised. When a MissingTranslationData - # was caught and the option :raise is not set the handler returns an error - # message string containing the key/scope. - def default_exception_handler(exception, locale, key, options) - return exception.message if MissingTranslationData === exception - raise exception - end - - # Merges the given locale, key and scope into a single array of keys. - # Splits keys that contain dots into multiple keys. Makes sure all - # keys are Symbols. - def normalize_translation_keys(locale, key, scope) - keys = [locale] + Array(scope) + [key] - keys = keys.map{|k| k.to_s.split(/\./) } - keys.flatten.map{|k| k.to_sym} - end - end -end - - diff --git a/activesupport/lib/active_support/vendor/i18n-0.0.1/lib/i18n/backend/simple.rb b/activesupport/lib/active_support/vendor/i18n-0.0.1/lib/i18n/backend/simple.rb deleted file mode 100644 index b8be1cecfb..0000000000 --- a/activesupport/lib/active_support/vendor/i18n-0.0.1/lib/i18n/backend/simple.rb +++ /dev/null @@ -1,154 +0,0 @@ -require 'strscan' - -module I18n - module Backend - module Simple - @@translations = {} - - class << self - # Allow client libraries to pass a block that populates the translation - # storage. Decoupled for backends like a db backend that persist their - # translations, so the backend can decide whether/when to yield or not. - def populate(&block) - yield - end - - # Stores translations for the given locale in memory. - # This uses a deep merge for the translations hash, so existing - # translations will be overwritten by new ones only at the deepest - # level of the hash. - def store_translations(locale, data) - merge_translations(locale, data) - end - - def translate(locale, key, options = {}) - raise InvalidLocale.new(locale) if locale.nil? - return key.map{|k| translate locale, k, options } if key.is_a? Array - - reserved = :scope, :default - count, scope, default = options.values_at(:count, *reserved) - options.delete(:default) - values = options.reject{|name, value| reserved.include? name } - - entry = lookup(locale, key, scope) || default(locale, default, options) || raise(I18n::MissingTranslationData.new(locale, key, options)) - entry = pluralize entry, count - entry = interpolate entry, values - entry - end - - # Acts the same as +strftime+, but returns a localized version of the - # formatted date string. Takes a key from the date/time formats - # translations as a format argument (e.g., :short in :'date.formats'). - def localize(locale, object, format = :default) - raise ArgumentError, "Object must be a Date, DateTime or Time object. #{object.inspect} given." unless object.respond_to?(:strftime) - - type = object.respond_to?(:sec) ? 'time' : 'date' - formats = translate(locale, :"#{type}.formats") - format = formats[format.to_sym] if formats && formats[format.to_sym] - # TODO raise exception unless format found? - format = format.to_s.dup - - format.gsub!(/%a/, translate(locale, :"date.abbr_day_names")[object.wday]) - format.gsub!(/%A/, translate(locale, :"date.day_names")[object.wday]) - format.gsub!(/%b/, translate(locale, :"date.abbr_month_names")[object.mon]) - format.gsub!(/%B/, translate(locale, :"date.month_names")[object.mon]) - format.gsub!(/%p/, translate(locale, :"time.#{object.hour < 12 ? :am : :pm}")) if object.respond_to? :hour - object.strftime(format) - end - - protected - - # Looks up a translation from the translations hash. Returns nil if - # eiher key is nil, or locale, scope or key do not exist as a key in the - # nested translations hash. Splits keys or scopes containing dots - # into multiple keys, i.e. currency.format is regarded the same as - # %w(currency format). - def lookup(locale, key, scope = []) - return unless key - keys = I18n.send :normalize_translation_keys, locale, key, scope - keys.inject(@@translations){|result, k| result[k.to_sym] or return nil } - end - - # Evaluates a default translation. - # If the given default is a String it is used literally. If it is a Symbol - # it will be translated with the given options. If it is an Array the first - # translation yielded will be returned. - # - # I.e., default(locale, [:foo, 'default']) will return +default+ if - # translate(locale, :foo) does not yield a result. - def default(locale, default, options = {}) - case default - when String then default - when Symbol then translate locale, default, options - when Array then default.each do |obj| - result = default(locale, obj, options.dup) and return result - end - end - rescue MissingTranslationData - nil - end - - # Picks a translation from an array according to English pluralization - # rules. It will pick the first translation if count is not equal to 1 - # and the second translation if it is equal to 1. Other backends can - # implement more flexible or complex pluralization rules. - def pluralize(entry, count) - return entry unless entry.is_a?(Array) and count - raise InvalidPluralizationData.new(entry, count) unless entry.size == 2 - entry[count == 1 ? 0 : 1] - end - - # Interpolates values into a given string. - # - # interpolate "file {{file}} opened by \\{{user}}", :file => 'test.txt', :user => 'Mr. X' - # # => "file test.txt opened by {{user}}" - # - # Note that you have to double escape the \\ when you want to escape - # the {{...}} key in a string (once for the string and once for the - # interpolation). - def interpolate(string, values = {}) - return string if !string.is_a?(String) - - map = {'%d' => '{{count}}', '%s' => '{{value}}'} # TODO deprecate this? - string.gsub!(/#{map.keys.join('|')}/){|key| map[key]} - - s = StringScanner.new string.dup - while s.skip_until(/\{\{/) - s.string[s.pos - 3, 1] = '' and next if s.pre_match[-1, 1] == '\\' - start_pos = s.pos - 2 - key = s.scan_until(/\}\}/)[0..-3] - end_pos = s.pos - 1 - - raise ReservedInterpolationKey.new(key, string) if %w(scope default).include?(key) - raise MissingInterpolationArgument.new(key, string) unless values.has_key? key.to_sym - - s.string[start_pos..end_pos] = values[key.to_sym].to_s - s.unscan - end - s.string - end - - # Deep merges the given translations hash with the existing translations - # for the given locale - def merge_translations(locale, data) - locale = locale.to_sym - @@translations[locale] ||= {} - data = deep_symbolize_keys data - - # deep_merge by Stefan Rusterholz, see http://www.ruby-forum.com/topic/142809 - merger = proc{|key, v1, v2| Hash === v1 && Hash === v2 ? v1.merge(v2, &merger) : v2 } - @@translations[locale].merge! data, &merger - end - - # Return a new hash with all keys and nested keys converted to symbols. - def deep_symbolize_keys(hash) - hash.inject({}){|result, (key, value)| - value = deep_symbolize_keys(value) if value.is_a? Hash - result[(key.to_sym rescue key) || key] = value - result - } - end - end - end - end -end diff --git a/activesupport/lib/active_support/vendor/i18n-0.0.1/lib/i18n/exceptions.rb b/activesupport/lib/active_support/vendor/i18n-0.0.1/lib/i18n/exceptions.rb deleted file mode 100644 index 6c1fc6d9b6..0000000000 --- a/activesupport/lib/active_support/vendor/i18n-0.0.1/lib/i18n/exceptions.rb +++ /dev/null @@ -1,45 +0,0 @@ -module I18n - class ArgumentError < ::ArgumentError; end - - class InvalidLocale < ArgumentError - attr_reader :locale - def initialize(locale) - @locale = locale - super "#{locale.inspect} is not a valid locale" - end - end - - class MissingTranslationData < ArgumentError - attr_reader :locale, :key, :options - def initialize(locale, key, options) - @key, @locale, @options = key, locale, options - keys = I18n.send(:normalize_translation_keys, locale, key, options[:scope]) - keys << 'no key' if keys.size < 2 - super "translation missing: #{keys.join(', ')}" - end - end - - class InvalidPluralizationData < ArgumentError - attr_reader :entry, :count - def initialize(entry, count) - @entry, @count = entry, count - super "translation data #{entry.inspect} can not be used with :count => #{count}" - end - end - - class MissingInterpolationArgument < ArgumentError - attr_reader :key, :string - def initialize(key, string) - @key, @string = key, string - super "interpolation argument #{key} missing in #{string.inspect}" - end - end - - class ReservedInterpolationKey < ArgumentError - attr_reader :key, :string - def initialize(key, string) - @key, @string = key, string - super "reserved key #{key.inspect} used in #{string.inspect}" - end - end -end \ No newline at end of file diff --git a/activesupport/lib/active_support/vendor/i18n-0.0.1/test/all.rb b/activesupport/lib/active_support/vendor/i18n-0.0.1/test/all.rb deleted file mode 100644 index 048b62f8c3..0000000000 --- a/activesupport/lib/active_support/vendor/i18n-0.0.1/test/all.rb +++ /dev/null @@ -1,4 +0,0 @@ -dir = File.dirname(__FILE__) -require dir + '/i18n_test.rb' -require dir + '/simple_backend_test.rb' -require dir + '/i18n_exceptions_test.rb' diff --git a/activesupport/lib/active_support/vendor/i18n-0.0.1/test/i18n_exceptions_test.rb b/activesupport/lib/active_support/vendor/i18n-0.0.1/test/i18n_exceptions_test.rb deleted file mode 100644 index 1ea1601681..0000000000 --- a/activesupport/lib/active_support/vendor/i18n-0.0.1/test/i18n_exceptions_test.rb +++ /dev/null @@ -1,100 +0,0 @@ -$:.unshift "lib" - -require 'rubygems' -require 'test/unit' -require 'mocha' -require 'i18n' -require 'active_support' - -class I18nExceptionsTest < Test::Unit::TestCase - def test_invalid_locale_stores_locale - force_invalid_locale - rescue I18n::ArgumentError => e - assert_nil e.locale - end - - def test_invalid_locale_message - force_invalid_locale - rescue I18n::ArgumentError => e - assert_equal 'nil is not a valid locale', e.message - end - - def test_missing_translation_data_stores_locale_key_and_options - force_missing_translation_data - rescue I18n::ArgumentError => e - options = {:scope => :bar} - assert_equal 'de-DE', e.locale - assert_equal :foo, e.key - assert_equal options, e.options - end - - def test_missing_translation_data_message - force_missing_translation_data - rescue I18n::ArgumentError => e - assert_equal 'translation missing: de-DE, bar, foo', e.message - end - - def test_invalid_pluralization_data_stores_entry_and_count - force_invalid_pluralization_data - rescue I18n::ArgumentError => e - assert_equal [:bar], e.entry - assert_equal 1, e.count - end - - def test_invalid_pluralization_data_message - force_invalid_pluralization_data - rescue I18n::ArgumentError => e - assert_equal 'translation data [:bar] can not be used with :count => 1', e.message - end - - def test_missing_interpolation_argument_stores_key_and_string - force_missing_interpolation_argument - rescue I18n::ArgumentError => e - assert_equal 'bar', e.key - assert_equal "{{bar}}", e.string - end - - def test_missing_interpolation_argument_message - force_missing_interpolation_argument - rescue I18n::ArgumentError => e - assert_equal 'interpolation argument bar missing in "{{bar}}"', e.message - end - - def test_reserved_interpolation_key_stores_key_and_string - force_reserved_interpolation_key - rescue I18n::ArgumentError => e - assert_equal 'scope', e.key - assert_equal "{{scope}}", e.string - end - - def test_reserved_interpolation_key_message - force_reserved_interpolation_key - rescue I18n::ArgumentError => e - assert_equal 'reserved key "scope" used in "{{scope}}"', e.message - end - - private - def force_invalid_locale - I18n.backend.translate nil, :foo - end - - def force_missing_translation_data - I18n.store_translations 'de-DE', :bar => nil - I18n.backend.translate 'de-DE', :foo, :scope => :bar - end - - def force_invalid_pluralization_data - I18n.store_translations 'de-DE', :foo => [:bar] - I18n.backend.translate 'de-DE', :foo, :count => 1 - end - - def force_missing_interpolation_argument - I18n.store_translations 'de-DE', :foo => "{{bar}}" - I18n.backend.translate 'de-DE', :foo, :baz => 'baz' - end - - def force_reserved_interpolation_key - I18n.store_translations 'de-DE', :foo => "{{scope}}" - I18n.backend.translate 'de-DE', :foo, :baz => 'baz' - end -end \ No newline at end of file diff --git a/activesupport/lib/active_support/vendor/i18n-0.0.1/test/i18n_test.rb b/activesupport/lib/active_support/vendor/i18n-0.0.1/test/i18n_test.rb deleted file mode 100644 index bbb1316b49..0000000000 --- a/activesupport/lib/active_support/vendor/i18n-0.0.1/test/i18n_test.rb +++ /dev/null @@ -1,141 +0,0 @@ -$:.unshift "lib" - -require 'rubygems' -require 'test/unit' -require 'mocha' -require 'i18n' -require 'active_support' - -class I18nTest < Test::Unit::TestCase - def setup - I18n.store_translations :'en-US', { - :currency => { - :format => { - :separator => '.', - :delimiter => ',', - } - } - } - end - - def test_uses_simple_backend_set_by_default - assert_equal I18n::Backend::Simple, I18n.backend - end - - def test_can_set_backend - assert_nothing_raised{ I18n.backend = self } - assert_equal self, I18n.backend - I18n.backend = I18n::Backend::Simple - end - - def test_uses_en_us_as_default_locale_by_default - assert_equal 'en-US', I18n.default_locale - end - - def test_can_set_default_locale - assert_nothing_raised{ I18n.default_locale = 'de-DE' } - assert_equal 'de-DE', I18n.default_locale - I18n.default_locale = 'en-US' - end - - def test_uses_default_locale_as_locale_by_default - assert_equal I18n.default_locale, I18n.locale - end - - def test_can_set_locale_to_thread_current - assert_nothing_raised{ I18n.locale = 'de-DE' } - assert_equal 'de-DE', I18n.locale - assert_equal 'de-DE', Thread.current[:locale] - I18n.locale = 'en-US' - end - - def test_can_set_exception_handler - assert_nothing_raised{ I18n.exception_handler = :custom_exception_handler } - I18n.exception_handler = :default_exception_handler # revert it - end - - def test_uses_custom_exception_handler - I18n.exception_handler = :custom_exception_handler - I18n.expects(:custom_exception_handler) - I18n.translate :bogus - I18n.exception_handler = :default_exception_handler # revert it - end - - def test_delegates_translate_to_backend - I18n.backend.expects(:translate).with 'de-DE', :foo, {} - I18n.translate :foo, :locale => 'de-DE' - end - - def test_delegates_localize_to_backend - I18n.backend.expects(:localize).with 'de-DE', :whatever, :default - I18n.localize :whatever, :locale => 'de-DE' - end - - def test_delegates_store_translations_to_backend - I18n.backend.expects(:store_translations).with 'de-DE', {:foo => :bar} - I18n.store_translations 'de-DE', {:foo => :bar} - end - - def test_delegates_populate_to_backend - I18n.backend.expects(:populate) # can't specify a block here as an expected argument - I18n.populate{ } - end - - def test_populate_yields_the_block - tmp = nil - I18n.populate do tmp = 'yielded' end - assert_equal 'yielded', tmp - end - - def test_translate_given_no_locale_uses_i18n_locale - I18n.backend.expects(:translate).with 'en-US', :foo, {} - I18n.translate :foo - end - - def test_translate_on_nested_symbol_keys_works - assert_equal ".", I18n.t(:'currency.format.separator') - end - - def test_translate_with_nested_string_keys_works - assert_equal ".", I18n.t('currency.format.separator') - end - - def test_translate_with_array_as_scope_works - assert_equal ".", I18n.t(:separator, :scope => ['currency.format']) - end - - def test_translate_with_array_containing_dot_separated_strings_as_scope_works - assert_equal ".", I18n.t(:separator, :scope => ['currency.format']) - end - - def test_translate_with_key_array_and_dot_separated_scope_works - assert_equal [".", ","], I18n.t(%w(separator delimiter), :scope => 'currency.format') - end - - def test_translate_with_dot_separated_key_array_and_scope_works - assert_equal [".", ","], I18n.t(%w(format.separator format.delimiter), :scope => 'currency') - end - - def test_translate_with_options_using_scope_works - I18n.backend.expects(:translate).with('de-DE', :precision, :scope => :"currency.format") - I18n.with_options :locale => 'de-DE', :scope => :'currency.format' do |locale| - locale.t :precision - end - end - - # def test_translate_given_no_args_raises_missing_translation_data - # assert_equal "translation missing: en-US, no key", I18n.t - # end - - def test_translate_given_a_bogus_key_raises_missing_translation_data - assert_equal "translation missing: en-US, bogus", I18n.t(:bogus) - end - - def test_localize_nil_raises_argument_error - assert_raises(I18n::ArgumentError) { I18n.l nil } - end - - def test_localize_object_raises_argument_error - assert_raises(I18n::ArgumentError) { I18n.l Object.new } - end -end diff --git a/activesupport/lib/active_support/vendor/i18n-0.0.1/test/simple_backend_test.rb b/activesupport/lib/active_support/vendor/i18n-0.0.1/test/simple_backend_test.rb deleted file mode 100644 index c94d742e2d..0000000000 --- a/activesupport/lib/active_support/vendor/i18n-0.0.1/test/simple_backend_test.rb +++ /dev/null @@ -1,376 +0,0 @@ -$:.unshift "lib" - -require 'rubygems' -require 'test/unit' -require 'mocha' -require 'i18n' - -module I18nSimpleBackendTestSetup - def setup_backend - @backend = I18n::Backend::Simple - @backend.send :class_variable_set, :@@translations, {} - @backend.store_translations 'en-US', :foo => {:bar => 'bar', :baz => 'baz'} - end - alias :setup :setup_backend - - def add_datetime_translations - @backend.store_translations :'de-DE', { - :date => { - :formats => { - :default => "%d.%m.%Y", - :short => "%d. %b", - :long => "%d. %B %Y", - }, - :day_names => %w(Sonntag Montag Dienstag Mittwoch Donnerstag Freitag Samstag), - :abbr_day_names => %w(So Mo Di Mi Do Fr Sa), - :month_names => %w(Januar Februar März April Mai Juni Juli August September Oktober November Dezember).unshift(nil), - :abbr_month_names => %w(Jan Feb Mar Apr Mai Jun Jul Aug Sep Okt Nov Dez).unshift(nil), - :order => [:day, :month, :year] - }, - :time => { - :formats => { - :default => "%a, %d. %b %Y %H:%M:%S %z", - :short => "%d. %b %H:%M", - :long => "%d. %B %Y %H:%M", - }, - :am => 'am', - :pm => 'pm' - }, - :datetime => { - :distance_in_words => { - :half_a_minute => 'half a minute', - :less_than_x_seconds => ['less than 1 second', 'less than {{count}} seconds'], - :x_seconds => ['1 second', '{{count}} seconds'], - :less_than_x_minutes => ['less than a minute', 'less than {{count}} minutes'], - :x_minutes => ['1 minute', '{{count}} minutes'], - :about_x_hours => ['about 1 hour', 'about {{count}} hours'], - :x_days => ['1 day', '{{count}} days'], - :about_x_months => ['about 1 month', 'about {{count}} months'], - :x_months => ['1 month', '{{count}} months'], - :about_x_years => ['about 1 year', 'about {{count}} year'], - :over_x_years => ['over 1 year', 'over {{count}} years'] - } - } - } - end -end - -class I18nSimpleBackendTranslationsTest < Test::Unit::TestCase - include I18nSimpleBackendTestSetup - - def test_store_translations_adds_translations # no, really :-) - @backend.store_translations :'en-US', :foo => 'bar' - assert_equal Hash[:'en-US', {:foo => 'bar'}], @backend.send(:class_variable_get, :@@translations) - end - - def test_store_translations_deep_merges_translations - @backend.store_translations :'en-US', :foo => {:bar => 'bar'} - @backend.store_translations :'en-US', :foo => {:baz => 'baz'} - assert_equal Hash[:'en-US', {:foo => {:bar => 'bar', :baz => 'baz'}}], @backend.send(:class_variable_get, :@@translations) - end - - def test_store_translations_forces_locale_to_sym - @backend.store_translations 'en-US', :foo => 'bar' - assert_equal Hash[:'en-US', {:foo => 'bar'}], @backend.send(:class_variable_get, :@@translations) - end - - def test_store_translations_covert_key_symbols - @backend.send :class_variable_set, :@@translations, {} # reset translations - @backend.store_translations :'en-US', 'foo' => {'bar' => 'baz'} - assert_equal Hash[:'en-US', {:foo => {:bar => 'baz'}}], - @backend.send(:class_variable_get, :@@translations) - end -end - -class I18nSimpleBackendTranslateTest < Test::Unit::TestCase - include I18nSimpleBackendTestSetup - - def test_translate_calls_lookup_with_locale_given - @backend.expects(:lookup).with('de-DE', :bar, [:foo]).returns 'bar' - @backend.translate 'de-DE', :bar, :scope => [:foo] - end - - def test_translate_given_a_symbol_as_a_default_translates_the_symbol - assert_equal 'bar', @backend.translate('en-US', nil, :scope => [:foo], :default => :bar) - end - - def test_translate_given_an_array_as_default_uses_the_first_match - assert_equal 'bar', @backend.translate('en-US', :does_not_exist, :scope => [:foo], :default => [:does_not_exist_2, :bar]) - end - - def test_translate_an_array_of_keys_translates_all_of_them - assert_equal %w(bar baz), @backend.translate('en-US', [:bar, :baz], :scope => [:foo]) - end - - def test_translate_calls_pluralize - @backend.expects(:pluralize).with 'bar', 1 - @backend.translate 'en-US', :bar, :scope => [:foo], :count => 1 - end - - def test_translate_calls_interpolate - @backend.expects(:interpolate).with 'bar', {} - @backend.translate 'en-US', :bar, :scope => [:foo] - end - - def test_translate_calls_interpolate_including_count_as_a_value - @backend.expects(:interpolate).with 'bar', {:count => 1} - @backend.translate 'en-US', :bar, :scope => [:foo], :count => 1 - end - - def test_given_no_keys_it_returns_the_default - assert_equal 'default', @backend.translate('en-US', nil, :default => 'default') - end - - def test_translate_given_nil_as_a_locale_raises_an_argument_error - assert_raises(I18n::InvalidLocale){ @backend.translate nil, :bar } - end - - def test_translate_with_a_bogus_key_and_no_default_raises_missing_translation_data - assert_raises(I18n::MissingTranslationData){ @backend.translate 'de-DE', :bogus } - end -end - -class I18nSimpleBackendLookupTest < Test::Unit::TestCase - include I18nSimpleBackendTestSetup - - # useful because this way we can use the backend with no key for interpolation/pluralization - def test_lookup_given_nil_as_a_key_returns_nil - assert_nil @backend.send(:lookup, 'en-US', nil) - end - - def test_lookup_given_nested_keys_looks_up_a_nested_hash_value - assert_equal 'bar', @backend.send(:lookup, 'en-US', :bar, [:foo]) - end -end - -class I18nSimpleBackendPluralizeTest < Test::Unit::TestCase - include I18nSimpleBackendTestSetup - - def test_pluralize_given_nil_returns_the_given_entry - assert_equal ['bar', 'bars'], @backend.send(:pluralize, ['bar', 'bars'], nil) - end - - def test_pluralize_given_0_returns_plural_string - assert_equal 'bars', @backend.send(:pluralize, ['bar', 'bars'], 0) - end - - def test_pluralize_given_1_returns_singular_string - assert_equal 'bar', @backend.send(:pluralize, ['bar', 'bars'], 1) - end - - def test_pluralize_given_2_returns_plural_string - assert_equal 'bars', @backend.send(:pluralize, ['bar', 'bars'], 2) - end - - def test_pluralize_given_3_returns_plural_string - assert_equal 'bars', @backend.send(:pluralize, ['bar', 'bars'], 3) - end - - def test_interpolate_given_invalid_pluralization_data_raises_invalid_pluralization_data - assert_raises(I18n::InvalidPluralizationData){ @backend.send(:pluralize, ['bar'], 2) } - end -end - -class I18nSimpleBackendInterpolateTest < Test::Unit::TestCase - include I18nSimpleBackendTestSetup - - def test_interpolate_given_a_value_hash_interpolates_the_values_to_the_string - assert_equal 'Hi David!', @backend.send(:interpolate, 'Hi {{name}}!', :name => 'David') - end - - def test_interpolate_given_nil_as_a_string_returns_nil - assert_nil @backend.send(:interpolate, nil, :name => 'David') - end - - def test_interpolate_given_an_non_string_as_a_string_returns_nil - assert_equal [], @backend.send(:interpolate, [], :name => 'David') - end - - def test_interpolate_given_a_values_hash_with_nil_values_interpolates_the_string - assert_equal 'Hi !', @backend.send(:interpolate, 'Hi {{name}}!', {:name => nil}) - end - - def test_interpolate_given_an_empty_values_hash_raises_missing_interpolation_argument - assert_raises(I18n::MissingInterpolationArgument) { @backend.send(:interpolate, 'Hi {{name}}!', {}) } - end - - def test_interpolate_given_a_string_containing_a_reserved_key_raises_reserved_interpolation_key - assert_raises(I18n::ReservedInterpolationKey) { @backend.send(:interpolate, '{{default}}', {:default => nil}) } - end -end - -class I18nSimpleBackendLocalizeDateTest < Test::Unit::TestCase - include I18nSimpleBackendTestSetup - - def setup - @backend = I18n::Backend::Simple - add_datetime_translations - @date = Date.new 2008, 1, 1 - end - - def test_translate_given_the_short_format_it_uses_it - assert_equal '01. Jan', @backend.localize('de-DE', @date, :short) - end - - def test_translate_given_the_long_format_it_uses_it - assert_equal '01. Januar 2008', @backend.localize('de-DE', @date, :long) - end - - def test_translate_given_the_default_format_it_uses_it - assert_equal '01.01.2008', @backend.localize('de-DE', @date, :default) - end - - def test_translate_given_a_day_name_format_it_returns_a_day_name - assert_equal 'Dienstag', @backend.localize('de-DE', @date, '%A') - end - - def test_translate_given_an_abbr_day_name_format_it_returns_an_abbrevated_day_name - assert_equal 'Di', @backend.localize('de-DE', @date, '%a') - end - - def test_translate_given_a_month_name_format_it_returns_a_month_name - assert_equal 'Januar', @backend.localize('de-DE', @date, '%B') - end - - def test_translate_given_an_abbr_month_name_format_it_returns_an_abbrevated_month_name - assert_equal 'Jan', @backend.localize('de-DE', @date, '%b') - end - - def test_translate_given_no_format_it_does_not_fail - assert_nothing_raised{ @backend.localize 'de-DE', @date } - end - - def test_translate_given_an_unknown_format_it_does_not_fail - assert_nothing_raised{ @backend.localize 'de-DE', @date, '%x' } - end - - def test_localize_nil_raises_argument_error - assert_raises(I18n::ArgumentError) { @backend.localize 'de-DE', nil } - end - - def test_localize_object_raises_argument_error - assert_raises(I18n::ArgumentError) { @backend.localize 'de-DE', Object.new } - end -end - -class I18nSimpleBackendLocalizeDateTimeTest < Test::Unit::TestCase - include I18nSimpleBackendTestSetup - - def setup - @backend = I18n::Backend::Simple - add_datetime_translations - @morning = DateTime.new 2008, 1, 1, 6 - @evening = DateTime.new 2008, 1, 1, 18 - end - - def test_translate_given_the_short_format_it_uses_it - assert_equal '01. Jan 06:00', @backend.localize('de-DE', @morning, :short) - end - - def test_translate_given_the_long_format_it_uses_it - assert_equal '01. Januar 2008 06:00', @backend.localize('de-DE', @morning, :long) - end - - def test_translate_given_the_default_format_it_uses_it - assert_equal 'Di, 01. Jan 2008 06:00:00 +0000', @backend.localize('de-DE', @morning, :default) - end - - def test_translate_given_a_day_name_format_it_returns_the_correct_day_name - assert_equal 'Dienstag', @backend.localize('de-DE', @morning, '%A') - end - - def test_translate_given_an_abbr_day_name_format_it_returns_the_correct_abbrevated_day_name - assert_equal 'Di', @backend.localize('de-DE', @morning, '%a') - end - - def test_translate_given_a_month_name_format_it_returns_the_correct_month_name - assert_equal 'Januar', @backend.localize('de-DE', @morning, '%B') - end - - def test_translate_given_an_abbr_month_name_format_it_returns_the_correct_abbrevated_month_name - assert_equal 'Jan', @backend.localize('de-DE', @morning, '%b') - end - - def test_translate_given_a_meridian_indicator_format_it_returns_the_correct_meridian_indicator - assert_equal 'am', @backend.localize('de-DE', @morning, '%p') - assert_equal 'pm', @backend.localize('de-DE', @evening, '%p') - end - - def test_translate_given_no_format_it_does_not_fail - assert_nothing_raised{ @backend.localize 'de-DE', @morning } - end - - def test_translate_given_an_unknown_format_it_does_not_fail - assert_nothing_raised{ @backend.localize 'de-DE', @morning, '%x' } - end -end - -class I18nSimpleBackendLocalizeTimeTest < Test::Unit::TestCase - include I18nSimpleBackendTestSetup - - def setup - @old_timezone, ENV['TZ'] = ENV['TZ'], 'UTC' - @backend = I18n::Backend::Simple - add_datetime_translations - @morning = Time.parse '2008-01-01 6:00 UTC' - @evening = Time.parse '2008-01-01 18:00 UTC' - end - - def teardown - ENV['TZ'] = @old_timezone - end - - def test_translate_given_the_short_format_it_uses_it - assert_equal '01. Jan 06:00', @backend.localize('de-DE', @morning, :short) - end - - def test_translate_given_the_long_format_it_uses_it - assert_equal '01. Januar 2008 06:00', @backend.localize('de-DE', @morning, :long) - end - - # TODO Seems to break on Windows because ENV['TZ'] is ignored. What's a better way to do this? - # def test_translate_given_the_default_format_it_uses_it - # assert_equal 'Di, 01. Jan 2008 06:00:00 +0000', @backend.localize('de-DE', @morning, :default) - # end - - def test_translate_given_a_day_name_format_it_returns_the_correct_day_name - assert_equal 'Dienstag', @backend.localize('de-DE', @morning, '%A') - end - - def test_translate_given_an_abbr_day_name_format_it_returns_the_correct_abbrevated_day_name - assert_equal 'Di', @backend.localize('de-DE', @morning, '%a') - end - - def test_translate_given_a_month_name_format_it_returns_the_correct_month_name - assert_equal 'Januar', @backend.localize('de-DE', @morning, '%B') - end - - def test_translate_given_an_abbr_month_name_format_it_returns_the_correct_abbrevated_month_name - assert_equal 'Jan', @backend.localize('de-DE', @morning, '%b') - end - - def test_translate_given_a_meridian_indicator_format_it_returns_the_correct_meridian_indicator - assert_equal 'am', @backend.localize('de-DE', @morning, '%p') - assert_equal 'pm', @backend.localize('de-DE', @evening, '%p') - end - - def test_translate_given_no_format_it_does_not_fail - assert_nothing_raised{ @backend.localize 'de-DE', @morning } - end - - def test_translate_given_an_unknown_format_it_does_not_fail - assert_nothing_raised{ @backend.localize 'de-DE', @morning, '%x' } - end -end - -class I18nSimpleBackendHelperMethodsTest < Test::Unit::TestCase - def setup - @backend = I18n::Backend::Simple - end - - def test_deep_symbolize_keys_works - result = @backend.send :deep_symbolize_keys, 'foo' => {'bar' => {'baz' => 'bar'}} - expected = {:foo => {:bar => {:baz => 'bar'}}} - assert_equal expected, result - end -end -- cgit v1.2.3 From bfa143fd4d15544e788d25ec163f9cc57a1e2a03 Mon Sep 17 00:00:00 2001 From: Sven Fuchs Date: Wed, 13 Aug 2008 09:44:46 +0200 Subject: fix require path in vendor.rb for fixed vendor/gem dir structure --- activesupport/lib/active_support/vendor.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'activesupport/lib') diff --git a/activesupport/lib/active_support/vendor.rb b/activesupport/lib/active_support/vendor.rb index 381471b833..acd94af783 100644 --- a/activesupport/lib/active_support/vendor.rb +++ b/activesupport/lib/active_support/vendor.rb @@ -29,6 +29,6 @@ end # begin # gem 'i18n', '~> 0.0.1' # rescue Gem::LoadError - $:.unshift "#{File.dirname(__FILE__)}/vendor/i18n-0.0.1/lib" + $:.unshift "#{File.dirname(__FILE__)}/vendor/i18n-0.0.1" require 'i18n' # end \ No newline at end of file -- cgit v1.2.3 From f26380b7757666fa793c150538e8444a640d29aa Mon Sep 17 00:00:00 2001 From: Sven Fuchs Date: Wed, 13 Aug 2008 09:53:25 +0200 Subject: switch to using I18n.load_translations instead of requiring plain ruby files --- activesupport/lib/active_support.rb | 4 +- activesupport/lib/active_support/locale/en-US.rb | 49 ++++++++++++------------ 2 files changed, 27 insertions(+), 26 deletions(-) (limited to 'activesupport/lib') diff --git a/activesupport/lib/active_support.rb b/activesupport/lib/active_support.rb index 51067e910e..6056067efd 100644 --- a/activesupport/lib/active_support.rb +++ b/activesupport/lib/active_support.rb @@ -58,8 +58,8 @@ require 'active_support/base64' require 'active_support/time_with_zone' -I18n.backend.populate do - require 'active_support/locale/en-US.rb' +I18n.populate do + I18n.load_translations File.dirname(__FILE__) + '/active_support/locale/en-US.rb' end Inflector = ActiveSupport::Deprecation::DeprecatedConstantProxy.new('Inflector', 'ActiveSupport::Inflector') diff --git a/activesupport/lib/active_support/locale/en-US.rb b/activesupport/lib/active_support/locale/en-US.rb index 51324a90bf..ed457d6f4f 100644 --- a/activesupport/lib/active_support/locale/en-US.rb +++ b/activesupport/lib/active_support/locale/en-US.rb @@ -1,28 +1,29 @@ -I18n.backend.store_translations :'en-US', { - :support => { - :array => { - :sentence_connector => 'and' - } - }, - :date => { - :formats => { - :default => "%Y-%m-%d", - :short => "%b %d", - :long => "%B %d, %Y", +{ :'en-US' => { + :support => { + :array => { + :sentence_connector => 'and' + } }, - :day_names => Date::DAYNAMES, - :abbr_day_names => Date::ABBR_DAYNAMES, - :month_names => Date::MONTHNAMES, - :abbr_month_names => Date::ABBR_MONTHNAMES, - :order => [:year, :month, :day] - }, - :time => { - :formats => { - :default => "%a, %d %b %Y %H:%M:%S %z", - :short => "%d %b %H:%M", - :long => "%B %d, %Y %H:%M", + :date => { + :formats => { + :default => "%Y-%m-%d", + :short => "%b %d", + :long => "%B %d, %Y", + }, + :day_names => Date::DAYNAMES, + :abbr_day_names => Date::ABBR_DAYNAMES, + :month_names => Date::MONTHNAMES, + :abbr_month_names => Date::ABBR_MONTHNAMES, + :order => [:year, :month, :day] }, - :am => 'am', - :pm => 'pm' + :time => { + :formats => { + :default => "%a, %d %b %Y %H:%M:%S %z", + :short => "%d %b %H:%M", + :long => "%B %d, %Y %H:%M", + }, + :am => 'am', + :pm => 'pm' + } } } \ No newline at end of file -- cgit v1.2.3 From 78677cf6af339a6e23a93a45c905d6d1545ccc33 Mon Sep 17 00:00:00 2001 From: Sven Fuchs Date: Wed, 13 Aug 2008 11:42:02 +0200 Subject: update activesupport/vendor i18n gem --- activesupport/lib/active_support/vendor/i18n-0.0.1/i18n.rb | 10 ++++++++-- .../active_support/vendor/i18n-0.0.1/i18n/backend/simple.rb | 13 ++++++++++++- 2 files changed, 20 insertions(+), 3 deletions(-) (limited to 'activesupport/lib') diff --git a/activesupport/lib/active_support/vendor/i18n-0.0.1/i18n.rb b/activesupport/lib/active_support/vendor/i18n-0.0.1/i18n.rb index 86005553c0..5c6c4eb783 100755 --- a/activesupport/lib/active_support/vendor/i18n-0.0.1/i18n.rb +++ b/activesupport/lib/active_support/vendor/i18n-0.0.1/i18n.rb @@ -56,8 +56,14 @@ module I18n backend.populate(&block) end - def load_translations(filename) - backend.load_translations filename + # Allows client libraries to pass arguments that specify a source for + # translation data to be loaded by the backend. The backend defines + # acceptable sources. + # E.g. the provided SimpleBackend accepts a list of paths to translation + # files which are either named *.rb and contain plain Ruby Hashes or are + # named *.yml and contain YAML data.) + def load_translations(*args) + backend.load_translations *args end # Stores translations for the given locale in the backend. diff --git a/activesupport/lib/active_support/vendor/i18n-0.0.1/i18n/backend/simple.rb b/activesupport/lib/active_support/vendor/i18n-0.0.1/i18n/backend/simple.rb index 98c7964b21..ba7e11210a 100644 --- a/activesupport/lib/active_support/vendor/i18n-0.0.1/i18n/backend/simple.rb +++ b/activesupport/lib/active_support/vendor/i18n-0.0.1/i18n/backend/simple.rb @@ -12,7 +12,10 @@ module I18n def populate(&block) yield end - + + # Accepts a list of paths to translation files. Loads translations from + # plain Ruby (*.rb) or YAML files (*.yml). See #load_rb and #load_yml + # for details. def load_translations(*filenames) filenames.each {|filename| load_file filename } end @@ -135,6 +138,10 @@ module I18n s.string end + # Loads a single translations file by delegating to #load_rb or + # #load_yml depending on the file extension and directly merges the + # data to the existing translations. Raises I18n::UnknownFileType + # for all other file extensions. def load_file(filename) type = File.extname(filename).tr('.', '').downcase raise UnknownFileType.new(type, filename) unless respond_to? :"load_#{type}" @@ -144,10 +151,14 @@ module I18n end end + # Loads a plain Ruby translations file. eval'ing the file must yield + # a Hash containing translation data with locales as toplevel keys. def load_rb(filename) eval IO.read(filename), binding, filename end + # Loads a YAML translations file. The data must have locales as + # toplevel keys. def load_yml(filename) YAML::load IO.read(filename) end -- cgit v1.2.3 From 282b42021306f73d4cc8f8a06713da9a55ed044b Mon Sep 17 00:00:00 2001 From: Jeffrey Hardy Date: Wed, 13 Aug 2008 00:51:47 -0400 Subject: Account for the possibility of a nil options argument to CompressedMemCacheStore#read/#write --- .../lib/active_support/cache/compressed_mem_cache_store.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'activesupport/lib') diff --git a/activesupport/lib/active_support/cache/compressed_mem_cache_store.rb b/activesupport/lib/active_support/cache/compressed_mem_cache_store.rb index 9470ac9f66..0bff6cf9ad 100644 --- a/activesupport/lib/active_support/cache/compressed_mem_cache_store.rb +++ b/activesupport/lib/active_support/cache/compressed_mem_cache_store.rb @@ -1,14 +1,14 @@ module ActiveSupport module Cache class CompressedMemCacheStore < MemCacheStore - def read(name, options = {}) - if value = super(name, options.merge(:raw => true)) + def read(name, options = nil) + if value = super(name, (options || {}).merge(:raw => true)) Marshal.load(ActiveSupport::Gzip.decompress(value)) end end - def write(name, value, options = {}) - super(name, ActiveSupport::Gzip.compress(Marshal.dump(value)), options.merge(:raw => true)) + def write(name, value, options = nil) + super(name, ActiveSupport::Gzip.compress(Marshal.dump(value)), (options || {}).merge(:raw => true)) end end end -- cgit v1.2.3 From 906e79396badfe9fb6b7f0457e835e5f1a9b09b2 Mon Sep 17 00:00:00 2001 From: Sven Fuchs Date: Wed, 13 Aug 2008 13:43:02 +0200 Subject: fix bug in I18n::Backend::Simple (A default array of non-existant keys returns the default array) --- .../lib/active_support/vendor/i18n-0.0.1/i18n/backend/simple.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'activesupport/lib') diff --git a/activesupport/lib/active_support/vendor/i18n-0.0.1/i18n/backend/simple.rb b/activesupport/lib/active_support/vendor/i18n-0.0.1/i18n/backend/simple.rb index ba7e11210a..530e9eca50 100644 --- a/activesupport/lib/active_support/vendor/i18n-0.0.1/i18n/backend/simple.rb +++ b/activesupport/lib/active_support/vendor/i18n-0.0.1/i18n/backend/simple.rb @@ -89,7 +89,7 @@ module I18n when Symbol then translate locale, default, options when Array then default.each do |obj| result = default(locale, obj, options.dup) and return result - end + end and nil end rescue MissingTranslationData nil -- cgit v1.2.3 From 3fc9a67c04bade858e7ac7eb8cd94eec6a63ec27 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Wed, 13 Aug 2008 17:22:38 -0700 Subject: memoize_ and unmemoize_all --- activesupport/lib/active_support/memoizable.rb | 51 +++++++++++++++++--------- 1 file changed, 33 insertions(+), 18 deletions(-) (limited to 'activesupport/lib') diff --git a/activesupport/lib/active_support/memoizable.rb b/activesupport/lib/active_support/memoizable.rb index b5adc2330c..5aa73bce52 100644 --- a/activesupport/lib/active_support/memoizable.rb +++ b/activesupport/lib/active_support/memoizable.rb @@ -10,25 +10,37 @@ module ActiveSupport end def freeze_with_memoizable - unless frozen? - methods.each do |method| - if method.to_s =~ /^_unmemoized_(.*)/ - begin - __send__($1).freeze - rescue ArgumentError - end + memoize_all unless frozen? + freeze_without_memoizable + end + + def memoize_all + methods.each do |m| + if m.to_s =~ /^_unmemoized_(.*)/ + if method(m).arity == 0 + __send__($1) + else + ivar = :"@_memoized_#{$1}" + instance_variable_set(ivar, {}) end end end + end - freeze_without_memoizable + def unmemoize_all + methods.each do |m| + if m.to_s =~ /^_unmemoized_(.*)/ + ivar = :"@_memoized_#{$1}" + instance_variable_get(ivar).clear if instance_variable_defined?(ivar) + end + end end end def memoize(*symbols) symbols.each do |symbol| - original_method = "_unmemoized_#{symbol}" - memoized_ivar = "@_memoized_#{symbol.to_s.sub(/\?\Z/, '_query').sub(/!\Z/, '_bang')}" + original_method = :"_unmemoized_#{symbol}" + memoized_ivar = :"@_memoized_#{symbol.to_s.sub(/\?\Z/, '_query').sub(/!\Z/, '_bang')}" class_eval <<-EOS, __FILE__, __LINE__ include Freezable @@ -38,21 +50,24 @@ module ActiveSupport if instance_method(:#{symbol}).arity == 0 def #{symbol}(reload = false) - if !reload && defined? #{memoized_ivar} - #{memoized_ivar} - else - #{memoized_ivar} = #{original_method} + if reload || !defined?(#{memoized_ivar}) || #{memoized_ivar}.empty? + #{memoized_ivar} = [#{original_method}] end + #{memoized_ivar}[0] end else def #{symbol}(*args) - #{memoized_ivar} ||= {} + #{memoized_ivar} ||= {} unless frozen? reload = args.pop if args.last == true || args.last == :reload - if !reload && #{memoized_ivar} && #{memoized_ivar}.has_key?(args) - #{memoized_ivar}[args] + if #{memoized_ivar} + if !reload && #{memoized_ivar}.has_key?(args) + #{memoized_ivar}[args] + elsif #{memoized_ivar} + #{memoized_ivar}[args] = #{original_method}(*args) + end else - #{memoized_ivar}[args] = #{original_method}(*args) + #{original_method}(*args) end end end -- cgit v1.2.3 From b8b30985d525fd15b6c16d29fc115e83e3ee5037 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Wed, 13 Aug 2008 20:57:26 -0500 Subject: Marshal FileStore values --- activesupport/lib/active_support/cache/file_store.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'activesupport/lib') diff --git a/activesupport/lib/active_support/cache/file_store.rb b/activesupport/lib/active_support/cache/file_store.rb index 7b6ca39091..437679cc05 100644 --- a/activesupport/lib/active_support/cache/file_store.rb +++ b/activesupport/lib/active_support/cache/file_store.rb @@ -9,13 +9,13 @@ module ActiveSupport def read(name, options = nil) super - File.open(real_file_path(name), 'rb') { |f| f.read } rescue nil + File.open(real_file_path(name), 'rb') { |f| Marshal.load(f) } rescue nil end def write(name, value, options = nil) super ensure_cache_path(File.dirname(real_file_path(name))) - File.atomic_write(real_file_path(name), cache_path) { |f| f.write(value) } + File.atomic_write(real_file_path(name), cache_path) { |f| Marshal.dump(value, f) } rescue => e RAILS_DEFAULT_LOGGER.error "Couldn't create cache directory: #{name} (#{e.message})" if RAILS_DEFAULT_LOGGER end -- cgit v1.2.3 From 8cb14ee1203c9ed380c4b192e8730757a52d43cb Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Wed, 13 Aug 2008 21:30:46 -0500 Subject: Ensure results returned by a memoized method are immutable --- activesupport/lib/active_support/memoizable.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'activesupport/lib') diff --git a/activesupport/lib/active_support/memoizable.rb b/activesupport/lib/active_support/memoizable.rb index 5aa73bce52..6506238ac0 100644 --- a/activesupport/lib/active_support/memoizable.rb +++ b/activesupport/lib/active_support/memoizable.rb @@ -51,7 +51,7 @@ module ActiveSupport if instance_method(:#{symbol}).arity == 0 def #{symbol}(reload = false) if reload || !defined?(#{memoized_ivar}) || #{memoized_ivar}.empty? - #{memoized_ivar} = [#{original_method}] + #{memoized_ivar} = [#{original_method}.freeze] end #{memoized_ivar}[0] end @@ -64,7 +64,7 @@ module ActiveSupport if !reload && #{memoized_ivar}.has_key?(args) #{memoized_ivar}[args] elsif #{memoized_ivar} - #{memoized_ivar}[args] = #{original_method}(*args) + #{memoized_ivar}[args] = #{original_method}(*args).freeze end else #{original_method}(*args) -- cgit v1.2.3 From 7fbe226de5c63565fcca67d01687d83009ab9886 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Thu, 7 Aug 2008 01:22:03 -0700 Subject: Ruby 1.9 and GC::Profiler updates --- .../lib/active_support/testing/performance.rb | 66 ++++++++++++++++++++-- 1 file changed, 60 insertions(+), 6 deletions(-) (limited to 'activesupport/lib') diff --git a/activesupport/lib/active_support/testing/performance.rb b/activesupport/lib/active_support/testing/performance.rb index 70a7f84023..3ad7289571 100644 --- a/activesupport/lib/active_support/testing/performance.rb +++ b/activesupport/lib/active_support/testing/performance.rb @@ -25,7 +25,7 @@ module ActiveSupport def self.included(base) base.class_inheritable_hash :profile_options - base.profile_options = DEFAULTS.dup + base.profile_options = DEFAULTS end def full_test_name @@ -34,6 +34,7 @@ module ActiveSupport def run(result) return if method_name =~ /^default_test$/ + self.profile_options ||= DEFAULTS yield(self.class::STARTED, name) @_result = result @@ -43,8 +44,6 @@ module ActiveSupport if klass = Metrics[metric_name.to_sym] run_profile(klass.new) result.add_run - else - $stderr.puts '%20s: unsupported' % metric_name.to_s end end @@ -164,7 +163,14 @@ module ActiveSupport end class Profiler < Performer + def initialize(*args) + super + @supported = @metric.measure_mode rescue false + end + def run + return unless @supported + RubyProf.measure_mode = @metric.measure_mode RubyProf.start RubyProf.pause @@ -173,7 +179,17 @@ module ActiveSupport @total = @data.threads.values.sum(0) { |method_infos| method_infos.sort.last.total_time } end + def report + if @supported + super + else + '%20s: unsupported' % @metric.name + end + end + def record + return unless @supported + klasses = profile_options[:formats].map { |f| RubyProf.const_get("#{f.to_s.camelize}Printer") }.compact klasses.each do |klass| @@ -202,8 +218,7 @@ module ActiveSupport module Metrics def self.[](name) - klass = const_get(name.to_s.camelize) - klass if klass::Mode + const_get(name.to_s.camelize) rescue NameError nil end @@ -250,6 +265,16 @@ module ActiveSupport ensure GC.disable_stats end + elsif defined?(GC::Profiler) + def with_gc_stats + GC.start + GC.disable + GC::Profiler.enable + yield + ensure + GC::Profiler.disable + GC.enable + end else def with_gc_stats yield @@ -310,7 +335,7 @@ module ActiveSupport RubyProf.measure_memory / 1024.0 end - # Ruby 1.8 + adymo patch + # Ruby 1.8 + railsbench patch elsif GC.respond_to?(:allocated_size) def measure GC.allocated_size / 1024.0 @@ -322,11 +347,27 @@ module ActiveSupport GC.heap_info['heap_current_memory'] / 1024.0 end + # Ruby 1.9 with total_malloc_allocated_size patch + elsif GC.respond_to?(:malloc_total_allocated_size) + def measure + GC.total_malloc_allocated_size / 1024.0 + end + # Ruby 1.9 unpatched elsif GC.respond_to?(:malloc_allocated_size) def measure GC.malloc_allocated_size / 1024.0 end + + # Ruby 1.9 + GC profiler patch + elsif defined?(GC::Profiler) + def measure + GC.enable + GC.start + kb = GC::Profiler.data.last[:HEAP_USE_SIZE] / 1024.0 + GC.disable + kb + end end def format(measurement) @@ -341,10 +382,23 @@ module ActiveSupport def measure RubyProf.measure_allocations end + + # Ruby 1.8 + railsbench patch elsif ObjectSpace.respond_to?(:allocated_objects) def measure ObjectSpace.allocated_objects end + + # Ruby 1.9 + GC profiler patch + elsif defined?(GC::Profiler) + def measure + GC.enable + GC.start + last = GC::Profiler.data.last + count = last[:HEAP_LIVE_OBJECTS] + last[:HEAP_FREE_OBJECTS] + GC.disable + count + end end def format(measurement) -- cgit v1.2.3 From a4da8175a2c989104de1a38e43d5ddfb0f89b055 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Mon, 18 Aug 2008 20:14:56 -0500 Subject: Replace MemoryStore mutex with a monitor to avoid issues with nested calls --- .../lib/active_support/cache/memory_store.rb | 36 ++++++++++++++-------- 1 file changed, 24 insertions(+), 12 deletions(-) (limited to 'activesupport/lib') diff --git a/activesupport/lib/active_support/cache/memory_store.rb b/activesupport/lib/active_support/cache/memory_store.rb index a44f877414..7ac6f35357 100644 --- a/activesupport/lib/active_support/cache/memory_store.rb +++ b/activesupport/lib/active_support/cache/memory_store.rb @@ -3,51 +3,63 @@ module ActiveSupport class MemoryStore < Store def initialize @data = {} - @mutex = Mutex.new + @guard = Monitor.new end def fetch(key, options = {}) - @mutex.synchronize do + @guard.synchronize do super end end def read(name, options = nil) - super - @data[name] + @guard.synchronize do + super + @data[name] + end end def write(name, value, options = nil) - super - @data[name] = value + @guard.synchronize do + super + @data[name] = value + end end def delete(name, options = nil) - @data.delete(name) + @guard.synchronize do + @data.delete(name) + end end def delete_matched(matcher, options = nil) - @data.delete_if { |k,v| k =~ matcher } + @guard.synchronize do + @data.delete_if { |k,v| k =~ matcher } + end end def exist?(name,options = nil) - @data.has_key?(name) + @guard.synchronize do + @data.has_key?(name) + end end def increment(key, amount = 1) - @mutex.synchronize do + @guard.synchronize do super end end def decrement(key, amount = 1) - @mutex.synchronize do + @guard.synchronize do super end end def clear - @data.clear + @guard.synchronize do + @data.clear + end end end end -- cgit v1.2.3 From c1a8690d582c08777055caf449c03f85b4c8aa4b Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Mon, 18 Aug 2008 22:38:58 -0500 Subject: Consistently use the framework's configured logger and avoid reverting to RAILS_DEFAULT_LOGGER unless necessary. --- activesupport/lib/active_support/cache/file_store.rb | 4 ++-- activesupport/lib/active_support/core_ext/kernel/debugger.rb | 8 ++++---- activesupport/lib/active_support/dependencies.rb | 10 +++++++--- 3 files changed, 13 insertions(+), 9 deletions(-) (limited to 'activesupport/lib') diff --git a/activesupport/lib/active_support/cache/file_store.rb b/activesupport/lib/active_support/cache/file_store.rb index 437679cc05..659bde64f0 100644 --- a/activesupport/lib/active_support/cache/file_store.rb +++ b/activesupport/lib/active_support/cache/file_store.rb @@ -17,7 +17,7 @@ module ActiveSupport ensure_cache_path(File.dirname(real_file_path(name))) File.atomic_write(real_file_path(name), cache_path) { |f| Marshal.dump(value, f) } rescue => e - RAILS_DEFAULT_LOGGER.error "Couldn't create cache directory: #{name} (#{e.message})" if RAILS_DEFAULT_LOGGER + logger.error "Couldn't create cache directory: #{name} (#{e.message})" if logger end def delete(name, options = nil) @@ -67,4 +67,4 @@ module ActiveSupport end end end -end \ No newline at end of file +end diff --git a/activesupport/lib/active_support/core_ext/kernel/debugger.rb b/activesupport/lib/active_support/core_ext/kernel/debugger.rb index c74d6cf884..4007a647be 100644 --- a/activesupport/lib/active_support/core_ext/kernel/debugger.rb +++ b/activesupport/lib/active_support/core_ext/kernel/debugger.rb @@ -2,12 +2,12 @@ module Kernel unless respond_to?(:debugger) # Starts a debugging session if ruby-debug has been loaded (call script/server --debugger to do load it). def debugger - RAILS_DEFAULT_LOGGER.info "\n***** Debugger requested, but was not available: Start server with --debugger to enable *****\n" + Rails.logger.info "\n***** Debugger requested, but was not available: Start server with --debugger to enable *****\n" end end - + def breakpoint - RAILS_DEFAULT_LOGGER.info "\n***** The 'breakpoint' command has been renamed 'debugger' -- please change *****\n" + Rails.logger.info "\n***** The 'breakpoint' command has been renamed 'debugger' -- please change *****\n" debugger end -end \ No newline at end of file +end diff --git a/activesupport/lib/active_support/dependencies.rb b/activesupport/lib/active_support/dependencies.rb index a3f5f799a2..3d871eec11 100644 --- a/activesupport/lib/active_support/dependencies.rb +++ b/activesupport/lib/active_support/dependencies.rb @@ -39,6 +39,10 @@ module ActiveSupport #:nodoc: mattr_accessor :explicitly_unloadable_constants self.explicitly_unloadable_constants = [] + # The logger is used for generating information on the action run-time (including benchmarking) if available. + # Can be set to nil for no logging. Compatible with both Ruby's own Logger and Log4r loggers. + mattr_accessor :logger + # Set to true to enable logging of const_missing and file loads mattr_accessor :log_activity self.log_activity = false @@ -584,7 +588,7 @@ module ActiveSupport #:nodoc: protected def log_call(*args) - if defined?(RAILS_DEFAULT_LOGGER) && RAILS_DEFAULT_LOGGER && log_activity + if logger && log_activity arg_str = args.collect { |arg| arg.inspect } * ', ' /in `([a-z_\?\!]+)'/ =~ caller(1).first selector = $1 || '' @@ -593,8 +597,8 @@ module ActiveSupport #:nodoc: end def log(msg) - if defined?(RAILS_DEFAULT_LOGGER) && RAILS_DEFAULT_LOGGER && log_activity - RAILS_DEFAULT_LOGGER.debug "Dependencies: #{msg}" + if logger && log_activity + logger.debug "Dependencies: #{msg}" end end end -- cgit v1.2.3 From 96ab01e8f2b5a4475453acf60f9cf9bd8cd98483 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Mon, 18 Aug 2008 23:33:46 -0500 Subject: Maintain a seperate buffer for each thread --- activesupport/lib/active_support/buffered_logger.rb | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) (limited to 'activesupport/lib') diff --git a/activesupport/lib/active_support/buffered_logger.rb b/activesupport/lib/active_support/buffered_logger.rb index cedc1afe7f..6553d72b4f 100644 --- a/activesupport/lib/active_support/buffered_logger.rb +++ b/activesupport/lib/active_support/buffered_logger.rb @@ -33,11 +33,10 @@ module ActiveSupport attr_accessor :level attr_reader :auto_flushing - attr_reader :buffer def initialize(log, level = DEBUG) @level = level - @buffer = [] + @buffer = {} @auto_flushing = 1 @guard = Mutex.new @@ -60,9 +59,7 @@ module ActiveSupport # If a newline is necessary then create a new message ending with a newline. # Ensures that the original message is not mutated. message = "#{message}\n" unless message[-1] == ?\n - @guard.synchronize do - buffer << message - end + buffer << message auto_flush message end @@ -96,8 +93,8 @@ module ActiveSupport def flush @guard.synchronize do unless buffer.empty? - old_buffer = @buffer - @buffer = [] + old_buffer = buffer + clear_buffer @log.write(old_buffer.join) end end @@ -113,5 +110,13 @@ module ActiveSupport def auto_flush flush if buffer.size >= @auto_flushing end + + def buffer + @buffer[Thread.current] ||= [] + end + + def clear_buffer + @buffer[Thread.current] = [] + end end end -- cgit v1.2.3 From c379582064b4f345ecb6bab999e2f1c5685313a8 Mon Sep 17 00:00:00 2001 From: Sven Fuchs Date: Tue, 19 Aug 2008 14:25:51 +0200 Subject: switch to class and instance instead of a module for the simple backend --- .../lib/active_support/vendor/i18n-0.0.1/i18n.rb | 4 +- .../vendor/i18n-0.0.1/i18n/backend/simple.rb | 334 ++++++++++----------- 2 files changed, 169 insertions(+), 169 deletions(-) (limited to 'activesupport/lib') diff --git a/activesupport/lib/active_support/vendor/i18n-0.0.1/i18n.rb b/activesupport/lib/active_support/vendor/i18n-0.0.1/i18n.rb index 5c6c4eb783..145840aa36 100755 --- a/activesupport/lib/active_support/vendor/i18n-0.0.1/i18n.rb +++ b/activesupport/lib/active_support/vendor/i18n-0.0.1/i18n.rb @@ -9,14 +9,14 @@ require 'i18n/backend/simple' require 'i18n/exceptions' module I18n - @@backend = Backend::Simple + @@backend = nil @@default_locale = 'en-US' @@exception_handler = :default_exception_handler class << self # Returns the current backend. Defaults to +Backend::Simple+. def backend - @@backend + @@backend ||= Backend::Simple.new end # Sets the current backend. Used to set a custom backend. diff --git a/activesupport/lib/active_support/vendor/i18n-0.0.1/i18n/backend/simple.rb b/activesupport/lib/active_support/vendor/i18n-0.0.1/i18n/backend/simple.rb index 530e9eca50..63ef55631f 100644 --- a/activesupport/lib/active_support/vendor/i18n-0.0.1/i18n/backend/simple.rb +++ b/activesupport/lib/active_support/vendor/i18n-0.0.1/i18n/backend/simple.rb @@ -2,188 +2,188 @@ require 'strscan' module I18n module Backend - module Simple - @@translations = {} + class Simple + # Allow client libraries to pass a block that populates the translation + # storage. Decoupled for backends like a db backend that persist their + # translations, so the backend can decide whether/when to yield or not. + def populate(&block) + yield + end + + # Accepts a list of paths to translation files. Loads translations from + # plain Ruby (*.rb) or YAML files (*.yml). See #load_rb and #load_yml + # for details. + def load_translations(*filenames) + filenames.each {|filename| load_file filename } + end - class << self - # Allow client libraries to pass a block that populates the translation - # storage. Decoupled for backends like a db backend that persist their - # translations, so the backend can decide whether/when to yield or not. - def populate(&block) - yield - end + # Stores translations for the given locale in memory. + # This uses a deep merge for the translations hash, so existing + # translations will be overwritten by new ones only at the deepest + # level of the hash. + def store_translations(locale, data) + merge_translations(locale, data) + end - # Accepts a list of paths to translation files. Loads translations from - # plain Ruby (*.rb) or YAML files (*.yml). See #load_rb and #load_yml - # for details. - def load_translations(*filenames) - filenames.each {|filename| load_file filename } + def translate(locale, key, options = {}) + raise InvalidLocale.new(locale) if locale.nil? + return key.map{|key| translate locale, key, options } if key.is_a? Array + + reserved = :scope, :default + count, scope, default = options.values_at(:count, *reserved) + options.delete(:default) + values = options.reject{|name, value| reserved.include? name } + + entry = lookup(locale, key, scope) || default(locale, default, options) || raise(I18n::MissingTranslationData.new(locale, key, options)) + entry = pluralize locale, entry, count + entry = interpolate locale, entry, values + entry + end + + # Acts the same as +strftime+, but returns a localized version of the + # formatted date string. Takes a key from the date/time formats + # translations as a format argument (e.g., :short in :'date.formats'). + def localize(locale, object, format = :default) + raise ArgumentError, "Object must be a Date, DateTime or Time object. #{object.inspect} given." unless object.respond_to?(:strftime) + + type = object.respond_to?(:sec) ? 'time' : 'date' + formats = translate(locale, :"#{type}.formats") + format = formats[format.to_sym] if formats && formats[format.to_sym] + # TODO raise exception unless format found? + format = format.to_s.dup + + format.gsub!(/%a/, translate(locale, :"date.abbr_day_names")[object.wday]) + format.gsub!(/%A/, translate(locale, :"date.day_names")[object.wday]) + format.gsub!(/%b/, translate(locale, :"date.abbr_month_names")[object.mon]) + format.gsub!(/%B/, translate(locale, :"date.month_names")[object.mon]) + format.gsub!(/%p/, translate(locale, :"time.#{object.hour < 12 ? :am : :pm}")) if object.respond_to? :hour + object.strftime(format) + end + + protected + + def translations + @translations ||= {} end - # Stores translations for the given locale in memory. - # This uses a deep merge for the translations hash, so existing - # translations will be overwritten by new ones only at the deepest - # level of the hash. - def store_translations(locale, data) - merge_translations(locale, data) + # Looks up a translation from the translations hash. Returns nil if + # eiher key is nil, or locale, scope or key do not exist as a key in the + # nested translations hash. Splits keys or scopes containing dots + # into multiple keys, i.e. currency.format is regarded the same as + # %w(currency format). + def lookup(locale, key, scope = []) + return unless key + keys = I18n.send :normalize_translation_keys, locale, key, scope + keys.inject(translations){|result, key| result[key.to_sym] or return nil } + end + + # Evaluates a default translation. + # If the given default is a String it is used literally. If it is a Symbol + # it will be translated with the given options. If it is an Array the first + # translation yielded will be returned. + # + # I.e., default(locale, [:foo, 'default']) will return +default+ if + # translate(locale, :foo) does not yield a result. + def default(locale, default, options = {}) + case default + when String then default + when Symbol then translate locale, default, options + when Array then default.each do |obj| + result = default(locale, obj, options.dup) and return result + end and nil + end + rescue MissingTranslationData + nil + end + + # Picks a translation from an array according to English pluralization + # rules. It will pick the first translation if count is not equal to 1 + # and the second translation if it is equal to 1. Other backends can + # implement more flexible or complex pluralization rules. + def pluralize(locale, entry, count) + return entry unless entry.is_a?(Hash) and count + # raise InvalidPluralizationData.new(entry, count) unless entry.is_a?(Hash) + key = :zero if count == 0 && entry.has_key?(:zero) + key ||= count == 1 ? :one : :many + raise InvalidPluralizationData.new(entry, count) unless entry.has_key?(key) + entry[key] end + + # Interpolates values into a given string. + # + # interpolate "file {{file}} opened by \\{{user}}", :file => 'test.txt', :user => 'Mr. X' + # # => "file test.txt opened by {{user}}" + # + # Note that you have to double escape the \\ when you want to escape + # the {{...}} key in a string (once for the string and once for the + # interpolation). + def interpolate(locale, string, values = {}) + return string if !string.is_a?(String) + + map = {'%d' => '{{count}}', '%s' => '{{value}}'} # TODO deprecate this? + string.gsub!(/#{map.keys.join('|')}/){|key| map[key]} - def translate(locale, key, options = {}) - raise InvalidLocale.new(locale) if locale.nil? - return key.map{|key| translate locale, key, options } if key.is_a? Array + s = StringScanner.new string.dup + while s.skip_until(/\{\{/) + s.string[s.pos - 3, 1] = '' and next if s.pre_match[-1, 1] == '\\' + start_pos = s.pos - 2 + key = s.scan_until(/\}\}/)[0..-3] + end_pos = s.pos - 1 - reserved = :scope, :default - count, scope, default = options.values_at(:count, *reserved) - options.delete(:default) - values = options.reject{|name, value| reserved.include? name } + raise ReservedInterpolationKey.new(key, string) if %w(scope default).include?(key) + raise MissingInterpolationArgument.new(key, string) unless values.has_key? key.to_sym - entry = lookup(locale, key, scope) || default(locale, default, options) || raise(I18n::MissingTranslationData.new(locale, key, options)) - entry = pluralize locale, entry, count - entry = interpolate locale, entry, values - entry + s.string[start_pos..end_pos] = values[key.to_sym].to_s + s.unscan + end + s.string end - # Acts the same as +strftime+, but returns a localized version of the - # formatted date string. Takes a key from the date/time formats - # translations as a format argument (e.g., :short in :'date.formats'). - def localize(locale, object, format = :default) - raise ArgumentError, "Object must be a Date, DateTime or Time object. #{object.inspect} given." unless object.respond_to?(:strftime) - - type = object.respond_to?(:sec) ? 'time' : 'date' - formats = translate(locale, :"#{type}.formats") - format = formats[format.to_sym] if formats && formats[format.to_sym] - # TODO raise exception unless format found? - format = format.to_s.dup - - format.gsub!(/%a/, translate(locale, :"date.abbr_day_names")[object.wday]) - format.gsub!(/%A/, translate(locale, :"date.day_names")[object.wday]) - format.gsub!(/%b/, translate(locale, :"date.abbr_month_names")[object.mon]) - format.gsub!(/%B/, translate(locale, :"date.month_names")[object.mon]) - format.gsub!(/%p/, translate(locale, :"time.#{object.hour < 12 ? :am : :pm}")) if object.respond_to? :hour - object.strftime(format) + # Loads a single translations file by delegating to #load_rb or + # #load_yml depending on the file extension and directly merges the + # data to the existing translations. Raises I18n::UnknownFileType + # for all other file extensions. + def load_file(filename) + type = File.extname(filename).tr('.', '').downcase + raise UnknownFileType.new(type, filename) unless respond_to? :"load_#{type}" + data = send :"load_#{type}", filename # TODO raise a meaningful exception if this does not yield a Hash + data.each do |locale, data| + merge_translations locale, data + end end - protected - - # Looks up a translation from the translations hash. Returns nil if - # eiher key is nil, or locale, scope or key do not exist as a key in the - # nested translations hash. Splits keys or scopes containing dots - # into multiple keys, i.e. currency.format is regarded the same as - # %w(currency format). - def lookup(locale, key, scope = []) - return unless key - keys = I18n.send :normalize_translation_keys, locale, key, scope - keys.inject(@@translations){|result, key| result[key.to_sym] or return nil } - end + # Loads a plain Ruby translations file. eval'ing the file must yield + # a Hash containing translation data with locales as toplevel keys. + def load_rb(filename) + eval IO.read(filename), binding, filename + end - # Evaluates a default translation. - # If the given default is a String it is used literally. If it is a Symbol - # it will be translated with the given options. If it is an Array the first - # translation yielded will be returned. - # - # I.e., default(locale, [:foo, 'default']) will return +default+ if - # translate(locale, :foo) does not yield a result. - def default(locale, default, options = {}) - case default - when String then default - when Symbol then translate locale, default, options - when Array then default.each do |obj| - result = default(locale, obj, options.dup) and return result - end and nil - end - rescue MissingTranslationData - nil - end + # Loads a YAML translations file. The data must have locales as + # toplevel keys. + def load_yml(filename) + YAML::load IO.read(filename) + end - # Picks a translation from an array according to English pluralization - # rules. It will pick the first translation if count is not equal to 1 - # and the second translation if it is equal to 1. Other backends can - # implement more flexible or complex pluralization rules. - def pluralize(locale, entry, count) - return entry unless entry.is_a?(Hash) and count - # raise InvalidPluralizationData.new(entry, count) unless entry.is_a?(Hash) - key = :zero if count == 0 && entry.has_key?(:zero) - key ||= count == 1 ? :one : :many - raise InvalidPluralizationData.new(entry, count) unless entry.has_key?(key) - entry[key] - end - - # Interpolates values into a given string. - # - # interpolate "file {{file}} opened by \\{{user}}", :file => 'test.txt', :user => 'Mr. X' - # # => "file test.txt opened by {{user}}" - # - # Note that you have to double escape the \\ when you want to escape - # the {{...}} key in a string (once for the string and once for the - # interpolation). - def interpolate(locale, string, values = {}) - return string if !string.is_a?(String) - - map = {'%d' => '{{count}}', '%s' => '{{value}}'} # TODO deprecate this? - string.gsub!(/#{map.keys.join('|')}/){|key| map[key]} - - s = StringScanner.new string.dup - while s.skip_until(/\{\{/) - s.string[s.pos - 3, 1] = '' and next if s.pre_match[-1, 1] == '\\' - start_pos = s.pos - 2 - key = s.scan_until(/\}\}/)[0..-3] - end_pos = s.pos - 1 - - raise ReservedInterpolationKey.new(key, string) if %w(scope default).include?(key) - raise MissingInterpolationArgument.new(key, string) unless values.has_key? key.to_sym - - s.string[start_pos..end_pos] = values[key.to_sym].to_s - s.unscan - end - s.string - end - - # Loads a single translations file by delegating to #load_rb or - # #load_yml depending on the file extension and directly merges the - # data to the existing translations. Raises I18n::UnknownFileType - # for all other file extensions. - def load_file(filename) - type = File.extname(filename).tr('.', '').downcase - raise UnknownFileType.new(type, filename) unless respond_to? :"load_#{type}" - data = send :"load_#{type}", filename # TODO raise a meaningful exception if this does not yield a Hash - data.each do |locale, data| - merge_translations locale, data - end - end - - # Loads a plain Ruby translations file. eval'ing the file must yield - # a Hash containing translation data with locales as toplevel keys. - def load_rb(filename) - eval IO.read(filename), binding, filename - end - - # Loads a YAML translations file. The data must have locales as - # toplevel keys. - def load_yml(filename) - YAML::load IO.read(filename) - end - - # Deep merges the given translations hash with the existing translations - # for the given locale - def merge_translations(locale, data) - locale = locale.to_sym - @@translations[locale] ||= {} - data = deep_symbolize_keys data + # Deep merges the given translations hash with the existing translations + # for the given locale + def merge_translations(locale, data) + locale = locale.to_sym + translations[locale] ||= {} + data = deep_symbolize_keys data - # deep_merge by Stefan Rusterholz, see http://www.ruby-forum.com/topic/142809 - merger = proc{|key, v1, v2| Hash === v1 && Hash === v2 ? v1.merge(v2, &merger) : v2 } - @@translations[locale].merge! data, &merger - end - - # Return a new hash with all keys and nested keys converted to symbols. - def deep_symbolize_keys(hash) - hash.inject({}){|result, (key, value)| - value = deep_symbolize_keys(value) if value.is_a? Hash - result[(key.to_sym rescue key) || key] = value - result - } - end - end + # deep_merge by Stefan Rusterholz, see http://www.ruby-forum.com/topic/142809 + merger = proc{|key, v1, v2| Hash === v1 && Hash === v2 ? v1.merge(v2, &merger) : v2 } + translations[locale].merge! data, &merger + end + + # Return a new hash with all keys and nested keys converted to symbols. + def deep_symbolize_keys(hash) + hash.inject({}){|result, (key, value)| + value = deep_symbolize_keys(value) if value.is_a? Hash + result[(key.to_sym rescue key) || key] = value + result + } + end end end end -- cgit v1.2.3 From 5de340e79f1d11973b7c7bbec82f320fc92b9c99 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Tue, 19 Aug 2008 19:20:10 -0500 Subject: Ensure objects cached with MemoryStore are immutable --- activesupport/lib/active_support/cache/memory_store.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'activesupport/lib') diff --git a/activesupport/lib/active_support/cache/memory_store.rb b/activesupport/lib/active_support/cache/memory_store.rb index 7ac6f35357..f3e4b8c13b 100644 --- a/activesupport/lib/active_support/cache/memory_store.rb +++ b/activesupport/lib/active_support/cache/memory_store.rb @@ -22,7 +22,7 @@ module ActiveSupport def write(name, value, options = nil) @guard.synchronize do super - @data[name] = value + @data[name] = value.freeze end end -- cgit v1.2.3 From a6a62004c93d792c230d80f8a65da0bb45cb369f Mon Sep 17 00:00:00 2001 From: Sven Fuchs Date: Wed, 20 Aug 2008 17:51:42 +0200 Subject: add human_name and value to ar validation #generate_message --- activesupport/lib/active_support/vendor/i18n-0.0.1/i18n.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'activesupport/lib') diff --git a/activesupport/lib/active_support/vendor/i18n-0.0.1/i18n.rb b/activesupport/lib/active_support/vendor/i18n-0.0.1/i18n.rb index 145840aa36..0e2a2d7051 100755 --- a/activesupport/lib/active_support/vendor/i18n-0.0.1/i18n.rb +++ b/activesupport/lib/active_support/vendor/i18n-0.0.1/i18n.rb @@ -63,7 +63,7 @@ module I18n # files which are either named *.rb and contain plain Ruby Hashes or are # named *.yml and contain YAML data.) def load_translations(*args) - backend.load_translations *args + backend.load_translations(*args) end # Stores translations for the given locale in the backend. -- cgit v1.2.3 From c1e0d8aa48c2f9139af42b3cf79e42bb5e0f1f03 Mon Sep 17 00:00:00 2001 From: Iain Hecker Date: Tue, 19 Aug 2008 23:21:32 +0200 Subject: Locale file changed to yaml --- activesupport/lib/active_support.rb | 2 +- activesupport/lib/active_support/locale/en-US.rb | 29 --------------------- activesupport/lib/active_support/locale/en-US.yml | 31 +++++++++++++++++++++++ 3 files changed, 32 insertions(+), 30 deletions(-) delete mode 100644 activesupport/lib/active_support/locale/en-US.rb create mode 100644 activesupport/lib/active_support/locale/en-US.yml (limited to 'activesupport/lib') diff --git a/activesupport/lib/active_support.rb b/activesupport/lib/active_support.rb index 6056067efd..46ca9f93df 100644 --- a/activesupport/lib/active_support.rb +++ b/activesupport/lib/active_support.rb @@ -59,7 +59,7 @@ require 'active_support/base64' require 'active_support/time_with_zone' I18n.populate do - I18n.load_translations File.dirname(__FILE__) + '/active_support/locale/en-US.rb' + I18n.load_translations File.dirname(__FILE__) + '/active_support/locale/en-US.yml' end Inflector = ActiveSupport::Deprecation::DeprecatedConstantProxy.new('Inflector', 'ActiveSupport::Inflector') diff --git a/activesupport/lib/active_support/locale/en-US.rb b/activesupport/lib/active_support/locale/en-US.rb deleted file mode 100644 index ed457d6f4f..0000000000 --- a/activesupport/lib/active_support/locale/en-US.rb +++ /dev/null @@ -1,29 +0,0 @@ -{ :'en-US' => { - :support => { - :array => { - :sentence_connector => 'and' - } - }, - :date => { - :formats => { - :default => "%Y-%m-%d", - :short => "%b %d", - :long => "%B %d, %Y", - }, - :day_names => Date::DAYNAMES, - :abbr_day_names => Date::ABBR_DAYNAMES, - :month_names => Date::MONTHNAMES, - :abbr_month_names => Date::ABBR_MONTHNAMES, - :order => [:year, :month, :day] - }, - :time => { - :formats => { - :default => "%a, %d %b %Y %H:%M:%S %z", - :short => "%d %b %H:%M", - :long => "%B %d, %Y %H:%M", - }, - :am => 'am', - :pm => 'pm' - } - } -} \ No newline at end of file diff --git a/activesupport/lib/active_support/locale/en-US.yml b/activesupport/lib/active_support/locale/en-US.yml new file mode 100644 index 0000000000..60ecb1d42a --- /dev/null +++ b/activesupport/lib/active_support/locale/en-US.yml @@ -0,0 +1,31 @@ +en-US: + date: + formats: + # Use the strftime parameters for formats. + # When no format has been given, it uses default. + # You can provide other formats here if you like! + 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] + # Used in date_select and datime_select. + order: [ :year, :month, :day ] + + time: + formats: + default: "%a, %d %b %Y %H:%M:%S %z" + short: "%d %b %H:%M" + long: "%B %d, %Y %H:%M" + am: "am" + pm: "pm" + +# Used in array.to_sentence. + support: + array: + sentence_connector: "and" -- cgit v1.2.3 From f388725bd61d8ae246c0c8e42eaec1a2be4620ac Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Thu, 21 Aug 2008 00:28:25 -0500 Subject: Partial revert of 2681685 premature TypeArray abstraction --- activesupport/lib/active_support.rb | 1 - activesupport/lib/active_support/typed_array.rb | 31 ------------------------- 2 files changed, 32 deletions(-) delete mode 100644 activesupport/lib/active_support/typed_array.rb (limited to 'activesupport/lib') diff --git a/activesupport/lib/active_support.rb b/activesupport/lib/active_support.rb index 51067e910e..1df911a3f2 100644 --- a/activesupport/lib/active_support.rb +++ b/activesupport/lib/active_support.rb @@ -39,7 +39,6 @@ require 'active_support/cache' require 'active_support/dependencies' require 'active_support/deprecation' -require 'active_support/typed_array' require 'active_support/ordered_hash' require 'active_support/ordered_options' require 'active_support/option_merger' diff --git a/activesupport/lib/active_support/typed_array.rb b/activesupport/lib/active_support/typed_array.rb deleted file mode 100644 index 1a4d8a8faf..0000000000 --- a/activesupport/lib/active_support/typed_array.rb +++ /dev/null @@ -1,31 +0,0 @@ -module ActiveSupport - class TypedArray < Array - def self.type_cast(obj) - obj - end - - def initialize(*args) - super(*args).map! { |obj| self.class.type_cast(obj) } - end - - def <<(obj) - super(self.class.type_cast(obj)) - end - - def concat(array) - super(array.map! { |obj| self.class.type_cast(obj) }) - end - - def insert(index, obj) - super(index, self.class.type_cast(obj)) - end - - def push(*objs) - super(*objs.map { |obj| self.class.type_cast(obj) }) - end - - def unshift(*objs) - super(*objs.map { |obj| self.class.type_cast(obj) }) - end - end -end -- cgit v1.2.3 From 6be8251ec86b74b92e7bd922fafe9224281d2d26 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Thu, 21 Aug 2008 00:51:06 -0500 Subject: Simplified and renamed CallbackChain union method to replace_or_append! --- activesupport/lib/active_support/callbacks.rb | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) (limited to 'activesupport/lib') diff --git a/activesupport/lib/active_support/callbacks.rb b/activesupport/lib/active_support/callbacks.rb index 9c59b7ac76..7b905930bb 100644 --- a/activesupport/lib/active_support/callbacks.rb +++ b/activesupport/lib/active_support/callbacks.rb @@ -96,15 +96,12 @@ module ActiveSupport end end - def |(chain) - if chain.is_a?(CallbackChain) - chain.each { |callback| self | callback } + # TODO: Decompose into more Array like behavior + def replace_or_append!(chain) + if index = index(chain) + self[index] = chain else - if (found_callback = find(chain)) && (index = index(chain)) - self[index] = chain - else - self << chain - end + self << chain end self end @@ -157,6 +154,14 @@ module ActiveSupport self.class.new(@kind, @method, @options.dup) end + def hash + if @identifier + @identifier.hash + else + @method.hash + end + end + def call(*args, &block) evaluate_method(method, *args, &block) if should_run_callback?(*args) rescue LocalJumpError -- cgit v1.2.3 From 654c41255d22b2767b943dbe970d8b24f2a1387b Mon Sep 17 00:00:00 2001 From: Frederick Cheung Date: Thu, 21 Aug 2008 18:23:18 +0100 Subject: Mark Class as not being duplicable. [#829 state:resolved] Signed-off-by: Pratik Naik --- activesupport/lib/active_support/core_ext/duplicable.rb | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'activesupport/lib') diff --git a/activesupport/lib/active_support/core_ext/duplicable.rb b/activesupport/lib/active_support/core_ext/duplicable.rb index adbbfd8c60..8f49ddfd9e 100644 --- a/activesupport/lib/active_support/core_ext/duplicable.rb +++ b/activesupport/lib/active_support/core_ext/duplicable.rb @@ -35,3 +35,9 @@ class Numeric #:nodoc: false end end + +class Class #:nodoc: + def duplicable? + false + end +end -- cgit v1.2.3 From 381210daa0b8db26be85841b8ccf889d0ef67d75 Mon Sep 17 00:00:00 2001 From: Amos King Date: Fri, 22 Aug 2008 13:31:13 +0100 Subject: camelize(:lower) should always downcase first character. [#696 state:resolved] Signed-off-by: Pratik Naik --- activesupport/lib/active_support/inflector.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'activesupport/lib') diff --git a/activesupport/lib/active_support/inflector.rb b/activesupport/lib/active_support/inflector.rb index c2738b39fc..1e189465bd 100644 --- a/activesupport/lib/active_support/inflector.rb +++ b/activesupport/lib/active_support/inflector.rb @@ -173,7 +173,7 @@ module ActiveSupport if first_letter_in_uppercase lower_case_and_underscored_word.to_s.gsub(/\/(.?)/) { "::#{$1.upcase}" }.gsub(/(?:^|_)(.)/) { $1.upcase } else - lower_case_and_underscored_word.first + camelize(lower_case_and_underscored_word)[1..-1] + lower_case_and_underscored_word.first.downcase + camelize(lower_case_and_underscored_word)[1..-1] end end -- cgit v1.2.3 From 5232d812819d1d44187a54cb025835b1f9cb2296 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tarmo=20T=C3=A4nav?= Date: Sat, 23 Aug 2008 19:12:14 +0300 Subject: Pass class through to DeprecatedConstantProxy target This is needed because include_all_modules_from checks calls "class" on every constant and sometimes it can hit deprecated constants which aren't even Modules, but while checking for it deprecation warnings are shown. --- activesupport/lib/active_support/deprecation.rb | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'activesupport/lib') diff --git a/activesupport/lib/active_support/deprecation.rb b/activesupport/lib/active_support/deprecation.rb index ebdaf86146..01eb5df593 100644 --- a/activesupport/lib/active_support/deprecation.rb +++ b/activesupport/lib/active_support/deprecation.rb @@ -185,6 +185,10 @@ module ActiveSupport @new_const = new_const end + def class + target.class + end + private def target @new_const.to_s.constantize -- cgit v1.2.3 From a652c300ac9d60f6420d1cf86632f6a3c4ceef17 Mon Sep 17 00:00:00 2001 From: Peter Wagenet Date: Sat, 23 Aug 2008 13:33:07 -0400 Subject: New inflectors will overwrite defaults [#337 state:resolved] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Tarmo Tänav --- activesupport/lib/active_support/inflector.rb | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'activesupport/lib') diff --git a/activesupport/lib/active_support/inflector.rb b/activesupport/lib/active_support/inflector.rb index 1e189465bd..f2ca94115e 100644 --- a/activesupport/lib/active_support/inflector.rb +++ b/activesupport/lib/active_support/inflector.rb @@ -39,12 +39,16 @@ module ActiveSupport # Specifies a new pluralization rule and its replacement. The rule can either be a string or a regular expression. # The replacement should always be a string that may include references to the matched data from the rule. def plural(rule, replacement) + @uncountables.delete(rule) if rule.is_a?(String) + @uncountables.delete(replacement) @plurals.insert(0, [rule, replacement]) end # Specifies a new singularization rule and its replacement. The rule can either be a string or a regular expression. # The replacement should always be a string that may include references to the matched data from the rule. def singular(rule, replacement) + @uncountables.delete(rule) if rule.is_a?(String) + @uncountables.delete(replacement) @singulars.insert(0, [rule, replacement]) end @@ -55,6 +59,8 @@ module ActiveSupport # irregular 'octopus', 'octopi' # irregular 'person', 'people' def irregular(singular, plural) + @uncountables.delete(singular) + @uncountables.delete(plural) if singular[0,1].upcase == plural[0,1].upcase plural(Regexp.new("(#{singular[0,1]})#{singular[1..-1]}$", "i"), '\1' + plural[1..-1]) singular(Regexp.new("(#{plural[0,1]})#{plural[1..-1]}$", "i"), '\1' + singular[1..-1]) -- cgit v1.2.3 From d6989aa0e1fe5e49fe1fccc3702aa7ff62a63faf Mon Sep 17 00:00:00 2001 From: Sven Fuchs Date: Sat, 23 Aug 2008 19:43:57 +0200 Subject: I18n: use :other instead of :many as default key for pluralization to better conform w/ cldr pluralization rules Signed-off-by: Michael Koziarski --- .../lib/active_support/vendor/i18n-0.0.1/i18n/backend/simple.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'activesupport/lib') diff --git a/activesupport/lib/active_support/vendor/i18n-0.0.1/i18n/backend/simple.rb b/activesupport/lib/active_support/vendor/i18n-0.0.1/i18n/backend/simple.rb index 63ef55631f..6c7c54777c 100644 --- a/activesupport/lib/active_support/vendor/i18n-0.0.1/i18n/backend/simple.rb +++ b/activesupport/lib/active_support/vendor/i18n-0.0.1/i18n/backend/simple.rb @@ -104,7 +104,7 @@ module I18n return entry unless entry.is_a?(Hash) and count # raise InvalidPluralizationData.new(entry, count) unless entry.is_a?(Hash) key = :zero if count == 0 && entry.has_key?(:zero) - key ||= count == 1 ? :one : :many + key ||= count == 1 ? :one : :other raise InvalidPluralizationData.new(entry, count) unless entry.has_key?(key) entry[key] end -- cgit v1.2.3 From e7127be365a0a507c8538313b52ba62f476c2076 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Sat, 23 Aug 2008 15:59:59 -0700 Subject: Ruby 1.9: constantize takes advantage of new inherit arg to const_get and const_defined? --- activesupport/lib/active_support/inflector.rb | 63 +++++++++++++++++---------- 1 file changed, 39 insertions(+), 24 deletions(-) (limited to 'activesupport/lib') diff --git a/activesupport/lib/active_support/inflector.rb b/activesupport/lib/active_support/inflector.rb index f2ca94115e..7ae9e0c6ab 100644 --- a/activesupport/lib/active_support/inflector.rb +++ b/activesupport/lib/active_support/inflector.rb @@ -279,32 +279,47 @@ module ActiveSupport underscore(demodulize(class_name)) + (separate_class_name_and_id_with_underscore ? "_id" : "id") end - # Tries to find a constant with the name specified in the argument string: - # - # "Module".constantize # => Module - # "Test::Unit".constantize # => Test::Unit - # - # The name is assumed to be the one of a top-level constant, no matter whether - # it starts with "::" or not. No lexical context is taken into account: - # - # C = 'outside' - # module M - # C = 'inside' - # C # => 'inside' - # "C".constantize # => 'outside', same as ::C - # end - # - # NameError is raised when the name is not in CamelCase or the constant is - # unknown. - def constantize(camel_cased_word) - names = camel_cased_word.split('::') - names.shift if names.empty? || names.first.empty? + # Ruby 1.9 introduces an inherit argument for Module#const_get and + # #const_defined? and changes their default behavior. + if Module.method(:const_get).arity == 1 + # Tries to find a constant with the name specified in the argument string: + # + # "Module".constantize # => Module + # "Test::Unit".constantize # => Test::Unit + # + # The name is assumed to be the one of a top-level constant, no matter whether + # it starts with "::" or not. No lexical context is taken into account: + # + # C = 'outside' + # module M + # C = 'inside' + # C # => 'inside' + # "C".constantize # => 'outside', same as ::C + # end + # + # NameError is raised when the name is not in CamelCase or the constant is + # unknown. + def constantize(camel_cased_word) + names = camel_cased_word.split('::') + names.shift if names.empty? || names.first.empty? + + constant = Object + names.each do |name| + constant = constant.const_defined?(name) ? constant.const_get(name) : constant.const_missing(name) + end + constant + end + else + def constantize(camel_cased_word) #:nodoc: + names = camel_cased_word.split('::') + names.shift if names.empty? || names.first.empty? - constant = Object - names.each do |name| - constant = constant.const_defined?(name) ? constant.const_get(name) : constant.const_missing(name) + constant = Object + names.each do |name| + constant = constant.const_get(name, false) || constant.const_missing(name) + end + constant end - constant end # Turns a number into an ordinal string used to denote the position in an -- cgit v1.2.3 From 92a7239a3dd1de672730f7b0bcf5f5d2cb0f877f Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Sat, 23 Aug 2008 16:03:00 -0700 Subject: Ruby 1.9: silence some warnings for block args shadowing local vars --- activesupport/lib/active_support/vendor/i18n-0.0.1/i18n.rb | 4 ++-- .../active_support/vendor/i18n-0.0.1/i18n/backend/simple.rb | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) (limited to 'activesupport/lib') diff --git a/activesupport/lib/active_support/vendor/i18n-0.0.1/i18n.rb b/activesupport/lib/active_support/vendor/i18n-0.0.1/i18n.rb index 0e2a2d7051..9e347d94e9 100755 --- a/activesupport/lib/active_support/vendor/i18n-0.0.1/i18n.rb +++ b/activesupport/lib/active_support/vendor/i18n-0.0.1/i18n.rb @@ -183,8 +183,8 @@ module I18n # keys are Symbols. def normalize_translation_keys(locale, key, scope) keys = [locale] + Array(scope) + [key] - keys = keys.map{|key| key.to_s.split(/\./) } - keys.flatten.map{|key| key.to_sym} + keys = keys.map{|k| k.to_s.split(/\./) } + keys.flatten.map{|k| k.to_sym} end end end diff --git a/activesupport/lib/active_support/vendor/i18n-0.0.1/i18n/backend/simple.rb b/activesupport/lib/active_support/vendor/i18n-0.0.1/i18n/backend/simple.rb index 6c7c54777c..43ff686514 100644 --- a/activesupport/lib/active_support/vendor/i18n-0.0.1/i18n/backend/simple.rb +++ b/activesupport/lib/active_support/vendor/i18n-0.0.1/i18n/backend/simple.rb @@ -27,7 +27,7 @@ module I18n def translate(locale, key, options = {}) raise InvalidLocale.new(locale) if locale.nil? - return key.map{|key| translate locale, key, options } if key.is_a? Array + return key.map{|k| translate locale, k, options } if key.is_a? Array reserved = :scope, :default count, scope, default = options.values_at(:count, *reserved) @@ -74,7 +74,7 @@ module I18n def lookup(locale, key, scope = []) return unless key keys = I18n.send :normalize_translation_keys, locale, key, scope - keys.inject(translations){|result, key| result[key.to_sym] or return nil } + keys.inject(translations){|result, k| result[k.to_sym] or return nil } end # Evaluates a default translation. @@ -147,9 +147,9 @@ module I18n type = File.extname(filename).tr('.', '').downcase raise UnknownFileType.new(type, filename) unless respond_to? :"load_#{type}" data = send :"load_#{type}", filename # TODO raise a meaningful exception if this does not yield a Hash - data.each do |locale, data| - merge_translations locale, data - end + data.each do |locale, d| + merge_translations locale, d + end end # Loads a plain Ruby translations file. eval'ing the file must yield -- cgit v1.2.3 From bb3dd6ad2e5f823b21fc02dcc5b23aa5d4bf6465 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Sat, 23 Aug 2008 21:51:06 -0700 Subject: Ruby 1.9 compat: update bundled i18n lib --- .../lib/active_support/vendor/i18n-0.0.1/i18n.rb | 4 +- .../vendor/i18n-0.0.1/i18n/backend/simple.rb | 338 +++++++++++---------- 2 files changed, 174 insertions(+), 168 deletions(-) (limited to 'activesupport/lib') diff --git a/activesupport/lib/active_support/vendor/i18n-0.0.1/i18n.rb b/activesupport/lib/active_support/vendor/i18n-0.0.1/i18n.rb index 9e347d94e9..d4adbde727 100755 --- a/activesupport/lib/active_support/vendor/i18n-0.0.1/i18n.rb +++ b/activesupport/lib/active_support/vendor/i18n-0.0.1/i18n.rb @@ -9,14 +9,14 @@ require 'i18n/backend/simple' require 'i18n/exceptions' module I18n - @@backend = nil + @@backend = Backend::Simple @@default_locale = 'en-US' @@exception_handler = :default_exception_handler class << self # Returns the current backend. Defaults to +Backend::Simple+. def backend - @@backend ||= Backend::Simple.new + @@backend end # Sets the current backend. Used to set a custom backend. diff --git a/activesupport/lib/active_support/vendor/i18n-0.0.1/i18n/backend/simple.rb b/activesupport/lib/active_support/vendor/i18n-0.0.1/i18n/backend/simple.rb index 43ff686514..917646fffe 100644 --- a/activesupport/lib/active_support/vendor/i18n-0.0.1/i18n/backend/simple.rb +++ b/activesupport/lib/active_support/vendor/i18n-0.0.1/i18n/backend/simple.rb @@ -2,188 +2,194 @@ require 'strscan' module I18n module Backend - class Simple - # Allow client libraries to pass a block that populates the translation - # storage. Decoupled for backends like a db backend that persist their - # translations, so the backend can decide whether/when to yield or not. - def populate(&block) - yield - end - - # Accepts a list of paths to translation files. Loads translations from - # plain Ruby (*.rb) or YAML files (*.yml). See #load_rb and #load_yml - # for details. - def load_translations(*filenames) - filenames.each {|filename| load_file filename } - end - - # Stores translations for the given locale in memory. - # This uses a deep merge for the translations hash, so existing - # translations will be overwritten by new ones only at the deepest - # level of the hash. - def store_translations(locale, data) - merge_translations(locale, data) - end - - def translate(locale, key, options = {}) - raise InvalidLocale.new(locale) if locale.nil? - return key.map{|k| translate locale, k, options } if key.is_a? Array - - reserved = :scope, :default - count, scope, default = options.values_at(:count, *reserved) - options.delete(:default) - values = options.reject{|name, value| reserved.include? name } - - entry = lookup(locale, key, scope) || default(locale, default, options) || raise(I18n::MissingTranslationData.new(locale, key, options)) - entry = pluralize locale, entry, count - entry = interpolate locale, entry, values - entry - end + module Simple + @@translations = {} - # Acts the same as +strftime+, but returns a localized version of the - # formatted date string. Takes a key from the date/time formats - # translations as a format argument (e.g., :short in :'date.formats'). - def localize(locale, object, format = :default) - raise ArgumentError, "Object must be a Date, DateTime or Time object. #{object.inspect} given." unless object.respond_to?(:strftime) - - type = object.respond_to?(:sec) ? 'time' : 'date' - formats = translate(locale, :"#{type}.formats") - format = formats[format.to_sym] if formats && formats[format.to_sym] - # TODO raise exception unless format found? - format = format.to_s.dup - - format.gsub!(/%a/, translate(locale, :"date.abbr_day_names")[object.wday]) - format.gsub!(/%A/, translate(locale, :"date.day_names")[object.wday]) - format.gsub!(/%b/, translate(locale, :"date.abbr_month_names")[object.mon]) - format.gsub!(/%B/, translate(locale, :"date.month_names")[object.mon]) - format.gsub!(/%p/, translate(locale, :"time.#{object.hour < 12 ? :am : :pm}")) if object.respond_to? :hour - object.strftime(format) - end - - protected - - def translations - @translations ||= {} - end - - # Looks up a translation from the translations hash. Returns nil if - # eiher key is nil, or locale, scope or key do not exist as a key in the - # nested translations hash. Splits keys or scopes containing dots - # into multiple keys, i.e. currency.format is regarded the same as - # %w(currency format). - def lookup(locale, key, scope = []) - return unless key - keys = I18n.send :normalize_translation_keys, locale, key, scope - keys.inject(translations){|result, k| result[k.to_sym] or return nil } + class << self + # Allow client libraries to pass a block that populates the translation + # storage. Decoupled for backends like a db backend that persist their + # translations, so the backend can decide whether/when to yield or not. + def populate(&block) + yield end - # Evaluates a default translation. - # If the given default is a String it is used literally. If it is a Symbol - # it will be translated with the given options. If it is an Array the first - # translation yielded will be returned. - # - # I.e., default(locale, [:foo, 'default']) will return +default+ if - # translate(locale, :foo) does not yield a result. - def default(locale, default, options = {}) - case default - when String then default - when Symbol then translate locale, default, options - when Array then default.each do |obj| - result = default(locale, obj, options.dup) and return result - end and nil - end - rescue MissingTranslationData - nil + # Accepts a list of paths to translation files. Loads translations from + # plain Ruby (*.rb) or YAML files (*.yml). See #load_rb and #load_yml + # for details. + def load_translations(*filenames) + filenames.each {|filename| load_file filename } end - - # Picks a translation from an array according to English pluralization - # rules. It will pick the first translation if count is not equal to 1 - # and the second translation if it is equal to 1. Other backends can - # implement more flexible or complex pluralization rules. - def pluralize(locale, entry, count) - return entry unless entry.is_a?(Hash) and count - # raise InvalidPluralizationData.new(entry, count) unless entry.is_a?(Hash) - key = :zero if count == 0 && entry.has_key?(:zero) - key ||= count == 1 ? :one : :other - raise InvalidPluralizationData.new(entry, count) unless entry.has_key?(key) - entry[key] + + # Stores translations for the given locale in memory. + # This uses a deep merge for the translations hash, so existing + # translations will be overwritten by new ones only at the deepest + # level of the hash. + def store_translations(locale, data) + merge_translations(locale, data) end - - # Interpolates values into a given string. - # - # interpolate "file {{file}} opened by \\{{user}}", :file => 'test.txt', :user => 'Mr. X' - # # => "file test.txt opened by {{user}}" - # - # Note that you have to double escape the \\ when you want to escape - # the {{...}} key in a string (once for the string and once for the - # interpolation). - def interpolate(locale, string, values = {}) - return string if !string.is_a?(String) - - map = {'%d' => '{{count}}', '%s' => '{{value}}'} # TODO deprecate this? - string.gsub!(/#{map.keys.join('|')}/){|key| map[key]} - s = StringScanner.new string.dup - while s.skip_until(/\{\{/) - s.string[s.pos - 3, 1] = '' and next if s.pre_match[-1, 1] == '\\' - start_pos = s.pos - 2 - key = s.scan_until(/\}\}/)[0..-3] - end_pos = s.pos - 1 + def translate(locale, key, options = {}) + raise InvalidLocale.new(locale) if locale.nil? + return key.map{|k| translate locale, k, options } if key.is_a? Array - raise ReservedInterpolationKey.new(key, string) if %w(scope default).include?(key) - raise MissingInterpolationArgument.new(key, string) unless values.has_key? key.to_sym + reserved = :scope, :default + count, scope, default = options.values_at(:count, *reserved) + options.delete(:default) + values = options.reject{|name, value| reserved.include? name } - s.string[start_pos..end_pos] = values[key.to_sym].to_s - s.unscan - end - s.string + entry = lookup(locale, key, scope) || default(locale, default, options) || raise(I18n::MissingTranslationData.new(locale, key, options)) + entry = pluralize locale, entry, count + entry = interpolate locale, entry, values + entry end - # Loads a single translations file by delegating to #load_rb or - # #load_yml depending on the file extension and directly merges the - # data to the existing translations. Raises I18n::UnknownFileType - # for all other file extensions. - def load_file(filename) - type = File.extname(filename).tr('.', '').downcase - raise UnknownFileType.new(type, filename) unless respond_to? :"load_#{type}" - data = send :"load_#{type}", filename # TODO raise a meaningful exception if this does not yield a Hash - data.each do |locale, d| - merge_translations locale, d - end + # Acts the same as +strftime+, but returns a localized version of the + # formatted date string. Takes a key from the date/time formats + # translations as a format argument (e.g., :short in :'date.formats'). + def localize(locale, object, format = :default) + raise ArgumentError, "Object must be a Date, DateTime or Time object. #{object.inspect} given." unless object.respond_to?(:strftime) + + type = object.respond_to?(:sec) ? 'time' : 'date' + formats = translate(locale, :"#{type}.formats") + format = formats[format.to_sym] if formats && formats[format.to_sym] + # TODO raise exception unless format found? + format = format.to_s.dup + + format.gsub!(/%a/, translate(locale, :"date.abbr_day_names")[object.wday]) + format.gsub!(/%A/, translate(locale, :"date.day_names")[object.wday]) + format.gsub!(/%b/, translate(locale, :"date.abbr_month_names")[object.mon]) + format.gsub!(/%B/, translate(locale, :"date.month_names")[object.mon]) + format.gsub!(/%p/, translate(locale, :"time.#{object.hour < 12 ? :am : :pm}")) if object.respond_to? :hour + object.strftime(format) end - # Loads a plain Ruby translations file. eval'ing the file must yield - # a Hash containing translation data with locales as toplevel keys. - def load_rb(filename) - eval IO.read(filename), binding, filename - end + protected - # Loads a YAML translations file. The data must have locales as - # toplevel keys. - def load_yml(filename) - YAML::load IO.read(filename) - end + # Looks up a translation from the translations hash. Returns nil if + # eiher key is nil, or locale, scope or key do not exist as a key in the + # nested translations hash. Splits keys or scopes containing dots + # into multiple keys, i.e. currency.format is regarded the same as + # %w(currency format). + def lookup(locale, key, scope = []) + return unless key + keys = I18n.send :normalize_translation_keys, locale, key, scope + keys.inject(@@translations){|result, k| result[k.to_sym] or return nil } + end - # Deep merges the given translations hash with the existing translations - # for the given locale - def merge_translations(locale, data) - locale = locale.to_sym - translations[locale] ||= {} - data = deep_symbolize_keys data - - # deep_merge by Stefan Rusterholz, see http://www.ruby-forum.com/topic/142809 - merger = proc{|key, v1, v2| Hash === v1 && Hash === v2 ? v1.merge(v2, &merger) : v2 } - translations[locale].merge! data, &merger - end + # Evaluates a default translation. + # If the given default is a String it is used literally. If it is a Symbol + # it will be translated with the given options. If it is an Array the first + # translation yielded will be returned. + # + # I.e., default(locale, [:foo, 'default']) will return +default+ if + # translate(locale, :foo) does not yield a result. + def default(locale, default, options = {}) + case default + when String then default + when Symbol then translate locale, default, options + when Array then default.each do |obj| + result = default(locale, obj, options.dup) and return result + end and nil + end + rescue MissingTranslationData + nil + end - # Return a new hash with all keys and nested keys converted to symbols. - def deep_symbolize_keys(hash) - hash.inject({}){|result, (key, value)| - value = deep_symbolize_keys(value) if value.is_a? Hash - result[(key.to_sym rescue key) || key] = value + # Picks a translation from an array according to English pluralization + # rules. It will pick the first translation if count is not equal to 1 + # and the second translation if it is equal to 1. Other backends can + # implement more flexible or complex pluralization rules. + def pluralize(locale, entry, count) + return entry unless entry.is_a?(Hash) and count + # raise InvalidPluralizationData.new(entry, count) unless entry.is_a?(Hash) + key = :zero if count == 0 && entry.has_key?(:zero) + key ||= count == 1 ? :one : :many + raise InvalidPluralizationData.new(entry, count) unless entry.has_key?(key) + entry[key] + end + + # Interpolates values into a given string. + # + # interpolate "file {{file}} opened by \\{{user}}", :file => 'test.txt', :user => 'Mr. X' + # # => "file test.txt opened by {{user}}" + # + # Note that you have to double escape the \\ when you want to escape + # the {{...}} key in a string (once for the string and once for the + # interpolation). + def interpolate(locale, string, values = {}) + return string if !string.is_a?(String) + + string = string.gsub(/%d/, '{{count}}').gsub(/%s/, '{{value}}') + if string.respond_to?(:force_encoding) + original_encoding = string.encoding + string.force_encoding(Encoding::BINARY) + end + + s = StringScanner.new(string) + while s.skip_until(/\{\{/) + s.string[s.pos - 3, 1] = '' and next if s.pre_match[-1, 1] == '\\' + start_pos = s.pos - 2 + key = s.scan_until(/\}\}/)[0..-3] + end_pos = s.pos - 1 + + raise ReservedInterpolationKey.new(key, string) if %w(scope default).include?(key) + raise MissingInterpolationArgument.new(key, string) unless values.has_key? key.to_sym + + s.string[start_pos..end_pos] = values[key.to_sym].to_s + s.unscan + end + + result = s.string + result.force_encoding(original_encoding) if original_encoding result - } - end + end + + # Loads a single translations file by delegating to #load_rb or + # #load_yml depending on the file extension and directly merges the + # data to the existing translations. Raises I18n::UnknownFileType + # for all other file extensions. + def load_file(filename) + type = File.extname(filename).tr('.', '').downcase + raise UnknownFileType.new(type, filename) unless respond_to? :"load_#{type}" + data = send :"load_#{type}", filename # TODO raise a meaningful exception if this does not yield a Hash + data.each do |locale, d| + merge_translations locale, d + end + end + + # Loads a plain Ruby translations file. eval'ing the file must yield + # a Hash containing translation data with locales as toplevel keys. + def load_rb(filename) + eval IO.read(filename), binding, filename + end + + # Loads a YAML translations file. The data must have locales as + # toplevel keys. + def load_yml(filename) + YAML::load IO.read(filename) + end + + # Deep merges the given translations hash with the existing translations + # for the given locale + def merge_translations(locale, data) + locale = locale.to_sym + @@translations[locale] ||= {} + data = deep_symbolize_keys data + + # deep_merge by Stefan Rusterholz, see http://www.ruby-forum.com/topic/142809 + merger = proc{|key, v1, v2| Hash === v1 && Hash === v2 ? v1.merge(v2, &merger) : v2 } + @@translations[locale].merge! data, &merger + end + + # Return a new hash with all keys and nested keys converted to symbols. + def deep_symbolize_keys(hash) + hash.inject({}){|result, (key, value)| + value = deep_symbolize_keys(value) if value.is_a? Hash + result[(key.to_sym rescue key) || key] = value + result + } + end + end end end end -- cgit v1.2.3 From a61e87aeb920e64ebfc79cfcbcee2508c900b4e2 Mon Sep 17 00:00:00 2001 From: Sven Fuchs Date: Mon, 25 Aug 2008 11:20:24 +0200 Subject: update i18n gem --- .../lib/active_support/vendor/i18n-0.0.1/i18n.rb | 4 +- .../vendor/i18n-0.0.1/i18n/backend/simple.rb | 344 ++++++++++----------- 2 files changed, 173 insertions(+), 175 deletions(-) (limited to 'activesupport/lib') diff --git a/activesupport/lib/active_support/vendor/i18n-0.0.1/i18n.rb b/activesupport/lib/active_support/vendor/i18n-0.0.1/i18n.rb index d4adbde727..9e347d94e9 100755 --- a/activesupport/lib/active_support/vendor/i18n-0.0.1/i18n.rb +++ b/activesupport/lib/active_support/vendor/i18n-0.0.1/i18n.rb @@ -9,14 +9,14 @@ require 'i18n/backend/simple' require 'i18n/exceptions' module I18n - @@backend = Backend::Simple + @@backend = nil @@default_locale = 'en-US' @@exception_handler = :default_exception_handler class << self # Returns the current backend. Defaults to +Backend::Simple+. def backend - @@backend + @@backend ||= Backend::Simple.new end # Sets the current backend. Used to set a custom backend. diff --git a/activesupport/lib/active_support/vendor/i18n-0.0.1/i18n/backend/simple.rb b/activesupport/lib/active_support/vendor/i18n-0.0.1/i18n/backend/simple.rb index 917646fffe..a53f7fe772 100644 --- a/activesupport/lib/active_support/vendor/i18n-0.0.1/i18n/backend/simple.rb +++ b/activesupport/lib/active_support/vendor/i18n-0.0.1/i18n/backend/simple.rb @@ -2,194 +2,192 @@ require 'strscan' module I18n module Backend - module Simple - @@translations = {} + class Simple + # Allow client libraries to pass a block that populates the translation + # storage. Decoupled for backends like a db backend that persist their + # translations, so the backend can decide whether/when to yield or not. + def populate(&block) + yield + end + + # Accepts a list of paths to translation files. Loads translations from + # plain Ruby (*.rb) or YAML files (*.yml). See #load_rb and #load_yml + # for details. + def load_translations(*filenames) + filenames.each {|filename| load_file filename } + end - class << self - # Allow client libraries to pass a block that populates the translation - # storage. Decoupled for backends like a db backend that persist their - # translations, so the backend can decide whether/when to yield or not. - def populate(&block) - yield - end + # Stores translations for the given locale in memory. + # This uses a deep merge for the translations hash, so existing + # translations will be overwritten by new ones only at the deepest + # level of the hash. + def store_translations(locale, data) + merge_translations(locale, data) + end - # Accepts a list of paths to translation files. Loads translations from - # plain Ruby (*.rb) or YAML files (*.yml). See #load_rb and #load_yml - # for details. - def load_translations(*filenames) - filenames.each {|filename| load_file filename } - end - - # Stores translations for the given locale in memory. - # This uses a deep merge for the translations hash, so existing - # translations will be overwritten by new ones only at the deepest - # level of the hash. - def store_translations(locale, data) - merge_translations(locale, data) - end - - def translate(locale, key, options = {}) - raise InvalidLocale.new(locale) if locale.nil? - return key.map{|k| translate locale, k, options } if key.is_a? Array + def translate(locale, key, options = {}) + raise InvalidLocale.new(locale) if locale.nil? + return key.map{|k| translate locale, k, options } if key.is_a? Array - reserved = :scope, :default - count, scope, default = options.values_at(:count, *reserved) - options.delete(:default) - values = options.reject{|name, value| reserved.include? name } + reserved = :scope, :default + count, scope, default = options.values_at(:count, *reserved) + options.delete(:default) + values = options.reject{|name, value| reserved.include? name } - entry = lookup(locale, key, scope) || default(locale, default, options) || raise(I18n::MissingTranslationData.new(locale, key, options)) - entry = pluralize locale, entry, count - entry = interpolate locale, entry, values - entry - end + entry = lookup(locale, key, scope) || default(locale, default, options) || raise(I18n::MissingTranslationData.new(locale, key, options)) + entry = pluralize locale, entry, count + entry = interpolate locale, entry, values + entry + end + + # Acts the same as +strftime+, but returns a localized version of the + # formatted date string. Takes a key from the date/time formats + # translations as a format argument (e.g., :short in :'date.formats'). + def localize(locale, object, format = :default) + raise ArgumentError, "Object must be a Date, DateTime or Time object. #{object.inspect} given." unless object.respond_to?(:strftime) - # Acts the same as +strftime+, but returns a localized version of the - # formatted date string. Takes a key from the date/time formats - # translations as a format argument (e.g., :short in :'date.formats'). - def localize(locale, object, format = :default) - raise ArgumentError, "Object must be a Date, DateTime or Time object. #{object.inspect} given." unless object.respond_to?(:strftime) - - type = object.respond_to?(:sec) ? 'time' : 'date' - formats = translate(locale, :"#{type}.formats") - format = formats[format.to_sym] if formats && formats[format.to_sym] - # TODO raise exception unless format found? - format = format.to_s.dup + type = object.respond_to?(:sec) ? 'time' : 'date' + formats = translate(locale, :"#{type}.formats") + format = formats[format.to_sym] if formats && formats[format.to_sym] + # TODO raise exception unless format found? + format = format.to_s.dup - format.gsub!(/%a/, translate(locale, :"date.abbr_day_names")[object.wday]) - format.gsub!(/%A/, translate(locale, :"date.day_names")[object.wday]) - format.gsub!(/%b/, translate(locale, :"date.abbr_month_names")[object.mon]) - format.gsub!(/%B/, translate(locale, :"date.month_names")[object.mon]) - format.gsub!(/%p/, translate(locale, :"time.#{object.hour < 12 ? :am : :pm}")) if object.respond_to? :hour - object.strftime(format) - end - - protected - - # Looks up a translation from the translations hash. Returns nil if - # eiher key is nil, or locale, scope or key do not exist as a key in the - # nested translations hash. Splits keys or scopes containing dots - # into multiple keys, i.e. currency.format is regarded the same as - # %w(currency format). - def lookup(locale, key, scope = []) - return unless key - keys = I18n.send :normalize_translation_keys, locale, key, scope - keys.inject(@@translations){|result, k| result[k.to_sym] or return nil } - end + format.gsub!(/%a/, translate(locale, :"date.abbr_day_names")[object.wday]) + format.gsub!(/%A/, translate(locale, :"date.day_names")[object.wday]) + format.gsub!(/%b/, translate(locale, :"date.abbr_month_names")[object.mon]) + format.gsub!(/%B/, translate(locale, :"date.month_names")[object.mon]) + format.gsub!(/%p/, translate(locale, :"time.#{object.hour < 12 ? :am : :pm}")) if object.respond_to? :hour + object.strftime(format) + end + + protected - # Evaluates a default translation. - # If the given default is a String it is used literally. If it is a Symbol - # it will be translated with the given options. If it is an Array the first - # translation yielded will be returned. - # - # I.e., default(locale, [:foo, 'default']) will return +default+ if - # translate(locale, :foo) does not yield a result. - def default(locale, default, options = {}) - case default - when String then default - when Symbol then translate locale, default, options - when Array then default.each do |obj| - result = default(locale, obj, options.dup) and return result - end and nil - end - rescue MissingTranslationData - nil - end + def translations + @translations ||= {} + end - # Picks a translation from an array according to English pluralization - # rules. It will pick the first translation if count is not equal to 1 - # and the second translation if it is equal to 1. Other backends can - # implement more flexible or complex pluralization rules. - def pluralize(locale, entry, count) - return entry unless entry.is_a?(Hash) and count - # raise InvalidPluralizationData.new(entry, count) unless entry.is_a?(Hash) - key = :zero if count == 0 && entry.has_key?(:zero) - key ||= count == 1 ? :one : :many - raise InvalidPluralizationData.new(entry, count) unless entry.has_key?(key) - entry[key] + # Looks up a translation from the translations hash. Returns nil if + # eiher key is nil, or locale, scope or key do not exist as a key in the + # nested translations hash. Splits keys or scopes containing dots + # into multiple keys, i.e. currency.format is regarded the same as + # %w(currency format). + def lookup(locale, key, scope = []) + return unless key + keys = I18n.send :normalize_translation_keys, locale, key, scope + keys.inject(translations){|result, k| result[k.to_sym] or return nil } + end + + # Evaluates a default translation. + # If the given default is a String it is used literally. If it is a Symbol + # it will be translated with the given options. If it is an Array the first + # translation yielded will be returned. + # + # I.e., default(locale, [:foo, 'default']) will return +default+ if + # translate(locale, :foo) does not yield a result. + def default(locale, default, options = {}) + case default + when String then default + when Symbol then translate locale, default, options + when Array then default.each do |obj| + result = default(locale, obj, options.dup) and return result + end and nil end - - # Interpolates values into a given string. - # - # interpolate "file {{file}} opened by \\{{user}}", :file => 'test.txt', :user => 'Mr. X' - # # => "file test.txt opened by {{user}}" - # - # Note that you have to double escape the \\ when you want to escape - # the {{...}} key in a string (once for the string and once for the - # interpolation). - def interpolate(locale, string, values = {}) - return string if !string.is_a?(String) - - string = string.gsub(/%d/, '{{count}}').gsub(/%s/, '{{value}}') - if string.respond_to?(:force_encoding) - original_encoding = string.encoding - string.force_encoding(Encoding::BINARY) - end - - s = StringScanner.new(string) - while s.skip_until(/\{\{/) - s.string[s.pos - 3, 1] = '' and next if s.pre_match[-1, 1] == '\\' - start_pos = s.pos - 2 - key = s.scan_until(/\}\}/)[0..-3] - end_pos = s.pos - 1 - - raise ReservedInterpolationKey.new(key, string) if %w(scope default).include?(key) - raise MissingInterpolationArgument.new(key, string) unless values.has_key? key.to_sym + rescue MissingTranslationData + nil + end + + # Picks a translation from an array according to English pluralization + # rules. It will pick the first translation if count is not equal to 1 + # and the second translation if it is equal to 1. Other backends can + # implement more flexible or complex pluralization rules. + def pluralize(locale, entry, count) + return entry unless entry.is_a?(Hash) and count + # raise InvalidPluralizationData.new(entry, count) unless entry.is_a?(Hash) + key = :zero if count == 0 && entry.has_key?(:zero) + key ||= count == 1 ? :one : :other + raise InvalidPluralizationData.new(entry, count) unless entry.has_key?(key) + entry[key] + end + + # Interpolates values into a given string. + # + # interpolate "file {{file}} opened by \\{{user}}", :file => 'test.txt', :user => 'Mr. X' + # # => "file test.txt opened by {{user}}" + # + # Note that you have to double escape the \\ when you want to escape + # the {{...}} key in a string (once for the string and once for the + # interpolation). + def interpolate(locale, string, values = {}) + return string if !string.is_a?(String) - s.string[start_pos..end_pos] = values[key.to_sym].to_s - s.unscan - end + string = string.gsub(/%d/, '{{count}}').gsub(/%s/, '{{value}}') + if string.respond_to?(:force_encoding) + original_encoding = string.encoding + string.force_encoding(Encoding::BINARY) + end + s = StringScanner.new(string) + + while s.skip_until(/\{\{/) + s.string[s.pos - 3, 1] = '' and next if s.pre_match[-1, 1] == '\\' + start_pos = s.pos - 2 + key = s.scan_until(/\}\}/)[0..-3] + end_pos = s.pos - 1 - result = s.string - result.force_encoding(original_encoding) if original_encoding - result - end + raise ReservedInterpolationKey.new(key, string) if %w(scope default).include?(key) + raise MissingInterpolationArgument.new(key, string) unless values.has_key? key.to_sym - # Loads a single translations file by delegating to #load_rb or - # #load_yml depending on the file extension and directly merges the - # data to the existing translations. Raises I18n::UnknownFileType - # for all other file extensions. - def load_file(filename) - type = File.extname(filename).tr('.', '').downcase - raise UnknownFileType.new(type, filename) unless respond_to? :"load_#{type}" - data = send :"load_#{type}", filename # TODO raise a meaningful exception if this does not yield a Hash - data.each do |locale, d| - merge_translations locale, d - end + s.string[start_pos..end_pos] = values[key.to_sym].to_s + s.unscan end - # Loads a plain Ruby translations file. eval'ing the file must yield - # a Hash containing translation data with locales as toplevel keys. - def load_rb(filename) - eval IO.read(filename), binding, filename - end - - # Loads a YAML translations file. The data must have locales as - # toplevel keys. - def load_yml(filename) - YAML::load IO.read(filename) - end - - # Deep merges the given translations hash with the existing translations - # for the given locale - def merge_translations(locale, data) - locale = locale.to_sym - @@translations[locale] ||= {} - data = deep_symbolize_keys data + result = s.string + result.force_encoding(original_encoding) if original_encoding + result + end + + # Loads a single translations file by delegating to #load_rb or + # #load_yml depending on the file extension and directly merges the + # data to the existing translations. Raises I18n::UnknownFileType + # for all other file extensions. + def load_file(filename) + type = File.extname(filename).tr('.', '').downcase + raise UnknownFileType.new(type, filename) unless respond_to? :"load_#{type}" + data = send :"load_#{type}", filename # TODO raise a meaningful exception if this does not yield a Hash + data.each{|locale, d| merge_translations locale, d } + end + + # Loads a plain Ruby translations file. eval'ing the file must yield + # a Hash containing translation data with locales as toplevel keys. + def load_rb(filename) + eval IO.read(filename), binding, filename + end + + # Loads a YAML translations file. The data must have locales as + # toplevel keys. + def load_yml(filename) + YAML::load IO.read(filename) + end + + # Deep merges the given translations hash with the existing translations + # for the given locale + def merge_translations(locale, data) + locale = locale.to_sym + translations[locale] ||= {} + data = deep_symbolize_keys data - # deep_merge by Stefan Rusterholz, see http://www.ruby-forum.com/topic/142809 - merger = proc{|key, v1, v2| Hash === v1 && Hash === v2 ? v1.merge(v2, &merger) : v2 } - @@translations[locale].merge! data, &merger - end - - # Return a new hash with all keys and nested keys converted to symbols. - def deep_symbolize_keys(hash) - hash.inject({}){|result, (key, value)| - value = deep_symbolize_keys(value) if value.is_a? Hash - result[(key.to_sym rescue key) || key] = value - result - } - end - end + # deep_merge by Stefan Rusterholz, see http://www.ruby-forum.com/topic/142809 + merger = proc{|key, v1, v2| Hash === v1 && Hash === v2 ? v1.merge(v2, &merger) : v2 } + translations[locale].merge! data, &merger + end + + # Return a new hash with all keys and nested keys converted to symbols. + def deep_symbolize_keys(hash) + hash.inject({}){|result, (key, value)| + value = deep_symbolize_keys(value) if value.is_a? Hash + result[(key.to_sym rescue key) || key] = value + result + } + end end end end -- cgit v1.2.3 From 5e1ceb153c6f0445ec8925e9077859d963118eaf Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Mon, 25 Aug 2008 17:05:31 -0700 Subject: Work around frozen Date memoization --- .../lib/active_support/core_ext/date/behavior.rb | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'activesupport/lib') diff --git a/activesupport/lib/active_support/core_ext/date/behavior.rb b/activesupport/lib/active_support/core_ext/date/behavior.rb index 011cc17cbf..6f8f7c6a82 100644 --- a/activesupport/lib/active_support/core_ext/date/behavior.rb +++ b/activesupport/lib/active_support/core_ext/date/behavior.rb @@ -7,6 +7,22 @@ module ActiveSupport #:nodoc: def acts_like_date? true end + + # Date memoizes some instance methods using metaprogramming to wrap + # the methods with one that caches the result in an instance variable. + # If a Date is frozen but the memoized method hasn't been called, the + # first call will result in a frozen object error since the memo + # instance variable is uninitialized. Work around by eagerly memoizing + # before freezing. + def freeze #:nodoc: + self.class.private_instance_methods(false).each do |m| + if m.to_s =~ /\A__\d+__\Z/ + instance_variable_set(:"@#{m}", [send(m)]) + end + end + + super + end end end end -- cgit v1.2.3 From 172606e21f54fea39af68ede5f55a43deaf3ac68 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Mon, 25 Aug 2008 21:22:34 -0700 Subject: Harmonize framework require strategy. Don't add self to load path since Rails initializer and RubyGems handle it. --- activesupport/lib/active_support.rb | 2 -- 1 file changed, 2 deletions(-) (limited to 'activesupport/lib') diff --git a/activesupport/lib/active_support.rb b/activesupport/lib/active_support.rb index b6c8be37c5..ae3e2360cd 100644 --- a/activesupport/lib/active_support.rb +++ b/activesupport/lib/active_support.rb @@ -21,8 +21,6 @@ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #++ -$:.unshift(File.dirname(__FILE__)) - require 'active_support/vendor' require 'active_support/basic_object' require 'active_support/inflector' -- cgit v1.2.3 From 4bcd64c9e93af2f13dc7309cd76bb764e4d7d23d Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Mon, 25 Aug 2008 22:01:02 -0700 Subject: Ruby 1.9 compat: switch profile_options to superclass_delegating_accessor --- activesupport/lib/active_support/testing/performance.rb | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) (limited to 'activesupport/lib') diff --git a/activesupport/lib/active_support/testing/performance.rb b/activesupport/lib/active_support/testing/performance.rb index 3ad7289571..f996c40793 100644 --- a/activesupport/lib/active_support/testing/performance.rb +++ b/activesupport/lib/active_support/testing/performance.rb @@ -17,14 +17,14 @@ module ActiveSupport else { :benchmark => false, :runs => 1, - :min_percent => 0.02, + :min_percent => 0.01, :metrics => [:process_time, :memory, :objects], :formats => [:flat, :graph_html, :call_tree], :output => 'tmp/performance' } - end + end.freeze def self.included(base) - base.class_inheritable_hash :profile_options + base.superclass_delegating_accessor :profile_options base.profile_options = DEFAULTS end @@ -34,16 +34,17 @@ module ActiveSupport def run(result) return if method_name =~ /^default_test$/ - self.profile_options ||= DEFAULTS yield(self.class::STARTED, name) @_result = result run_warmup - profile_options[:metrics].each do |metric_name| - if klass = Metrics[metric_name.to_sym] - run_profile(klass.new) - result.add_run + if profile_options && metrics = profile_options[:metrics] + metrics.each do |metric_name| + if klass = Metrics[metric_name.to_sym] + run_profile(klass.new) + result.add_run + end end end -- cgit v1.2.3