diff options
Diffstat (limited to 'activesupport')
366 files changed, 9615 insertions, 7195 deletions
diff --git a/activesupport/CHANGELOG.md b/activesupport/CHANGELOG.md index 3d4cc8fae6..83ff80e31a 100644 --- a/activesupport/CHANGELOG.md +++ b/activesupport/CHANGELOG.md @@ -1,553 +1,245 @@ -* Add `Array#second_to_last` and `Array#third_to_last` methods. +* Use `Hash#compact` and `Hash#compact!` from Ruby 2.4. Old Ruby versions + will continue to get these methods from Active Support as before. - *Brian Christian* + *Prathamesh Sonpatki* -* Fix regression in `Hash#dig` for HashWithIndifferentAccess. - *Jon Moss* +* Fix `ActiveSupport::TimeZone#strptime`. + Support for timestamps in format of seconds (%s) and milliseconds (%Q). -## Rails 5.0.0.beta2 (February 01, 2016) ## + Fixes #26840. -* Change number_to_currency behavior for checking negativity. + *Lev Denisov* - Used `to_f.negative` instead of using `to_f.phase` for checking negativity - of a number in number_to_currency helper. - This change works same for all cases except when number is "-0.0". +* Fix `DateAndTime::Calculations#copy_time_to`. Copy `nsec` instead of `usec`. - -0.0.to_f.negative? => false - -0.0.to_f.phase? => 3.14 + Jumping forward or backward between weeks now preserves nanosecond digits. - This change reverts changes from https://github.com/rails/rails/pull/6512. - But it should be acceptable as we could not find any currency which - supports negative zeros. + *Josua Schmid* - *Prathamesh Sonpatki*, *Rafael Mendonça França* +* Fix `ActiveSupport::TimeWithZone#in` across DST boundaries. -* Match `HashWithIndifferentAccess#default`'s behaviour with `Hash#default`. + Previously calls to `in` were being sent to the non-DST aware + method `Time#since` via `method_missing`. It is now aliased to + the DST aware `ActiveSupport::TimeWithZone#+` which handles + transitions across DST boundaries, e.g: - *David Cornu* + Time.zone = "US/Eastern" -* Adds `:exception_object` key to `ActiveSupport::Notifications::Instrumenter` - payload when an exception is raised. + t = Time.zone.local(2016,11,6,1) + # => Sun, 06 Nov 2016 01:00:00 EDT -05:00 - Adds new key/value pair to payload when an exception is raised: - e.g. `:exception_object => #<RuntimeError: FAIL>`. + t.in(1.hour) + # => Sun, 06 Nov 2016 01:00:00 EST -05:00 - *Ryan T. Hosford* + Fixes #26580. -* Support extended grapheme clusters and UAX 29. + *Thomas Balthazar* - *Adam Roben* +* Remove unused parameter `options = nil` for `#clear` of + `ActiveSupport::Cache::Strategy::LocalCache::LocalStore` and + `ActiveSupport::Cache::Strategy::LocalCache`. -* Add petabyte and exabyte numeric conversion. + *Yosuke Kabuto* - *Akshay Vishnoi* +* Fix `thread_mattr_accessor` subclass no longer overwrites parent. -## Rails 5.0.0.beta1 (December 18, 2015) ## + Assigning a value to a subclass using `thread_mattr_accessor` no + longer changes the value of the parent class. This brings the + behavior inline with the documentation. -* Add thread_m/cattr_accessor/reader/writer suite of methods for declaring class and module variables that live per-thread. - This makes it easy to declare per-thread globals that are encapsulated. Note: This is a sharp edge. A wild proliferation - of globals is A Bad Thing. But like other sharp tools, when it's right, it's right. + Given: - Here's an example of a simple event tracking system where the object being tracked needs not pass a creator that it - doesn't need itself along: - - module Current - thread_mattr_accessor :account + class Account thread_mattr_accessor :user - - def self.reset() self.account = self.user = nil end - end - - class ApplicationController < ActionController::Base - before_action :set_current - after_action { Current.reset } - - private - def set_current - Current.account = Account.find(params[:account_id]) - Current.user = Current.account.users.find(params[:user_id]) - end - end - - class MessagesController < ApplicationController - def create - @message = Message.create!(message_params) - end end - class Message < ApplicationRecord - has_many :events - after_create :track_created - - private - def track_created - events.create! origin: self, action: :create - end - end - - class Event < ApplicationRecord - belongs_to :creator, class_name: 'User' - before_validation { self.creator ||= Current.user } - end - - *DHH* - - -* Deprecated `Module#qualified_const_` in favour of the builtin Module#const_ - methods. - - *Genadi Samokovarov* - -* Deprecate passing string to define callback. - - *Yuichiro Kaneko* - -* `ActiveSupport::Cache::Store#namespaced_key`, - `ActiveSupport::Cache::MemCachedStore#escape_key`, and - `ActiveSupport::Cache::FileStore#key_file_path` - are deprecated and replaced with `normalize_key` that now calls `super`. - - `ActiveSupport::Cache::LocaleCache#set_cache_value` is deprecated and replaced with `write_cache_value`. - - *Michael Grosser* - -* Implements an evented file watcher to asynchronously detect changes in the - application source code, routes, locales, etc. - - This watcher is disabled by default, applications my enable it in the configuration: - - # config/environments/development.rb - config.file_watcher = ActiveSupport::EventedFileUpdateChecker - - This feature depends on the [listen](https://github.com/guard/listen) gem: - - group :development do - gem 'listen', '~> 3.0.5' + class Customer < Account end - *Puneet Agarwal* and *Xavier Noria* - -* Added `Time.days_in_year` to return the number of days in the given year, or the - current year if no argument is provided. - - *Jon Pascoe* - -* Updated `parameterize` to preserve the case of a string, optionally. - - Example: - - parameterize("Donald E. Knuth", separator: '_') # => "donald_e_knuth" - parameterize("Donald E. Knuth", preserve_case: true) # => "Donald-E-Knuth" - - *Swaathi Kakarla* - -* `HashWithIndifferentAccess.new` respects the default value or proc on objects - that respond to `#to_hash`. `.new_from_hash_copying_default` simply invokes `.new`. - All calls to `.new_from_hash_copying_default` are replaced with `.new`. - - *Gordon Chan* - -* Change Integer#year to return a Fixnum instead of a Float to improve - consistency. - - Integer#years returned a Float while the rest of the accompanying methods - (days, weeks, months, etc.) return a Fixnum. + Account.user = "DHH" + Customer.user = "Rafael" Before: - 1.year # => 31557600.0 + Account.user # => "Rafael" After: - 1.year # => 31557600 - - *Konstantinos Rousis* - -* Handle invalid UTF-8 strings when HTML escaping. - - Use `ActiveSupport::Multibyte::Unicode.tidy_bytes` to handle invalid UTF-8 - strings in `ERB::Util.unwrapped_html_escape` and `ERB::Util.html_escape_once`. - Prevents user-entered input passed from a querystring into a form field from - causing invalid byte sequence errors. - - *Grey Baker* - -* Update `ActiveSupport::Multibyte::Chars#slice!` to return `nil` if the - arguments are out of bounds, to mirror the behavior of `String#slice!` - - *Gourav Tiwari* - -* Fix `number_to_human` so that 999999999 rounds to "1 Billion" instead of - "1000 Million". - - *Max Jacobson* - -* Fix `ActiveSupport::Deprecation#deprecate_methods` to report using the - current deprecator instance, where applicable. + Account.user # => "DHH" - *Brandon Dunne* + *Shinichi Maeshima* -* `Cache#fetch` instrumentation marks whether it was a `:hit`. +* Since weeks are no longer converted to days, add `:weeks` to the list of + parts that `ActiveSupport::TimeWithZone` will recognize as possibly being + of variable duration to take account of DST transitions. - *Robin Clowers* - -* `assert_difference` and `assert_no_difference` now returns the result of the - yielded block. - - Example: - - post = assert_difference -> { Post.count }, 1 do - Post.create - end - - *Lucas Mazza* - -* Short-circuit `blank?` on date and time values since they are never blank. - - Fixes #21657. + Fixes #26039. *Andrew White* -* Replaced deprecated `ThreadSafe::Cache` with its successor `Concurrent::Map` now that - the thread_safe gem has been merged into concurrent-ruby. - - *Jerry D'Antonio* - -* Updated Unicode version to 8.0.0 - - *Anshul Sharma* - -* `number_to_currency` and `number_with_delimiter` now accept custom `delimiter_pattern` option - to handle placement of delimiter, to support currency formats like INR +* Defines `Regexp.match?` for Ruby versions prior to 2.4. The predicate + has the same interface, but it does not have the performance boost. Its + purpose is to be able to write 2.4 compatible code. - Example: + *Xavier Noria* - number_to_currency(1230000, delimiter_pattern: /(\d+?)(?=(\d\d)+(\d)(?!\d))/, unit: '₹', format: "%u %n") - # => '₹ 12,30,000.00' +* Allow `MessageEncryptor` to take advantage of authenticated encryption modes. - *Vipul A M* + AEAD modes like `aes-256-gcm` provide both confidentiality and data + authenticity, eliminating the need to use `MessageVerifier` to check if the + encrypted data has been tampered with. This speeds up encryption/decryption + and results in shorter cipher text. -* Deprecate `:prefix` option of `number_to_human_size` with no replacement. + *Bart de Water* - *Jean Boussier* +* Introduce `assert_changes` and `assert_no_changes`. -* Fix `TimeWithZone#eql?` to properly handle `TimeWithZone` created from `DateTime`: - twz = DateTime.now.in_time_zone - twz.eql?(twz.dup) => true - - Fixes #14178. - - *Roque Pinel* - -* ActiveSupport::HashWithIndifferentAccess `select` and `reject` will now return - enumerator if called without block. - - Fixes #20095. - - *Bernard Potocki* - -* Removed `ActiveSupport::Concurrency::Latch`, superseded by `Concurrent::CountDownLatch` - from the concurrent-ruby gem. - - *Jerry D'Antonio* - -* Fix not calling `#default` on `HashWithIndifferentAccess#to_hash` when only - `default_proc` is set, which could raise. - - *Simon Eskildsen* - -* Fix setting `default_proc` on `HashWithIndifferentAccess#dup`. - - *Simon Eskildsen* - -* Fix a range of values for parameters of the Time#change. - - *Nikolay Kondratyev* - -* Add `Enumerable#pluck` to get the same values from arrays as from ActiveRecord - associations. - - Fixes #20339. - - *Kevin Deisz* - -* Add a bang version to `ActiveSupport::OrderedOptions` get methods which will raise - an `KeyError` if the value is `.blank?`. - - Before: + `assert_changes` is a more general `assert_difference` that works with any + value. - if (slack_url = Rails.application.secrets.slack_url).present? - # Do something worthwhile - else - # Raise as important secret password is not specified + assert_changes 'Error.current', from: nil, to: 'ERR' do + expected_bad_operation end - After: - - slack_url = Rails.application.secrets.slack_url! - - *Aditya Sanghi*, *Gaurish Sharma* - -* Remove deprecated `Class#superclass_delegating_accessor`. - Use `Class#class_attribute` instead. - - *Akshay Vishnoi* - -* Patch `Delegator` to work with `#try`. - - Fixes #5790. - - *Nate Smith* - -* Add `Integer#positive?` and `Integer#negative?` query methods - in the vein of `Fixnum#zero?`. - - This makes it nicer to do things like `bunch_of_numbers.select(&:positive?)`. - - *DHH* - -* Encoding `ActiveSupport::TimeWithZone` to YAML now preserves the timezone information. - - Fixes #9183. - - *Andrew White* - -* Added `ActiveSupport::TimeZone#strptime` to allow parsing times as if - from a given timezone. - - *Paul A Jungwirth* - -* `ActiveSupport::Callbacks#skip_callback` now raises an `ArgumentError` if - an unrecognized callback is removed. - - *Iain Beeston* - -* Added `ActiveSupport::ArrayInquirer` and `Array#inquiry`. - - Wrapping an array in an `ArrayInquirer` gives a friendlier way to check its - contents: - - variants = ActiveSupport::ArrayInquirer.new([:phone, :tablet]) - - variants.phone? # => true - variants.tablet? # => true - variants.desktop? # => false - - variants.any?(:phone, :tablet) # => true - variants.any?(:phone, :desktop) # => true - variants.any?(:desktop, :watch) # => false - - `Array#inquiry` is a shortcut for wrapping the receiving array in an - `ArrayInquirer`. - - *George Claghorn* - -* Deprecate `alias_method_chain` in favour of `Module#prepend` introduced in - Ruby 2.0. - - *Kir Shatrov* - -* Added `#without` on `Enumerable` and `Array` to return a copy of an - enumerable without the specified elements. - - *Todd Bealmear* - -* Fixed a problem where `String#truncate_words` would get stuck with a complex - string. - - *Henrik Nygren* - -* Fixed a roundtrip problem with `AS::SafeBuffer` where primitive-like strings - will be dumped as primitives: - - Before: - - YAML.load ActiveSupport::SafeBuffer.new("Hello").to_yaml # => "Hello" - YAML.load ActiveSupport::SafeBuffer.new("true").to_yaml # => true - YAML.load ActiveSupport::SafeBuffer.new("false").to_yaml # => false - YAML.load ActiveSupport::SafeBuffer.new("1").to_yaml # => 1 - YAML.load ActiveSupport::SafeBuffer.new("1.1").to_yaml # => 1.1 - - After: - - YAML.load ActiveSupport::SafeBuffer.new("Hello").to_yaml # => "Hello" - YAML.load ActiveSupport::SafeBuffer.new("true").to_yaml # => "true" - YAML.load ActiveSupport::SafeBuffer.new("false").to_yaml # => "false" - YAML.load ActiveSupport::SafeBuffer.new("1").to_yaml # => "1" - YAML.load ActiveSupport::SafeBuffer.new("1.1").to_yaml # => "1.1" - - *Godfrey Chan* + Can be called with strings, to be evaluated in the binding (context) of + the block given to the assertion, or a lambda. -* Enable `number_to_percentage` to keep the number's precision by allowing - `:precision` to be `nil`. - - *Jack Xu* - -* `config_accessor` became a private method, as with Ruby's `attr_accessor`. - - *Akira Matsuda* - -* `AS::Testing::TimeHelpers#travel_to` now changes `DateTime.now` as well as - `Time.now` and `Date.today`. - - *Yuki Nishijima* - -* Add `file_fixture` to `ActiveSupport::TestCase`. - It provides a simple mechanism to access sample files in your test cases. - - By default file fixtures are stored in `test/fixtures/files`. This can be - configured per test-case using the `file_fixture_path` class attribute. - - *Yves Senn* - -* Return value of yielded block in `File.atomic_write`. - - *Ian Ker-Seymer* - -* Duplicate frozen array when assigning it to a `HashWithIndifferentAccess` so - that it doesn't raise a `RuntimeError` when calling `map!` on it in `convert_value`. - - Fixes #18550. - - *Aditya Kapoor* - -* Add missing time zone definitions for Russian Federation and sync them - with `zone.tab` file from tzdata version 2014j (latest). - - *Andrey Novikov* - -* Add `SecureRandom.base58` for generation of random base58 strings. - - *Matthew Draper*, *Guillermo Iguaran* - -* Add `#prev_day` and `#next_day` counterparts to `#yesterday` and - `#tomorrow` for `Date`, `Time`, and `DateTime`. - - *George Claghorn* - -* Add `same_time` option to `#next_week` and `#prev_week` for `Date`, `Time`, - and `DateTime`. - - *George Claghorn* - -* Add `#on_weekend?`, `#next_weekday`, `#prev_weekday` methods to `Date`, - `Time`, and `DateTime`. - - `#on_weekend?` returns `true` if the receiving date/time falls on a Saturday - or Sunday. + assert_changes -> { Error.current }, from: nil, to: 'ERR' do + expected_bad_operation + end - `#next_weekday` returns a new date/time representing the next day that does - not fall on a Saturday or Sunday. + The `from` and `to` arguments are compared with the case operator (`===`). - `#prev_weekday` returns a new date/time representing the previous day that - does not fall on a Saturday or Sunday. + assert_changes 'Error.current', from: nil, to: Error do + expected_bad_operation + end - *George Claghorn* + This is pretty useful, if you need to loosely compare a value. For example, + you need to test a token has been generated and it has that many random + characters. -* Change the default test order from `:sorted` to `:random`. + user = User.start_registration + assert_changes 'user.token', to: /\w{32}/ do + user.finish_registration + end - *Rafael Mendonça França* + *Genadi Samokovarov* -* Remove deprecated `ActiveSupport::JSON::Encoding::CircularReferenceError`. +* Add `:fallback_string` option to `Array#to_sentence`. If an empty array + calls the function and a fallback string option is set then it returns the + fallback string other than an empty string. - *Rafael Mendonça França* + *Mohamed Osama* -* Remove deprecated methods `ActiveSupport::JSON::Encoding.encode_big_decimal_as_string=` - and `ActiveSupport::JSON::Encoding.encode_big_decimal_as_string`. +* Fix `ActiveSupport::TimeZone#strptime`. Now raises `ArgumentError` when the + given time doesn't match the format. The error is the same as the one given + by Ruby's `Date.strptime`. Previously it raised + `NoMethodError: undefined method empty? for nil:NilClass.` due to a bug. - *Rafael Mendonça França* + Fixes #25701. -* Remove deprecated `ActiveSupport::SafeBuffer#prepend`. + *John Gesimondo* - *Rafael Mendonça França* +* `travel/travel_to` travel time helpers, now raise on nested calls, + as this can lead to confusing time stubbing. -* Remove deprecated methods at `Kernel`. + Instead of: - `silence_stderr`, `silence_stream`, `capture` and `quietly`. + travel_to 2.days.from_now do + # 2 days from today + travel_to 3.days.from_now do + # 5 days from today + end + end - *Rafael Mendonça França* + preferred way to achieve above is: -* Remove deprecated `active_support/core_ext/big_decimal/yaml_conversions` - file. + travel 2.days do + # 2 days from today + end - *Rafael Mendonça França* + travel 5.days do + # 5 days from today + end -* Remove deprecated methods `ActiveSupport::Cache::Store.instrument` and - `ActiveSupport::Cache::Store.instrument=`. + *Vipul A M* - *Rafael Mendonça França* +* Support parsing JSON time in ISO8601 local time strings in + `ActiveSupport::JSON.decode` when `parse_json_times` is enabled. + Strings in the format of `YYYY-MM-DD hh:mm:ss` (without a `Z` at + the end) will be parsed in the local timezone (`Time.zone`). In + addition, date strings (`YYYY-MM-DD`) are now parsed into `Date` + objects. -* Change the way in which callback chains can be halted. + *Grzegorz Witek* - The preferred method to halt a callback chain from now on is to explicitly - `throw(:abort)`. - In the past, callbacks could only be halted by explicitly providing a - terminator and by having a callback match the conditions of the terminator. +* Fixed `ActiveSupport::Logger.broadcast` so that calls to `#silence` now + properly delegate to all loggers. Silencing now properly suppresses logging + to both the log and the console. -* Add `ActiveSupport.halt_callback_chains_on_return_false` + *Kevin McPhillips* - Setting `ActiveSupport.halt_callback_chains_on_return_false` - to `true` will let an app support the deprecated way of halting Active Record, - and Active Model callback chains by returning `false`. +* Remove deprecated arguments in `assert_nothing_raised`. - Setting the value to `false` will tell the app to ignore any `false` value - returned by those callbacks, and only halt the chain upon `throw(:abort)`. + *Rafel Mendonça França* - When the configuration option is missing, its value is `true`, so older apps - ported to Rails 5.0 will not break (but display a deprecation warning). - For new Rails 5.0 apps, its value is set to `false` in an initializer, so - these apps will support the new behavior by default. +* `Date.to_s` doesn't produce too many spaces. For example, `to_s(:short)` + will now produce `01 Feb` instead of ` 1 Feb`. - *claudiob*, *Roque Pinel* + Fixes #25251. -* Changes arguments and default value of CallbackChain's `:terminator` option + *Sean Griffin* - Chains of callbacks defined without an explicit `:terminator` option will - now be halted as soon as a `before_` callback throws `:abort`. +* Introduce `Module#delegate_missing_to`. - Chains of callbacks defined with a `:terminator` option will maintain their - existing behavior of halting as soon as a `before_` callback matches the - terminator's expectation. + When building a decorator, a common pattern emerges: - *claudiob* + class Partition + def initialize(first_event) + @events = [ first_event ] + end -* Deprecate `MissingSourceFile` in favor of `LoadError`. + def people + if @events.first.detail.people.any? + @events.collect { |e| Array(e.detail.people) }.flatten.uniq + else + @events.collect(&:creator).uniq + end + end - `MissingSourceFile` was just an alias to `LoadError` and was not being - raised inside the framework. + private + def respond_to_missing?(name, include_private = false) + @events.respond_to?(name, include_private) + end - *Rafael Mendonça França* + def method_missing(method, *args, &block) + @events.send(method, *args, &block) + end + end -* Add support for error dispatcher classes in `ActiveSupport::Rescuable`. - Now it acts closer to Ruby's rescue. + With `Module#delegate_missing_to`, the above is condensed to: - Example: + class Partition + delegate_missing_to :@events - class BaseController < ApplicationController - module ErrorDispatcher - def self.===(other) - Exception === other && other.respond_to?(:status) - end + def initialize(first_event) + @events = [ first_event ] end - rescue_from ErrorDispatcher do |error| - render status: error.status, json: { error: error.to_s } + def people + if @events.first.detail.people.any? + @events.collect { |e| Array(e.detail.people) }.flatten.uniq + else + @events.collect(&:creator).uniq + end end end - *Genadi Samokovarov* - -* Add `#verified` and `#valid_message?` methods to `ActiveSupport::MessageVerifier` - - Previously, the only way to decode a message with `ActiveSupport::MessageVerifier` - was to use `#verify`, which would raise an exception on invalid messages. Now - `#verified` can also be used, which returns `nil` on messages that cannot be - decoded. + *Genadi Samokovarov*, *DHH* - Previously, there was no way to check if a message's format was valid without - attempting to decode it. `#valid_message?` is a boolean convenience method that - checks whether the message is valid without actually decoding it. +* Rescuable: If a handler doesn't match the exception, check for handlers + matching the exception's cause. - *Logan Leger* + *Jeremy Daer* -Please check [4-2-stable](https://github.com/rails/rails/blob/4-2-stable/activesupport/CHANGELOG.md) for previous changes. +Please check [5-0-stable](https://github.com/rails/rails/blob/5-0-stable/activesupport/CHANGELOG.md) for previous changes. diff --git a/activesupport/Rakefile b/activesupport/Rakefile index 33ee62aa1b..2e1c50cc3d 100644 --- a/activesupport/Rakefile +++ b/activesupport/Rakefile @@ -1,13 +1,12 @@ -require 'rake/testtask' +require "rake/testtask" -task :default => :test +task default: :test task :package -task "package:clean" Rake::TestTask.new do |t| - t.libs << 'test' - t.pattern = 'test/**/*_test.rb' + t.libs << "test" + t.pattern = "test/**/*_test.rb" t.warning = true t.verbose = true t.ruby_opts = ["--dev"] if defined?(JRUBY_VERSION) @@ -16,7 +15,7 @@ end namespace :test do task :isolated do Dir.glob("test/**/*_test.rb").all? do |file| - sh(Gem.ruby, '-w', '-Ilib:test', file) - end or raise "Failures" + sh(Gem.ruby, "-w", "-Ilib:test", file) + end || raise("Failures") end end diff --git a/activesupport/activesupport.gemspec b/activesupport/activesupport.gemspec index 68a80701ed..08370cba85 100644 --- a/activesupport/activesupport.gemspec +++ b/activesupport/activesupport.gemspec @@ -1,27 +1,27 @@ -version = File.read(File.expand_path('../../RAILS_VERSION', __FILE__)).strip +version = File.read(File.expand_path("../../RAILS_VERSION", __FILE__)).strip Gem::Specification.new do |s| s.platform = Gem::Platform::RUBY - s.name = 'activesupport' + s.name = "activesupport" s.version = version - s.summary = 'A toolkit of support libraries and Ruby core extensions extracted from the Rails framework.' - s.description = 'A toolkit of support libraries and Ruby core extensions extracted from the Rails framework. Rich support for multibyte strings, internationalization, time zones, and testing.' + s.summary = "A toolkit of support libraries and Ruby core extensions extracted from the Rails framework." + s.description = "A toolkit of support libraries and Ruby core extensions extracted from the Rails framework. Rich support for multibyte strings, internationalization, time zones, and testing." - s.required_ruby_version = '>= 2.2.2' + s.required_ruby_version = ">= 2.2.2" - s.license = 'MIT' + s.license = "MIT" - s.author = 'David Heinemeier Hansson' - s.email = 'david@loudthinking.com' - s.homepage = 'http://www.rubyonrails.org' + s.author = "David Heinemeier Hansson" + s.email = "david@loudthinking.com" + s.homepage = "http://rubyonrails.org" - s.files = Dir['CHANGELOG.md', 'MIT-LICENSE', 'README.rdoc', 'lib/**/*'] - s.require_path = 'lib' + s.files = Dir["CHANGELOG.md", "MIT-LICENSE", "README.rdoc", "lib/**/*"] + s.require_path = "lib" - s.rdoc_options.concat ['--encoding', 'UTF-8'] + s.rdoc_options.concat ["--encoding", "UTF-8"] - s.add_dependency 'i18n', '~> 0.7' - s.add_dependency 'tzinfo', '~> 1.1' - s.add_dependency 'minitest', '~> 5.1' - s.add_dependency 'concurrent-ruby', '~> 1.0' + s.add_dependency "i18n", "~> 0.7" + s.add_dependency "tzinfo", "~> 1.1" + s.add_dependency "minitest", "~> 5.1" + s.add_dependency "concurrent-ruby", "~> 1.0", ">= 1.0.2" end diff --git a/activesupport/bin/generate_tables b/activesupport/bin/generate_tables index 2193533588..ef220e0329 100755 --- a/activesupport/bin/generate_tables +++ b/activesupport/bin/generate_tables @@ -1,18 +1,17 @@ #!/usr/bin/env ruby begin - $:.unshift(File.expand_path(File.dirname(__FILE__) + '/../lib')) - require 'active_support' + $:.unshift(File.expand_path(File.dirname(__FILE__) + "/../lib")) + require "active_support" rescue IOError end -require 'open-uri' -require 'tmpdir' +require "open-uri" +require "tmpdir" module ActiveSupport module Multibyte module Unicode - class UnicodeDatabase def load; end end @@ -20,10 +19,10 @@ module ActiveSupport class DatabaseGenerator BASE_URI = "http://www.unicode.org/Public/#{UNICODE_VERSION}/ucd/" SOURCES = { - :codepoints => BASE_URI + 'UnicodeData.txt', - :composition_exclusion => BASE_URI + 'CompositionExclusions.txt', - :grapheme_break_property => BASE_URI + 'auxiliary/GraphemeBreakProperty.txt', - :cp1252 => 'http://unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WINDOWS/CP1252.TXT' + codepoints: BASE_URI + "UnicodeData.txt", + composition_exclusion: BASE_URI + "CompositionExclusions.txt", + grapheme_break_property: BASE_URI + "auxiliary/GraphemeBreakProperty.txt", + cp1252: "http://unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WINDOWS/CP1252.TXT" } def initialize @@ -52,9 +51,9 @@ module ActiveSupport codepoint.code = $1.hex codepoint.combining_class = Integer($4) codepoint.decomp_type = $7 - codepoint.decomp_mapping = ($8=='') ? nil : $8.split.collect(&:hex) - codepoint.uppercase_mapping = ($16=='') ? 0 : $16.hex - codepoint.lowercase_mapping = ($17=='') ? 0 : $17.hex + codepoint.decomp_mapping = ($8=="") ? nil : $8.split.collect(&:hex) + codepoint.uppercase_mapping = ($16=="") ? 0 : $16.hex + codepoint.lowercase_mapping = ($17=="") ? 0 : $17.hex @ucd.codepoints[codepoint.code] = codepoint end @@ -62,8 +61,8 @@ module ActiveSupport if line =~ /^([0-9A-F.]+)\s*;\s*([\w]+)\s*#/ type = $2.downcase.intern @ucd.boundary[type] ||= [] - if $1.include? '..' - parts = $1.split '..' + if $1.include? ".." + parts = $1.split ".." @ucd.boundary[type] << (parts[0].hex..parts[1].hex) else @ucd.boundary[type] << $1.hex @@ -85,7 +84,7 @@ module ActiveSupport def create_composition_map @ucd.codepoints.each do |_, cp| - if !cp.nil? and cp.combining_class == 0 and cp.decomp_type.nil? and !cp.decomp_mapping.nil? and cp.decomp_mapping.length == 2 and @ucd.codepoints[cp.decomp_mapping[0]].combining_class == 0 and !@ucd.composition_exclusion.include?(cp.code) + if !cp.nil? && cp.combining_class == 0 && cp.decomp_type.nil? && !cp.decomp_mapping.nil? && cp.decomp_mapping.length == 2 && @ucd.codepoints[cp.decomp_mapping[0]].combining_class == 0 && !@ucd.composition_exclusion.include?(cp.code) @ucd.composition_map[cp.decomp_mapping[0]] ||= {} @ucd.composition_map[cp.decomp_mapping[0]][cp.decomp_mapping[1]] = cp.code end @@ -105,7 +104,7 @@ module ActiveSupport filename = File.join(Dir.tmpdir, "#{url.split('/').last}") unless File.exist?(filename) $stderr.puts "Downloading #{url.split('/').last}" - File.open(filename, 'wb') do |target| + File.open(filename, "wb") do |target| open(url) do |source| source.each_line { |line| target.write line } end @@ -120,7 +119,7 @@ module ActiveSupport end def dump_to(filename) - File.open(filename, 'wb') do |f| + File.open(filename, "wb") do |f| f.write Marshal.dump([@ucd.codepoints, @ucd.composition_exclusion, @ucd.composition_map, @ucd.boundary, @ucd.cp1252]) end end diff --git a/activesupport/bin/test b/activesupport/bin/test index 404cabba51..84a05bba08 100755 --- a/activesupport/bin/test +++ b/activesupport/bin/test @@ -1,4 +1,6 @@ #!/usr/bin/env ruby -COMPONENT_ROOT = File.expand_path("../../", __FILE__) + +COMPONENT_ROOT = File.expand_path("..", __dir__) require File.expand_path("../tools/test", COMPONENT_ROOT) + exit Minitest.run(ARGV) diff --git a/activesupport/lib/active_support.rb b/activesupport/lib/active_support.rb index 94fe893149..2fc42e1975 100644 --- a/activesupport/lib/active_support.rb +++ b/activesupport/lib/active_support.rb @@ -21,11 +21,12 @@ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #++ -require 'securerandom' +require "securerandom" require "active_support/dependencies/autoload" require "active_support/version" require "active_support/logger" require "active_support/lazy_load_hooks" +require "active_support/core_ext/date_and_time/compatibility" module ActiveSupport extend ActiveSupport::Autoload @@ -33,10 +34,13 @@ module ActiveSupport autoload :Concern autoload :Dependencies autoload :DescendantsTracker + autoload :ExecutionWrapper + autoload :Executor autoload :FileUpdateChecker autoload :EventedFileUpdateChecker autoload :LogSubscriber autoload :Notifications + autoload :Reloader eager_autoload do autoload :BacktraceCleaner @@ -82,6 +86,14 @@ module ActiveSupport def self.halt_callback_chains_on_return_false=(value) Callbacks.halt_and_display_warning_on_return_false = value end + + def self.to_time_preserves_timezone + DateAndTime::Compatibility.preserve_timezone + end + + def self.to_time_preserves_timezone=(value) + DateAndTime::Compatibility.preserve_timezone = value + end end autoload :I18n, "active_support/i18n" diff --git a/activesupport/lib/active_support/all.rb b/activesupport/lib/active_support/all.rb index f537818300..72a23075af 100644 --- a/activesupport/lib/active_support/all.rb +++ b/activesupport/lib/active_support/all.rb @@ -1,3 +1,3 @@ -require 'active_support' -require 'active_support/time' -require 'active_support/core_ext' +require "active_support" +require "active_support/time" +require "active_support/core_ext" diff --git a/activesupport/lib/active_support/array_inquirer.rb b/activesupport/lib/active_support/array_inquirer.rb index f59ddf5403..85122e39b2 100644 --- a/activesupport/lib/active_support/array_inquirer.rb +++ b/activesupport/lib/active_support/array_inquirer.rb @@ -9,8 +9,10 @@ module ActiveSupport # variants.desktop? # => false class ArrayInquirer < Array # Passes each element of +candidates+ collection to ArrayInquirer collection. - # The method returns true if at least one element is the same. If +candidates+ - # collection is not given, method returns true. + # The method returns true if any element from the ArrayInquirer collection + # is equal to the stringified or symbolized form of any element in the +candidates+ collection. + # + # If +candidates+ collection is not given, method returns true. # # variants = ActiveSupport::ArrayInquirer.new([:phone, :tablet]) # @@ -30,11 +32,11 @@ module ActiveSupport private def respond_to_missing?(name, include_private = false) - name[-1] == '?' + name[-1] == "?" end def method_missing(name, *args) - if name[-1] == '?' + if name[-1] == "?" any?(name[0..-2]) else super diff --git a/activesupport/lib/active_support/backtrace_cleaner.rb b/activesupport/lib/active_support/backtrace_cleaner.rb index e161ec4cca..169a58ecd1 100644 --- a/activesupport/lib/active_support/backtrace_cleaner.rb +++ b/activesupport/lib/active_support/backtrace_cleaner.rb @@ -14,7 +14,7 @@ module ActiveSupport # # bc = BacktraceCleaner.new # bc.add_filter { |line| line.gsub(Rails.root.to_s, '') } # strip the Rails.root prefix - # bc.add_silencer { |line| line =~ /mongrel|rubygems/ } # skip any lines from mongrel or rubygems + # bc.add_silencer { |line| line =~ /puma|rubygems/ } # skip any lines from puma or rubygems # bc.clean(exception.backtrace) # perform the cleanup # # To reconfigure an existing BacktraceCleaner (like the default one in Rails) @@ -59,8 +59,8 @@ module ActiveSupport # Adds a silencer from the block provided. If the silencer returns +true+ # for a given line, it will be excluded from the clean backtrace. # - # # Will reject all lines that include the word "mongrel", like "/gems/mongrel/server.rb" or "/app/my_mongrel_server/rb" - # backtrace_cleaner.add_silencer { |line| line =~ /mongrel/ } + # # Will reject all lines that include the word "puma", like "/gems/puma/server.rb" or "/app/my_puma_server/rb" + # backtrace_cleaner.add_silencer { |line| line =~ /puma/ } def add_silencer(&block) @silencers << block end diff --git a/activesupport/lib/active_support/benchmarkable.rb b/activesupport/lib/active_support/benchmarkable.rb index 805b7a714f..70493c8da7 100644 --- a/activesupport/lib/active_support/benchmarkable.rb +++ b/activesupport/lib/active_support/benchmarkable.rb @@ -1,5 +1,5 @@ -require 'active_support/core_ext/benchmark' -require 'active_support/core_ext/hash/keys' +require "active_support/core_ext/benchmark" +require "active_support/core_ext/hash/keys" module ActiveSupport module Benchmarkable @@ -38,8 +38,8 @@ module ActiveSupport options[:level] ||= :info result = nil - ms = Benchmark.ms { result = options[:silence] ? silence { yield } : yield } - logger.send(options[:level], '%s (%.1fms)' % [ message, ms ]) + ms = Benchmark.ms { result = options[:silence] ? logger.silence { yield } : yield } + logger.send(options[:level], "%s (%.1fms)" % [ message, ms ]) result else yield diff --git a/activesupport/lib/active_support/builder.rb b/activesupport/lib/active_support/builder.rb index 321e462acd..0f010c5d96 100644 --- a/activesupport/lib/active_support/builder.rb +++ b/activesupport/lib/active_support/builder.rb @@ -1,5 +1,5 @@ begin - require 'builder' + require "builder" rescue LoadError => e $stderr.puts "You don't have builder installed in your application. Please add it to your Gemfile and run bundle install" raise e diff --git a/activesupport/lib/active_support/cache.rb b/activesupport/lib/active_support/cache.rb index 610105f41c..ad02546755 100644 --- a/activesupport/lib/active_support/cache.rb +++ b/activesupport/lib/active_support/cache.rb @@ -1,29 +1,27 @@ -require 'benchmark' -require 'zlib' -require 'active_support/core_ext/array/extract_options' -require 'active_support/core_ext/array/wrap' -require 'active_support/core_ext/benchmark' -require 'active_support/core_ext/module/attribute_accessors' -require 'active_support/core_ext/numeric/bytes' -require 'active_support/core_ext/numeric/time' -require 'active_support/core_ext/object/to_param' -require 'active_support/core_ext/string/inflections' -require 'active_support/core_ext/string/strip' +require "zlib" +require "active_support/core_ext/array/extract_options" +require "active_support/core_ext/array/wrap" +require "active_support/core_ext/module/attribute_accessors" +require "active_support/core_ext/numeric/bytes" +require "active_support/core_ext/numeric/time" +require "active_support/core_ext/object/to_param" +require "active_support/core_ext/string/inflections" +require "active_support/core_ext/string/strip" module ActiveSupport # See ActiveSupport::Cache::Store for documentation. module Cache - autoload :FileStore, 'active_support/cache/file_store' - autoload :MemoryStore, 'active_support/cache/memory_store' - autoload :MemCacheStore, 'active_support/cache/mem_cache_store' - autoload :NullStore, 'active_support/cache/null_store' + autoload :FileStore, "active_support/cache/file_store" + autoload :MemoryStore, "active_support/cache/memory_store" + autoload :MemCacheStore, "active_support/cache/mem_cache_store" + autoload :NullStore, "active_support/cache/null_store" # These options mean something to all cache implementations. Individual cache # implementations may support additional options. UNIVERSAL_OPTIONS = [:namespace, :compress, :compress_threshold, :expires_in, :race_condition_ttl] module Strategy - autoload :LocalCache, 'active_support/cache/strategy/local_cache' + autoload :LocalCache, "active_support/cache/strategy/local_cache" end class << self @@ -153,25 +151,25 @@ module ActiveSupport # or +write+. To specify the threshold at which to compress values, set the # <tt>:compress_threshold</tt> option. The default threshold is 16K. class Store - cattr_accessor :logger, :instance_writer => true + cattr_accessor :logger, instance_writer: true attr_reader :silence, :options alias :silence? :silence - # Create a new cache. The options will be passed to any write method calls + # Creates a new cache. The options will be passed to any write method calls # except for <tt>:namespace</tt> which can be used to set the global # namespace for the cache. def initialize(options = nil) @options = options ? options.dup : {} end - # Silence the logger. + # Silences the logger. def silence! @silence = true self end - # Silence the logger within a block. + # Silences the logger within a block. def mute previous_silence, @silence = defined?(@silence) && @silence, true yield @@ -198,10 +196,17 @@ module ActiveSupport # cache.fetch('city') # => "Duckburgh" # # You may also specify additional options via the +options+ argument. - # Setting <tt>force: true</tt> will force a cache miss: + # Setting <tt>force: true</tt> forces a cache "miss," meaning we treat + # the cache value as missing even if it's present. Passing a block is + # required when +force+ is true so this always results in a cache write. # # cache.write('today', 'Monday') - # cache.fetch('today', force: true) # => nil + # cache.fetch('today', force: true) { 'Tuesday' } # => 'Tuesday' + # cache.fetch('today', force: true) # => ArgumentError + # + # The +:force+ option is useful when you're calling some other method to + # ask whether you should force a cache write. Otherwise, it's clearer to + # just call <tt>Cache#write</tt>. # # Setting <tt>:compress</tt> will store a large cache entry set by the call # in a compressed format. @@ -243,14 +248,14 @@ module ActiveSupport # sleep 60 # # Thread.new do - # val_1 = cache.fetch('foo', race_condition_ttl: 10) do + # val_1 = cache.fetch('foo', race_condition_ttl: 10.seconds) do # sleep 1 # 'new value 1' # end # end # # Thread.new do - # val_2 = cache.fetch('foo', race_condition_ttl: 10) do + # val_2 = cache.fetch('foo', race_condition_ttl: 10.seconds) do # 'new value 2' # end # end @@ -292,6 +297,8 @@ module ActiveSupport else save_block_result_to_cache(name, options) { |_name| yield _name } end + elsif options && options[:force] + raise ArgumentError, "Missing block: Calling `Cache#fetch` with `force: true` requires a block." else read(name, options) end @@ -323,7 +330,7 @@ module ActiveSupport end end - # Read multiple values at once from the cache. Options can be passed + # Reads multiple values at once from the cache. Options can be passed # in the last argument. # # Some cache implementation may optimize this method. @@ -333,27 +340,28 @@ module ActiveSupport options = names.extract_options! options = merged_options(options) - instrument_multi(:read, names, options) do |payload| - results = {} - names.each do |name| - key = normalize_key(name, options) - entry = read_entry(key, options) - if entry - if entry.expired? - delete_entry(key, options) - else - results[name] = entry.value - end + results = {} + names.each do |name| + key = normalize_key(name, options) + entry = read_entry(key, options) + if entry + if entry.expired? + delete_entry(key, options) + else + results[name] = entry.value end end - results end + results end # Fetches data from the cache, using the given keys. If there is data in # the cache with the given keys, then that data is returned. Otherwise, # the supplied block is called for each key for which there was no data, # and the result will be written to the cache and returned. + # Therefore, you need to pass a block that returns the data to be written + # to the cache. If you do not want to write the cache when the cache is + # not found, use #read_multi. # # Options are passed to the underlying cache implementation. # @@ -367,6 +375,8 @@ module ActiveSupport # # "unknown_key" => "Fallback value for key: unknown_key" } # def fetch_multi(*names) + raise ArgumentError, "Missing block: `Cache#fetch_multi` requires a block." unless block_given? + options = names.extract_options! options = merged_options(options) results = read_multi(*names, options) @@ -415,7 +425,7 @@ module ActiveSupport end end - # Delete all entries with keys matching the pattern. + # Deletes all entries with keys matching the pattern. # # Options are passed to the underlying cache implementation. # @@ -424,7 +434,7 @@ module ActiveSupport raise NotImplementedError.new("#{self.class.name} does not support delete_matched") end - # Increment an integer value in the cache. + # Increments an integer value in the cache. # # Options are passed to the underlying cache implementation. # @@ -433,7 +443,7 @@ module ActiveSupport raise NotImplementedError.new("#{self.class.name} does not support increment") end - # Decrement an integer value in the cache. + # Decrements an integer value in the cache. # # Options are passed to the underlying cache implementation. # @@ -442,7 +452,7 @@ module ActiveSupport raise NotImplementedError.new("#{self.class.name} does not support decrement") end - # Cleanup the cache by removing expired entries. + # Cleanups the cache by removing expired entries. # # Options are passed to the underlying cache implementation. # @@ -451,18 +461,18 @@ module ActiveSupport raise NotImplementedError.new("#{self.class.name} does not support cleanup") end - # Clear the entire cache. Be careful with this method since it could + # Clears the entire cache. Be careful with this method since it could # affect other processes if shared cache is being used. # # The options hash is passed to the underlying cache implementation. # # All implementations may not support this method. - def clear(options = nil) + def clear raise NotImplementedError.new("#{self.class.name} does not support clear") end protected - # Add the namespace defined in the options to a pattern designed to + # Adds the namespace defined in the options to a pattern designed to # match keys. Implementations that support delete_matched should call # this method to translate a pattern that matches names into one that # matches namespaced keys. @@ -470,7 +480,7 @@ module ActiveSupport prefix = options[:namespace].is_a?(Proc) ? options[:namespace].call : options[:namespace] if prefix source = pattern.source - if source.start_with?('^') + if source.start_with?("^") source = source[1, source.length] else source = ".*#{source[0, source.length]}" @@ -481,26 +491,26 @@ module ActiveSupport end end - # Read an entry from the cache implementation. Subclasses must implement + # Reads an entry from the cache implementation. Subclasses must implement # this method. def read_entry(key, options) # :nodoc: raise NotImplementedError.new end - # Write an entry to the cache implementation. Subclasses must implement + # Writes an entry to the cache implementation. Subclasses must implement # this method. def write_entry(key, entry, options) # :nodoc: raise NotImplementedError.new end - # Delete an entry from the cache implementation. Subclasses must + # Deletes an entry from the cache implementation. Subclasses must # implement this method. def delete_entry(key, options) # :nodoc: raise NotImplementedError.new end private - # Merge the default options with ones specific to a method call. + # Merges the default options with ones specific to a method call. def merged_options(call_options) # :nodoc: if call_options options.merge(call_options) @@ -509,7 +519,7 @@ module ActiveSupport end end - # Expand key to be a consistent string value. Invoke +cache_key+ if + # Expands key to be a consistent string value. Invokes +cache_key+ if # object responds to +cache_key+. Otherwise, +to_param+ method will be # called. If the key is a Hash, then keys will be sorted alphabetically. def expanded_key(key) # :nodoc: @@ -518,18 +528,18 @@ module ActiveSupport case key when Array if key.size > 1 - key = key.collect{|element| expanded_key(element)} + key = key.collect { |element| expanded_key(element) } else key = key.first end when Hash - key = key.sort_by { |k,_| k.to_s }.collect{|k,v| "#{k}=#{v}"} + key = key.sort_by { |k,_| k.to_s }.collect { |k,v| "#{k}=#{v}" } end key.to_param end - # Prefix a key with the namespace. Namespace and key will be delimited + # Prefixes a key with the namespace. Namespace and key will be delimited # with a colon. def normalize_key(key, options) key = expanded_key(key) @@ -550,20 +560,9 @@ module ActiveSupport def instrument(operation, key, options = nil) log { "Cache #{operation}: #{normalize_key(key, options)}#{options.blank? ? "" : " (#{options.inspect})"}" } - payload = { :key => key } - payload.merge!(options) if options.is_a?(Hash) - ActiveSupport::Notifications.instrument("cache_#{operation}.active_support", payload){ yield(payload) } - end - - def instrument_multi(operation, keys, options = nil) - log do - formatted_keys = keys.map { |k| "- #{k}" }.join("\n") - "Caches multi #{operation}:\n#{formatted_keys}#{options.blank? ? "" : " (#{options.inspect})"}" - end - - payload = { key: keys } + payload = { key: key } payload.merge!(options) if options.is_a?(Hash) - ActiveSupport::Notifications.instrument("cache_#{operation}_multi.active_support", payload) { yield(payload) } + ActiveSupport::Notifications.instrument("cache_#{operation}.active_support", payload) { yield(payload) } end def log @@ -578,7 +577,7 @@ module ActiveSupport # When an entry has a positive :race_condition_ttl defined, put the stale entry back into the cache # for a brief period while the entry is being recalculated. entry.expires_at = Time.now + race_ttl - write_entry(key, entry, :expires_in => race_ttl * 2) + write_entry(key, entry, expires_in: race_ttl * 2) else delete_entry(key, options) end @@ -588,12 +587,12 @@ module ActiveSupport end def get_entry_value(entry, name, options) - instrument(:fetch_hit, name, options) { |payload| } + instrument(:fetch_hit, name, options) {} entry.value end def save_block_result_to_cache(name, options) - result = instrument(:generate, name, options) do |payload| + result = instrument(:generate, name, options) do yield(name) end @@ -611,7 +610,7 @@ module ActiveSupport class Entry # :nodoc: DEFAULT_COMPRESS_LIMIT = 16.kilobytes - # Create a new cache entry for the specified value. Options supported are + # Creates a new cache entry for the specified value. Options supported are # +:compress+, +:compress_threshold+, and +:expires_in+. def initialize(value, options = {}) if should_compress?(value, options) @@ -630,7 +629,7 @@ module ActiveSupport compressed? ? uncompress(@value) : @value end - # Check if the entry is expired. The +expires_in+ parameter can override + # Checks if the entry is expired. The +expires_in+ parameter can override # the value set when the entry was created. def expired? @expires_in && @created_at + @expires_in <= Time.now.to_f @@ -665,7 +664,7 @@ module ActiveSupport end end - # Duplicate the value in a class. This is used by cache implementations that don't natively + # Duplicates the value in a class. This is used by cache implementations that don't natively # serialize entries to protect against accidental cache modifications. def dup_value! if @value && !compressed? && !(@value.is_a?(Numeric) || @value == true || @value == false) diff --git a/activesupport/lib/active_support/cache/file_store.rb b/activesupport/lib/active_support/cache/file_store.rb index 99c55b1aa4..1971ff182e 100644 --- a/activesupport/lib/active_support/cache/file_store.rb +++ b/activesupport/lib/active_support/cache/file_store.rb @@ -1,7 +1,7 @@ -require 'active_support/core_ext/marshal' -require 'active_support/core_ext/file/atomic' -require 'active_support/core_ext/string/conversions' -require 'uri/common' +require "active_support/core_ext/marshal" +require "active_support/core_ext/file/atomic" +require "active_support/core_ext/string/conversions" +require "uri/common" module ActiveSupport module Cache @@ -16,8 +16,8 @@ module ActiveSupport DIR_FORMATTER = "%03X" FILENAME_MAX_SIZE = 228 # max filename size on file system is 255, minus room for timestamp and random characters appended by Tempfile (used by atomic write) FILEPATH_MAX_SIZE = 900 # max is 1024, plus some room - EXCLUDED_DIRS = ['.', '..'].freeze - GITKEEP_FILES = ['.gitkeep', '.keep'].freeze + EXCLUDED_DIRS = [".", ".."].freeze + GITKEEP_FILES = [".gitkeep", ".keep"].freeze def initialize(cache_path, options = nil) super(options) @@ -27,9 +27,9 @@ module ActiveSupport # Deletes all items from the cache. In this case it deletes all the entries in the specified # file store directory except for .keep or .gitkeep. Be careful which directory is specified in your # config file when using +FileStore+ because everything in that directory will be deleted. - def clear(options = nil) + def clear root_dirs = exclude_from(cache_path, EXCLUDED_DIRS + GITKEEP_FILES) - FileUtils.rm_r(root_dirs.collect{|f| File.join(cache_path, f)}) + FileUtils.rm_r(root_dirs.collect { |f| File.join(cache_path, f) }) rescue Errno::ENOENT end @@ -80,7 +80,7 @@ module ActiveSupport def write_entry(key, entry, options) return false if options[:unless_exist] && File.exist?(key) ensure_cache_path(File.dirname(key)) - File.atomic_write(key, cache_path) {|f| Marshal.dump(entry, f)} + File.atomic_write(key, cache_path) { |f| Marshal.dump(entry, f) } true end @@ -102,7 +102,7 @@ module ActiveSupport # Lock a file for a block so only one process can modify it at a time. def lock_file(file_name, &block) # :nodoc: if File.exist?(file_name) - File.open(file_name, 'r+') do |f| + File.open(file_name, "r+") do |f| begin f.flock File::LOCK_EX yield diff --git a/activesupport/lib/active_support/cache/mem_cache_store.rb b/activesupport/lib/active_support/cache/mem_cache_store.rb index 174913365a..cfd5e39bc4 100644 --- a/activesupport/lib/active_support/cache/mem_cache_store.rb +++ b/activesupport/lib/active_support/cache/mem_cache_store.rb @@ -1,13 +1,13 @@ begin - require 'dalli' + require "dalli" rescue LoadError => e $stderr.puts "You don't have dalli installed in your application. Please add it to your Gemfile and run bundle install" raise e end -require 'digest/md5' -require 'active_support/core_ext/marshal' -require 'active_support/core_ext/array/extract_options' +require "digest/md5" +require "active_support/core_ext/marshal" +require "active_support/core_ext/array/extract_options" module ActiveSupport module Cache @@ -27,23 +27,23 @@ module ActiveSupport # Provide support for raw values in the local cache strategy. module LocalCacheWithRaw # :nodoc: protected - def read_entry(key, options) - entry = super - if options[:raw] && local_cache && entry - entry = deserialize_entry(entry.value) + def read_entry(key, options) + entry = super + if options[:raw] && local_cache && entry + entry = deserialize_entry(entry.value) + end + entry end - entry - end - def write_entry(key, entry, options) # :nodoc: - if options[:raw] && local_cache - raw_entry = Entry.new(entry.value.to_s) - raw_entry.expires_at = entry.expires_at - super(key, raw_entry, options) - else - super + def write_entry(key, entry, options) # :nodoc: + if options[:raw] && local_cache + raw_entry = Entry.new(entry.value.to_s) + raw_entry.expires_at = entry.expires_at + super(key, raw_entry, options) + else + super + end end - end end prepend Strategy::LocalCache @@ -85,7 +85,7 @@ module ActiveSupport @data = addresses.first else mem_cache_options = options.dup - UNIVERSAL_OPTIONS.each{|name| mem_cache_options.delete(name)} + UNIVERSAL_OPTIONS.each { |name| mem_cache_options.delete(name) } @data = self.class.build_mem_cache(*(addresses + [mem_cache_options])) end end @@ -96,16 +96,14 @@ module ActiveSupport options = names.extract_options! options = merged_options(options) - instrument_multi(:read, names, options) do - keys_to_names = Hash[names.map{|name| [normalize_key(name, options), name]}] - raw_values = @data.get_multi(keys_to_names.keys, :raw => true) - values = {} - raw_values.each do |key, value| - entry = deserialize_entry(value) - values[keys_to_names[key]] = entry.value unless entry.expired? - end - values + keys_to_names = Hash[names.map { |name| [normalize_key(name, options), name] }] + raw_values = @data.get_multi(keys_to_names.keys, raw: true) + values = {} + raw_values.each do |key, value| + entry = deserialize_entry(value) + values[keys_to_names[key]] = entry.value unless entry.expired? end + values end # Increment a cached value. This method uses the memcached incr atomic @@ -114,7 +112,7 @@ module ActiveSupport # to zero. def increment(name, amount = 1, options = nil) # :nodoc: options = merged_options(options) - instrument(:increment, name, :amount => amount) do + instrument(:increment, name, amount: amount) do rescue_error_with nil do @data.incr(normalize_key(name, options), amount) end @@ -127,7 +125,7 @@ module ActiveSupport # to zero. def decrement(name, amount = 1, options = nil) # :nodoc: options = merged_options(options) - instrument(:decrement, name, :amount => amount) do + instrument(:decrement, name, amount: amount) do rescue_error_with nil do @data.decr(normalize_key(name, options), amount) end @@ -178,7 +176,7 @@ module ActiveSupport def normalize_key(key, options) key = super.dup key = key.force_encoding(Encoding::ASCII_8BIT) - key = key.gsub(ESCAPE_KEY_CHARS){ |match| "%#{match.getbyte(0).to_s(16).upcase}" } + key = key.gsub(ESCAPE_KEY_CHARS) { |match| "%#{match.getbyte(0).to_s(16).upcase}" } key = "#{key[0, 213]}:md5:#{Digest::MD5.hexdigest(key)}" if key.size > 250 key end diff --git a/activesupport/lib/active_support/cache/memory_store.rb b/activesupport/lib/active_support/cache/memory_store.rb index 896c28ad8b..1a8477f9fe 100644 --- a/activesupport/lib/active_support/cache/memory_store.rb +++ b/activesupport/lib/active_support/cache/memory_store.rb @@ -1,10 +1,10 @@ -require 'monitor' +require "monitor" module ActiveSupport module Cache # A cache store implementation which stores everything into memory in the # same process. If you're running multiple Ruby on Rails server processes - # (which is the case if you're using mongrel_cluster or Phusion Passenger), + # (which is the case if you're using Phusion Passenger or puma clustered mode), # then this means that Rails server process instances won't be able # to share cache data with each other and this may not be the most # appropriate cache in that scenario. @@ -39,8 +39,8 @@ module ActiveSupport # Preemptively iterates through all stored keys and removes the ones which have expired. def cleanup(options = nil) options = merged_options(options) - instrument(:cleanup, :size => @data.size) do - keys = synchronize{ @data.keys } + instrument(:cleanup, size: @data.size) do + keys = synchronize { @data.keys } keys.each do |key| entry = @data[key] delete_entry(key, options) if entry && entry.expired? @@ -56,8 +56,8 @@ module ActiveSupport begin start_time = Time.now cleanup - instrument(:prune, target_size, :from => @cache_size) do - keys = synchronize{ @key_access.keys.sort{|a,b| @key_access[a].to_f <=> @key_access[b].to_f} } + instrument(:prune, target_size, from: @cache_size) do + keys = synchronize { @key_access.keys.sort { |a,b| @key_access[a].to_f <=> @key_access[b].to_f } } keys.each do |key| delete_entry(key, options) return if @cache_size <= target_size || (max_time && Time.now - start_time > max_time) diff --git a/activesupport/lib/active_support/cache/strategy/local_cache.rb b/activesupport/lib/active_support/cache/strategy/local_cache.rb index df38dbcf11..f41cc23eb0 100644 --- a/activesupport/lib/active_support/cache/strategy/local_cache.rb +++ b/activesupport/lib/active_support/cache/strategy/local_cache.rb @@ -1,6 +1,6 @@ -require 'active_support/core_ext/object/duplicable' -require 'active_support/core_ext/string/inflections' -require 'active_support/per_thread_registry' +require "active_support/core_ext/object/duplicable" +require "active_support/core_ext/string/inflections" +require "active_support/per_thread_registry" module ActiveSupport module Cache @@ -9,7 +9,7 @@ module ActiveSupport # duration of a block. Repeated calls to the cache for the same key will hit the # in-memory cache for faster access. module LocalCache - autoload :Middleware, 'active_support/cache/strategy/local_cache_middleware' + autoload :Middleware, "active_support/cache/strategy/local_cache_middleware" # Class for storing and registering the local caches. class LocalCacheRegistry # :nodoc: @@ -44,7 +44,7 @@ module ActiveSupport yield end - def clear(options = nil) + def clear @data.clear end @@ -70,6 +70,7 @@ module ActiveSupport def with_local_cache use_temporary_local_cache(LocalStore.new) { yield } end + # Middleware class can be inserted as a Rack handler to be local cache for the # duration of request. def middleware @@ -78,9 +79,9 @@ module ActiveSupport local_cache_key) end - def clear(options = nil) # :nodoc: + def clear # :nodoc: return super unless cache = local_cache - cache.clear(options) + cache.clear super end @@ -92,14 +93,14 @@ module ActiveSupport def increment(name, amount = 1, options = nil) # :nodoc: return super unless local_cache - value = bypass_local_cache{super} + value = bypass_local_cache { super } write_cache_value(name, value, options) value end def decrement(name, amount = 1, options = nil) # :nodoc: return super unless local_cache - value = bypass_local_cache{super} + value = bypass_local_cache { super } write_cache_value(name, value, options) value end @@ -126,7 +127,7 @@ module ActiveSupport def set_cache_value(value, name, amount, options) # :nodoc: ActiveSupport::Deprecation.warn(<<-MESSAGE.strip_heredoc) `set_cache_value` is deprecated and will be removed from Rails 5.1. - Please use `write_cache_value` + Please use `write_cache_value` instead. MESSAGE write_cache_value name, value, options end @@ -146,7 +147,7 @@ module ActiveSupport private def local_cache_key - @local_cache_key ||= "#{self.class.name.underscore}_local_cache_#{object_id}".gsub(/[\/-]/, '_').to_sym + @local_cache_key ||= "#{self.class.name.underscore}_local_cache_#{object_id}".gsub(/[\/-]/, "_").to_sym end def local_cache diff --git a/activesupport/lib/active_support/cache/strategy/local_cache_middleware.rb b/activesupport/lib/active_support/cache/strategy/local_cache_middleware.rb index a6f24b1a3c..af51f66dda 100644 --- a/activesupport/lib/active_support/cache/strategy/local_cache_middleware.rb +++ b/activesupport/lib/active_support/cache/strategy/local_cache_middleware.rb @@ -1,11 +1,10 @@ -require 'rack/body_proxy' -require 'rack/utils' +require "rack/body_proxy" +require "rack/utils" module ActiveSupport module Cache module Strategy module LocalCache - #-- # This class wraps up local storage for middlewares. Only the middleware method should # construct them. diff --git a/activesupport/lib/active_support/callbacks.rb b/activesupport/lib/active_support/callbacks.rb index e6baddf5db..2ad1145fae 100644 --- a/activesupport/lib/active_support/callbacks.rb +++ b/activesupport/lib/active_support/callbacks.rb @@ -1,13 +1,13 @@ -require 'active_support/concern' -require 'active_support/descendants_tracker' -require 'active_support/core_ext/array/extract_options' -require 'active_support/core_ext/class/attribute' -require 'active_support/core_ext/kernel/reporting' -require 'active_support/core_ext/kernel/singleton_class' -require 'active_support/core_ext/module/attribute_accessors' -require 'active_support/core_ext/string/filters' -require 'active_support/deprecation' -require 'thread' +require "active_support/concern" +require "active_support/descendants_tracker" +require "active_support/core_ext/array/extract_options" +require "active_support/core_ext/class/attribute" +require "active_support/core_ext/kernel/reporting" +require "active_support/core_ext/kernel/singleton_class" +require "active_support/core_ext/module/attribute_accessors" +require "active_support/core_ext/string/filters" +require "active_support/deprecation" +require "thread" module ActiveSupport # Callbacks are code hooks that are run at key points in an object's life cycle. @@ -63,6 +63,8 @@ module ActiveSupport included do extend ActiveSupport::DescendantsTracker + class_attribute :__callbacks, instance_writer: false + self.__callbacks ||= {} end CALLBACK_FILTER_TYPES = [:before, :after, :around] @@ -86,706 +88,777 @@ module ActiveSupport # run_callbacks :save do # save # end - def run_callbacks(kind, &block) - send "_run_#{kind}_callbacks", &block - end - - private + # + #-- + # + # As this method is used in many places, and often wraps large portions of + # user code, it has an additional design goal of minimizing its impact on + # the visible call stack. An exception from inside a :before or :after + # callback can be as noisy as it likes -- but when control has passed + # smoothly through and into the supplied block, we want as little evidence + # as possible that we were here. + def run_callbacks(kind) + callbacks = __callbacks[kind.to_sym] - def __run_callbacks__(callbacks, &block) if callbacks.empty? yield if block_given? else - runner = callbacks.compile - e = Filters::Environment.new(self, false, nil, block) - runner.call(e).value - end - end - - # A hook invoked every time a before callback is halted. - # This can be overridden in AS::Callback implementors in order - # to provide better debugging/logging. - def halted_callback_hook(filter) - end + env = Filters::Environment.new(self, false, nil) + next_sequence = callbacks.compile + + invoke_sequence = Proc.new do + skipped = nil + while true + current, next_sequence = next_sequence, next_sequence.nested + current.invoke_before(env) + if current.final? + env.value = !env.halted && (!block_given? || yield) + elsif current.skip?(env) + (skipped ||= []) << current + next + else + target, block, method, *arguments = current.expand_call_template(env, invoke_sequence) + target.send(method, *arguments, &block) + end + current.invoke_after(env) + skipped.pop.invoke_after(env) while skipped && skipped.first + break env.value + end + end - module Conditionals # :nodoc: - class Value - def initialize(&block) - @block = block + # Common case: no 'around' callbacks defined + if next_sequence.final? + next_sequence.invoke_before(env) + env.value = !env.halted && (!block_given? || yield) + next_sequence.invoke_after(env) + env.value + else + invoke_sequence.call end - def call(target, value); @block.call(value); end end end - module Filters - Environment = Struct.new(:target, :halted, :value, :run_block) + private - class End - def call(env) - block = env.run_block - env.value = !env.halted && (!block || block.call) - env - end + # A hook invoked every time a before callback is halted. + # This can be overridden in ActiveSupport::Callbacks implementors in order + # to provide better debugging/logging. + def halted_callback_hook(filter) end - ENDING = End.new - - class Before - def self.build(callback_sequence, user_callback, user_conditions, chain_config, filter) - halted_lambda = chain_config[:terminator] - if user_conditions.any? - halting_and_conditional(callback_sequence, user_callback, user_conditions, halted_lambda, filter) - else - halting(callback_sequence, user_callback, halted_lambda, filter) + module Conditionals # :nodoc: + class Value + def initialize(&block) + @block = block end + def call(target, value); @block.call(value); end end + end - def self.halting_and_conditional(callback_sequence, user_callback, user_conditions, halted_lambda, filter) - callback_sequence.before do |env| - target = env.target - value = env.value - halted = env.halted + module Filters + Environment = Struct.new(:target, :halted, :value) - if !halted && user_conditions.all? { |c| c.call(target, value) } - result_lambda = -> { user_callback.call target, value } - env.halted = halted_lambda.call(target, result_lambda) - if env.halted - target.send :halted_callback_hook, filter - end + class Before + def self.build(callback_sequence, user_callback, user_conditions, chain_config, filter) + halted_lambda = chain_config[:terminator] + + if user_conditions.any? + halting_and_conditional(callback_sequence, user_callback, user_conditions, halted_lambda, filter) + else + halting(callback_sequence, user_callback, halted_lambda, filter) end + end + + def self.halting_and_conditional(callback_sequence, user_callback, user_conditions, halted_lambda, filter) + callback_sequence.before do |env| + target = env.target + value = env.value + halted = env.halted + + if !halted && user_conditions.all? { |c| c.call(target, value) } + result_lambda = -> { user_callback.call target, value } + env.halted = halted_lambda.call(target, result_lambda) + if env.halted + target.send :halted_callback_hook, filter + end + end - env + env + end end - end - private_class_method :halting_and_conditional + private_class_method :halting_and_conditional - def self.halting(callback_sequence, user_callback, halted_lambda, filter) - callback_sequence.before do |env| - target = env.target - value = env.value - halted = env.halted + def self.halting(callback_sequence, user_callback, halted_lambda, filter) + callback_sequence.before do |env| + target = env.target + value = env.value + halted = env.halted - unless halted - result_lambda = -> { user_callback.call target, value } - env.halted = halted_lambda.call(target, result_lambda) + unless halted + result_lambda = -> { user_callback.call target, value } + env.halted = halted_lambda.call(target, result_lambda) - if env.halted - target.send :halted_callback_hook, filter + if env.halted + target.send :halted_callback_hook, filter + end end - end - env + env + end end + private_class_method :halting end - private_class_method :halting - end - class After - def self.build(callback_sequence, user_callback, user_conditions, chain_config) - if chain_config[:skip_after_callbacks_if_terminated] - if user_conditions.any? - halting_and_conditional(callback_sequence, user_callback, user_conditions) + class After + def self.build(callback_sequence, user_callback, user_conditions, chain_config) + if chain_config[:skip_after_callbacks_if_terminated] + if user_conditions.any? + halting_and_conditional(callback_sequence, user_callback, user_conditions) + else + halting(callback_sequence, user_callback) + end else - halting(callback_sequence, user_callback) + if user_conditions.any? + conditional callback_sequence, user_callback, user_conditions + else + simple callback_sequence, user_callback + end end - else - if user_conditions.any? - conditional callback_sequence, user_callback, user_conditions - else - simple callback_sequence, user_callback + end + + def self.halting_and_conditional(callback_sequence, user_callback, user_conditions) + callback_sequence.after do |env| + target = env.target + value = env.value + halted = env.halted + + if !halted && user_conditions.all? { |c| c.call(target, value) } + user_callback.call target, value + end + + env end end - end + private_class_method :halting_and_conditional - def self.halting_and_conditional(callback_sequence, user_callback, user_conditions) - callback_sequence.after do |env| - target = env.target - value = env.value - halted = env.halted + def self.halting(callback_sequence, user_callback) + callback_sequence.after do |env| + unless env.halted + user_callback.call env.target, env.value + end - if !halted && user_conditions.all? { |c| c.call(target, value) } - user_callback.call target, value + env end + end + private_class_method :halting + + def self.conditional(callback_sequence, user_callback, user_conditions) + callback_sequence.after do |env| + target = env.target + value = env.value + + if user_conditions.all? { |c| c.call(target, value) } + user_callback.call target, value + end - env + env + end end - end - private_class_method :halting_and_conditional + private_class_method :conditional - def self.halting(callback_sequence, user_callback) - callback_sequence.after do |env| - unless env.halted + def self.simple(callback_sequence, user_callback) + callback_sequence.after do |env| user_callback.call env.target, env.value - end - env + env + end end + private_class_method :simple end - private_class_method :halting + end - def self.conditional(callback_sequence, user_callback, user_conditions) - callback_sequence.after do |env| - target = env.target - value = env.value + class Callback #:nodoc:# + def self.build(chain, filter, kind, options) + if filter.is_a?(String) + ActiveSupport::Deprecation.warn(<<-MSG.squish) + Passing string to define callback is deprecated and will be removed + in Rails 5.1 without replacement. + MSG + end - if user_conditions.all? { |c| c.call(target, value) } - user_callback.call target, value - end + new chain.name, filter, kind, options, chain.config + end - env - end + attr_accessor :kind, :name + attr_reader :chain_config + + def initialize(name, filter, kind, options, chain_config) + @chain_config = chain_config + @name = name + @kind = kind + @filter = filter + @key = compute_identifier filter + @if = Array(options[:if]) + @unless = Array(options[:unless]) end - private_class_method :conditional - def self.simple(callback_sequence, user_callback) - callback_sequence.after do |env| - user_callback.call env.target, env.value + def filter; @key; end + def raw_filter; @filter; end - env - end + def merge_conditional_options(chain, if_option:, unless_option:) + options = { + if: @if.dup, + unless: @unless.dup + } + + options[:if].concat Array(unless_option) + options[:unless].concat Array(if_option) + + self.class.build chain, @filter, @kind, options + end + + def matches?(_kind, _filter) + @kind == _kind && filter == _filter end - private_class_method :simple - end - class Around - def self.build(callback_sequence, user_callback, user_conditions, chain_config) - if user_conditions.any? - halting_and_conditional(callback_sequence, user_callback, user_conditions) + def duplicates?(other) + case @filter + when Symbol, String + matches?(other.kind, other.filter) else - halting(callback_sequence, user_callback) + false end end - def self.halting_and_conditional(callback_sequence, user_callback, user_conditions) - callback_sequence.around do |env, &run| - target = env.target - value = env.value - halted = env.halted - - if !halted && user_conditions.all? { |c| c.call(target, value) } - user_callback.call(target, value) { - run.call.value - } - env - else - run.call - end + # Wraps code with filter + def apply(callback_sequence) + user_conditions = conditions_lambdas + user_callback = CallTemplate.build(@filter, self) + + case kind + when :before + Filters::Before.build(callback_sequence, user_callback.make_lambda, user_conditions, chain_config, @filter) + when :after + Filters::After.build(callback_sequence, user_callback.make_lambda, user_conditions, chain_config) + when :around + callback_sequence.around(user_callback, user_conditions) end end - private_class_method :halting_and_conditional - def self.halting(callback_sequence, user_callback) - callback_sequence.around do |env, &run| - target = env.target - value = env.value + def current_scopes + Array(chain_config[:scope]).map { |s| public_send(s) } + end - if env.halted - run.call + private + def compute_identifier(filter) + case filter + when String, ::Proc + filter.object_id else - user_callback.call(target, value) { - run.call.value - } - env + filter end end - end - private_class_method :halting + + def conditions_lambdas + @if.map { |c| CallTemplate.build(c, self).make_lambda } + + @unless.map { |c| CallTemplate.build(c, self).inverted_lambda } + end end - end - class Callback #:nodoc:# - def self.build(chain, filter, kind, options) - if filter.is_a?(String) - ActiveSupport::Deprecation.warn(<<-MSG.squish) - Passing string to define callback is deprecated and will be removed - in Rails 5.1 without replacement. - MSG + # A future invocation of user-supplied code (either as a callback, + # or a condition filter). + class CallTemplate # :nodoc: + def initialize(target, method, arguments, block) + @override_target = target + @method_name = method + @arguments = arguments + @override_block = block end - new chain.name, filter, kind, options, chain.config - end + # Return the parts needed to make this call, with the given + # input values. + # + # Returns an array of the form: + # + # [target, block, method, *arguments] + # + # This array can be used as such: + # + # target.send(method, *arguments, &block) + # + # The actual invocation is left up to the caller to minimize + # call stack pollution. + def expand(target, value, block) + result = @arguments.map { |arg| + case arg + when :value; value + when :target; target + when :block; block || raise(ArgumentError) + end + } - attr_accessor :kind, :name - attr_reader :chain_config - - def initialize(name, filter, kind, options, chain_config) - @chain_config = chain_config - @name = name - @kind = kind - @filter = filter - @key = compute_identifier filter - @if = Array(options[:if]) - @unless = Array(options[:unless]) - end + result.unshift @method_name + result.unshift @override_block || block + result.unshift @override_target || target - def filter; @key; end - def raw_filter; @filter; end + # target, block, method, *arguments = result + # target.send(method, *arguments, &block) + result + end - def merge_conditional_options(chain, if_option:, unless_option:) - options = { - :if => @if.dup, - :unless => @unless.dup - } + # Return a lambda that will make this call when given the input + # values. + def make_lambda + lambda do |target, value, &block| + target, block, method, *arguments = expand(target, value, block) + target.send(method, *arguments, &block) + end + end - options[:if].concat Array(unless_option) - options[:unless].concat Array(if_option) + # Return a lambda that will make this call when given the input + # values, but then return the boolean inverse of that result. + def inverted_lambda + lambda do |target, value, &block| + target, block, method, *arguments = expand(target, value, block) + ! target.send(method, *arguments, &block) + end + end - self.class.build chain, @filter, @kind, options - end + # Filters support: + # + # Symbols:: A method to call. + # Strings:: Some content to evaluate. + # Procs:: A proc to call with the object. + # Objects:: An object with a <tt>before_foo</tt> method on it to call. + # + # All of these objects are converted into a CallTemplate and handled + # the same after this point. + def self.build(filter, callback) + case filter + when Symbol + new(nil, filter, [], nil) + when String + new(nil, :instance_exec, [:value], compile_lambda(filter)) + when Conditionals::Value + new(filter, :call, [:target, :value], nil) + when ::Proc + if filter.arity > 1 + new(nil, :instance_exec, [:target, :block], filter) + elsif filter.arity > 0 + new(nil, :instance_exec, [:target], filter) + else + new(nil, :instance_exec, [], filter) + end + else + method_to_call = callback.current_scopes.join("_") - def matches?(_kind, _filter) - @kind == _kind && filter == _filter - end + new(filter, method_to_call, [:target], nil) + end + end - def duplicates?(other) - case @filter - when Symbol, String - matches?(other.kind, other.filter) - else - false + def self.compile_lambda(filter) + eval("lambda { |value| #{filter} }") end end - # Wraps code with filter - def apply(callback_sequence) - user_conditions = conditions_lambdas - user_callback = make_lambda @filter + # Execute before and after filters in a sequence instead of + # chaining them with nested lambda calls, see: + # https://github.com/rails/rails/issues/18011 + class CallbackSequence # :nodoc: + def initialize(nested = nil, call_template = nil, user_conditions = nil) + @nested = nested + @call_template = call_template + @user_conditions = user_conditions - case kind - when :before - Filters::Before.build(callback_sequence, user_callback, user_conditions, chain_config, @filter) - when :after - Filters::After.build(callback_sequence, user_callback, user_conditions, chain_config) - when :around - Filters::Around.build(callback_sequence, user_callback, user_conditions, chain_config) + @before = [] + @after = [] end - end - private - - def invert_lambda(l) - lambda { |*args, &blk| !l.call(*args, &blk) } - end + def before(&before) + @before.unshift(before) + self + end - # Filters support: - # - # Symbols:: A method to call. - # Strings:: Some content to evaluate. - # Procs:: A proc to call with the object. - # Objects:: An object with a <tt>before_foo</tt> method on it to call. - # - # All of these objects are converted into a lambda and handled - # the same after this point. - def make_lambda(filter) - case filter - when Symbol - lambda { |target, _, &blk| target.send filter, &blk } - when String - l = eval "lambda { |value| #{filter} }" - lambda { |target, value| target.instance_exec(value, &l) } - when Conditionals::Value then filter - when ::Proc - if filter.arity > 1 - return lambda { |target, _, &block| - raise ArgumentError unless block - target.instance_exec(target, block, &filter) - } - end - - if filter.arity <= 0 - lambda { |target, _| target.instance_exec(&filter) } - else - lambda { |target, _| target.instance_exec(target, &filter) } - end - else - scopes = Array(chain_config[:scope]) - method_to_call = scopes.map{ |s| public_send(s) }.join("_") + def after(&after) + @after.push(after) + self + end - lambda { |target, _, &blk| - filter.public_send method_to_call, target, &blk - } + def around(call_template, user_conditions) + CallbackSequence.new(self, call_template, user_conditions) end - end - def compute_identifier(filter) - case filter - when String, ::Proc - filter.object_id - else - filter + def skip?(arg) + arg.halted || !@user_conditions.all? { |c| c.call(arg.target, arg.value) } end - end - def conditions_lambdas - @if.map { |c| make_lambda c } + - @unless.map { |c| invert_lambda make_lambda c } - end - end + def nested + @nested + end - # Execute before and after filters in a sequence instead of - # chaining them with nested lambda calls, see: - # https://github.com/rails/rails/issues/18011 - class CallbackSequence - def initialize(&call) - @call = call - @before = [] - @after = [] - end + def final? + !@call_template + end - def before(&before) - @before.unshift(before) - self - end + def expand_call_template(arg, block) + @call_template.expand(arg.target, arg.value, block) + end - def after(&after) - @after.push(after) - self - end + def invoke_before(arg) + @before.each { |b| b.call(arg) } + end - def around(&around) - CallbackSequence.new do |arg| - around.call(arg) { - self.call(arg) - } + def invoke_after(arg) + @after.each { |a| a.call(arg) } end end - def call(arg) - @before.each { |b| b.call(arg) } - value = @call.call(arg) - @after.each { |a| a.call(arg) } - value - end - end + # An Array with a compile method. + class CallbackChain #:nodoc:# + include Enumerable - # An Array with a compile method. - class CallbackChain #:nodoc:# - include Enumerable - - attr_reader :name, :config - - def initialize(name, config) - @name = name - @config = { - scope: [:kind], - terminator: default_terminator - }.merge!(config) - @chain = [] - @callbacks = nil - @mutex = Mutex.new - end + attr_reader :name, :config - def each(&block); @chain.each(&block); end - def index(o); @chain.index(o); end - def empty?; @chain.empty?; end + def initialize(name, config) + @name = name + @config = { + scope: [:kind], + terminator: default_terminator + }.merge!(config) + @chain = [] + @callbacks = nil + @mutex = Mutex.new + end - def insert(index, o) - @callbacks = nil - @chain.insert(index, o) - end + def each(&block); @chain.each(&block); end + def index(o); @chain.index(o); end + def empty?; @chain.empty?; end - def delete(o) - @callbacks = nil - @chain.delete(o) - end + def insert(index, o) + @callbacks = nil + @chain.insert(index, o) + end - def clear - @callbacks = nil - @chain.clear - self - end + def delete(o) + @callbacks = nil + @chain.delete(o) + end - def initialize_copy(other) - @callbacks = nil - @chain = other.chain.dup - @mutex = Mutex.new - end + def clear + @callbacks = nil + @chain.clear + self + end - def compile - @callbacks || @mutex.synchronize do - final_sequence = CallbackSequence.new { |env| Filters::ENDING.call(env) } - @callbacks ||= @chain.reverse.inject(final_sequence) do |callback_sequence, callback| - callback.apply callback_sequence + def initialize_copy(other) + @callbacks = nil + @chain = other.chain.dup + @mutex = Mutex.new + end + + def compile + @callbacks || @mutex.synchronize do + final_sequence = CallbackSequence.new + @callbacks ||= @chain.reverse.inject(final_sequence) do |callback_sequence, callback| + callback.apply callback_sequence + end end end - end - def append(*callbacks) - callbacks.each { |c| append_one(c) } - end + def append(*callbacks) + callbacks.each { |c| append_one(c) } + end - def prepend(*callbacks) - callbacks.each { |c| prepend_one(c) } - end + def prepend(*callbacks) + callbacks.each { |c| prepend_one(c) } + end - protected - def chain; @chain; end + protected + def chain; @chain; end - private + private - def append_one(callback) - @callbacks = nil - remove_duplicates(callback) - @chain.push(callback) - end + def append_one(callback) + @callbacks = nil + remove_duplicates(callback) + @chain.push(callback) + end - def prepend_one(callback) - @callbacks = nil - remove_duplicates(callback) - @chain.unshift(callback) - end + def prepend_one(callback) + @callbacks = nil + remove_duplicates(callback) + @chain.unshift(callback) + end - def remove_duplicates(callback) - @callbacks = nil - @chain.delete_if { |c| callback.duplicates?(c) } - end + def remove_duplicates(callback) + @callbacks = nil + @chain.delete_if { |c| callback.duplicates?(c) } + end - def default_terminator - Proc.new do |target, result_lambda| - terminate = true - catch(:abort) do - result_lambda.call if result_lambda.is_a?(Proc) - terminate = false + def default_terminator + Proc.new do |target, result_lambda| + terminate = true + catch(:abort) do + result_lambda.call if result_lambda.is_a?(Proc) + terminate = false + end + terminate + end end - terminate - end end - end - module ClassMethods - def normalize_callback_params(filters, block) # :nodoc: - type = CALLBACK_FILTER_TYPES.include?(filters.first) ? filters.shift : :before - options = filters.extract_options! - filters.unshift(block) if block - [type, filters, options.dup] - end + module ClassMethods + def normalize_callback_params(filters, block) # :nodoc: + type = CALLBACK_FILTER_TYPES.include?(filters.first) ? filters.shift : :before + options = filters.extract_options! + filters.unshift(block) if block + [type, filters, options.dup] + end - # This is used internally to append, prepend and skip callbacks to the - # CallbackChain. - def __update_callbacks(name) #:nodoc: - ([self] + ActiveSupport::DescendantsTracker.descendants(self)).reverse_each do |target| - chain = target.get_callbacks name - yield target, chain.dup + # This is used internally to append, prepend and skip callbacks to the + # CallbackChain. + def __update_callbacks(name) #:nodoc: + ([self] + ActiveSupport::DescendantsTracker.descendants(self)).reverse_each do |target| + chain = target.get_callbacks name + yield target, chain.dup + end end - end - # Install a callback for the given event. - # - # set_callback :save, :before, :before_meth - # set_callback :save, :after, :after_meth, if: :condition - # set_callback :save, :around, ->(r, block) { stuff; result = block.call; stuff } - # - # The second argument indicates whether the callback is to be run +:before+, - # +:after+, or +:around+ the event. If omitted, +:before+ is assumed. This - # means the first example above can also be written as: - # - # set_callback :save, :before_meth - # - # The callback can be specified as a symbol naming an instance method; as a - # proc, lambda, or block; as a string to be instance evaluated(deprecated); or as an - # object that responds to a certain method determined by the <tt>:scope</tt> - # argument to +define_callbacks+. - # - # If a proc, lambda, or block is given, its body is evaluated in the context - # of the current object. It can also optionally accept the current object as - # an argument. - # - # Before and around callbacks are called in the order that they are set; - # after callbacks are called in the reverse order. - # - # Around callbacks can access the return value from the event, if it - # wasn't halted, from the +yield+ call. - # - # ===== Options - # - # * <tt>:if</tt> - A symbol, a string or an array of symbols and strings, - # each naming an instance method or a proc; the callback will be called - # only when they all return a true value. - # * <tt>:unless</tt> - A symbol, a string or an array of symbols and - # strings, each naming an instance method or a proc; the callback will - # be called only when they all return a false value. - # * <tt>:prepend</tt> - If +true+, the callback will be prepended to the - # existing chain rather than appended. - def set_callback(name, *filter_list, &block) - type, filters, options = normalize_callback_params(filter_list, block) - self_chain = get_callbacks name - mapped = filters.map do |filter| - Callback.build(self_chain, filter, type, options) - end - - __update_callbacks(name) do |target, chain| - options[:prepend] ? chain.prepend(*mapped) : chain.append(*mapped) - target.set_callbacks name, chain + # Install a callback for the given event. + # + # set_callback :save, :before, :before_method + # set_callback :save, :after, :after_method, if: :condition + # set_callback :save, :around, ->(r, block) { stuff; result = block.call; stuff } + # + # The second argument indicates whether the callback is to be run +:before+, + # +:after+, or +:around+ the event. If omitted, +:before+ is assumed. This + # means the first example above can also be written as: + # + # set_callback :save, :before_method + # + # The callback can be specified as a symbol naming an instance method; as a + # proc, lambda, or block; as a string to be instance evaluated(deprecated); or as an + # object that responds to a certain method determined by the <tt>:scope</tt> + # argument to +define_callbacks+. + # + # If a proc, lambda, or block is given, its body is evaluated in the context + # of the current object. It can also optionally accept the current object as + # an argument. + # + # Before and around callbacks are called in the order that they are set; + # after callbacks are called in the reverse order. + # + # Around callbacks can access the return value from the event, if it + # wasn't halted, from the +yield+ call. + # + # ===== Options + # + # * <tt>:if</tt> - A symbol, a string or an array of symbols and strings, + # each naming an instance method or a proc; the callback will be called + # only when they all return a true value. + # * <tt>:unless</tt> - A symbol, a string or an array of symbols and + # strings, each naming an instance method or a proc; the callback will + # be called only when they all return a false value. + # * <tt>:prepend</tt> - If +true+, the callback will be prepended to the + # existing chain rather than appended. + def set_callback(name, *filter_list, &block) + type, filters, options = normalize_callback_params(filter_list, block) + self_chain = get_callbacks name + mapped = filters.map do |filter| + Callback.build(self_chain, filter, type, options) + end + + __update_callbacks(name) do |target, chain| + options[:prepend] ? chain.prepend(*mapped) : chain.append(*mapped) + target.set_callbacks name, chain + end end - end - # Skip a previously set callback. Like +set_callback+, <tt>:if</tt> or - # <tt>:unless</tt> options may be passed in order to control when the - # callback is skipped. - # - # class Writer < Person - # skip_callback :validate, :before, :check_membership, if: -> { self.age > 18 } - # end - # - # An <tt>ArgumentError</tt> will be raised if the callback has not - # already been set (unless the <tt>:raise</tt> option is set to <tt>false</tt>). - def skip_callback(name, *filter_list, &block) - type, filters, options = normalize_callback_params(filter_list, block) - options[:raise] = true unless options.key?(:raise) - - __update_callbacks(name) do |target, chain| - filters.each do |filter| - callback = chain.find {|c| c.matches?(type, filter) } - - if !callback && options[:raise] - raise ArgumentError, "#{type.to_s.capitalize} #{name} callback #{filter.inspect} has not been defined" - end + # Skip a previously set callback. Like +set_callback+, <tt>:if</tt> or + # <tt>:unless</tt> options may be passed in order to control when the + # callback is skipped. + # + # class Writer < Person + # skip_callback :validate, :before, :check_membership, if: -> { age > 18 } + # end + # + # An <tt>ArgumentError</tt> will be raised if the callback has not + # already been set (unless the <tt>:raise</tt> option is set to <tt>false</tt>). + def skip_callback(name, *filter_list, &block) + type, filters, options = normalize_callback_params(filter_list, block) + options[:raise] = true unless options.key?(:raise) + + __update_callbacks(name) do |target, chain| + filters.each do |filter| + callback = chain.find { |c| c.matches?(type, filter) } + + if !callback && options[:raise] + raise ArgumentError, "#{type.to_s.capitalize} #{name} callback #{filter.inspect} has not been defined" + end - if callback && (options.key?(:if) || options.key?(:unless)) - new_callback = callback.merge_conditional_options(chain, if_option: options[:if], unless_option: options[:unless]) - chain.insert(chain.index(callback), new_callback) - end + if callback && (options.key?(:if) || options.key?(:unless)) + new_callback = callback.merge_conditional_options(chain, if_option: options[:if], unless_option: options[:unless]) + chain.insert(chain.index(callback), new_callback) + end - chain.delete(callback) + chain.delete(callback) + end + target.set_callbacks name, chain end - target.set_callbacks name, chain end - end - # Remove all set callbacks for the given event. - def reset_callbacks(name) - callbacks = get_callbacks name + # Remove all set callbacks for the given event. + def reset_callbacks(name) + callbacks = get_callbacks name + + ActiveSupport::DescendantsTracker.descendants(self).each do |target| + chain = target.get_callbacks(name).dup + callbacks.each { |c| chain.delete(c) } + target.set_callbacks name, chain + end - ActiveSupport::DescendantsTracker.descendants(self).each do |target| - chain = target.get_callbacks(name).dup - callbacks.each { |c| chain.delete(c) } - target.set_callbacks name, chain + set_callbacks(name, callbacks.dup.clear) end - self.set_callbacks name, callbacks.dup.clear - end + # Define sets of events in the object life cycle that support callbacks. + # + # define_callbacks :validate + # define_callbacks :initialize, :save, :destroy + # + # ===== Options + # + # * <tt>:terminator</tt> - Determines when a before filter will halt the + # callback chain, preventing following before and around callbacks from + # being called and the event from being triggered. + # This should be a lambda to be executed. + # The current object and the result lambda of the callback will be provided + # to the terminator lambda. + # + # define_callbacks :validate, terminator: ->(target, result_lambda) { result_lambda.call == false } + # + # In this example, if any before validate callbacks returns +false+, + # any successive before and around callback is not executed. + # + # The default terminator halts the chain when a callback throws +:abort+. + # + # * <tt>:skip_after_callbacks_if_terminated</tt> - Determines if after + # callbacks should be terminated by the <tt>:terminator</tt> option. By + # default after callbacks are executed no matter if callback chain was + # terminated or not. This option makes sense only when <tt>:terminator</tt> + # option is specified. + # + # * <tt>:scope</tt> - Indicates which methods should be executed when an + # object is used as a callback. + # + # class Audit + # def before(caller) + # puts 'Audit: before is called' + # end + # + # def before_save(caller) + # puts 'Audit: before_save is called' + # end + # end + # + # class Account + # include ActiveSupport::Callbacks + # + # define_callbacks :save + # set_callback :save, :before, Audit.new + # + # def save + # run_callbacks :save do + # puts 'save in main' + # end + # end + # end + # + # In the above case whenever you save an account the method + # <tt>Audit#before</tt> will be called. On the other hand + # + # define_callbacks :save, scope: [:kind, :name] + # + # would trigger <tt>Audit#before_save</tt> instead. That's constructed + # by calling <tt>#{kind}_#{name}</tt> on the given instance. In this + # case "kind" is "before" and "name" is "save". In this context +:kind+ + # and +:name+ have special meanings: +:kind+ refers to the kind of + # callback (before/after/around) and +:name+ refers to the method on + # which callbacks are being defined. + # + # A declaration like + # + # define_callbacks :save, scope: [:name] + # + # would call <tt>Audit#save</tt>. + # + # ===== Notes + # + # +names+ passed to +define_callbacks+ must not end with + # <tt>!</tt>, <tt>?</tt> or <tt>=</tt>. + # + # Calling +define_callbacks+ multiple times with the same +names+ will + # overwrite previous callbacks registered with +set_callback+. + def define_callbacks(*names) + options = names.extract_options! + + names.each do |name| + name = name.to_sym + + set_callbacks name, CallbackChain.new(name, options) + + module_eval <<-RUBY, __FILE__, __LINE__ + 1 + def _run_#{name}_callbacks(&block) + run_callbacks #{name.inspect}, &block + end - # Define sets of events in the object life cycle that support callbacks. - # - # define_callbacks :validate - # define_callbacks :initialize, :save, :destroy - # - # ===== Options - # - # * <tt>:terminator</tt> - Determines when a before filter will halt the - # callback chain, preventing following before and around callbacks from - # being called and the event from being triggered. - # This should be a lambda to be executed. - # The current object and the result lambda of the callback will be provided - # to the terminator lambda. - # - # define_callbacks :validate, terminator: ->(target, result_lambda) { result_lambda.call == false } - # - # In this example, if any before validate callbacks returns +false+, - # any successive before and around callback is not executed. - # - # The default terminator halts the chain when a callback throws +:abort+. - # - # * <tt>:skip_after_callbacks_if_terminated</tt> - Determines if after - # callbacks should be terminated by the <tt>:terminator</tt> option. By - # default after callbacks are executed no matter if callback chain was - # terminated or not. This option makes sense only when <tt>:terminator</tt> - # option is specified. - # - # * <tt>:scope</tt> - Indicates which methods should be executed when an - # object is used as a callback. - # - # class Audit - # def before(caller) - # puts 'Audit: before is called' - # end - # - # def before_save(caller) - # puts 'Audit: before_save is called' - # end - # end - # - # class Account - # include ActiveSupport::Callbacks - # - # define_callbacks :save - # set_callback :save, :before, Audit.new - # - # def save - # run_callbacks :save do - # puts 'save in main' - # end - # end - # end - # - # In the above case whenever you save an account the method - # <tt>Audit#before</tt> will be called. On the other hand - # - # define_callbacks :save, scope: [:kind, :name] - # - # would trigger <tt>Audit#before_save</tt> instead. That's constructed - # by calling <tt>#{kind}_#{name}</tt> on the given instance. In this - # case "kind" is "before" and "name" is "save". In this context +:kind+ - # and +:name+ have special meanings: +:kind+ refers to the kind of - # callback (before/after/around) and +:name+ refers to the method on - # which callbacks are being defined. - # - # A declaration like - # - # define_callbacks :save, scope: [:name] - # - # would call <tt>Audit#save</tt>. - # - # NOTE: +method_name+ passed to `define_model_callbacks` must not end with - # `!`, `?` or `=`. - def define_callbacks(*names) - options = names.extract_options! - - names.each do |name| - class_attribute "_#{name}_callbacks", instance_writer: false - set_callbacks name, CallbackChain.new(name, options) - - module_eval <<-RUBY, __FILE__, __LINE__ + 1 - def _run_#{name}_callbacks(&block) - __run_callbacks__(_#{name}_callbacks, &block) - end - RUBY + def self._#{name}_callbacks + get_callbacks(#{name.inspect}) + end + + def self._#{name}_callbacks=(value) + set_callbacks(#{name.inspect}, value) + end + + def _#{name}_callbacks + __callbacks[#{name.inspect}] + end + RUBY + end end - end - protected + protected - def get_callbacks(name) # :nodoc: - send "_#{name}_callbacks" - end + def get_callbacks(name) # :nodoc: + __callbacks[name.to_sym] + end - def set_callbacks(name, callbacks) # :nodoc: - send "_#{name}_callbacks=", callbacks - end + def set_callbacks(name, callbacks) # :nodoc: + self.__callbacks = __callbacks.merge(name.to_sym => callbacks) + end - def deprecated_false_terminator # :nodoc: - Proc.new do |target, result_lambda| - terminate = true - catch(:abort) do - result = result_lambda.call if result_lambda.is_a?(Proc) - if Callbacks.halt_and_display_warning_on_return_false && result == false - display_deprecation_warning_for_false_terminator - else - terminate = false + def deprecated_false_terminator # :nodoc: + Proc.new do |target, result_lambda| + terminate = true + catch(:abort) do + result = result_lambda.call if result_lambda.is_a?(Proc) + if Callbacks.halt_and_display_warning_on_return_false && result == false + display_deprecation_warning_for_false_terminator + else + terminate = false + end + end + terminate end end - terminate - end - end - private + private - def display_deprecation_warning_for_false_terminator - ActiveSupport::Deprecation.warn(<<-MSG.squish) - Returning `false` in Active Record and Active Model callbacks will not implicitly halt a callback chain in the next release of Rails. - To explicitly halt the callback chain, please use `throw :abort` instead. - MSG + def display_deprecation_warning_for_false_terminator + ActiveSupport::Deprecation.warn(<<-MSG.squish) + Returning `false` in Active Record and Active Model callbacks will not implicitly halt a callback chain in Rails 5.1. + To explicitly halt the callback chain, please use `throw :abort` instead. + MSG + end end - end end end diff --git a/activesupport/lib/active_support/concurrency/latch.rb b/activesupport/lib/active_support/concurrency/latch.rb index 4abe5ece6f..53e09b685c 100644 --- a/activesupport/lib/active_support/concurrency/latch.rb +++ b/activesupport/lib/active_support/concurrency/latch.rb @@ -1,18 +1,24 @@ -require 'concurrent/atomic/count_down_latch' +require "concurrent/atomic/count_down_latch" module ActiveSupport module Concurrency - class Latch < Concurrent::CountDownLatch - + class Latch def initialize(count = 1) - ActiveSupport::Deprecation.warn("ActiveSupport::Concurrency::Latch is deprecated. Please use Concurrent::CountDownLatch instead.") - super(count) + if count == 1 + ActiveSupport::Deprecation.warn("ActiveSupport::Concurrency::Latch is deprecated. Please use Concurrent::Event instead.") + else + ActiveSupport::Deprecation.warn("ActiveSupport::Concurrency::Latch is deprecated. Please use Concurrent::CountDownLatch instead.") + end + + @inner = Concurrent::CountDownLatch.new(count) end - alias_method :release, :count_down + def release + @inner.count_down + end def await - wait(nil) + @inner.wait(nil) end end end diff --git a/activesupport/lib/active_support/concurrency/share_lock.rb b/activesupport/lib/active_support/concurrency/share_lock.rb index 54244317e4..4318523b07 100644 --- a/activesupport/lib/active_support/concurrency/share_lock.rb +++ b/activesupport/lib/active_support/concurrency/share_lock.rb @@ -1,5 +1,5 @@ -require 'thread' -require 'monitor' +require "thread" +require "monitor" module ActiveSupport module Concurrency @@ -13,6 +13,37 @@ module ActiveSupport # we need exclusive locks to be reentrant, and we need to be able # to upgrade share locks to exclusive. + def raw_state # :nodoc: + synchronize do + threads = @sleeping.keys | @sharing.keys | @waiting.keys + threads |= [@exclusive_thread] if @exclusive_thread + + data = {} + + threads.each do |thread| + purpose, compatible = @waiting[thread] + + data[thread] = { + thread: thread, + sharing: @sharing[thread], + exclusive: @exclusive_thread == thread, + purpose: purpose, + compatible: compatible, + waiting: !!@waiting[thread], + sleeper: @sleeping[thread], + } + end + + # NB: Yields while holding our *internal* synchronize lock, + # which is supposed to be used only for a few instructions at + # a time. This allows the caller to inspect additional state + # without things changing out from underneath, but would have + # disastrous effects upon normal operation. Fortunately, this + # method is only intended to be called when things have + # already gone wrong. + yield data + end + end def initialize super() @@ -21,6 +52,7 @@ module ActiveSupport @sharing = Hash.new(0) @waiting = {} + @sleeping = {} @exclusive_thread = nil @exclusive_depth = 0 end @@ -46,7 +78,7 @@ module ActiveSupport return false if no_wait yield_shares(purpose: purpose, compatible: compatible, block_share: true) do - @cv.wait_while { busy_for_exclusive?(purpose) } + wait_for(:start_exclusive) { busy_for_exclusive?(purpose) } end end @exclusive_thread = Thread.current @@ -69,7 +101,7 @@ module ActiveSupport if eligible_waiters?(compatible) yield_shares(compatible: compatible, block_share: true) do - @cv.wait_while { @exclusive_thread || eligible_waiters?(compatible) } + wait_for(:stop_exclusive) { @exclusive_thread || eligible_waiters?(compatible) } end end @cv.broadcast @@ -84,11 +116,11 @@ module ActiveSupport elsif @waiting[Thread.current] # We're nested inside a +yield_shares+ call: we'll resume as # soon as there isn't an exclusive lock in our way - @cv.wait_while { @exclusive_thread } + wait_for(:start_sharing) { @exclusive_thread } else # This is an initial / outermost share call: any outstanding # requests for an exclusive lock get to go first - @cv.wait_while { busy_for_sharing?(false) } + wait_for(:start_sharing) { busy_for_sharing?(false) } end @sharing[Thread.current] += 1 end @@ -144,16 +176,16 @@ module ActiveSupport end compatible |= [false] unless block_share @waiting[Thread.current] = [purpose, compatible] - - @cv.broadcast end + + @cv.broadcast end begin yield ensure synchronize do - @cv.wait_while { @exclusive_thread && @exclusive_thread != Thread.current } + wait_for(:yield_shares) { @exclusive_thread && @exclusive_thread != Thread.current } if previous_wait @waiting[Thread.current] = previous_wait @@ -167,20 +199,27 @@ module ActiveSupport private - # Must be called within synchronize - def busy_for_exclusive?(purpose) - busy_for_sharing?(purpose) || - @sharing.size > (@sharing[Thread.current] > 0 ? 1 : 0) - end + # Must be called within synchronize + def busy_for_exclusive?(purpose) + busy_for_sharing?(purpose) || + @sharing.size > (@sharing[Thread.current] > 0 ? 1 : 0) + end - def busy_for_sharing?(purpose) - (@exclusive_thread && @exclusive_thread != Thread.current) || - @waiting.any? { |t, (_, c)| t != Thread.current && !c.include?(purpose) } - end + def busy_for_sharing?(purpose) + (@exclusive_thread && @exclusive_thread != Thread.current) || + @waiting.any? { |t, (_, c)| t != Thread.current && !c.include?(purpose) } + end - def eligible_waiters?(compatible) - @waiting.any? { |t, (p, _)| compatible.include?(p) && @waiting.all? { |t2, (_, c2)| t == t2 || c2.include?(p) } } - end + def eligible_waiters?(compatible) + @waiting.any? { |t, (p, _)| compatible.include?(p) && @waiting.all? { |t2, (_, c2)| t == t2 || c2.include?(p) } } + end + + def wait_for(method) + @sleeping[Thread.current] = method + @cv.wait_while { yield } + ensure + @sleeping.delete Thread.current + end end end end diff --git a/activesupport/lib/active_support/configurable.rb b/activesupport/lib/active_support/configurable.rb index 8256c325af..f72a893bcc 100644 --- a/activesupport/lib/active_support/configurable.rb +++ b/activesupport/lib/active_support/configurable.rb @@ -1,6 +1,7 @@ -require 'active_support/concern' -require 'active_support/ordered_options' -require 'active_support/core_ext/array/extract_options' +require "active_support/concern" +require "active_support/ordered_options" +require "active_support/core_ext/array/extract_options" +require "active_support/core_ext/regexp" module ActiveSupport # Configurable provides a <tt>config</tt> method to store and retrieve @@ -107,7 +108,7 @@ module ActiveSupport options = names.extract_options! names.each do |name| - raise NameError.new('invalid config attribute name') unless name =~ /\A[_A-Za-z]\w*\z/ + raise NameError.new("invalid config attribute name") unless /\A[_A-Za-z]\w*\z/.match?(name) reader, reader_line = "def #{name}; config.#{name}; end", __LINE__ writer, writer_line = "def #{name}=(value); config.#{name} = value; end", __LINE__ @@ -145,4 +146,3 @@ module ActiveSupport end end end - diff --git a/activesupport/lib/active_support/core_ext/array.rb b/activesupport/lib/active_support/core_ext/array.rb index 7551551bd7..e908386a1c 100644 --- a/activesupport/lib/active_support/core_ext/array.rb +++ b/activesupport/lib/active_support/core_ext/array.rb @@ -1,7 +1,7 @@ -require 'active_support/core_ext/array/wrap' -require 'active_support/core_ext/array/access' -require 'active_support/core_ext/array/conversions' -require 'active_support/core_ext/array/extract_options' -require 'active_support/core_ext/array/grouping' -require 'active_support/core_ext/array/prepend_and_append' -require 'active_support/core_ext/array/inquiry' +require "active_support/core_ext/array/wrap" +require "active_support/core_ext/array/access" +require "active_support/core_ext/array/conversions" +require "active_support/core_ext/array/extract_options" +require "active_support/core_ext/array/grouping" +require "active_support/core_ext/array/prepend_and_append" +require "active_support/core_ext/array/inquiry" diff --git a/activesupport/lib/active_support/core_ext/array/conversions.rb b/activesupport/lib/active_support/core_ext/array/conversions.rb index 8718b7e1e5..1d4c83ae52 100644 --- a/activesupport/lib/active_support/core_ext/array/conversions.rb +++ b/activesupport/lib/active_support/core_ext/array/conversions.rb @@ -1,8 +1,8 @@ -require 'active_support/xml_mini' -require 'active_support/core_ext/hash/keys' -require 'active_support/core_ext/string/inflections' -require 'active_support/core_ext/object/to_param' -require 'active_support/core_ext/object/to_query' +require "active_support/xml_mini" +require "active_support/core_ext/hash/keys" +require "active_support/core_ext/string/inflections" +require "active_support/core_ext/object/to_param" +require "active_support/core_ext/object/to_query" class Array # Converts the array to a comma-separated sentence where the last element is @@ -40,6 +40,12 @@ class Array # ['one', 'two', 'three'].to_sentence(words_connector: ' or ', last_word_connector: ' or at least ') # # => "one or two or at least three" # + # [].to_sentence(fallback_string: 'none') + # # => "none" + # + # ['one', 'two'].to_sentence(fallback_string: 'none') + # # => "one and two" + # # Using <tt>:locale</tt> option: # # # Given this locale dictionary: @@ -57,12 +63,12 @@ class Array # ['uno', 'dos', 'tres'].to_sentence(locale: :es) # # => "uno o dos o al menos tres" def to_sentence(options = {}) - options.assert_valid_keys(:words_connector, :two_words_connector, :last_word_connector, :locale) + options.assert_valid_keys(:words_connector, :two_words_connector, :last_word_connector, :locale, :fallback_string) default_connectors = { - :words_connector => ', ', - :two_words_connector => ' and ', - :last_word_connector => ', and ' + words_connector: ", ", + two_words_connector: " and ", + last_word_connector: ", and " } if defined?(I18n) i18n_connectors = I18n.translate(:'support.array', locale: options[:locale], default: {}) @@ -72,7 +78,7 @@ class Array case length when 0 - '' + "#{options[:fallback_string] || ''}" when 1 "#{self[0]}" when 2 @@ -92,9 +98,9 @@ class Array case format when :db if empty? - 'null' + "null" else - collect(&:id).join(',') + collect(&:id).join(",") end else to_default_s @@ -179,7 +185,7 @@ class Array # </messages> # def to_xml(options = {}) - require 'active_support/builder' unless defined?(Builder) + require "active_support/builder" unless defined?(Builder) options = options.dup options[:indent] ||= 2 @@ -187,9 +193,9 @@ class Array options[:root] ||= \ if first.class != Hash && all? { |e| e.is_a?(first.class) } underscored = ActiveSupport::Inflector.underscore(first.class.name) - ActiveSupport::Inflector.pluralize(underscored).tr('/', '_') + ActiveSupport::Inflector.pluralize(underscored).tr("/", "_") else - 'objects' + "objects" end builder = options[:builder] @@ -197,7 +203,7 @@ class Array root = ActiveSupport::XmlMini.rename_key(options[:root].to_s, options) children = options.delete(:children) || root.singularize - attributes = options[:skip_types] ? {} : { type: 'array' } + attributes = options[:skip_types] ? {} : { type: "array" } if empty? builder.tag!(root, attributes) diff --git a/activesupport/lib/active_support/core_ext/array/grouping.rb b/activesupport/lib/active_support/core_ext/array/grouping.rb index 87ae052eb0..ea9d85f6e3 100644 --- a/activesupport/lib/active_support/core_ext/array/grouping.rb +++ b/activesupport/lib/active_support/core_ext/array/grouping.rb @@ -89,28 +89,19 @@ class Array # [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) + arr = self.dup + result = [] if block_given? - inject([[]]) do |results, element| - if yield(element) - results << [] - else - results.last << element - end - - results + while (idx = arr.index { |i| yield i }) + result << arr.shift(idx) + arr.shift end else - results, arr = [[]], self.dup - until arr.empty? - if (idx = arr.index(value)) - results.last.concat(arr.shift(idx)) - arr.shift - results << [] - else - results.last.concat(arr.shift(arr.size)) - end + while (idx = arr.index(value)) + result << arr.shift(idx) + arr.shift end - results end + result << arr end end diff --git a/activesupport/lib/active_support/core_ext/array/inquiry.rb b/activesupport/lib/active_support/core_ext/array/inquiry.rb index e8f44cc378..66fa5fcd0c 100644 --- a/activesupport/lib/active_support/core_ext/array/inquiry.rb +++ b/activesupport/lib/active_support/core_ext/array/inquiry.rb @@ -1,4 +1,4 @@ -require 'active_support/array_inquirer' +require "active_support/array_inquirer" class Array # Wraps the array in an +ArrayInquirer+ object, which gives a friendlier way diff --git a/activesupport/lib/active_support/core_ext/array/prepend_and_append.rb b/activesupport/lib/active_support/core_ext/array/prepend_and_append.rb index f8d48b69df..16a6789f8d 100644 --- a/activesupport/lib/active_support/core_ext/array/prepend_and_append.rb +++ b/activesupport/lib/active_support/core_ext/array/prepend_and_append.rb @@ -4,4 +4,4 @@ class Array # The human way of thinking about adding stuff to the beginning of a list is with prepend. alias_method :prepend, :unshift -end
\ No newline at end of file +end diff --git a/activesupport/lib/active_support/core_ext/benchmark.rb b/activesupport/lib/active_support/core_ext/benchmark.rb index eb25b2bc44..2300953860 100644 --- a/activesupport/lib/active_support/core_ext/benchmark.rb +++ b/activesupport/lib/active_support/core_ext/benchmark.rb @@ -1,4 +1,4 @@ -require 'benchmark' +require "benchmark" class << Benchmark # Benchmark realtime in milliseconds. diff --git a/activesupport/lib/active_support/core_ext/big_decimal.rb b/activesupport/lib/active_support/core_ext/big_decimal.rb index 8143113cfa..7b4f87f10e 100644 --- a/activesupport/lib/active_support/core_ext/big_decimal.rb +++ b/activesupport/lib/active_support/core_ext/big_decimal.rb @@ -1 +1 @@ -require 'active_support/core_ext/big_decimal/conversions' +require "active_support/core_ext/big_decimal/conversions" diff --git a/activesupport/lib/active_support/core_ext/big_decimal/conversions.rb b/activesupport/lib/active_support/core_ext/big_decimal/conversions.rb index 22fc7ecf92..decd4e1699 100644 --- a/activesupport/lib/active_support/core_ext/big_decimal/conversions.rb +++ b/activesupport/lib/active_support/core_ext/big_decimal/conversions.rb @@ -1,12 +1,10 @@ -require 'bigdecimal' -require 'bigdecimal/util' +require "bigdecimal" +require "bigdecimal/util" module ActiveSupport module BigDecimalWithDefaultFormat #:nodoc: - DEFAULT_STRING_FORMAT = 'F' - - def to_s(format = nil) - super(format || DEFAULT_STRING_FORMAT) + def to_s(format = "F") + super(format) end end end diff --git a/activesupport/lib/active_support/core_ext/class.rb b/activesupport/lib/active_support/core_ext/class.rb index ef903d59b5..6a19e862d0 100644 --- a/activesupport/lib/active_support/core_ext/class.rb +++ b/activesupport/lib/active_support/core_ext/class.rb @@ -1,2 +1,2 @@ -require 'active_support/core_ext/class/attribute' -require 'active_support/core_ext/class/subclasses' +require "active_support/core_ext/class/attribute" +require "active_support/core_ext/class/subclasses" diff --git a/activesupport/lib/active_support/core_ext/class/attribute.rb b/activesupport/lib/active_support/core_ext/class/attribute.rb index 802d988af2..ba422f9071 100644 --- a/activesupport/lib/active_support/core_ext/class/attribute.rb +++ b/activesupport/lib/active_support/core_ext/class/attribute.rb @@ -1,6 +1,6 @@ -require 'active_support/core_ext/kernel/singleton_class' -require 'active_support/core_ext/module/remove_method' -require 'active_support/core_ext/array/extract_options' +require "active_support/core_ext/kernel/singleton_class" +require "active_support/core_ext/module/remove_method" +require "active_support/core_ext/array/extract_options" class Class # Declare a class-level attribute whose value is inheritable by subclasses. @@ -20,14 +20,14 @@ class Class # Base.setting # => true # # In the above case as long as Subclass does not assign a value to setting - # by performing <tt>Subclass.setting = _something_ </tt>, <tt>Subclass.setting</tt> + # by performing <tt>Subclass.setting = _something_</tt>, <tt>Subclass.setting</tt> # would read value assigned to parent class. Once Subclass assigns a value then # the value assigned by Subclass would be returned. # # This matches normal Ruby method inheritance: think of writing an attribute # on a subclass as overriding the reader method. However, you need to be aware # when using +class_attribute+ with mutable structures as +Array+ or +Hash+. - # In such cases, you don't want to do changes in places but use setters: + # In such cases, you don't want to do changes in place. Instead use setters: # # Base.setting = [] # Base.setting # => [] diff --git a/activesupport/lib/active_support/core_ext/class/attribute_accessors.rb b/activesupport/lib/active_support/core_ext/class/attribute_accessors.rb index 84d5e95e7a..0f767925ed 100644 --- a/activesupport/lib/active_support/core_ext/class/attribute_accessors.rb +++ b/activesupport/lib/active_support/core_ext/class/attribute_accessors.rb @@ -1,4 +1,4 @@ # cattr_* became mattr_* aliases in 7dfbd91b0780fbd6a1dd9bfbc176e10894871d2d, # but we keep this around for libraries that directly require it knowing they # want cattr_*. No need to deprecate. -require 'active_support/core_ext/module/attribute_accessors' +require "active_support/core_ext/module/attribute_accessors" diff --git a/activesupport/lib/active_support/core_ext/class/subclasses.rb b/activesupport/lib/active_support/core_ext/class/subclasses.rb index b0f9a8be34..10a7c787f6 100644 --- a/activesupport/lib/active_support/core_ext/class/subclasses.rb +++ b/activesupport/lib/active_support/core_ext/class/subclasses.rb @@ -1,12 +1,25 @@ -require 'active_support/core_ext/module/anonymous' -require 'active_support/core_ext/module/reachable' +require "active_support/core_ext/module/anonymous" +require "active_support/core_ext/module/reachable" class Class begin # Test if this Ruby supports each_object against singleton_class ObjectSpace.each_object(Numeric.singleton_class) {} - def descendants # :nodoc: + # Returns an array with all classes that are < than its receiver. + # + # class C; end + # C.descendants # => [] + # + # class B < C; end + # C.descendants # => [B] + # + # class A < B; end + # C.descendants # => [B, A] + # + # class D < C; end + # C.descendants # => [B, A, D] + def descendants descendants = [] ObjectSpace.each_object(singleton_class) do |k| descendants.unshift k unless k == self @@ -14,7 +27,7 @@ class Class descendants end rescue StandardError # JRuby 9.0.4.0 and earlier - def descendants # :nodoc: + def descendants descendants = [] ObjectSpace.each_object(Class) do |k| descendants.unshift k if k < self @@ -26,8 +39,6 @@ class Class # Returns an array with the direct children of +self+. # - # Integer.subclasses # => [Fixnum, Bignum] - # # class Foo; end # class Bar < Foo; end # class Baz < Bar; end diff --git a/activesupport/lib/active_support/core_ext/date.rb b/activesupport/lib/active_support/core_ext/date.rb index 7f0f4639a2..4f66804da2 100644 --- a/activesupport/lib/active_support/core_ext/date.rb +++ b/activesupport/lib/active_support/core_ext/date.rb @@ -1,5 +1,5 @@ -require 'active_support/core_ext/date/acts_like' -require 'active_support/core_ext/date/blank' -require 'active_support/core_ext/date/calculations' -require 'active_support/core_ext/date/conversions' -require 'active_support/core_ext/date/zones' +require "active_support/core_ext/date/acts_like" +require "active_support/core_ext/date/blank" +require "active_support/core_ext/date/calculations" +require "active_support/core_ext/date/conversions" +require "active_support/core_ext/date/zones" diff --git a/activesupport/lib/active_support/core_ext/date/acts_like.rb b/activesupport/lib/active_support/core_ext/date/acts_like.rb index cd90cee236..46fe99ad47 100644 --- a/activesupport/lib/active_support/core_ext/date/acts_like.rb +++ b/activesupport/lib/active_support/core_ext/date/acts_like.rb @@ -1,4 +1,4 @@ -require 'active_support/core_ext/object/acts_like' +require "active_support/core_ext/object/acts_like" class Date # Duck-types as a Date-like class. See Object#acts_like?. diff --git a/activesupport/lib/active_support/core_ext/date/blank.rb b/activesupport/lib/active_support/core_ext/date/blank.rb index 71627b6a6f..edd2847126 100644 --- a/activesupport/lib/active_support/core_ext/date/blank.rb +++ b/activesupport/lib/active_support/core_ext/date/blank.rb @@ -1,4 +1,4 @@ -require 'date' +require "date" class Date #:nodoc: # No Date is blank: diff --git a/activesupport/lib/active_support/core_ext/date/calculations.rb b/activesupport/lib/active_support/core_ext/date/calculations.rb index d589b67bf7..2e64097933 100644 --- a/activesupport/lib/active_support/core_ext/date/calculations.rb +++ b/activesupport/lib/active_support/core_ext/date/calculations.rb @@ -1,9 +1,9 @@ -require 'date' -require 'active_support/duration' -require 'active_support/core_ext/object/acts_like' -require 'active_support/core_ext/date/zones' -require 'active_support/core_ext/time/zones' -require 'active_support/core_ext/date_and_time/calculations' +require "date" +require "active_support/duration" +require "active_support/core_ext/object/acts_like" +require "active_support/core_ext/date/zones" +require "active_support/core_ext/time/zones" +require "active_support/core_ext/date_and_time/calculations" class Date include DateAndTime::Calculations @@ -129,7 +129,7 @@ class Date options.fetch(:day, day) ) end - + # Allow Date to be compared with Time by converting to DateTime and relying on the <=> from there. def compare_with_coercion(other) if other.is_a?(Time) diff --git a/activesupport/lib/active_support/core_ext/date/conversions.rb b/activesupport/lib/active_support/core_ext/date/conversions.rb index ed8bca77ac..d553406dff 100644 --- a/activesupport/lib/active_support/core_ext/date/conversions.rb +++ b/activesupport/lib/active_support/core_ext/date/conversions.rb @@ -1,20 +1,20 @@ -require 'date' -require 'active_support/inflector/methods' -require 'active_support/core_ext/date/zones' -require 'active_support/core_ext/module/remove_method' +require "date" +require "active_support/inflector/methods" +require "active_support/core_ext/date/zones" +require "active_support/core_ext/module/remove_method" class Date DATE_FORMATS = { - :short => '%e %b', - :long => '%B %e, %Y', - :db => '%Y-%m-%d', - :number => '%Y%m%d', - :long_ordinal => lambda { |date| + short: "%d %b", + long: "%B %d, %Y", + db: "%Y-%m-%d", + number: "%Y%m%d", + long_ordinal: lambda { |date| day_format = ActiveSupport::Inflector.ordinalize(date.day) date.strftime("%B #{day_format}, %Y") # => "April 25th, 2007" }, - :rfc822 => '%e %b %Y', - :iso8601 => lambda { |date| date.iso8601 } + rfc822: "%d %b %Y", + iso8601: lambda { |date| date.iso8601 } } # Ruby 1.9 has Date#to_time which converts to localtime only. @@ -65,7 +65,7 @@ class Date # Overrides the default inspect method with a human readable one, e.g., "Mon, 21 Feb 2005" def readable_inspect - strftime('%a, %d %b %Y') + strftime("%a, %d %b %Y") end alias_method :default_inspect, :inspect alias_method :inspect, :readable_inspect @@ -80,6 +80,7 @@ class Date # # date.to_time(:utc) # => 2007-11-10 00:00:00 UTC def to_time(form = :local) + raise ArgumentError, "Expected :local or :utc, got #{form.inspect}." unless [:local, :utc].include?(form) ::Time.send(form, year, month, day) end diff --git a/activesupport/lib/active_support/core_ext/date/zones.rb b/activesupport/lib/active_support/core_ext/date/zones.rb index d109b430db..da23fe4892 100644 --- a/activesupport/lib/active_support/core_ext/date/zones.rb +++ b/activesupport/lib/active_support/core_ext/date/zones.rb @@ -1,5 +1,5 @@ -require 'date' -require 'active_support/core_ext/date_and_time/zones' +require "date" +require "active_support/core_ext/date_and_time/zones" class Date include DateAndTime::Zones diff --git a/activesupport/lib/active_support/core_ext/date_and_time/calculations.rb b/activesupport/lib/active_support/core_ext/date_and_time/calculations.rb index e079af594d..f2ba7fdda5 100644 --- a/activesupport/lib/active_support/core_ext/date_and_time/calculations.rb +++ b/activesupport/lib/active_support/core_ext/date_and_time/calculations.rb @@ -1,13 +1,15 @@ +require "active_support/core_ext/object/try" + module DateAndTime module Calculations DAYS_INTO_WEEK = { - :monday => 0, - :tuesday => 1, - :wednesday => 2, - :thursday => 3, - :friday => 4, - :saturday => 5, - :sunday => 6 + monday: 0, + tuesday: 1, + wednesday: 2, + thursday: 3, + friday: 4, + saturday: 5, + sunday: 6 } WEEKEND_DAYS = [ 6, 0 ] @@ -51,44 +53,49 @@ module DateAndTime WEEKEND_DAYS.include?(wday) end + # Returns true if the date/time does not fall on a Saturday or Sunday. + def on_weekday? + !WEEKEND_DAYS.include?(wday) + end + # Returns a new date/time the specified number of days ago. def days_ago(days) - advance(:days => -days) + advance(days: -days) end # Returns a new date/time the specified number of days in the future. def days_since(days) - advance(:days => days) + advance(days: days) end # Returns a new date/time the specified number of weeks ago. def weeks_ago(weeks) - advance(:weeks => -weeks) + advance(weeks: -weeks) end # Returns a new date/time the specified number of weeks in the future. def weeks_since(weeks) - advance(:weeks => weeks) + advance(weeks: weeks) end # Returns a new date/time the specified number of months ago. def months_ago(months) - advance(:months => -months) + advance(months: -months) end # Returns a new date/time the specified number of months in the future. def months_since(months) - advance(:months => months) + advance(months: months) end # Returns a new date/time the specified number of years ago. def years_ago(years) - advance(:years => -years) + advance(years: -years) end # Returns a new date/time the specified number of years in the future. def years_since(years) - advance(:years => years) + advance(years: years) end # Returns a new date/time at the start of the month. @@ -101,7 +108,7 @@ module DateAndTime # now = DateTime.current # => Thu, 18 Jun 2015 15:23:13 +0000 # now.beginning_of_month # => Mon, 01 Jun 2015 00:00:00 +0000 def beginning_of_month - first_hour(change(:day => 1)) + first_hour(change(day: 1)) end alias :at_beginning_of_month :beginning_of_month @@ -116,7 +123,7 @@ module DateAndTime # now.beginning_of_quarter # => Wed, 01 Jul 2015 00:00:00 +0000 def beginning_of_quarter first_quarter_month = [10, 7, 4, 1].detect { |m| m <= month } - beginning_of_month.change(:month => first_quarter_month) + beginning_of_month.change(month: first_quarter_month) end alias :at_beginning_of_quarter :beginning_of_quarter @@ -131,7 +138,7 @@ module DateAndTime # now.end_of_quarter # => Wed, 30 Sep 2015 23:59:59 +0000 def end_of_quarter last_quarter_month = [3, 6, 9, 12].detect { |m| m >= month } - beginning_of_month.change(:month => last_quarter_month).end_of_month + beginning_of_month.change(month: last_quarter_month).end_of_month end alias :at_end_of_quarter :end_of_quarter @@ -145,7 +152,7 @@ module DateAndTime # now = DateTime.current # => Fri, 10 Jul 2015 18:41:29 +0000 # now.beginning_of_year # => Thu, 01 Jan 2015 00:00:00 +0000 def beginning_of_year - change(:month => 1).beginning_of_month + change(month: 1).beginning_of_month end alias :at_beginning_of_year :beginning_of_year @@ -283,12 +290,17 @@ module DateAndTime # Returns a new date/time representing the end of the year. # DateTime objects will have a time set to 23:59:59. def end_of_year - change(:month => 12).end_of_month + change(month: 12).end_of_month end alias :at_end_of_year :end_of_year + # Returns a Range representing the whole day of the current date/time. + def all_day + beginning_of_day..end_of_day + end + # Returns a Range representing the whole week of the current date/time. - # Week starts on start_day, default is <tt>Date.week_start</tt> or <tt>config.week_start</tt> when set. + # Week starts on start_day, default is <tt>Date.beginning_of_week</tt> or <tt>config.beginning_of_week</tt> when set. def all_week(start_day = Date.beginning_of_week) beginning_of_week(start_day)..end_of_week(start_day) end @@ -322,7 +334,7 @@ module DateAndTime end def copy_time_to(other) - other.change(hour: hour, min: min, sec: sec, usec: try(:usec)) + other.change(hour: hour, min: min, sec: sec, nsec: try(:nsec)) end end end diff --git a/activesupport/lib/active_support/core_ext/date_and_time/compatibility.rb b/activesupport/lib/active_support/core_ext/date_and_time/compatibility.rb new file mode 100644 index 0000000000..db95ae0db5 --- /dev/null +++ b/activesupport/lib/active_support/core_ext/date_and_time/compatibility.rb @@ -0,0 +1,22 @@ +require "active_support/core_ext/module/attribute_accessors" + +module DateAndTime + module Compatibility + # If true, +to_time+ preserves the timezone offset of receiver. + # + # NOTE: With Ruby 2.4+ the default for +to_time+ changed from + # converting to the local system time, to preserving the offset + # of the receiver. For backwards compatibility we're overriding + # this behavior, but new apps will have an initializer that sets + # this to true, because the new behavior is preferred. + mattr_accessor(:preserve_timezone, instance_writer: false) { false } + + def to_time + if preserve_timezone + @_to_time_with_instance_offset ||= getlocal(utc_offset) + else + @_to_time_with_system_offset ||= getlocal + end + end + end +end diff --git a/activesupport/lib/active_support/core_ext/date_and_time/zones.rb b/activesupport/lib/active_support/core_ext/date_and_time/zones.rb index d29a8db5cf..edd724f1d0 100644 --- a/activesupport/lib/active_support/core_ext/date_and_time/zones.rb +++ b/activesupport/lib/active_support/core_ext/date_and_time/zones.rb @@ -5,7 +5,7 @@ module DateAndTime # # Time.zone = 'Hawaii' # => 'Hawaii' # Time.utc(2000).in_time_zone # => Fri, 31 Dec 1999 14:00:00 HST -10:00 - # Date.new(2000).in_time_zone # => Sat, 01 Jan 2000 00:00:00 HST -10:00 + # Date.new(2000).in_time_zone # => Sat, 01 Jan 2000 00:00:00 HST -10:00 # # This method is similar to Time#localtime, except that it uses <tt>Time.zone</tt> as the local zone # instead of the operating system's time zone. @@ -14,7 +14,7 @@ module DateAndTime # and the conversion will be based on that zone instead of <tt>Time.zone</tt>. # # Time.utc(2000).in_time_zone('Alaska') # => Fri, 31 Dec 1999 15:00:00 AKST -09:00 - # Date.new(2000).in_time_zone('Alaska') # => Sat, 01 Jan 2000 00:00:00 AKST -09:00 + # Date.new(2000).in_time_zone('Alaska') # => Sat, 01 Jan 2000 00:00:00 AKST -09:00 def in_time_zone(zone = ::Time.zone) time_zone = ::Time.find_zone! zone time = acts_like?(:time) ? self : nil @@ -22,19 +22,18 @@ module DateAndTime if time_zone time_with_zone(time, time_zone) else - time || self.to_time + time || to_time end end private - def time_with_zone(time, zone) - if time - ActiveSupport::TimeWithZone.new(time.utc? ? time : time.getutc, zone) - else - ActiveSupport::TimeWithZone.new(nil, zone, to_time(:utc)) + def time_with_zone(time, zone) + if time + ActiveSupport::TimeWithZone.new(time.utc? ? time : time.getutc, zone) + else + ActiveSupport::TimeWithZone.new(nil, zone, to_time(:utc)) + end end - end end end - diff --git a/activesupport/lib/active_support/core_ext/date_time.rb b/activesupport/lib/active_support/core_ext/date_time.rb index bcb228b09a..6fd498f864 100644 --- a/activesupport/lib/active_support/core_ext/date_time.rb +++ b/activesupport/lib/active_support/core_ext/date_time.rb @@ -1,5 +1,5 @@ -require 'active_support/core_ext/date_time/acts_like' -require 'active_support/core_ext/date_time/blank' -require 'active_support/core_ext/date_time/calculations' -require 'active_support/core_ext/date_time/conversions' -require 'active_support/core_ext/date_time/zones' +require "active_support/core_ext/date_time/acts_like" +require "active_support/core_ext/date_time/blank" +require "active_support/core_ext/date_time/calculations" +require "active_support/core_ext/date_time/compatibility" +require "active_support/core_ext/date_time/conversions" diff --git a/activesupport/lib/active_support/core_ext/date_time/acts_like.rb b/activesupport/lib/active_support/core_ext/date_time/acts_like.rb index 8fbbe0d3e9..6f50f55a53 100644 --- a/activesupport/lib/active_support/core_ext/date_time/acts_like.rb +++ b/activesupport/lib/active_support/core_ext/date_time/acts_like.rb @@ -1,5 +1,5 @@ -require 'date' -require 'active_support/core_ext/object/acts_like' +require "date" +require "active_support/core_ext/object/acts_like" class DateTime # Duck-types as a Date-like class. See Object#acts_like?. diff --git a/activesupport/lib/active_support/core_ext/date_time/blank.rb b/activesupport/lib/active_support/core_ext/date_time/blank.rb index 56981b75fb..b475fd926d 100644 --- a/activesupport/lib/active_support/core_ext/date_time/blank.rb +++ b/activesupport/lib/active_support/core_ext/date_time/blank.rb @@ -1,4 +1,4 @@ -require 'date' +require "date" class DateTime #:nodoc: # No DateTime is ever blank: diff --git a/activesupport/lib/active_support/core_ext/date_time/calculations.rb b/activesupport/lib/active_support/core_ext/date_time/calculations.rb index 95617fb8c2..70d5c9af8e 100644 --- a/activesupport/lib/active_support/core_ext/date_time/calculations.rb +++ b/activesupport/lib/active_support/core_ext/date_time/calculations.rb @@ -1,4 +1,4 @@ -require 'date' +require "date" class DateTime class << self @@ -28,6 +28,13 @@ class DateTime end_of_day.to_i - to_i end + # Returns the fraction of a second as a +Rational+ + # + # DateTime.new(2012, 8, 29, 0, 0, 0.5).subsec # => (1/2) + def subsec + sec_fraction + end + # Returns a new DateTime where one or more of the elements have been changed # according to the +options+ parameter. The time options (<tt>:hour</tt>, # <tt>:min</tt>, <tt>:sec</tt>) reset cascadingly, so if only the hour is @@ -68,7 +75,7 @@ class DateTime end d = to_date.advance(options) - datetime_advanced_by_date = change(:year => d.year, :month => d.month, :day => d.day) + datetime_advanced_by_date = change(year: d.year, month: d.month, day: d.day) seconds_to_advance = \ options.fetch(:seconds, 0) + options.fetch(:minutes, 0) * 60 + @@ -97,7 +104,7 @@ class DateTime # Returns a new DateTime representing the start of the day (0:00). def beginning_of_day - change(:hour => 0) + change(hour: 0) end alias :midnight :beginning_of_day alias :at_midnight :beginning_of_day @@ -105,7 +112,7 @@ class DateTime # Returns a new DateTime representing the middle of the day (12:00) def middle_of_day - change(:hour => 12) + change(hour: 12) end alias :midday :middle_of_day alias :noon :middle_of_day @@ -115,42 +122,60 @@ class DateTime # Returns a new DateTime representing the end of the day (23:59:59). def end_of_day - change(:hour => 23, :min => 59, :sec => 59) + change(hour: 23, min: 59, sec: 59) end alias :at_end_of_day :end_of_day # Returns a new DateTime representing the start of the hour (hh:00:00). def beginning_of_hour - change(:min => 0) + change(min: 0) end alias :at_beginning_of_hour :beginning_of_hour # Returns a new DateTime representing the end of the hour (hh:59:59). def end_of_hour - change(:min => 59, :sec => 59) + change(min: 59, sec: 59) end alias :at_end_of_hour :end_of_hour # Returns a new DateTime representing the start of the minute (hh:mm:00). def beginning_of_minute - change(:sec => 0) + change(sec: 0) end alias :at_beginning_of_minute :beginning_of_minute # Returns a new DateTime representing the end of the minute (hh:mm:59). def end_of_minute - change(:sec => 59) + change(sec: 59) end alias :at_end_of_minute :end_of_minute - # Adjusts DateTime to UTC by adding its offset value; offset is set to 0. + # Returns a <tt>Time</tt> instance of the simultaneous time in the system timezone. + def localtime(utc_offset = nil) + utc = new_offset(0) + + Time.utc( + utc.year, utc.month, utc.day, + utc.hour, utc.min, utc.sec + utc.sec_fraction + ).getlocal(utc_offset) + end + alias_method :getlocal, :localtime + + # Returns a <tt>Time</tt> instance of the simultaneous time in the UTC timezone. # # DateTime.civil(2005, 2, 21, 10, 11, 12, Rational(-6, 24)) # => Mon, 21 Feb 2005 10:11:12 -0600 - # DateTime.civil(2005, 2, 21, 10, 11, 12, Rational(-6, 24)).utc # => Mon, 21 Feb 2005 16:11:12 +0000 + # DateTime.civil(2005, 2, 21, 10, 11, 12, Rational(-6, 24)).utc # => Mon, 21 Feb 2005 16:11:12 UTC def utc - new_offset(0) + utc = new_offset(0) + + Time.utc( + utc.year, utc.month, utc.day, + utc.hour, utc.min, utc.sec + utc.sec_fraction + ) end + alias_method :getgm, :utc alias_method :getutc, :utc + alias_method :gmtime, :utc # Returns +true+ if <tt>offset == 0</tt>. def utc? @@ -165,13 +190,10 @@ class DateTime # Layers additional behavior on DateTime#<=> so that Time and # ActiveSupport::TimeWithZone instances can be compared with a DateTime. def <=>(other) - if other.kind_of?(Infinity) - super - elsif other.respond_to? :to_datetime + if other.respond_to? :to_datetime super other.to_datetime rescue nil else - nil + super end end - end diff --git a/activesupport/lib/active_support/core_ext/date_time/compatibility.rb b/activesupport/lib/active_support/core_ext/date_time/compatibility.rb new file mode 100644 index 0000000000..30bb7f4a60 --- /dev/null +++ b/activesupport/lib/active_support/core_ext/date_time/compatibility.rb @@ -0,0 +1,5 @@ +require "active_support/core_ext/date_and_time/compatibility" + +class DateTime + prepend DateAndTime::Compatibility +end diff --git a/activesupport/lib/active_support/core_ext/date_time/conversions.rb b/activesupport/lib/active_support/core_ext/date_time/conversions.rb index f59d05b214..44ae96dbe8 100644 --- a/activesupport/lib/active_support/core_ext/date_time/conversions.rb +++ b/activesupport/lib/active_support/core_ext/date_time/conversions.rb @@ -1,8 +1,8 @@ -require 'date' -require 'active_support/inflector/methods' -require 'active_support/core_ext/time/conversions' -require 'active_support/core_ext/date_time/calculations' -require 'active_support/values/time_zone' +require "date" +require "active_support/inflector/methods" +require "active_support/core_ext/time/conversions" +require "active_support/core_ext/date_time/calculations" +require "active_support/values/time_zone" class DateTime # Convert to a formatted string. See Time::DATE_FORMATS for predefined formats. @@ -95,11 +95,11 @@ class DateTime private - def offset_in_seconds - (offset * 86400).to_i - end + def offset_in_seconds + (offset * 86400).to_i + end - def seconds_since_unix_epoch - (jd - 2440588) * 86400 - offset_in_seconds + seconds_since_midnight - end + def seconds_since_unix_epoch + (jd - 2440588) * 86400 - offset_in_seconds + seconds_since_midnight + end end diff --git a/activesupport/lib/active_support/core_ext/date_time/zones.rb b/activesupport/lib/active_support/core_ext/date_time/zones.rb deleted file mode 100644 index c39f358395..0000000000 --- a/activesupport/lib/active_support/core_ext/date_time/zones.rb +++ /dev/null @@ -1,6 +0,0 @@ -require 'date' -require 'active_support/core_ext/date_and_time/zones' - -class DateTime - include DateAndTime::Zones -end diff --git a/activesupport/lib/active_support/core_ext/digest/uuid.rb b/activesupport/lib/active_support/core_ext/digest/uuid.rb index 593c51bba2..e6d60e3267 100644 --- a/activesupport/lib/active_support/core_ext/digest/uuid.rb +++ b/activesupport/lib/active_support/core_ext/digest/uuid.rb @@ -1,4 +1,4 @@ -require 'securerandom' +require "securerandom" module Digest module UUID @@ -26,7 +26,7 @@ module Digest hash.update(uuid_namespace) hash.update(name) - ary = hash.digest.unpack('NnnnnN') + ary = hash.digest.unpack("NnnnnN") ary[2] = (ary[2] & 0x0FFF) | (version << 12) ary[3] = (ary[3] & 0x3FFF) | 0x8000 @@ -35,12 +35,12 @@ module Digest # Convenience method for uuid_from_hash using Digest::MD5. def self.uuid_v3(uuid_namespace, name) - self.uuid_from_hash(Digest::MD5, uuid_namespace, name) + uuid_from_hash(Digest::MD5, uuid_namespace, name) end # Convenience method for uuid_from_hash using Digest::SHA1. def self.uuid_v5(uuid_namespace, name) - self.uuid_from_hash(Digest::SHA1, uuid_namespace, name) + uuid_from_hash(Digest::SHA1, uuid_namespace, name) end # Convenience method for SecureRandom.uuid. diff --git a/activesupport/lib/active_support/core_ext/enumerable.rb b/activesupport/lib/active_support/core_ext/enumerable.rb index 8a74ad4d66..8ebe758078 100644 --- a/activesupport/lib/active_support/core_ext/enumerable.rb +++ b/activesupport/lib/active_support/core_ext/enumerable.rb @@ -17,11 +17,12 @@ module Enumerable # The default sum of an empty list is zero. You can override this default: # # [].sum(Payment.new(0)) { |i| i.amount } # => Payment.new(0) - def sum(identity = 0, &block) + def sum(identity = nil, &block) if block_given? map(&block).sum(identity) else - inject(:+) || identity + sum = identity ? inject(identity, :+) : inject(:+) + sum || identity || 0 end end @@ -33,7 +34,9 @@ module Enumerable # => { "Chade- Fowlersburg-e" => <Person ...>, "David Heinemeier Hansson" => <Person ...>, ...} def index_by if block_given? - Hash[map { |elem| [yield(elem), elem] }] + result = {} + each { |elem| result[yield(elem)] = elem } + result else to_enum(:index_by) { size if respond_to?(:size) } end @@ -91,15 +94,36 @@ end class Range #:nodoc: # Optimize range sum to use arithmetic progression if a block is not given and # we have a range of numeric values. - def sum(identity = 0) + def sum(identity = nil) if block_given? || !(first.is_a?(Integer) && last.is_a?(Integer)) super else actual_last = exclude_end? ? (last - 1) : last if actual_last >= first - (actual_last - first + 1) * (actual_last + first) / 2 + sum = identity || 0 + sum + (actual_last - first + 1) * (actual_last + first) / 2 else - identity + identity || 0 + end + end + end +end + +# Array#sum was added in Ruby 2.4 but it only works with Numeric elements. +# +# We tried shimming it to attempt the fast native method, rescue TypeError, +# and fall back to the compatible implementation, but that's much slower than +# just calling the compat method in the first place. +if Array.instance_methods(false).include?(:sum) && !(%w[a].sum rescue false) + class Array + alias :orig_sum :sum + + def sum(init = nil, &block) #:nodoc: + if init.is_a?(Numeric) || first.is_a?(Numeric) + init ||= 0 + orig_sum(init, &block) + else + super end end end diff --git a/activesupport/lib/active_support/core_ext/file.rb b/activesupport/lib/active_support/core_ext/file.rb index dc24afbe7f..6d99bad2af 100644 --- a/activesupport/lib/active_support/core_ext/file.rb +++ b/activesupport/lib/active_support/core_ext/file.rb @@ -1 +1 @@ -require 'active_support/core_ext/file/atomic' +require "active_support/core_ext/file/atomic" diff --git a/activesupport/lib/active_support/core_ext/file/atomic.rb b/activesupport/lib/active_support/core_ext/file/atomic.rb index 463fd78412..8d6c0d3685 100644 --- a/activesupport/lib/active_support/core_ext/file/atomic.rb +++ b/activesupport/lib/active_support/core_ext/file/atomic.rb @@ -1,4 +1,4 @@ -require 'fileutils' +require "fileutils" class File # Write to a file atomically. Useful for situations where you don't @@ -17,7 +17,7 @@ class File # file.write('hello') # end def self.atomic_write(file_name, temp_dir = dirname(file_name)) - require 'tempfile' unless defined?(Tempfile) + require "tempfile" unless defined?(Tempfile) Tempfile.open(".#{basename(file_name)}", temp_dir) do |temp_file| temp_file.binmode @@ -53,11 +53,11 @@ class File # Private utility method. def self.probe_stat_in(dir) #:nodoc: basename = [ - '.permissions_check', + ".permissions_check", Thread.current.object_id, Process.pid, rand(1000000) - ].join('.') + ].join(".") file_name = join(dir, basename) FileUtils.touch(file_name) diff --git a/activesupport/lib/active_support/core_ext/hash.rb b/activesupport/lib/active_support/core_ext/hash.rb index af4d1da0eb..c819307e8a 100644 --- a/activesupport/lib/active_support/core_ext/hash.rb +++ b/activesupport/lib/active_support/core_ext/hash.rb @@ -1,9 +1,9 @@ -require 'active_support/core_ext/hash/compact' -require 'active_support/core_ext/hash/conversions' -require 'active_support/core_ext/hash/deep_merge' -require 'active_support/core_ext/hash/except' -require 'active_support/core_ext/hash/indifferent_access' -require 'active_support/core_ext/hash/keys' -require 'active_support/core_ext/hash/reverse_merge' -require 'active_support/core_ext/hash/slice' -require 'active_support/core_ext/hash/transform_values' +require "active_support/core_ext/hash/compact" +require "active_support/core_ext/hash/conversions" +require "active_support/core_ext/hash/deep_merge" +require "active_support/core_ext/hash/except" +require "active_support/core_ext/hash/indifferent_access" +require "active_support/core_ext/hash/keys" +require "active_support/core_ext/hash/reverse_merge" +require "active_support/core_ext/hash/slice" +require "active_support/core_ext/hash/transform_values" diff --git a/activesupport/lib/active_support/core_ext/hash/compact.rb b/activesupport/lib/active_support/core_ext/hash/compact.rb index 5dc9a05ec7..5cae495bda 100644 --- a/activesupport/lib/active_support/core_ext/hash/compact.rb +++ b/activesupport/lib/active_support/core_ext/hash/compact.rb @@ -1,20 +1,27 @@ class Hash - # Returns a hash with non +nil+ values. - # - # hash = { a: true, b: false, c: nil} - # hash.compact # => { a: true, b: false} - # hash # => { a: true, b: false, c: nil} - # { c: nil }.compact # => {} - def compact - self.select { |_, value| !value.nil? } + unless Hash.instance_methods(false).include?(:compact) + # Returns a hash with non +nil+ values. + # + # hash = { a: true, b: false, c: nil } + # hash.compact # => { a: true, b: false } + # hash # => { a: true, b: false, c: nil } + # { c: nil }.compact # => {} + # { c: true }.compact # => { c: true } + def compact + select { |_, value| !value.nil? } + end end - # Replaces current hash with non +nil+ values. - # - # hash = { a: true, b: false, c: nil} - # hash.compact! # => { a: true, b: false} - # hash # => { a: true, b: false} - def compact! - self.reject! { |_, value| value.nil? } + unless Hash.instance_methods(false).include?(:compact!) + # Replaces current hash with non +nil+ values. + # Returns nil if no changes were made, otherwise returns the hash. + # + # hash = { a: true, b: false, c: nil } + # hash.compact! # => { a: true, b: false } + # hash # => { a: true, b: false } + # { c: true }.compact! # => nil + def compact! + reject! { |_, value| value.nil? } + end end end diff --git a/activesupport/lib/active_support/core_ext/hash/conversions.rb b/activesupport/lib/active_support/core_ext/hash/conversions.rb index 6741e732f0..3cd96ccb9a 100644 --- a/activesupport/lib/active_support/core_ext/hash/conversions.rb +++ b/activesupport/lib/active_support/core_ext/hash/conversions.rb @@ -1,11 +1,11 @@ -require 'active_support/xml_mini' -require 'active_support/time' -require 'active_support/core_ext/object/blank' -require 'active_support/core_ext/object/to_param' -require 'active_support/core_ext/object/to_query' -require 'active_support/core_ext/array/wrap' -require 'active_support/core_ext/hash/reverse_merge' -require 'active_support/core_ext/string/inflections' +require "active_support/xml_mini" +require "active_support/time" +require "active_support/core_ext/object/blank" +require "active_support/core_ext/object/to_param" +require "active_support/core_ext/object/to_query" +require "active_support/core_ext/array/wrap" +require "active_support/core_ext/hash/reverse_merge" +require "active_support/core_ext/string/inflections" class Hash # Returns a string containing an XML representation of its receiver: @@ -31,7 +31,7 @@ class Hash # with +key+ as <tt>:root</tt>, and +key+ singularized as second argument. The # callable can add nodes by using <tt>options[:builder]</tt>. # - # 'foo'.to_xml(lambda { |options, key| options[:builder].b(key) }) + # {foo: lambda { |options, key| options[:builder].b(key) }}.to_xml # # => "<b>foo</b>" # # * If +value+ responds to +to_xml+ the method is invoked with +key+ as <tt>:root</tt>. @@ -55,8 +55,7 @@ class Hash # # XML_TYPE_NAMES = { # "Symbol" => "symbol", - # "Fixnum" => "integer", - # "Bignum" => "integer", + # "Integer" => "integer", # "BigDecimal" => "decimal", # "Float" => "float", # "TrueClass" => "boolean", @@ -72,11 +71,11 @@ class Hash # configure your own builder with the <tt>:builder</tt> option. The method also accepts # options like <tt>:dasherize</tt> and friends, they are forwarded to the builder. def to_xml(options = {}) - require 'active_support/builder' unless defined?(Builder) + require "active_support/builder" unless defined?(Builder) options = options.dup options[:indent] ||= 2 - options[:root] ||= 'hash' + options[:root] ||= "hash" options[:builder] ||= Builder::XmlMarkup.new(indent: options[:indent]) builder = options[:builder] @@ -160,36 +159,36 @@ module ActiveSupport private def normalize_keys(params) case params - when Hash - Hash[params.map { |k,v| [k.to_s.tr('-', '_'), normalize_keys(v)] } ] - when Array - params.map { |v| normalize_keys(v) } + when Hash + Hash[params.map { |k,v| [k.to_s.tr("-", "_"), normalize_keys(v)] } ] + when Array + params.map { |v| normalize_keys(v) } else - params + params end end def deep_to_h(value) case value - when Hash - process_hash(value) - when Array - process_array(value) - when String - value + when Hash + process_hash(value) + when Array + process_array(value) + when String + value else - raise "can't typecast #{value.class.name} - #{value.inspect}" + raise "can't typecast #{value.class.name} - #{value.inspect}" end end def process_hash(value) - if value.include?('type') && !value['type'].is_a?(Hash) && @disallowed_types.include?(value['type']) - raise DisallowedType, value['type'] + if value.include?("type") && !value["type"].is_a?(Hash) && @disallowed_types.include?(value["type"]) + raise DisallowedType, value["type"] end if become_array?(value) _, entries = Array.wrap(value.detect { |k,v| not v.is_a?(String) }) - if entries.nil? || value['__content__'].try(:empty?) + if entries.nil? || value["__content__"].try(:empty?) [] else case entries @@ -205,28 +204,28 @@ module ActiveSupport process_content(value) elsif become_empty_string?(value) - '' + "" elsif become_hash?(value) xml_value = Hash[value.map { |k,v| [k, deep_to_h(v)] }] # Turn { files: { file: #<StringIO> } } into { files: #<StringIO> } so it is compatible with # how multipart uploaded files from HTML appear - xml_value['file'].is_a?(StringIO) ? xml_value['file'] : xml_value + xml_value["file"].is_a?(StringIO) ? xml_value["file"] : xml_value end end def become_content?(value) - value['type'] == 'file' || (value['__content__'] && (value.keys.size == 1 || value['__content__'].present?)) + value["type"] == "file" || (value["__content__"] && (value.keys.size == 1 || value["__content__"].present?)) end def become_array?(value) - value['type'] == 'array' + value["type"] == "array" end def become_empty_string?(value) # { "string" => true } # No tests fail when the second term is removed. - value['type'] == 'string' && value['nil'] != 'true' + value["type"] == "string" && value["nil"] != "true" end def become_hash?(value) @@ -235,19 +234,19 @@ module ActiveSupport def nothing?(value) # blank or nil parsed values are represented by nil - value.blank? || value['nil'] == 'true' + value.blank? || value["nil"] == "true" end def garbage?(value) # If the type is the only element which makes it then # this still makes the value nil, except if type is # an XML node(where type['value'] is a Hash) - value['type'] && !value['type'].is_a?(::Hash) && value.size == 1 + value["type"] && !value["type"].is_a?(::Hash) && value.size == 1 end def process_content(value) - content = value['__content__'] - if parser = ActiveSupport::XmlMini::PARSING[value['type']] + content = value["__content__"] + if parser = ActiveSupport::XmlMini::PARSING[value["type"]] parser.arity == 1 ? parser.call(content) : parser.call(content, value) else content @@ -258,6 +257,5 @@ module ActiveSupport value.map! { |i| deep_to_h(i) } value.length > 1 ? value : value.first end - end end diff --git a/activesupport/lib/active_support/core_ext/hash/indifferent_access.rb b/activesupport/lib/active_support/core_ext/hash/indifferent_access.rb index 6df7b4121b..3e1ccecb6c 100644 --- a/activesupport/lib/active_support/core_ext/hash/indifferent_access.rb +++ b/activesupport/lib/active_support/core_ext/hash/indifferent_access.rb @@ -1,7 +1,6 @@ -require 'active_support/hash_with_indifferent_access' +require "active_support/hash_with_indifferent_access" class Hash - # Returns an <tt>ActiveSupport::HashWithIndifferentAccess</tt> out of its receiver: # # { a: 1 }.with_indifferent_access['a'] # => 1 diff --git a/activesupport/lib/active_support/core_ext/hash/keys.rb b/activesupport/lib/active_support/core_ext/hash/keys.rb index 8b2366c4b3..b7089357a8 100644 --- a/activesupport/lib/active_support/core_ext/hash/keys.rb +++ b/activesupport/lib/active_support/core_ext/hash/keys.rb @@ -11,7 +11,7 @@ class Hash # hash.transform_keys.with_index { |k, i| [k, i].join } # => {"name0"=>"Rob", "age1"=>"28"} def transform_keys return enum_for(:transform_keys) { size } unless block_given? - result = self.class.new + result = {} each_key do |key| result[yield(key)] = self[key] end @@ -52,14 +52,14 @@ class Hash # hash.symbolize_keys # # => {:name=>"Rob", :age=>"28"} def symbolize_keys - transform_keys{ |key| key.to_sym rescue key } + transform_keys { |key| key.to_sym rescue key } end alias_method :to_options, :symbolize_keys # Destructively converts all keys to symbols, as long as they respond # to +to_sym+. Same as +symbolize_keys+, but modifies +self+. def symbolize_keys! - transform_keys!{ |key| key.to_sym rescue key } + transform_keys! { |key| key.to_sym rescue key } end alias_method :to_options!, :symbolize_keys! @@ -128,14 +128,14 @@ class Hash # hash.deep_symbolize_keys # # => {:person=>{:name=>"Rob", :age=>"28"}} def deep_symbolize_keys - deep_transform_keys{ |key| key.to_sym rescue key } + deep_transform_keys { |key| key.to_sym rescue key } end # Destructively converts all keys to symbols, as long as they respond # to +to_sym+. This includes the keys from the root hash and from all # nested hashes and arrays. def deep_symbolize_keys! - deep_transform_keys!{ |key| key.to_sym rescue key } + deep_transform_keys! { |key| key.to_sym rescue key } end private @@ -147,7 +147,7 @@ class Hash result[yield(key)] = _deep_transform_keys_in_object(value, &block) end when Array - object.map {|e| _deep_transform_keys_in_object(e, &block) } + object.map { |e| _deep_transform_keys_in_object(e, &block) } else object end @@ -162,7 +162,7 @@ class Hash end object when Array - object.map! {|e| _deep_transform_keys_in_object!(e, &block)} + object.map! { |e| _deep_transform_keys_in_object!(e, &block) } else object end diff --git a/activesupport/lib/active_support/core_ext/hash/reverse_merge.rb b/activesupport/lib/active_support/core_ext/hash/reverse_merge.rb index fbb482435d..db3e7508e7 100644 --- a/activesupport/lib/active_support/core_ext/hash/reverse_merge.rb +++ b/activesupport/lib/active_support/core_ext/hash/reverse_merge.rb @@ -16,7 +16,7 @@ class Hash # Destructive +reverse_merge+. def reverse_merge!(other_hash) # right wins if there is no left - merge!( other_hash ){|key,left,right| left } + merge!( other_hash ) { |key,left,right| left } end alias_method :reverse_update, :reverse_merge! end diff --git a/activesupport/lib/active_support/core_ext/hash/slice.rb b/activesupport/lib/active_support/core_ext/hash/slice.rb index 1d5f38231a..161b00dfb3 100644 --- a/activesupport/lib/active_support/core_ext/hash/slice.rb +++ b/activesupport/lib/active_support/core_ext/hash/slice.rb @@ -1,11 +1,11 @@ class Hash - # Slices a hash to include only the given keys. Returns a hash containing + # Slices a hash to include only the given keys. Returns a hash containing # the given keys. - # + # # { a: 1, b: 2, c: 3, d: 4 }.slice(:a, :b) # # => {:a=>1, :b=>2} - # - # This is useful for limiting an options hash to valid keys before + # + # This is useful for limiting an options hash to valid keys before # passing to a method: # # def search(criteria = {}) diff --git a/activesupport/lib/active_support/core_ext/hash/transform_values.rb b/activesupport/lib/active_support/core_ext/hash/transform_values.rb index 7d507ac998..2f693bff0c 100644 --- a/activesupport/lib/active_support/core_ext/hash/transform_values.rb +++ b/activesupport/lib/active_support/core_ext/hash/transform_values.rb @@ -16,7 +16,7 @@ class Hash result[key] = yield(value) end result - end + end unless method_defined? :transform_values # Destructively converts all values using the +block+ operations. # Same as +transform_values+ but modifies +self+. @@ -25,5 +25,6 @@ class Hash each do |key, value| self[key] = yield(value) end - end + end unless method_defined? :transform_values! + # TODO: Remove this file when supporting only Ruby 2.4+. end diff --git a/activesupport/lib/active_support/core_ext/integer.rb b/activesupport/lib/active_support/core_ext/integer.rb index a44a1b4c74..8f0c55f9d3 100644 --- a/activesupport/lib/active_support/core_ext/integer.rb +++ b/activesupport/lib/active_support/core_ext/integer.rb @@ -1,3 +1,3 @@ -require 'active_support/core_ext/integer/multiple' -require 'active_support/core_ext/integer/inflections' -require 'active_support/core_ext/integer/time' +require "active_support/core_ext/integer/multiple" +require "active_support/core_ext/integer/inflections" +require "active_support/core_ext/integer/time" diff --git a/activesupport/lib/active_support/core_ext/integer/inflections.rb b/activesupport/lib/active_support/core_ext/integer/inflections.rb index 56f2ed5985..bc21b65533 100644 --- a/activesupport/lib/active_support/core_ext/integer/inflections.rb +++ b/activesupport/lib/active_support/core_ext/integer/inflections.rb @@ -1,4 +1,4 @@ -require 'active_support/inflector' +require "active_support/inflector" class Integer # Ordinalize turns a number into an ordinal string used to denote the diff --git a/activesupport/lib/active_support/core_ext/integer/time.rb b/activesupport/lib/active_support/core_ext/integer/time.rb index 87185b024f..4a64872392 100644 --- a/activesupport/lib/active_support/core_ext/integer/time.rb +++ b/activesupport/lib/active_support/core_ext/integer/time.rb @@ -1,5 +1,5 @@ -require 'active_support/duration' -require 'active_support/core_ext/numeric/time' +require "active_support/duration" +require "active_support/core_ext/numeric/time" class Integer # Enables the use of time calculations and declarations, like <tt>45.minutes + diff --git a/activesupport/lib/active_support/core_ext/kernel.rb b/activesupport/lib/active_support/core_ext/kernel.rb index 364ed9d65f..3d41ff7876 100644 --- a/activesupport/lib/active_support/core_ext/kernel.rb +++ b/activesupport/lib/active_support/core_ext/kernel.rb @@ -1,4 +1,4 @@ -require 'active_support/core_ext/kernel/agnostics' -require 'active_support/core_ext/kernel/concern' -require 'active_support/core_ext/kernel/reporting' -require 'active_support/core_ext/kernel/singleton_class' +require "active_support/core_ext/kernel/agnostics" +require "active_support/core_ext/kernel/concern" +require "active_support/core_ext/kernel/reporting" +require "active_support/core_ext/kernel/singleton_class" diff --git a/activesupport/lib/active_support/core_ext/kernel/concern.rb b/activesupport/lib/active_support/core_ext/kernel/concern.rb index 18bcc01fa4..307a7f7a63 100644 --- a/activesupport/lib/active_support/core_ext/kernel/concern.rb +++ b/activesupport/lib/active_support/core_ext/kernel/concern.rb @@ -1,4 +1,4 @@ -require 'active_support/core_ext/module/concerning' +require "active_support/core_ext/module/concerning" module Kernel module_function diff --git a/activesupport/lib/active_support/core_ext/kernel/debugger.rb b/activesupport/lib/active_support/core_ext/kernel/debugger.rb index 1fde3db070..dccfa3e9bb 100644 --- a/activesupport/lib/active_support/core_ext/kernel/debugger.rb +++ b/activesupport/lib/active_support/core_ext/kernel/debugger.rb @@ -1,3 +1,3 @@ -require 'active_support/deprecation' +require "active_support/deprecation" ActiveSupport::Deprecation.warn("This file is deprecated and will be removed in Rails 5.1 with no replacement.") diff --git a/activesupport/lib/active_support/core_ext/load_error.rb b/activesupport/lib/active_support/core_ext/load_error.rb index 60732eb41a..cd00d1b662 100644 --- a/activesupport/lib/active_support/core_ext/load_error.rb +++ b/activesupport/lib/active_support/core_ext/load_error.rb @@ -1,4 +1,5 @@ -require 'active_support/deprecation/proxy_wrappers' +require "active_support/deprecation" +require "active_support/deprecation/proxy_wrappers" class LoadError REGEXPS = [ @@ -23,8 +24,8 @@ class LoadError # Returns true if the given path name (except perhaps for the ".rb" # extension) is the missing file which caused the exception to be raised. def is_missing?(location) - location.sub(/\.rb$/, ''.freeze) == path.sub(/\.rb$/, ''.freeze) + location.sub(/\.rb$/, "".freeze) == path.sub(/\.rb$/, "".freeze) end end -MissingSourceFile = ActiveSupport::Deprecation::DeprecatedConstantProxy.new('MissingSourceFile', 'LoadError') +MissingSourceFile = ActiveSupport::Deprecation::DeprecatedConstantProxy.new("MissingSourceFile", "LoadError") diff --git a/activesupport/lib/active_support/core_ext/marshal.rb b/activesupport/lib/active_support/core_ext/marshal.rb index e333b26133..edfc8296fe 100644 --- a/activesupport/lib/active_support/core_ext/marshal.rb +++ b/activesupport/lib/active_support/core_ext/marshal.rb @@ -3,9 +3,12 @@ module ActiveSupport def load(source) super(source) rescue ArgumentError, NameError => exc - if exc.message.match(%r|undefined class/module (.+)|) + if exc.message.match(%r|undefined class/module (.+?)(?:::)?\z|) # try loading the class/module - $1.constantize + loaded = $1.constantize + + raise unless $1 == loaded.name + # if it is an IO we need to go back to read the object source.rewind if source.respond_to?(:rewind) retry diff --git a/activesupport/lib/active_support/core_ext/module.rb b/activesupport/lib/active_support/core_ext/module.rb index ef038331c2..57feea69a5 100644 --- a/activesupport/lib/active_support/core_ext/module.rb +++ b/activesupport/lib/active_support/core_ext/module.rb @@ -1,12 +1,12 @@ -require 'active_support/core_ext/module/aliasing' -require 'active_support/core_ext/module/introspection' -require 'active_support/core_ext/module/anonymous' -require 'active_support/core_ext/module/reachable' -require 'active_support/core_ext/module/attribute_accessors' -require 'active_support/core_ext/module/attribute_accessors_per_thread' -require 'active_support/core_ext/module/attr_internal' -require 'active_support/core_ext/module/concerning' -require 'active_support/core_ext/module/delegation' -require 'active_support/core_ext/module/deprecation' -require 'active_support/core_ext/module/remove_method' -require 'active_support/core_ext/module/qualified_const' +require "active_support/core_ext/module/aliasing" +require "active_support/core_ext/module/introspection" +require "active_support/core_ext/module/anonymous" +require "active_support/core_ext/module/reachable" +require "active_support/core_ext/module/attribute_accessors" +require "active_support/core_ext/module/attribute_accessors_per_thread" +require "active_support/core_ext/module/attr_internal" +require "active_support/core_ext/module/concerning" +require "active_support/core_ext/module/delegation" +require "active_support/core_ext/module/deprecation" +require "active_support/core_ext/module/remove_method" +require "active_support/core_ext/module/qualified_const" diff --git a/activesupport/lib/active_support/core_ext/module/aliasing.rb b/activesupport/lib/active_support/core_ext/module/aliasing.rb index b6934b9c54..4a04bdd446 100644 --- a/activesupport/lib/active_support/core_ext/module/aliasing.rb +++ b/activesupport/lib/active_support/core_ext/module/aliasing.rb @@ -28,7 +28,7 @@ class Module # Strip out punctuation on predicates, bang or writer methods since # e.g. target?_without_feature is not a valid method name. - aliased_target, punctuation = target.to_s.sub(/([?!=])$/, ''), $1 + aliased_target, punctuation = target.to_s.sub(/([?!=])$/, ""), $1 yield(aliased_target, punctuation) if block_given? with_method = "#{aliased_target}_with_#{feature}#{punctuation}" @@ -65,6 +65,9 @@ class Module # e.subject = "Megastars" # e.title # => "Megastars" def alias_attribute(new_name, old_name) + # The following reader methods use an explicit `self` receiver in order to + # support aliases that start with an uppercase letter. Otherwise, they would + # be resolved as constants instead. module_eval <<-STR, __FILE__, __LINE__ + 1 def #{new_name}; self.#{old_name}; end # def subject; self.title; end def #{new_name}?; self.#{old_name}?; end # def subject?; self.title?; end diff --git a/activesupport/lib/active_support/core_ext/module/attr_internal.rb b/activesupport/lib/active_support/core_ext/module/attr_internal.rb index 93fb598650..5081d5f7a3 100644 --- a/activesupport/lib/active_support/core_ext/module/attr_internal.rb +++ b/activesupport/lib/active_support/core_ext/module/attr_internal.rb @@ -1,12 +1,12 @@ class Module # Declares an attribute reader backed by an internally-named instance variable. def attr_internal_reader(*attrs) - attrs.each {|attr_name| attr_internal_define(attr_name, :reader)} + attrs.each { |attr_name| attr_internal_define(attr_name, :reader) } end # Declares an attribute writer backed by an internally-named instance variable. def attr_internal_writer(*attrs) - attrs.each {|attr_name| attr_internal_define(attr_name, :writer)} + attrs.each { |attr_name| attr_internal_define(attr_name, :writer) } end # Declares an attribute reader and writer backed by an internally-named instance @@ -18,7 +18,7 @@ class Module alias_method :attr_internal, :attr_internal_accessor class << self; attr_accessor :attr_internal_naming_format end - self.attr_internal_naming_format = '@_%s' + self.attr_internal_naming_format = "@_%s" private def attr_internal_ivar_name(attr) @@ -26,7 +26,7 @@ class Module end def attr_internal_define(attr_name, type) - internal_name = attr_internal_ivar_name(attr_name).sub(/\A@/, '') + internal_name = attr_internal_ivar_name(attr_name).sub(/\A@/, "") # use native attr_* methods as they are faster on some Ruby implementations send("attr_#{type}", internal_name) attr_name, internal_name = "#{attr_name}=", "#{internal_name}=" if type == :writer diff --git a/activesupport/lib/active_support/core_ext/module/attribute_accessors.rb b/activesupport/lib/active_support/core_ext/module/attribute_accessors.rb index 76825862d7..90989f4f3d 100644 --- a/activesupport/lib/active_support/core_ext/module/attribute_accessors.rb +++ b/activesupport/lib/active_support/core_ext/module/attribute_accessors.rb @@ -1,4 +1,5 @@ -require 'active_support/core_ext/array/extract_options' +require "active_support/core_ext/array/extract_options" +require "active_support/core_ext/regexp" # Extends the module object with class/module and instance accessors for # class/module attributes, just like the native attr* accessors for instance @@ -27,7 +28,7 @@ class Module # <tt>instance_reader: false</tt> or <tt>instance_accessor: false</tt>. # # module HairColors - # mattr_writer :hair_colors, instance_reader: false + # mattr_reader :hair_colors, instance_reader: false # end # # class Person @@ -40,7 +41,7 @@ class Module # Also, you can pass a block to set up the attribute with a default value. # # module HairColors - # cattr_reader :hair_colors do + # mattr_reader :hair_colors do # [:brown, :black, :blonde, :red] # end # end @@ -53,7 +54,7 @@ class Module def mattr_reader(*syms) options = syms.extract_options! syms.each do |sym| - raise NameError.new("invalid attribute name: #{sym}") unless sym =~ /\A[_A-Za-z]\w*\z/ + raise NameError.new("invalid attribute name: #{sym}") unless /\A[_A-Za-z]\w*\z/.match?(sym) class_eval(<<-EOS, __FILE__, __LINE__ + 1) @@#{sym} = nil unless defined? @@#{sym} @@ -119,7 +120,7 @@ class Module def mattr_writer(*syms) options = syms.extract_options! syms.each do |sym| - raise NameError.new("invalid attribute name: #{sym}") unless sym =~ /\A[_A-Za-z]\w*\z/ + raise NameError.new("invalid attribute name: #{sym}") unless /\A[_A-Za-z]\w*\z/.match?(sym) class_eval(<<-EOS, __FILE__, __LINE__ + 1) @@#{sym} = nil unless defined? @@#{sym} diff --git a/activesupport/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb b/activesupport/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb index 8a7e6776da..1e82b4acc2 100644 --- a/activesupport/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +++ b/activesupport/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb @@ -1,9 +1,10 @@ -require 'active_support/core_ext/array/extract_options' +require "active_support/core_ext/array/extract_options" +require "active_support/core_ext/regexp" # Extends the module object with class/module and instance accessors for # class/module attributes, just like the native attr* accessors for instance # attributes, but does so on a per-thread basis. -# +# # So the values are scoped within the Thread.current space under the class name # of the module. class Module @@ -25,7 +26,7 @@ class Module # end # # => NameError: invalid attribute name: 1_Badname # - # If you want to opt out the creation on the instance reader method, pass + # If you want to opt out of the creation of the instance reader method, pass # <tt>instance_reader: false</tt> or <tt>instance_accessor: false</tt>. # # class Current @@ -33,21 +34,24 @@ class Module # end # # Current.new.user # => NoMethodError - def thread_mattr_reader(*syms) + def thread_mattr_reader(*syms) # :nodoc: options = syms.extract_options! syms.each do |sym| - raise NameError.new("invalid attribute name: #{sym}") unless sym =~ /^[_A-Za-z]\w*$/ + raise NameError.new("invalid attribute name: #{sym}") unless /^[_A-Za-z]\w*$/.match?(sym) + + # The following generated method concatenates `name` because we want it + # to work with inheritance via polymorphism. class_eval(<<-EOS, __FILE__, __LINE__ + 1) def self.#{sym} - Thread.current[:"attr_#{name}_#{sym}"] + Thread.current["attr_" + name + "_#{sym}"] end EOS unless options[:instance_reader] == false || options[:instance_accessor] == false class_eval(<<-EOS, __FILE__, __LINE__ + 1) def #{sym} - Thread.current[:"attr_#{self.class.name}_#{sym}"] + self.class.#{sym} end EOS end @@ -65,7 +69,7 @@ class Module # Current.user = "DHH" # Thread.current[:attr_Current_user] # => "DHH" # - # If you want to opt out the instance writer method, pass + # If you want to opt out of the creation of the instance writer method, pass # <tt>instance_writer: false</tt> or <tt>instance_accessor: false</tt>. # # class Current @@ -73,20 +77,23 @@ class Module # end # # Current.new.user = "DHH" # => NoMethodError - def thread_mattr_writer(*syms) + def thread_mattr_writer(*syms) # :nodoc: options = syms.extract_options! syms.each do |sym| - raise NameError.new("invalid attribute name: #{sym}") unless sym =~ /^[_A-Za-z]\w*$/ + raise NameError.new("invalid attribute name: #{sym}") unless /^[_A-Za-z]\w*$/.match?(sym) + + # The following generated method concatenates `name` because we want it + # to work with inheritance via polymorphism. class_eval(<<-EOS, __FILE__, __LINE__ + 1) def self.#{sym}=(obj) - Thread.current[:"attr_#{name}_#{sym}"] = obj + Thread.current["attr_" + name + "_#{sym}"] = obj end EOS unless options[:instance_writer] == false || options[:instance_accessor] == false class_eval(<<-EOS, __FILE__, __LINE__ + 1) def #{sym}=(obj) - Thread.current[:"attr_#{self.class.name}_#{sym}"] = obj + self.class.#{sym} = obj end EOS end @@ -133,9 +140,9 @@ class Module # # Current.new.user = "DHH" # => NoMethodError # Current.new.user # => NoMethodError - def thread_mattr_accessor(*syms, &blk) - thread_mattr_reader(*syms, &blk) - thread_mattr_writer(*syms, &blk) + def thread_mattr_accessor(*syms) + thread_mattr_reader(*syms) + thread_mattr_writer(*syms) end alias :thread_cattr_accessor :thread_mattr_accessor end diff --git a/activesupport/lib/active_support/core_ext/module/concerning.rb b/activesupport/lib/active_support/core_ext/module/concerning.rb index 65b88b9bbd..97b0a382ce 100644 --- a/activesupport/lib/active_support/core_ext/module/concerning.rb +++ b/activesupport/lib/active_support/core_ext/module/concerning.rb @@ -1,4 +1,4 @@ -require 'active_support/concern' +require "active_support/concern" class Module # = Bite-sized separation of concerns diff --git a/activesupport/lib/active_support/core_ext/module/delegation.rb b/activesupport/lib/active_support/core_ext/module/delegation.rb index 0d46248582..f5f4ba61b7 100644 --- a/activesupport/lib/active_support/core_ext/module/delegation.rb +++ b/activesupport/lib/active_support/core_ext/module/delegation.rb @@ -1,4 +1,5 @@ -require 'set' +require "set" +require "active_support/core_ext/regexp" class Module # Error generated by +delegate+ when a method is called on +nil+ and +allow_nil+ @@ -148,28 +149,24 @@ class Module # Foo.new("Bar").name # raises NoMethodError: undefined method `name' # # The target method must be public, otherwise it will raise +NoMethodError+. - # - def delegate(*methods) - options = methods.pop - unless options.is_a?(Hash) && to = options[:to] - raise ArgumentError, 'Delegation needs a target. Supply an options hash with a :to key as the last argument (e.g. delegate :hello, to: :greeter).' + def delegate(*methods, to: nil, prefix: nil, allow_nil: nil) + unless to + raise ArgumentError, "Delegation needs a target. Supply an options hash with a :to key as the last argument (e.g. delegate :hello, to: :greeter)." end - prefix, allow_nil = options.values_at(:prefix, :allow_nil) - - if prefix == true && to =~ /^[^a-z_]/ - raise ArgumentError, 'Can only automatically set the delegation prefix when delegating to a method.' + if prefix == true && /^[^a-z_]/.match?(to) + raise ArgumentError, "Can only automatically set the delegation prefix when delegating to a method." end method_prefix = \ if prefix "#{prefix == true ? to : prefix}_" else - '' + "" end - file, line = caller(1, 1).first.split(':'.freeze, 2) - line = line.to_i + location = caller_locations(1, 1).first + file, line = location.path, location.lineno to = to.to_s to = "self.#{to}" if DELEGATION_RESERVED_METHOD_NAMES.include?(to) @@ -177,7 +174,7 @@ class Module methods.each do |method| # Attribute writer methods only accept one argument. Makes sure []= # methods still accept two arguments. - definition = (method =~ /[^\]]=$/) ? 'arg' : '*args, &block' + definition = /[^\]]=$/.match?(method) ? "arg" : "*args, &block" # The following generated method calls the target exactly once, storing # the returned value in a dummy variable. @@ -194,7 +191,7 @@ class Module " _.#{method}(#{definition})", "end", "end" - ].join ';' + ].join ";" else exception = %(raise DelegationError, "#{self}##{method_prefix}#{method} delegated to #{to}.#{method}, but #{to} is nil: \#{self.inspect}") @@ -209,10 +206,74 @@ class Module " raise", " end", "end" - ].join ';' + ].join ";" end module_eval(method_def, file, line) end end + + # When building decorators, a common pattern may emerge: + # + # class Partition + # def initialize(first_event) + # @events = [ first_event ] + # end + # + # def people + # if @events.first.detail.people.any? + # @events.collect { |e| Array(e.detail.people) }.flatten.uniq + # else + # @events.collect(&:creator).uniq + # end + # end + # + # private + # def respond_to_missing?(name, include_private = false) + # @events.respond_to?(name, include_private) + # end + # + # def method_missing(method, *args, &block) + # @events.send(method, *args, &block) + # end + # end + # + # With `Module#delegate_missing_to`, the above is condensed to: + # + # class Partition + # delegate_missing_to :@events + # + # def initialize(first_event) + # @events = [ first_event ] + # end + # + # def people + # if @events.first.detail.people.any? + # @events.collect { |e| Array(e.detail.people) }.flatten.uniq + # else + # @events.collect(&:creator).uniq + # end + # end + # end + # + # The target can be anything callable within the object. E.g. instance + # variables, methods, constants ant the likes. + def delegate_missing_to(target) + target = target.to_s + target = "self.#{target}" if DELEGATION_RESERVED_METHOD_NAMES.include?(target) + + module_eval <<-RUBY, __FILE__, __LINE__ + 1 + def respond_to_missing?(name, include_private = false) + #{target}.respond_to?(name, include_private) + end + + def method_missing(method, *args, &block) + if #{target}.respond_to?(method) + #{target}.public_send(method, *args, &block) + else + super + end + end + RUBY + end end diff --git a/activesupport/lib/active_support/core_ext/module/introspection.rb b/activesupport/lib/active_support/core_ext/module/introspection.rb index f1d26ef28f..4f854a718b 100644 --- a/activesupport/lib/active_support/core_ext/module/introspection.rb +++ b/activesupport/lib/active_support/core_ext/module/introspection.rb @@ -1,4 +1,4 @@ -require 'active_support/inflector' +require "active_support/inflector" class Module # Returns the name of the module containing this one. @@ -46,9 +46,9 @@ class Module def parents parents = [] if parent_name - parts = parent_name.split('::') + parts = parent_name.split("::") until parts.empty? - parents << ActiveSupport::Inflector.constantize(parts * '::') + parents << ActiveSupport::Inflector.constantize(parts * "::") parts.pop end end @@ -57,6 +57,10 @@ class Module end def local_constants #:nodoc: + ActiveSupport::Deprecation.warn(<<-MSG.squish) + Module#local_constants is deprecated and will be removed in Rails 5.1. + Use Module#constants(false) instead. + MSG constants(false) end end diff --git a/activesupport/lib/active_support/core_ext/module/method_transplanting.rb b/activesupport/lib/active_support/core_ext/module/method_transplanting.rb index 1fde3db070..dccfa3e9bb 100644 --- a/activesupport/lib/active_support/core_ext/module/method_transplanting.rb +++ b/activesupport/lib/active_support/core_ext/module/method_transplanting.rb @@ -1,3 +1,3 @@ -require 'active_support/deprecation' +require "active_support/deprecation" ActiveSupport::Deprecation.warn("This file is deprecated and will be removed in Rails 5.1 with no replacement.") diff --git a/activesupport/lib/active_support/core_ext/module/qualified_const.rb b/activesupport/lib/active_support/core_ext/module/qualified_const.rb index 3ea39d4267..62f0687ae9 100644 --- a/activesupport/lib/active_support/core_ext/module/qualified_const.rb +++ b/activesupport/lib/active_support/core_ext/module/qualified_const.rb @@ -1,4 +1,4 @@ -require 'active_support/core_ext/string/inflections' +require "active_support/core_ext/string/inflections" #-- # Allows code reuse in the methods below without polluting Module. @@ -11,7 +11,7 @@ module ActiveSupport end def self.names(path) - path.split('::') + path.split("::") end end end diff --git a/activesupport/lib/active_support/core_ext/module/reachable.rb b/activesupport/lib/active_support/core_ext/module/reachable.rb index 5d3d0e9851..b89a38f26c 100644 --- a/activesupport/lib/active_support/core_ext/module/reachable.rb +++ b/activesupport/lib/active_support/core_ext/module/reachable.rb @@ -1,5 +1,5 @@ -require 'active_support/core_ext/module/anonymous' -require 'active_support/core_ext/string/inflections' +require "active_support/core_ext/module/anonymous" +require "active_support/core_ext/string/inflections" class Module def reachable? #:nodoc: diff --git a/activesupport/lib/active_support/core_ext/numeric.rb b/activesupport/lib/active_support/core_ext/numeric.rb index bcdc3eace2..6062f9e3a8 100644 --- a/activesupport/lib/active_support/core_ext/numeric.rb +++ b/activesupport/lib/active_support/core_ext/numeric.rb @@ -1,4 +1,4 @@ -require 'active_support/core_ext/numeric/bytes' -require 'active_support/core_ext/numeric/time' -require 'active_support/core_ext/numeric/inquiry' -require 'active_support/core_ext/numeric/conversions' +require "active_support/core_ext/numeric/bytes" +require "active_support/core_ext/numeric/time" +require "active_support/core_ext/numeric/inquiry" +require "active_support/core_ext/numeric/conversions" diff --git a/activesupport/lib/active_support/core_ext/numeric/conversions.rb b/activesupport/lib/active_support/core_ext/numeric/conversions.rb index 9d832897ed..cebfda8d31 100644 --- a/activesupport/lib/active_support/core_ext/numeric/conversions.rb +++ b/activesupport/lib/active_support/core_ext/numeric/conversions.rb @@ -1,9 +1,8 @@ -require 'active_support/core_ext/big_decimal/conversions' -require 'active_support/number_helper' -require 'active_support/core_ext/module/deprecation' +require "active_support/core_ext/big_decimal/conversions" +require "active_support/number_helper" +require "active_support/core_ext/module/deprecation" module ActiveSupport::NumericWithFormat - # Provides options for converting numbers into formatted strings. # Options are provided for phone numbers, currency, percentage, # precision, positional notation, file size and pretty printing. @@ -15,72 +14,72 @@ module ActiveSupport::NumericWithFormat # ==== Examples # # Phone Numbers: - # 5551234.to_s(:phone) # => 555-1234 - # 1235551234.to_s(:phone) # => 123-555-1234 - # 1235551234.to_s(:phone, area_code: true) # => (123) 555-1234 - # 1235551234.to_s(:phone, delimiter: ' ') # => 123 555 1234 - # 1235551234.to_s(:phone, area_code: true, extension: 555) # => (123) 555-1234 x 555 - # 1235551234.to_s(:phone, country_code: 1) # => +1-123-555-1234 + # 5551234.to_s(:phone) # => "555-1234" + # 1235551234.to_s(:phone) # => "123-555-1234" + # 1235551234.to_s(:phone, area_code: true) # => "(123) 555-1234" + # 1235551234.to_s(:phone, delimiter: ' ') # => "123 555 1234" + # 1235551234.to_s(:phone, area_code: true, extension: 555) # => "(123) 555-1234 x 555" + # 1235551234.to_s(:phone, country_code: 1) # => "+1-123-555-1234" # 1235551234.to_s(:phone, country_code: 1, extension: 1343, delimiter: '.') - # # => +1.123.555.1234 x 1343 + # # => "+1.123.555.1234 x 1343" # # Currency: - # 1234567890.50.to_s(:currency) # => $1,234,567,890.50 - # 1234567890.506.to_s(:currency) # => $1,234,567,890.51 - # 1234567890.506.to_s(:currency, precision: 3) # => $1,234,567,890.506 - # 1234567890.506.to_s(:currency, locale: :fr) # => 1 234 567 890,51 € + # 1234567890.50.to_s(:currency) # => "$1,234,567,890.50" + # 1234567890.506.to_s(:currency) # => "$1,234,567,890.51" + # 1234567890.506.to_s(:currency, precision: 3) # => "$1,234,567,890.506" + # 1234567890.506.to_s(:currency, locale: :fr) # => "1 234 567 890,51 €" # -1234567890.50.to_s(:currency, negative_format: '(%u%n)') - # # => ($1,234,567,890.50) + # # => "($1,234,567,890.50)" # 1234567890.50.to_s(:currency, unit: '£', separator: ',', delimiter: '') - # # => £1234567890,50 + # # => "£1234567890,50" # 1234567890.50.to_s(:currency, unit: '£', separator: ',', delimiter: '', format: '%n %u') - # # => 1234567890,50 £ + # # => "1234567890,50 £" # # Percentage: - # 100.to_s(:percentage) # => 100.000% - # 100.to_s(:percentage, precision: 0) # => 100% - # 1000.to_s(:percentage, delimiter: '.', separator: ',') # => 1.000,000% - # 302.24398923423.to_s(:percentage, precision: 5) # => 302.24399% - # 1000.to_s(:percentage, locale: :fr) # => 1 000,000% - # 100.to_s(:percentage, format: '%n %') # => 100.000 % + # 100.to_s(:percentage) # => "100.000%" + # 100.to_s(:percentage, precision: 0) # => "100%" + # 1000.to_s(:percentage, delimiter: '.', separator: ',') # => "1.000,000%" + # 302.24398923423.to_s(:percentage, precision: 5) # => "302.24399%" + # 1000.to_s(:percentage, locale: :fr) # => "1 000,000%" + # 100.to_s(:percentage, format: '%n %') # => "100.000 %" # # Delimited: - # 12345678.to_s(:delimited) # => 12,345,678 - # 12345678.05.to_s(:delimited) # => 12,345,678.05 - # 12345678.to_s(:delimited, delimiter: '.') # => 12.345.678 - # 12345678.to_s(:delimited, delimiter: ',') # => 12,345,678 - # 12345678.05.to_s(:delimited, separator: ' ') # => 12,345,678 05 - # 12345678.05.to_s(:delimited, locale: :fr) # => 12 345 678,05 + # 12345678.to_s(:delimited) # => "12,345,678" + # 12345678.05.to_s(:delimited) # => "12,345,678.05" + # 12345678.to_s(:delimited, delimiter: '.') # => "12.345.678" + # 12345678.to_s(:delimited, delimiter: ',') # => "12,345,678" + # 12345678.05.to_s(:delimited, separator: ' ') # => "12,345,678 05" + # 12345678.05.to_s(:delimited, locale: :fr) # => "12 345 678,05" # 98765432.98.to_s(:delimited, delimiter: ' ', separator: ',') - # # => 98 765 432,98 + # # => "98 765 432,98" # # Rounded: - # 111.2345.to_s(:rounded) # => 111.235 - # 111.2345.to_s(:rounded, precision: 2) # => 111.23 - # 13.to_s(:rounded, precision: 5) # => 13.00000 - # 389.32314.to_s(:rounded, precision: 0) # => 389 - # 111.2345.to_s(:rounded, significant: true) # => 111 - # 111.2345.to_s(:rounded, precision: 1, significant: true) # => 100 - # 13.to_s(:rounded, precision: 5, significant: true) # => 13.000 - # 111.234.to_s(:rounded, locale: :fr) # => 111,234 + # 111.2345.to_s(:rounded) # => "111.235" + # 111.2345.to_s(:rounded, precision: 2) # => "111.23" + # 13.to_s(:rounded, precision: 5) # => "13.00000" + # 389.32314.to_s(:rounded, precision: 0) # => "389" + # 111.2345.to_s(:rounded, significant: true) # => "111" + # 111.2345.to_s(:rounded, precision: 1, significant: true) # => "100" + # 13.to_s(:rounded, precision: 5, significant: true) # => "13.000" + # 111.234.to_s(:rounded, locale: :fr) # => "111,234" # 13.to_s(:rounded, precision: 5, significant: true, strip_insignificant_zeros: true) - # # => 13 - # 389.32314.to_s(:rounded, precision: 4, significant: true) # => 389.3 + # # => "13" + # 389.32314.to_s(:rounded, precision: 4, significant: true) # => "389.3" # 1111.2345.to_s(:rounded, precision: 2, separator: ',', delimiter: '.') - # # => 1.111,23 + # # => "1.111,23" # # Human-friendly size in Bytes: - # 123.to_s(:human_size) # => 123 Bytes - # 1234.to_s(:human_size) # => 1.21 KB - # 12345.to_s(:human_size) # => 12.1 KB - # 1234567.to_s(:human_size) # => 1.18 MB - # 1234567890.to_s(:human_size) # => 1.15 GB - # 1234567890123.to_s(:human_size) # => 1.12 TB - # 1234567890123456.to_s(:human_size) # => 1.1 PB - # 1234567890123456789.to_s(:human_size) # => 1.07 EB - # 1234567.to_s(:human_size, precision: 2) # => 1.2 MB - # 483989.to_s(:human_size, precision: 2) # => 470 KB - # 1234567.to_s(:human_size, precision: 2, separator: ',') # => 1,2 MB + # 123.to_s(:human_size) # => "123 Bytes" + # 1234.to_s(:human_size) # => "1.21 KB" + # 12345.to_s(:human_size) # => "12.1 KB" + # 1234567.to_s(:human_size) # => "1.18 MB" + # 1234567890.to_s(:human_size) # => "1.15 GB" + # 1234567890123.to_s(:human_size) # => "1.12 TB" + # 1234567890123456.to_s(:human_size) # => "1.1 PB" + # 1234567890123456789.to_s(:human_size) # => "1.07 EB" + # 1234567.to_s(:human_size, precision: 2) # => "1.2 MB" + # 483989.to_s(:human_size, precision: 2) # => "470 KB" + # 1234567.to_s(:human_size, precision: 2, separator: ',') # => "1,2 MB" # 1234567890123.to_s(:human_size, precision: 5) # => "1.1228 TB" # 524288000.to_s(:human_size, precision: 5) # => "500 MB" # @@ -134,6 +133,12 @@ module ActiveSupport::NumericWithFormat deprecate to_formatted_s: :to_s end -[Fixnum, Bignum, Float, BigDecimal].each do |klass| - klass.prepend(ActiveSupport::NumericWithFormat) +# Ruby 2.4+ unifies Fixnum & Bignum into Integer. +if 0.class == Integer + Integer.prepend ActiveSupport::NumericWithFormat +else + Fixnum.prepend ActiveSupport::NumericWithFormat + Bignum.prepend ActiveSupport::NumericWithFormat end +Float.prepend ActiveSupport::NumericWithFormat +BigDecimal.prepend ActiveSupport::NumericWithFormat diff --git a/activesupport/lib/active_support/core_ext/numeric/inquiry.rb b/activesupport/lib/active_support/core_ext/numeric/inquiry.rb index 7e7ac1b0b2..ec79701189 100644 --- a/activesupport/lib/active_support/core_ext/numeric/inquiry.rb +++ b/activesupport/lib/active_support/core_ext/numeric/inquiry.rb @@ -1,26 +1,26 @@ unless 1.respond_to?(:positive?) # TODO: Remove this file when we drop support to ruby < 2.3 -class Numeric - # Returns true if the number is positive. - # - # 1.positive? # => true - # 0.positive? # => false - # -1.positive? # => false - def positive? - self > 0 - end + class Numeric + # Returns true if the number is positive. + # + # 1.positive? # => true + # 0.positive? # => false + # -1.positive? # => false + def positive? + self > 0 + end - # Returns true if the number is negative. - # - # -1.negative? # => true - # 0.negative? # => false - # 1.negative? # => false - def negative? - self < 0 + # Returns true if the number is negative. + # + # -1.negative? # => true + # 0.negative? # => false + # 1.negative? # => false + def negative? + self < 0 + end end -end -class Complex - undef :positive? - undef :negative? -end + class Complex + undef :positive? + undef :negative? + end end diff --git a/activesupport/lib/active_support/core_ext/numeric/time.rb b/activesupport/lib/active_support/core_ext/numeric/time.rb index 6c4a975495..809dfd4e07 100644 --- a/activesupport/lib/active_support/core_ext/numeric/time.rb +++ b/activesupport/lib/active_support/core_ext/numeric/time.rb @@ -1,8 +1,8 @@ -require 'active_support/duration' -require 'active_support/core_ext/time/calculations' -require 'active_support/core_ext/time/acts_like' -require 'active_support/core_ext/date/calculations' -require 'active_support/core_ext/date/acts_like' +require "active_support/duration" +require "active_support/core_ext/time/calculations" +require "active_support/core_ext/time/acts_like" +require "active_support/core_ext/date/calculations" +require "active_support/core_ext/date/acts_like" class Numeric # Enables the use of time calculations and declarations, like 45.minutes + 2.hours + 4.years. @@ -25,17 +25,17 @@ class Numeric # Returns a Duration instance matching the number of minutes provided. # - # 2.minutes # => 120 seconds + # 2.minutes # => 2 minutes def minutes - ActiveSupport::Duration.new(self * 60, [[:seconds, self * 60]]) + ActiveSupport::Duration.new(self * 60, [[:minutes, self]]) end alias :minute :minutes # Returns a Duration instance matching the number of hours provided. # - # 2.hours # => 7_200 seconds + # 2.hours # => 2 hours def hours - ActiveSupport::Duration.new(self * 3600, [[:seconds, self * 3600]]) + ActiveSupport::Duration.new(self * 3600, [[:hours, self]]) end alias :hour :hours @@ -49,17 +49,17 @@ class Numeric # Returns a Duration instance matching the number of weeks provided. # - # 2.weeks # => 14 days + # 2.weeks # => 2 weeks def weeks - ActiveSupport::Duration.new(self * 7.days, [[:days, self * 7]]) + ActiveSupport::Duration.new(self * 7.days, [[:weeks, self]]) end alias :week :weeks # Returns a Duration instance matching the number of fortnights provided. # - # 2.fortnights # => 28 days + # 2.fortnights # => 4 weeks def fortnights - ActiveSupport::Duration.new(self * 2.weeks, [[:days, self * 14]]) + ActiveSupport::Duration.new(self * 2.weeks, [[:weeks, self * 2]]) end alias :fortnight :fortnights diff --git a/activesupport/lib/active_support/core_ext/object.rb b/activesupport/lib/active_support/core_ext/object.rb index f4f9152d6a..58bbf78601 100644 --- a/activesupport/lib/active_support/core_ext/object.rb +++ b/activesupport/lib/active_support/core_ext/object.rb @@ -1,14 +1,14 @@ -require 'active_support/core_ext/object/acts_like' -require 'active_support/core_ext/object/blank' -require 'active_support/core_ext/object/duplicable' -require 'active_support/core_ext/object/deep_dup' -require 'active_support/core_ext/object/try' -require 'active_support/core_ext/object/inclusion' +require "active_support/core_ext/object/acts_like" +require "active_support/core_ext/object/blank" +require "active_support/core_ext/object/duplicable" +require "active_support/core_ext/object/deep_dup" +require "active_support/core_ext/object/try" +require "active_support/core_ext/object/inclusion" -require 'active_support/core_ext/object/conversions' -require 'active_support/core_ext/object/instance_variables' +require "active_support/core_ext/object/conversions" +require "active_support/core_ext/object/instance_variables" -require 'active_support/core_ext/object/json' -require 'active_support/core_ext/object/to_param' -require 'active_support/core_ext/object/to_query' -require 'active_support/core_ext/object/with_options' +require "active_support/core_ext/object/json" +require "active_support/core_ext/object/to_param" +require "active_support/core_ext/object/to_query" +require "active_support/core_ext/object/with_options" diff --git a/activesupport/lib/active_support/core_ext/object/blank.rb b/activesupport/lib/active_support/core_ext/object/blank.rb index 039c50a4a2..bdb50ee291 100644 --- a/activesupport/lib/active_support/core_ext/object/blank.rb +++ b/activesupport/lib/active_support/core_ext/object/blank.rb @@ -1,3 +1,5 @@ +require "active_support/core_ext/regexp" + class Object # An object is blank if it's false, empty, or a whitespace string. # For example, +false+, '', ' ', +nil+, [], and {} are all blank. @@ -112,7 +114,10 @@ class String # # @return [true, false] def blank? - BLANK_RE === self + # The regexp that matches blank strings is expensive. For the case of empty + # strings we can speed up this method (~3.5x) with an empty? call. The + # penalty for the rest of strings is marginal. + empty? || BLANK_RE.match?(self) end end diff --git a/activesupport/lib/active_support/core_ext/object/conversions.rb b/activesupport/lib/active_support/core_ext/object/conversions.rb index 540f7aadb0..918ebcdc9f 100644 --- a/activesupport/lib/active_support/core_ext/object/conversions.rb +++ b/activesupport/lib/active_support/core_ext/object/conversions.rb @@ -1,4 +1,4 @@ -require 'active_support/core_ext/object/to_param' -require 'active_support/core_ext/object/to_query' -require 'active_support/core_ext/array/conversions' -require 'active_support/core_ext/hash/conversions' +require "active_support/core_ext/object/to_param" +require "active_support/core_ext/object/to_query" +require "active_support/core_ext/array/conversions" +require "active_support/core_ext/hash/conversions" diff --git a/activesupport/lib/active_support/core_ext/object/deep_dup.rb b/activesupport/lib/active_support/core_ext/object/deep_dup.rb index 8dfeed0066..5ac649e552 100644 --- a/activesupport/lib/active_support/core_ext/object/deep_dup.rb +++ b/activesupport/lib/active_support/core_ext/object/deep_dup.rb @@ -1,4 +1,4 @@ -require 'active_support/core_ext/object/duplicable' +require "active_support/core_ext/object/duplicable" class Object # Returns a deep copy of object if it's duplicable. If it's diff --git a/activesupport/lib/active_support/core_ext/object/duplicable.rb b/activesupport/lib/active_support/core_ext/object/duplicable.rb index befa5aee21..aa2282cb7e 100644 --- a/activesupport/lib/active_support/core_ext/object/duplicable.rb +++ b/activesupport/lib/active_support/core_ext/object/duplicable.rb @@ -70,13 +70,13 @@ class Numeric # Numbers are not duplicable: # # 3.duplicable? # => false - # 3.dup # => TypeError: can't dup Fixnum + # 3.dup # => TypeError: can't dup Integer def duplicable? false end end -require 'bigdecimal' +require "bigdecimal" class BigDecimal # BigDecimals are duplicable: # diff --git a/activesupport/lib/active_support/core_ext/object/inclusion.rb b/activesupport/lib/active_support/core_ext/object/inclusion.rb index d4c17dfb07..98bf820d36 100644 --- a/activesupport/lib/active_support/core_ext/object/inclusion.rb +++ b/activesupport/lib/active_support/core_ext/object/inclusion.rb @@ -22,6 +22,6 @@ class Object # # @return [Object] def presence_in(another_object) - self.in?(another_object) ? self : nil + in?(another_object) ? self : nil end end diff --git a/activesupport/lib/active_support/core_ext/object/json.rb b/activesupport/lib/active_support/core_ext/object/json.rb index 0db787010c..1c4d181443 100644 --- a/activesupport/lib/active_support/core_ext/object/json.rb +++ b/activesupport/lib/active_support/core_ext/object/json.rb @@ -1,14 +1,16 @@ # Hack to load json gem first so we can overwrite its to_json. -require 'json' -require 'bigdecimal' -require 'active_support/core_ext/big_decimal/conversions' # for #to_s -require 'active_support/core_ext/hash/except' -require 'active_support/core_ext/hash/slice' -require 'active_support/core_ext/object/instance_variables' -require 'time' -require 'active_support/core_ext/time/conversions' -require 'active_support/core_ext/date_time/conversions' -require 'active_support/core_ext/date/conversions' +require "json" +require "bigdecimal" +require "uri/generic" +require "pathname" +require "active_support/core_ext/big_decimal/conversions" # for #to_s +require "active_support/core_ext/hash/except" +require "active_support/core_ext/hash/slice" +require "active_support/core_ext/object/instance_variables" +require "time" +require "active_support/core_ext/time/conversions" +require "active_support/core_ext/date_time/conversions" +require "active_support/core_ext/date/conversions" # The JSON gem adds a few modules to Ruby core classes containing :to_json definition, overwriting # their default behavior. That said, we need to define the basic to_json method in all of them, @@ -187,13 +189,31 @@ class DateTime if ActiveSupport::JSON::Encoding.use_standard_json_time_format xmlschema(ActiveSupport::JSON::Encoding.time_precision) else - strftime('%Y/%m/%d %H:%M:%S %z') + strftime("%Y/%m/%d %H:%M:%S %z") end end end +class URI::Generic #:nodoc: + def as_json(options = nil) + to_s + end +end + +class Pathname #:nodoc: + def as_json(options = nil) + to_s + end +end + class Process::Status #:nodoc: def as_json(options = nil) - { :exitstatus => exitstatus, :pid => pid } + { exitstatus: exitstatus, pid: pid } + end +end + +class Exception + def as_json(options = nil) + to_s end end diff --git a/activesupport/lib/active_support/core_ext/object/to_param.rb b/activesupport/lib/active_support/core_ext/object/to_param.rb index 684d4ef57e..5eeaf03163 100644 --- a/activesupport/lib/active_support/core_ext/object/to_param.rb +++ b/activesupport/lib/active_support/core_ext/object/to_param.rb @@ -1 +1 @@ -require 'active_support/core_ext/object/to_query' +require "active_support/core_ext/object/to_query" diff --git a/activesupport/lib/active_support/core_ext/object/to_query.rb b/activesupport/lib/active_support/core_ext/object/to_query.rb index ec5ace4e16..a3a3abacbb 100644 --- a/activesupport/lib/active_support/core_ext/object/to_query.rb +++ b/activesupport/lib/active_support/core_ext/object/to_query.rb @@ -1,4 +1,4 @@ -require 'cgi' +require "cgi" class Object # Alias of <tt>to_s</tt>. @@ -38,7 +38,7 @@ class Array # Calls <tt>to_param</tt> on all its elements and joins the result with # slashes. This is used by <tt>url_for</tt> in Action Pack. def to_param - collect(&:to_param).join '/' + collect(&:to_param).join "/" end # Converts an array into a string suitable for use as a URL query string, @@ -51,7 +51,7 @@ class Array if empty? nil.to_query(prefix) else - collect { |value| value.to_query(prefix) }.join '&' + collect { |value| value.to_query(prefix) }.join "&" end end end @@ -77,7 +77,7 @@ class Hash unless (value.is_a?(Hash) || value.is_a?(Array)) && value.empty? value.to_query(namespace ? "#{namespace}[#{key}]" : key) end - end.compact.sort! * '&' + end.compact.sort! * "&" end alias_method :to_param, :to_query diff --git a/activesupport/lib/active_support/core_ext/object/try.rb b/activesupport/lib/active_support/core_ext/object/try.rb index 8c16d95b62..b2be619b2d 100644 --- a/activesupport/lib/active_support/core_ext/object/try.rb +++ b/activesupport/lib/active_support/core_ext/object/try.rb @@ -1,4 +1,4 @@ -require 'delegate' +require "delegate" module ActiveSupport module Tryable #:nodoc: @@ -99,7 +99,7 @@ class Object # # "a".try!(:upcase) # => "A" # nil.try!(:upcase) # => nil - # 123.try!(:upcase) # => NoMethodError: undefined method `upcase' for 123:Fixnum + # 123.try!(:upcase) # => NoMethodError: undefined method `upcase' for 123:Integer end class Delegator diff --git a/activesupport/lib/active_support/core_ext/object/with_options.rb b/activesupport/lib/active_support/core_ext/object/with_options.rb index 513c8b1d55..cf39b1d312 100644 --- a/activesupport/lib/active_support/core_ext/object/with_options.rb +++ b/activesupport/lib/active_support/core_ext/object/with_options.rb @@ -1,4 +1,4 @@ -require 'active_support/option_merger' +require "active_support/option_merger" class Object # An elegant way to factor duplication out of options passed to a series of diff --git a/activesupport/lib/active_support/core_ext/range.rb b/activesupport/lib/active_support/core_ext/range.rb index 9368e81235..3190e3ff76 100644 --- a/activesupport/lib/active_support/core_ext/range.rb +++ b/activesupport/lib/active_support/core_ext/range.rb @@ -1,4 +1,4 @@ -require 'active_support/core_ext/range/conversions' -require 'active_support/core_ext/range/include_range' -require 'active_support/core_ext/range/overlaps' -require 'active_support/core_ext/range/each' +require "active_support/core_ext/range/conversions" +require "active_support/core_ext/range/include_range" +require "active_support/core_ext/range/overlaps" +require "active_support/core_ext/range/each" diff --git a/activesupport/lib/active_support/core_ext/range/conversions.rb b/activesupport/lib/active_support/core_ext/range/conversions.rb index 965436c23a..69ea046cb6 100644 --- a/activesupport/lib/active_support/core_ext/range/conversions.rb +++ b/activesupport/lib/active_support/core_ext/range/conversions.rb @@ -1,6 +1,6 @@ module ActiveSupport::RangeWithFormat RANGE_FORMATS = { - :db => Proc.new { |start, stop| "BETWEEN '#{start.to_s(:db)}' AND '#{stop.to_s(:db)}'" } + db: Proc.new { |start, stop| "BETWEEN '#{start.to_s(:db)}' AND '#{stop.to_s(:db)}'" } } # Convert range to a formatted string. See RANGE_FORMATS for predefined formats. diff --git a/activesupport/lib/active_support/core_ext/regexp.rb b/activesupport/lib/active_support/core_ext/regexp.rb index 784145f5fb..062d568228 100644 --- a/activesupport/lib/active_support/core_ext/regexp.rb +++ b/activesupport/lib/active_support/core_ext/regexp.rb @@ -2,4 +2,8 @@ class Regexp #:nodoc: def multiline? options & MULTILINE == MULTILINE end + + def match?(string, pos=0) + !!match(string, pos) + end unless //.respond_to?(:match?) end diff --git a/activesupport/lib/active_support/core_ext/securerandom.rb b/activesupport/lib/active_support/core_ext/securerandom.rb index 98cf7430f7..92392d1a92 100644 --- a/activesupport/lib/active_support/core_ext/securerandom.rb +++ b/activesupport/lib/active_support/core_ext/securerandom.rb @@ -1,7 +1,7 @@ -require 'securerandom' +require "securerandom" module SecureRandom - BASE58_ALPHABET = ('0'..'9').to_a + ('A'..'Z').to_a + ('a'..'z').to_a - ['0', 'O', 'I', 'l'] + BASE58_ALPHABET = ("0".."9").to_a + ("A".."Z").to_a + ("a".."z").to_a - ["0", "O", "I", "l"] # SecureRandom.base58 generates a random base58 string. # # The argument _n_ specifies the length, of the random string to be generated. diff --git a/activesupport/lib/active_support/core_ext/string.rb b/activesupport/lib/active_support/core_ext/string.rb index c656db2c6c..4cb3200875 100644 --- a/activesupport/lib/active_support/core_ext/string.rb +++ b/activesupport/lib/active_support/core_ext/string.rb @@ -1,13 +1,13 @@ -require 'active_support/core_ext/string/conversions' -require 'active_support/core_ext/string/filters' -require 'active_support/core_ext/string/multibyte' -require 'active_support/core_ext/string/starts_ends_with' -require 'active_support/core_ext/string/inflections' -require 'active_support/core_ext/string/access' -require 'active_support/core_ext/string/behavior' -require 'active_support/core_ext/string/output_safety' -require 'active_support/core_ext/string/exclude' -require 'active_support/core_ext/string/strip' -require 'active_support/core_ext/string/inquiry' -require 'active_support/core_ext/string/indent' -require 'active_support/core_ext/string/zones' +require "active_support/core_ext/string/conversions" +require "active_support/core_ext/string/filters" +require "active_support/core_ext/string/multibyte" +require "active_support/core_ext/string/starts_ends_with" +require "active_support/core_ext/string/inflections" +require "active_support/core_ext/string/access" +require "active_support/core_ext/string/behavior" +require "active_support/core_ext/string/output_safety" +require "active_support/core_ext/string/exclude" +require "active_support/core_ext/string/strip" +require "active_support/core_ext/string/inquiry" +require "active_support/core_ext/string/indent" +require "active_support/core_ext/string/zones" diff --git a/activesupport/lib/active_support/core_ext/string/access.rb b/activesupport/lib/active_support/core_ext/string/access.rb index ebd0dd3fc7..caa48e34c5 100644 --- a/activesupport/lib/active_support/core_ext/string/access.rb +++ b/activesupport/lib/active_support/core_ext/string/access.rb @@ -1,5 +1,5 @@ class String - # If you pass a single Fixnum, returns a substring of one character at that + # If you pass a single integer, returns a substring of one character at that # position. The first character of the string is at position 0, the next at # position 1, and so on. If a range is supplied, a substring containing # characters at offsets given by the range is returned. In both cases, if an @@ -74,9 +74,9 @@ class String # str.first(6) # => "hello" def first(limit = 1) if limit == 0 - '' + "" elsif limit >= size - self.dup + dup else to(limit - 1) end @@ -94,9 +94,9 @@ class String # str.last(6) # => "hello" def last(limit = 1) if limit == 0 - '' + "" elsif limit >= size - self.dup + dup else from(-limit) end diff --git a/activesupport/lib/active_support/core_ext/string/conversions.rb b/activesupport/lib/active_support/core_ext/string/conversions.rb index fd79a40e31..221b4969cc 100644 --- a/activesupport/lib/active_support/core_ext/string/conversions.rb +++ b/activesupport/lib/active_support/core_ext/string/conversions.rb @@ -1,5 +1,5 @@ -require 'date' -require 'active_support/core_ext/time/calculations' +require "date" +require "active_support/core_ext/time/calculations" class String # Converts a string to a Time value. @@ -18,7 +18,8 @@ class String # "12/13/2012".to_time # => ArgumentError: argument out of range def to_time(form = :local) parts = Date._parse(self, false) - return if parts.empty? + used_keys = %i(year mon mday hour min sec sec_fraction offset) + return if (parts.keys & used_keys).empty? now = Time.now time = Time.new( @@ -31,7 +32,7 @@ class String parts.fetch(:offset, form == :utc ? 0 : nil) ) - form == :utc ? time.utc : time.getlocal + form == :utc ? time.utc : time.to_time end # Converts a string to a Date value. diff --git a/activesupport/lib/active_support/core_ext/string/filters.rb b/activesupport/lib/active_support/core_ext/string/filters.rb index 375ec1aef8..a9ec2eb842 100644 --- a/activesupport/lib/active_support/core_ext/string/filters.rb +++ b/activesupport/lib/active_support/core_ext/string/filters.rb @@ -17,7 +17,7 @@ class String # str.squish! # => "foo bar boo" # str # => "foo bar boo" def squish! - gsub!(/[[:space:]]+/, ' ') + gsub!(/[[:space:]]+/, " ") strip! self end @@ -64,7 +64,7 @@ class String def truncate(truncate_at, options = {}) return dup unless length > truncate_at - omission = options[:omission] || '...' + omission = options[:omission] || "..." length_with_room_for_omission = truncate_at - omission.length stop = \ if options[:separator] @@ -94,7 +94,7 @@ class String sep = options[:separator] || /\s+/ sep = Regexp.escape(sep.to_s) unless Regexp === sep if self =~ /\A((?>.+?#{sep}){#{words_count - 1}}.+?)#{sep}.*/m - $1 + (options[:omission] || '...') + $1 + (options[:omission] || "...") else dup end diff --git a/activesupport/lib/active_support/core_ext/string/indent.rb b/activesupport/lib/active_support/core_ext/string/indent.rb index ce3a69cf5f..e87f72fdbd 100644 --- a/activesupport/lib/active_support/core_ext/string/indent.rb +++ b/activesupport/lib/active_support/core_ext/string/indent.rb @@ -3,7 +3,7 @@ class String # # Returns the indented string, or +nil+ if there was nothing to indent. def indent!(amount, indent_string=nil, indent_empty_lines=false) - indent_string = indent_string || self[/^[ \t]/] || ' ' + indent_string = indent_string || self[/^[ \t]/] || " " re = indent_empty_lines ? /^/ : /^(?!$)/ gsub!(re, indent_string * amount) end @@ -38,6 +38,6 @@ class String # "foo\n\nbar".indent(2, nil, true) # => " foo\n \n bar" # def indent(amount, indent_string=nil, indent_empty_lines=false) - dup.tap {|_| _.indent!(amount, indent_string, indent_empty_lines)} + dup.tap { |_| _.indent!(amount, indent_string, indent_empty_lines) } end end diff --git a/activesupport/lib/active_support/core_ext/string/inflections.rb b/activesupport/lib/active_support/core_ext/string/inflections.rb index cc71b8155d..7e12700c8c 100644 --- a/activesupport/lib/active_support/core_ext/string/inflections.rb +++ b/activesupport/lib/active_support/core_ext/string/inflections.rb @@ -1,5 +1,5 @@ -require 'active_support/inflector/methods' -require 'active_support/inflector/transliterate' +require "active_support/inflector/methods" +require "active_support/inflector/transliterate" # String inflections define new methods on the String class to transform names for different purposes. # For instance, you can figure out the name of a table from the name of a class. @@ -31,7 +31,7 @@ class String def pluralize(count = nil, locale = :en) locale = count if count.is_a?(Symbol) if count == 1 - self.dup + dup else ActiveSupport::Inflector.pluralize(self, locale) end @@ -164,7 +164,7 @@ class String # # <%= link_to(@person.name, person_path) %> # # => <a href="/person/1-donald-e-knuth">Donald E. Knuth</a> - # + # # To preserve the case of the characters in a string, use the `preserve_case` argument. # # class Person @@ -178,7 +178,7 @@ class String # # <%= link_to(@person.name, person_path) %> # # => <a href="/person/1-Donald-E-Knuth">Donald E. Knuth</a> - def parameterize(sep = :unused, separator: '-', preserve_case: false) + def parameterize(sep = :unused, separator: "-", preserve_case: false) unless sep == :unused ActiveSupport::Deprecation.warn("Passing the separator argument as a positional parameter is deprecated and will soon be removed. Use `separator: '#{sep}'` instead.") separator = sep @@ -222,6 +222,15 @@ class String ActiveSupport::Inflector.humanize(self, options) end + # Converts just the first character to uppercase. + # + # 'what a Lovely Day'.upcase_first # => "What a Lovely Day" + # 'w'.upcase_first # => "W" + # ''.upcase_first # => "" + def upcase_first + ActiveSupport::Inflector.upcase_first(self) + end + # Creates a foreign key name from a class name. # +separate_class_name_and_id_with_underscore+ sets whether # the method should put '_' between the name and 'id'. diff --git a/activesupport/lib/active_support/core_ext/string/inquiry.rb b/activesupport/lib/active_support/core_ext/string/inquiry.rb index 1dcd949536..c95d83beae 100644 --- a/activesupport/lib/active_support/core_ext/string/inquiry.rb +++ b/activesupport/lib/active_support/core_ext/string/inquiry.rb @@ -1,4 +1,4 @@ -require 'active_support/string_inquirer' +require "active_support/string_inquirer" class String # Wraps the current string in the <tt>ActiveSupport::StringInquirer</tt> class, diff --git a/activesupport/lib/active_support/core_ext/string/multibyte.rb b/activesupport/lib/active_support/core_ext/string/multibyte.rb index cc6f2158e7..1c73182259 100644 --- a/activesupport/lib/active_support/core_ext/string/multibyte.rb +++ b/activesupport/lib/active_support/core_ext/string/multibyte.rb @@ -1,4 +1,4 @@ -require 'active_support/multibyte' +require "active_support/multibyte" class String # == Multibyte proxy diff --git a/activesupport/lib/active_support/core_ext/string/output_safety.rb b/activesupport/lib/active_support/core_ext/string/output_safety.rb index 43b9fd4bf7..2b7e556ced 100644 --- a/activesupport/lib/active_support/core_ext/string/output_safety.rb +++ b/activesupport/lib/active_support/core_ext/string/output_safety.rb @@ -1,10 +1,11 @@ -require 'erb' -require 'active_support/core_ext/kernel/singleton_class' +require "erb" +require "active_support/core_ext/kernel/singleton_class" +require "active_support/multibyte/unicode" class ERB module Util - HTML_ESCAPE = { '&' => '&', '>' => '>', '<' => '<', '"' => '"', "'" => ''' } - JSON_ESCAPE = { '&' => '\u0026', '>' => '\u003e', '<' => '\u003c', "\u2028" => '\u2028', "\u2029" => '\u2029' } + HTML_ESCAPE = { "&" => "&", ">" => ">", "<" => "<", '"' => """, "'" => "'" } + JSON_ESCAPE = { "&" => '\u0026', ">" => '\u003e', "<" => '\u003c', "\u2028" => '\u2028', "\u2029" => '\u2029' } HTML_ESCAPE_ONCE_REGEXP = /["><']|&(?!([a-zA-Z]+|(#\d+)|(#[xX][\dA-Fa-f]+));)/ JSON_ESCAPE_REGEXP = /[\u2028\u2029&><]/u @@ -144,7 +145,7 @@ module ActiveSupport #:nodoc: # Raised when <tt>ActiveSupport::SafeBuffer#safe_concat</tt> is called on unsafe buffers. class SafeConcatError < StandardError def initialize - super 'Could not concatenate to the buffer because it is not html safe.' + super "Could not concatenate to the buffer because it is not html safe." end end @@ -171,7 +172,7 @@ module ActiveSupport #:nodoc: original_concat(value) end - def initialize(str = '') + def initialize(str = "") @html_safe = true super end @@ -242,15 +243,15 @@ module ActiveSupport #:nodoc: private - def html_escape_interpolated_argument(arg) - (!html_safe? || arg.html_safe?) ? arg : CGI.escapeHTML(arg.to_s) - end + def html_escape_interpolated_argument(arg) + (!html_safe? || arg.html_safe?) ? arg : CGI.escapeHTML(arg.to_s) + end end end class String # Marks a string as trusted safe. It will be inserted into HTML with no - # additional escaping performed. It is your responsibilty to ensure that the + # additional escaping performed. It is your responsibility to ensure that the # string contains no malicious content. This method is equivalent to the # `raw` helper in views. It is recommended that you use `sanitize` instead of # this method. It should never be called on user input. diff --git a/activesupport/lib/active_support/core_ext/string/strip.rb b/activesupport/lib/active_support/core_ext/string/strip.rb index 55b9b87352..bb62e6c0ba 100644 --- a/activesupport/lib/active_support/core_ext/string/strip.rb +++ b/activesupport/lib/active_support/core_ext/string/strip.rb @@ -18,6 +18,6 @@ class String # Technically, it looks for the least indented non-empty line # in the whole string, and removes that amount of leading whitespace. def strip_heredoc - gsub(/^#{scan(/^[ \t]*(?=\S)/).min}/, ''.freeze) + gsub(/^#{scan(/^[ \t]*(?=\S)/).min}/, "".freeze) end end diff --git a/activesupport/lib/active_support/core_ext/string/zones.rb b/activesupport/lib/active_support/core_ext/string/zones.rb index 510c884c18..de5a28e4f7 100644 --- a/activesupport/lib/active_support/core_ext/string/zones.rb +++ b/activesupport/lib/active_support/core_ext/string/zones.rb @@ -1,5 +1,5 @@ -require 'active_support/core_ext/string/conversions' -require 'active_support/core_ext/time/zones' +require "active_support/core_ext/string/conversions" +require "active_support/core_ext/time/zones" class String # Converts String to a TimeWithZone in the current zone if Time.zone or Time.zone_default diff --git a/activesupport/lib/active_support/core_ext/struct.rb b/activesupport/lib/active_support/core_ext/struct.rb index 1fde3db070..dccfa3e9bb 100644 --- a/activesupport/lib/active_support/core_ext/struct.rb +++ b/activesupport/lib/active_support/core_ext/struct.rb @@ -1,3 +1,3 @@ -require 'active_support/deprecation' +require "active_support/deprecation" ActiveSupport::Deprecation.warn("This file is deprecated and will be removed in Rails 5.1 with no replacement.") diff --git a/activesupport/lib/active_support/core_ext/time.rb b/activesupport/lib/active_support/core_ext/time.rb index 72c3234630..b1ae4a45d9 100644 --- a/activesupport/lib/active_support/core_ext/time.rb +++ b/activesupport/lib/active_support/core_ext/time.rb @@ -1,4 +1,5 @@ -require 'active_support/core_ext/time/acts_like' -require 'active_support/core_ext/time/calculations' -require 'active_support/core_ext/time/conversions' -require 'active_support/core_ext/time/zones' +require "active_support/core_ext/time/acts_like" +require "active_support/core_ext/time/calculations" +require "active_support/core_ext/time/compatibility" +require "active_support/core_ext/time/conversions" +require "active_support/core_ext/time/zones" diff --git a/activesupport/lib/active_support/core_ext/time/acts_like.rb b/activesupport/lib/active_support/core_ext/time/acts_like.rb index 3f853b7893..cf4b2539c5 100644 --- a/activesupport/lib/active_support/core_ext/time/acts_like.rb +++ b/activesupport/lib/active_support/core_ext/time/acts_like.rb @@ -1,4 +1,4 @@ -require 'active_support/core_ext/object/acts_like' +require "active_support/core_ext/object/acts_like" class Time # Duck-types as a Time-like class. See Object#acts_like?. diff --git a/activesupport/lib/active_support/core_ext/time/calculations.rb b/activesupport/lib/active_support/core_ext/time/calculations.rb index 768c9a1b2c..2cbfa14772 100644 --- a/activesupport/lib/active_support/core_ext/time/calculations.rb +++ b/activesupport/lib/active_support/core_ext/time/calculations.rb @@ -1,9 +1,9 @@ -require 'active_support/duration' -require 'active_support/core_ext/time/conversions' -require 'active_support/time_with_zone' -require 'active_support/core_ext/time/zones' -require 'active_support/core_ext/date_and_time/calculations' -require 'active_support/core_ext/date/calculations' +require "active_support/duration" +require "active_support/core_ext/time/conversions" +require "active_support/time_with_zone" +require "active_support/core_ext/time/zones" +require "active_support/core_ext/date_and_time/calculations" +require "active_support/core_ext/date/calculations" class Time include DateAndTime::Calculations @@ -61,7 +61,7 @@ class Time # Time.new(2012, 8, 29, 12, 34, 56).seconds_since_midnight # => 45296.0 # Time.new(2012, 8, 29, 23, 59, 59).seconds_since_midnight # => 86399.0 def seconds_since_midnight - to_i - change(:hour => 0).to_i + (usec / 1.0e+6) + to_i - change(hour: 0).to_i + (usec / 1.0e+6) end # Returns the number of seconds until 23:59:59. @@ -73,6 +73,13 @@ class Time end_of_day.to_i - to_i end + # Returns the fraction of a second as a +Rational+ + # + # Time.new(2012, 8, 29, 0, 0, 0.5).sec_fraction # => (1/2) + def sec_fraction + subsec + end + # Returns a new Time where one or more of the elements have been changed according # to the +options+ parameter. The time options (<tt>:hour</tt>, <tt>:min</tt>, # <tt>:sec</tt>, <tt>:usec</tt>, <tt>:nsec</tt>) reset cascadingly, so if only @@ -105,7 +112,7 @@ class Time elsif zone ::Time.local(new_year, new_month, new_day, new_hour, new_min, new_sec, new_usec) else - raise ArgumentError, 'argument out of range' if new_usec >= 1000000 + raise ArgumentError, "argument out of range" if new_usec >= 1000000 ::Time.new(new_year, new_month, new_day, new_hour, new_min, new_sec + (new_usec.to_r / 1000000), utc_offset) end end @@ -134,7 +141,7 @@ class Time d = to_date.advance(options) d = d.gregorian if d.julian? - time_advanced_by_date = change(:year => d.year, :month => d.month, :day => d.day) + time_advanced_by_date = change(year: d.year, month: d.month, day: d.day) seconds_to_advance = \ options.fetch(:seconds, 0) + options.fetch(:minutes, 0) * 60 + @@ -162,7 +169,7 @@ class Time # Returns a new Time representing the start of the day (0:00) def beginning_of_day - change(:hour => 0) + change(hour: 0) end alias :midnight :beginning_of_day alias :at_midnight :beginning_of_day @@ -170,7 +177,7 @@ class Time # Returns a new Time representing the middle of the day (12:00) def middle_of_day - change(:hour => 12) + change(hour: 12) end alias :midday :middle_of_day alias :noon :middle_of_day @@ -181,50 +188,45 @@ class Time # Returns a new Time representing the end of the day, 23:59:59.999999 def end_of_day change( - :hour => 23, - :min => 59, - :sec => 59, - :usec => Rational(999999999, 1000) + hour: 23, + min: 59, + sec: 59, + usec: Rational(999999999, 1000) ) end alias :at_end_of_day :end_of_day # Returns a new Time representing the start of the hour (x:00) def beginning_of_hour - change(:min => 0) + change(min: 0) end alias :at_beginning_of_hour :beginning_of_hour # Returns a new Time representing the end of the hour, x:59:59.999999 def end_of_hour change( - :min => 59, - :sec => 59, - :usec => Rational(999999999, 1000) + min: 59, + sec: 59, + usec: Rational(999999999, 1000) ) end alias :at_end_of_hour :end_of_hour # Returns a new Time representing the start of the minute (x:xx:00) def beginning_of_minute - change(:sec => 0) + change(sec: 0) end alias :at_beginning_of_minute :beginning_of_minute # Returns a new Time representing the end of the minute, x:xx:59.999999 def end_of_minute change( - :sec => 59, - :usec => Rational(999999999, 1000) + sec: 59, + usec: Rational(999999999, 1000) ) end alias :at_end_of_minute :end_of_minute - # Returns a Range representing the whole day of the current time. - def all_day - beginning_of_day..end_of_day - end - def plus_with_duration(other) #:nodoc: if ActiveSupport::Duration === other other.since(self) @@ -279,5 +281,4 @@ class Time end alias_method :eql_without_coercion, :eql? alias_method :eql?, :eql_with_coercion - end diff --git a/activesupport/lib/active_support/core_ext/time/compatibility.rb b/activesupport/lib/active_support/core_ext/time/compatibility.rb new file mode 100644 index 0000000000..ca4b9574d5 --- /dev/null +++ b/activesupport/lib/active_support/core_ext/time/compatibility.rb @@ -0,0 +1,5 @@ +require "active_support/core_ext/date_and_time/compatibility" + +class Time + prepend DateAndTime::Compatibility +end diff --git a/activesupport/lib/active_support/core_ext/time/conversions.rb b/activesupport/lib/active_support/core_ext/time/conversions.rb index 536c4bf525..f2bbe55aa6 100644 --- a/activesupport/lib/active_support/core_ext/time/conversions.rb +++ b/activesupport/lib/active_support/core_ext/time/conversions.rb @@ -1,24 +1,24 @@ -require 'active_support/inflector/methods' -require 'active_support/values/time_zone' +require "active_support/inflector/methods" +require "active_support/values/time_zone" class Time DATE_FORMATS = { - :db => '%Y-%m-%d %H:%M:%S', - :number => '%Y%m%d%H%M%S', - :nsec => '%Y%m%d%H%M%S%9N', - :usec => '%Y%m%d%H%M%S%6N', - :time => '%H:%M', - :short => '%d %b %H:%M', - :long => '%B %d, %Y %H:%M', - :long_ordinal => lambda { |time| + db: "%Y-%m-%d %H:%M:%S", + number: "%Y%m%d%H%M%S", + nsec: "%Y%m%d%H%M%S%9N", + usec: "%Y%m%d%H%M%S%6N", + time: "%H:%M", + short: "%d %b %H:%M", + long: "%B %d, %Y %H:%M", + long_ordinal: lambda { |time| day_format = ActiveSupport::Inflector.ordinalize(time.day) time.strftime("%B #{day_format}, %Y %H:%M") }, - :rfc822 => lambda { |time| + rfc822: lambda { |time| offset_format = time.formatted_offset(false) time.strftime("%a, %d %b %Y %H:%M:%S #{offset_format}") }, - :iso8601 => lambda { |time| time.iso8601 } + iso8601: lambda { |time| time.iso8601 } } # Converts to a formatted string. See DATE_FORMATS for built-in formats. diff --git a/activesupport/lib/active_support/core_ext/time/marshal.rb b/activesupport/lib/active_support/core_ext/time/marshal.rb index 467bad1726..d095d76ebb 100644 --- a/activesupport/lib/active_support/core_ext/time/marshal.rb +++ b/activesupport/lib/active_support/core_ext/time/marshal.rb @@ -1,3 +1,3 @@ -require 'active_support/deprecation' +require "active_support/deprecation" ActiveSupport::Deprecation.warn("This is deprecated and will be removed in Rails 5.1 with no replacement.") diff --git a/activesupport/lib/active_support/core_ext/time/zones.rb b/activesupport/lib/active_support/core_ext/time/zones.rb index 7a60f94996..87b5ad903a 100644 --- a/activesupport/lib/active_support/core_ext/time/zones.rb +++ b/activesupport/lib/active_support/core_ext/time/zones.rb @@ -1,6 +1,6 @@ -require 'active_support/time_with_zone' -require 'active_support/core_ext/time/acts_like' -require 'active_support/core_ext/date_and_time/zones' +require "active_support/time_with_zone" +require "active_support/core_ext/time/acts_like" +require "active_support/core_ext/date_and_time/zones" class Time include DateAndTime::Zones diff --git a/activesupport/lib/active_support/core_ext/uri.rb b/activesupport/lib/active_support/core_ext/uri.rb index c6c183edd9..342a5fcd52 100644 --- a/activesupport/lib/active_support/core_ext/uri.rb +++ b/activesupport/lib/active_support/core_ext/uri.rb @@ -1,4 +1,4 @@ -require 'uri' +require "uri" str = "\xE6\x97\xA5\xE6\x9C\xAC\xE8\xAA\x9E" # Ni-ho-nn-go in UTF-8, means Japanese. parser = URI::Parser.new @@ -10,7 +10,7 @@ unless str == parser.unescape(parser.escape(str)) # YK: My initial experiments say yes, but let's be sure please enc = str.encoding enc = Encoding::UTF_8 if enc == Encoding::US_ASCII - str.gsub(escaped) { |match| [match[1, 2].hex].pack('C') }.force_encoding(enc) + str.gsub(escaped) { |match| [match[1, 2].hex].pack("C") }.force_encoding(enc) end end end diff --git a/activesupport/lib/active_support/dependencies.rb b/activesupport/lib/active_support/dependencies.rb index af18ff746f..216d52164e 100644 --- a/activesupport/lib/active_support/dependencies.rb +++ b/activesupport/lib/active_support/dependencies.rb @@ -1,19 +1,19 @@ -require 'set' -require 'thread' -require 'concurrent/map' -require 'pathname' -require 'active_support/core_ext/module/aliasing' -require 'active_support/core_ext/module/attribute_accessors' -require 'active_support/core_ext/module/introspection' -require 'active_support/core_ext/module/anonymous' -require 'active_support/core_ext/module/qualified_const' -require 'active_support/core_ext/object/blank' -require 'active_support/core_ext/kernel/reporting' -require 'active_support/core_ext/load_error' -require 'active_support/core_ext/name_error' -require 'active_support/core_ext/string/starts_ends_with' +require "set" +require "thread" +require "concurrent/map" +require "pathname" +require "active_support/core_ext/module/aliasing" +require "active_support/core_ext/module/attribute_accessors" +require "active_support/core_ext/module/introspection" +require "active_support/core_ext/module/anonymous" +require "active_support/core_ext/module/qualified_const" +require "active_support/core_ext/object/blank" +require "active_support/core_ext/kernel/reporting" +require "active_support/core_ext/load_error" +require "active_support/core_ext/name_error" +require "active_support/core_ext/string/starts_ends_with" require "active_support/dependencies/interlock" -require 'active_support/inflector' +require "active_support/inflector" module ActiveSupport #:nodoc: module Dependencies #:nodoc: @@ -64,7 +64,7 @@ module ActiveSupport #:nodoc: # Should we load files or require them? mattr_accessor :mechanism - self.mechanism = ENV['NO_RELOAD'] ? :require : :load + self.mechanism = ENV["NO_RELOAD"] ? :require : :load # The set of directories from which we may automatically load files. Files # under these directories will be reloaded on each request in development mode, @@ -88,15 +88,6 @@ 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 - # The WatchStack keeps a stack of the modules being watched as files are # loaded. If a file in the process of being loaded (parent.rb) triggers the # load of another file (child.rb) the stack will ensure that child.rb @@ -143,11 +134,11 @@ module ActiveSupport #:nodoc: next unless mod.is_a?(Module) # Get a list of the constants that were added - new_constants = mod.local_constants - original_constants + new_constants = mod.constants(false) - original_constants - # self[namespace] returns an Array of the constants that are being evaluated + # @stack[namespace] returns an Array of the constants that are being evaluated # for that namespace. For instance, if parent.rb requires child.rb, the first - # element of self[Object] will be an Array of the constants that were present + # element of @stack[Object] will be an Array of the constants that were present # before parent.rb was required. The second element will be an Array of the # constants that were present before child.rb was required. @stack[namespace].each do |namespace_constants| @@ -171,7 +162,7 @@ module ActiveSupport #:nodoc: @watching << namespaces.map do |namespace| module_name = Dependencies.to_constant_name(namespace) original_constants = Dependencies.qualified_const_defined?(module_name) ? - Inflector.constantize(module_name).local_constants : [] + Inflector.constantize(module_name).constants(false) : [] @stack[module_name] << original_constants module_name @@ -179,9 +170,9 @@ module ActiveSupport #:nodoc: end private - def pop_modules(modules) - modules.each { |mod| @stack[mod].pop } - end + def pop_modules(modules) + modules.each { |mod| @stack[mod].pop } + end end # An internal stack used to record which constants are loaded by any block. @@ -262,7 +253,7 @@ module ActiveSupport #:nodoc: end def load_dependency(file) - if Dependencies.load? && ActiveSupport::Dependencies.constant_watch_stack.watching? + if Dependencies.load? && Dependencies.constant_watch_stack.watching? Dependencies.new_constants_in(Object) { yield } else yield @@ -291,17 +282,17 @@ module ActiveSupport #:nodoc: private - def load(file, wrap = false) - result = false - load_dependency(file) { result = super } - result - end + def load(file, wrap = false) + result = false + load_dependency(file) { result = super } + result + end - def require(file) - result = false - load_dependency(file) { result = super } - result - end + def require(file) + result = false + load_dependency(file) { result = super } + result + end end # Exception file-blaming. @@ -352,7 +343,6 @@ module ActiveSupport #:nodoc: end def clear - log_call Dependencies.unload_interlock do loaded.clear loading.clear @@ -361,7 +351,6 @@ module ActiveSupport #:nodoc: end def require_or_load(file_name, const_path = nil) - log_call file_name, const_path file_name = $` if file_name =~ /\.rb\z/ expanded = File.expand_path(file_name) return if loaded.include?(expanded) @@ -377,20 +366,17 @@ module ActiveSupport #:nodoc: begin if load? - log "loading #{file_name}" - # Enable warnings if this file has not been loaded before and # warnings_on_first_load is set. load_args = ["#{file_name}.rb"] load_args << const_path unless const_path.nil? - if !warnings_on_first_load or history.include?(expanded) + if !warnings_on_first_load || history.include?(expanded) result = load_file(*load_args) else enable_warnings { result = load_file(*load_args) } end else - log "requiring #{file_name}" result = require file_name end rescue Exception @@ -483,7 +469,6 @@ module ActiveSupport #:nodoc: # set of names that the file at +path+ may define. See # +loadable_constants_for_path+ for more details. def load_file(path, const_paths = loadable_constants_for_path(path)) - log_call path, const_paths const_paths = [const_paths].compact unless const_paths.is_a? Array parent_paths = const_paths.collect { |const_path| const_path[/.*(?=::)/] || ::Object } @@ -494,7 +479,6 @@ module ActiveSupport #:nodoc: autoloaded_constants.concat newly_defined_paths unless load_once_path?(path) autoloaded_constants.uniq! - log "loading #{path} defined #{newly_defined_paths * ', '}" unless newly_defined_paths.empty? result end @@ -508,8 +492,6 @@ module ActiveSupport #:nodoc: # it is not possible to load the constant into from_mod, try its parent # module using +const_missing+. def load_missing_constant(from_mod, const_name) - log_call from_mod, const_name - unless qualified_const_defined?(from_mod.name) && Inflector.constantize(from_mod.name).equal?(from_mod) raise ArgumentError, "A copy of #{from_mod} has been removed from the module tree but is still active!" end @@ -521,7 +503,7 @@ module ActiveSupport #:nodoc: if file_path expanded = File.expand_path(file_path) - expanded.sub!(/\.rb\z/, ''.freeze) + expanded.sub!(/\.rb\z/, "".freeze) if loading.include?(expanded) raise "Circular dependency detected while autoloading constant #{qualified_name}" @@ -565,7 +547,7 @@ module ActiveSupport #:nodoc: end name_error = NameError.new("uninitialized constant #{qualified_name}", const_name) - name_error.set_backtrace(caller.reject {|l| l.starts_with? __FILE__ }) + name_error.set_backtrace(caller.reject { |l| l.starts_with? __FILE__ }) raise name_error end @@ -609,7 +591,7 @@ module ActiveSupport #:nodoc: def store(klass) return self unless klass.respond_to?(:name) - raise(ArgumentError, 'anonymous classes cannot be cached') if klass.name.empty? + raise(ArgumentError, "anonymous classes cannot be cached") if klass.name.empty? @store[klass.name] = klass self end @@ -673,54 +655,49 @@ module ActiveSupport #:nodoc: # exception, any new constants are regarded as being only partially defined # and will be removed immediately. def new_constants_in(*descs) - log_call(*descs) - constant_watch_stack.watch_namespaces(descs) - aborting = true + success = false begin yield # Now yield to the code that is to define new constants. - aborting = false + success = true ensure new_constants = constant_watch_stack.new_constants - log "New constants: #{new_constants * ', '}" - return new_constants unless aborting + return new_constants if success - log "Error during loading, removing partially loaded constants " - new_constants.each { |c| remove_constant(c) }.clear + # Remove partially loaded constants. + new_constants.each { |c| remove_constant(c) } end - - [] end # Convert the provided const desc to a qualified constant name (as a string). # A module, class, symbol, or string may be provided. def to_constant_name(desc) #:nodoc: case desc - when String then desc.sub(/^::/, '') - when Symbol then desc.to_s - when Module - desc.name || - raise(ArgumentError, "Anonymous modules have no name to be referenced by") + when String then desc.sub(/^::/, "") + when Symbol then desc.to_s + when Module + desc.name || + raise(ArgumentError, "Anonymous modules have no name to be referenced by") else raise TypeError, "Not a valid constant descriptor: #{desc.inspect}" end end def remove_constant(const) #:nodoc: # Normalize ::Foo, ::Object::Foo, Object::Foo, Object::Object::Foo, etc. as Foo. - normalized = const.to_s.sub(/\A::/, '') - normalized.sub!(/\A(Object::)+/, '') + normalized = const.to_s.sub(/\A::/, "") + normalized.sub!(/\A(Object::)+/, "") - constants = normalized.split('::') + constants = normalized.split("::") to_remove = constants.pop # Remove the file path from the loaded list. file_path = search_for_file(const.underscore) if file_path expanded = File.expand_path(file_path) - expanded.sub!(/\.rb\z/, '') - self.loaded.delete(expanded) + expanded.sub!(/\.rb\z/, "") + loaded.delete(expanded) end if constants.empty? @@ -733,13 +710,11 @@ module ActiveSupport #:nodoc: # here than require the caller to be clever. We check the parent # rather than the very const argument because we do not want to # trigger Kernel#autoloads, see the comment below. - parent_name = constants.join('::') + parent_name = constants.join("::") return unless qualified_const_defined?(parent_name) parent = constantize(parent_name) end - log "removing constant #{const}" - # In an autoloaded user.rb like this # # autoload :Foo, 'foo' @@ -760,7 +735,7 @@ module ActiveSupport #:nodoc: begin constantized = parent.const_get(to_remove, false) rescue NameError - log "the constant #{const} is not reachable anymore, skipping" + # The constant is no longer reachable, just skip it. return else constantized.before_remove_const if constantized.respond_to?(:before_remove_const) @@ -770,27 +745,9 @@ module ActiveSupport #:nodoc: begin parent.instance_eval { remove_const to_remove } rescue NameError - log "the constant #{const} is not reachable anymore, skipping" + # The constant is no longer reachable, just skip it. end end - - protected - def log_call(*args) - if log_activity? - arg_str = args.collect(&:inspect) * ', ' - /in `([a-z_\?\!]+)'/ =~ caller(1).first - selector = $1 || '<unknown>' - log "called #{selector}(#{arg_str})" - end - end - - def log(msg) - logger.debug "Dependencies: #{msg}" if log_activity? - end - - def log_activity? - logger && log_activity - end end end diff --git a/activesupport/lib/active_support/dependencies/interlock.rb b/activesupport/lib/active_support/dependencies/interlock.rb index 47bcecbb35..e4e18439c5 100644 --- a/activesupport/lib/active_support/dependencies/interlock.rb +++ b/activesupport/lib/active_support/dependencies/interlock.rb @@ -1,4 +1,4 @@ -require 'active_support/concurrency/share_lock' +require "active_support/concurrency/share_lock" module ActiveSupport #:nodoc: module Dependencies #:nodoc: @@ -19,14 +19,12 @@ module ActiveSupport #:nodoc: end end - # Attempt to obtain an "unloading" (exclusive) lock. If possible, - # execute the supplied block while holding the lock. If there is - # concurrent activity, return immediately (without executing the - # block) instead of waiting. - def attempt_unloading - @lock.exclusive(purpose: :unload, compatible: [:load, :unload], after_compatible: [:load, :unload], no_wait: true) do - yield - end + def start_unloading + @lock.start_exclusive(purpose: :unload, compatible: [:load, :unload]) + end + + def done_unloading + @lock.stop_exclusive(compatible: [:load, :unload]) end def start_running @@ -48,6 +46,10 @@ module ActiveSupport #:nodoc: yield end end + + def raw_state(&block) # :nodoc: + @lock.raw_state(&block) + end end end end diff --git a/activesupport/lib/active_support/deprecation.rb b/activesupport/lib/active_support/deprecation.rb index 24545d766c..191e582de8 100644 --- a/activesupport/lib/active_support/deprecation.rb +++ b/activesupport/lib/active_support/deprecation.rb @@ -1,4 +1,4 @@ -require 'singleton' +require "singleton" module ActiveSupport # \Deprecation specifies the API used by Rails to deprecate methods, instance @@ -12,12 +12,12 @@ module ActiveSupport # a circular require warning for active_support/deprecation.rb. # # So, we define the constant first, and load dependencies later. - require 'active_support/deprecation/instance_delegator' - require 'active_support/deprecation/behaviors' - require 'active_support/deprecation/reporting' - require 'active_support/deprecation/method_wrappers' - require 'active_support/deprecation/proxy_wrappers' - require 'active_support/core_ext/module/deprecation' + require "active_support/deprecation/instance_delegator" + require "active_support/deprecation/behaviors" + require "active_support/deprecation/reporting" + require "active_support/deprecation/method_wrappers" + require "active_support/deprecation/proxy_wrappers" + require "active_support/core_ext/module/deprecation" include Singleton include InstanceDelegator @@ -32,7 +32,7 @@ module ActiveSupport # and the second is a library name # # ActiveSupport::Deprecation.new('2.0', 'MyLibrary') - def initialize(deprecation_horizon = '5.1', gem_name = 'Rails') + def initialize(deprecation_horizon = "5.2", gem_name = "Rails") self.gem_name = gem_name self.deprecation_horizon = deprecation_horizon # By default, warnings are not silenced and debugging is off. diff --git a/activesupport/lib/active_support/deprecation/behaviors.rb b/activesupport/lib/active_support/deprecation/behaviors.rb index dc24e2d0e1..1d1354c23e 100644 --- a/activesupport/lib/active_support/deprecation/behaviors.rb +++ b/activesupport/lib/active_support/deprecation/behaviors.rb @@ -2,7 +2,7 @@ require "active_support/notifications" module ActiveSupport # Raised when <tt>ActiveSupport::Deprecation::Behavior#behavior</tt> is set with <tt>:raise</tt>. - # You would set <tt>:raise</tt>, as a behaviour to raise errors and proactively report exceptions from deprecations. + # You would set <tt>:raise</tt>, as a behavior to raise errors and proactively report exceptions from deprecations. class DeprecationException < StandardError end @@ -25,7 +25,7 @@ module ActiveSupport if defined?(Rails.logger) && Rails.logger Rails.logger else - require 'active_support/logger' + require "active_support/logger" ActiveSupport::Logger.new($stderr) end logger.warn message @@ -34,7 +34,7 @@ module ActiveSupport notify: ->(message, callstack) { ActiveSupport::Notifications.instrument("deprecation.rails", - :message => message, :callstack => callstack) + message: message, callstack: callstack) }, silence: ->(message, callstack) {}, diff --git a/activesupport/lib/active_support/deprecation/instance_delegator.rb b/activesupport/lib/active_support/deprecation/instance_delegator.rb index 8472a58add..6d390f3b37 100644 --- a/activesupport/lib/active_support/deprecation/instance_delegator.rb +++ b/activesupport/lib/active_support/deprecation/instance_delegator.rb @@ -1,11 +1,12 @@ -require 'active_support/core_ext/kernel/singleton_class' -require 'active_support/core_ext/module/delegation' +require "active_support/core_ext/kernel/singleton_class" +require "active_support/core_ext/module/delegation" module ActiveSupport class Deprecation module InstanceDelegator # :nodoc: def self.included(base) base.extend(ClassMethods) + base.singleton_class.prepend(OverrideDelegators) base.public_class_method :new end @@ -19,6 +20,18 @@ module ActiveSupport singleton_class.delegate(method_name, to: :instance) end end + + module OverrideDelegators # :nodoc: + def warn(message = nil, callstack = nil) + callstack ||= caller_locations(2) + super + end + + def deprecation_warning(deprecated_method_name, message = nil, caller_backtrace = nil) + caller_backtrace ||= caller_locations(2) + super + end + end end end end diff --git a/activesupport/lib/active_support/deprecation/method_wrappers.rb b/activesupport/lib/active_support/deprecation/method_wrappers.rb index f5ea6669ce..7655fa4f99 100644 --- a/activesupport/lib/active_support/deprecation/method_wrappers.rb +++ b/activesupport/lib/active_support/deprecation/method_wrappers.rb @@ -1,5 +1,5 @@ -require 'active_support/core_ext/module/aliasing' -require 'active_support/core_ext/array/extract_options' +require "active_support/core_ext/module/aliasing" +require "active_support/core_ext/array/extract_options" module ActiveSupport class Deprecation diff --git a/activesupport/lib/active_support/deprecation/proxy_wrappers.rb b/activesupport/lib/active_support/deprecation/proxy_wrappers.rb index 0cb2d4d22e..1c6618b19a 100644 --- a/activesupport/lib/active_support/deprecation/proxy_wrappers.rb +++ b/activesupport/lib/active_support/deprecation/proxy_wrappers.rb @@ -1,4 +1,5 @@ -require 'active_support/inflector/methods' +require "active_support/inflector/methods" +require "active_support/core_ext/regexp" module ActiveSupport class Deprecation @@ -10,7 +11,7 @@ module ActiveSupport super end - instance_methods.each { |m| undef_method m unless m =~ /^__|^object_id$/ } + instance_methods.each { |m| undef_method m unless /^__|^object_id$/.match?(m) } # Don't give a deprecation warning on inspect since test/unit and error # logs rely on it for diagnostics. diff --git a/activesupport/lib/active_support/deprecation/reporting.rb b/activesupport/lib/active_support/deprecation/reporting.rb index f89fc0fe14..b8d200ba94 100644 --- a/activesupport/lib/active_support/deprecation/reporting.rb +++ b/activesupport/lib/active_support/deprecation/reporting.rb @@ -1,3 +1,5 @@ +require "rbconfig" + module ActiveSupport class Deprecation module Reporting @@ -55,15 +57,14 @@ module ActiveSupport def deprecated_method_warning(method_name, message = nil) warning = "#{method_name} is deprecated and will be removed from #{gem_name} #{deprecation_horizon}" case message - when Symbol then "#{warning} (use #{message} instead)" - when String then "#{warning} (#{message})" + when Symbol then "#{warning} (use #{message} instead)" + when String then "#{warning} (#{message})" else warning end end def deprecation_message(callstack, message = nil) message ||= "You are using deprecated behavior which will be removed from the next major or minor release." - message += '.' unless message =~ /\.$/ "DEPRECATION WARNING: #{message} #{deprecation_caller_message(callstack)}" end @@ -81,17 +82,17 @@ module ActiveSupport def extract_callstack(callstack) return _extract_callstack(callstack) if callstack.first.is_a? String - rails_gem_root = File.expand_path("../../../../..", __FILE__) + "/" offending_line = callstack.find { |frame| - frame.absolute_path && !frame.absolute_path.start_with?(rails_gem_root) + frame.absolute_path && !ignored_callstack(frame.absolute_path) } || callstack.first + [offending_line.path, offending_line.lineno, offending_line.label] end def _extract_callstack(callstack) warn "Please pass `caller_locations` to the deprecation API" if $VERBOSE - rails_gem_root = File.expand_path("../../../../..", __FILE__) + "/" - offending_line = callstack.find { |line| !line.start_with?(rails_gem_root) } || callstack.first + offending_line = callstack.find { |line| !ignored_callstack(line) } || callstack.first + if offending_line if md = offending_line.match(/^(.+?):(\d+)(?::in `(.*?)')?/) md.captures @@ -100,6 +101,12 @@ module ActiveSupport end end end + + RAILS_GEM_ROOT = File.expand_path("../../../../..", __FILE__) + "/" + + def ignored_callstack(path) + path.start_with?(RAILS_GEM_ROOT) || path.start_with?(RbConfig::CONFIG["rubylibdir"]) + end end end end diff --git a/activesupport/lib/active_support/duration.rb b/activesupport/lib/active_support/duration.rb index c63b61e97a..6ec0c3a70a 100644 --- a/activesupport/lib/active_support/duration.rb +++ b/activesupport/lib/active_support/duration.rb @@ -1,5 +1,5 @@ -require 'active_support/core_ext/array/conversions' -require 'active_support/core_ext/object/acts_like' +require "active_support/core_ext/array/conversions" +require "active_support/core_ext/object/acts_like" module ActiveSupport # Provides accurate date and time measurements using Date#advance and @@ -9,6 +9,9 @@ module ActiveSupport class Duration attr_accessor :value, :parts + autoload :ISO8601Parser, "active_support/duration/iso8601_parser" + autoload :ISO8601Serializer, "active_support/duration/iso8601_serializer" + def initialize(value, parts) #:nodoc: @value, @parts = value, parts end @@ -117,8 +120,8 @@ module ActiveSupport def inspect #:nodoc: parts. reduce(::Hash.new(0)) { |h,(l,r)| h[l] += r; h }. - sort_by {|unit, _ | [:years, :months, :days, :minutes, :seconds].index(unit)}. - map {|unit, val| "#{val} #{val == 1 ? unit.to_s.chop : unit.to_s}"}. + sort_by { |unit, _ | [:years, :months, :weeks, :days, :hours, :minutes, :seconds].index(unit) }. + map { |unit, val| "#{val} #{val == 1 ? unit.to_s.chop : unit.to_s}" }. to_sentence(locale: ::I18n.default_locale) end @@ -130,6 +133,23 @@ module ActiveSupport @value.respond_to?(method, include_private) end + # Creates a new Duration from string formatted according to ISO 8601 Duration. + # + # See {ISO 8601}[http://en.wikipedia.org/wiki/ISO_8601#Durations] for more information. + # This method allows negative parts to be present in pattern. + # If invalid string is provided, it will raise +ActiveSupport::Duration::ISO8601Parser::ParsingError+. + def self.parse(iso8601duration) + parts = ISO8601Parser.new(iso8601duration).parse! + time = ::Time.current + new(time.advance(parts) - time, parts) + end + + # Build ISO 8601 Duration string for this duration. + # The +precision+ parameter can be used to limit seconds' precision of duration. + def iso8601(precision: nil) + ISO8601Serializer.new(self, precision: precision).serialize + end + delegate :<=>, to: :value protected @@ -139,6 +159,10 @@ module ActiveSupport if t.acts_like?(:time) || t.acts_like?(:date) if type == :seconds t.since(sign * number) + elsif type == :minutes + t.since(sign * number * 60) + elsif type == :hours + t.since(sign * number * 3600) else t.advance(type => sign * number) end diff --git a/activesupport/lib/active_support/duration/iso8601_parser.rb b/activesupport/lib/active_support/duration/iso8601_parser.rb new file mode 100644 index 0000000000..e96cb8e883 --- /dev/null +++ b/activesupport/lib/active_support/duration/iso8601_parser.rb @@ -0,0 +1,123 @@ +require "strscan" +require "active_support/core_ext/regexp" + +module ActiveSupport + class Duration + # Parses a string formatted according to ISO 8601 Duration into the hash. + # + # See {ISO 8601}[http://en.wikipedia.org/wiki/ISO_8601#Durations] for more information. + # + # This parser allows negative parts to be present in pattern. + class ISO8601Parser # :nodoc: + class ParsingError < ::ArgumentError; end + + PERIOD_OR_COMMA = /\.|,/ + PERIOD = ".".freeze + COMMA = ",".freeze + + SIGN_MARKER = /\A\-|\+|/ + DATE_MARKER = /P/ + TIME_MARKER = /T/ + DATE_COMPONENT = /(\-?\d+(?:[.,]\d+)?)(Y|M|D|W)/ + TIME_COMPONENT = /(\-?\d+(?:[.,]\d+)?)(H|M|S)/ + + DATE_TO_PART = { "Y" => :years, "M" => :months, "W" => :weeks, "D" => :days } + TIME_TO_PART = { "H" => :hours, "M" => :minutes, "S" => :seconds } + + DATE_COMPONENTS = [:years, :months, :days] + TIME_COMPONENTS = [:hours, :minutes, :seconds] + + attr_reader :parts, :scanner + attr_accessor :mode, :sign + + def initialize(string) + @scanner = StringScanner.new(string) + @parts = {} + @mode = :start + @sign = 1 + end + + def parse! + while !finished? + case mode + when :start + if scan(SIGN_MARKER) + self.sign = (scanner.matched == "-") ? -1 : 1 + self.mode = :sign + else + raise_parsing_error + end + + when :sign + if scan(DATE_MARKER) + self.mode = :date + else + raise_parsing_error + end + + when :date + if scan(TIME_MARKER) + self.mode = :time + elsif scan(DATE_COMPONENT) + parts[DATE_TO_PART[scanner[2]]] = number * sign + else + raise_parsing_error + end + + when :time + if scan(TIME_COMPONENT) + parts[TIME_TO_PART[scanner[2]]] = number * sign + else + raise_parsing_error + end + + end + end + + validate! + parts + end + + private + + def finished? + scanner.eos? + end + + # Parses number which can be a float with either comma or period. + def number + PERIOD_OR_COMMA.match?(scanner[1]) ? scanner[1].tr(COMMA, PERIOD).to_f : scanner[1].to_i + end + + def scan(pattern) + scanner.scan(pattern) + end + + def raise_parsing_error(reason = nil) + raise ParsingError, "Invalid ISO 8601 duration: #{scanner.string.inspect} #{reason}".strip + end + + # Checks for various semantic errors as stated in ISO 8601 standard. + def validate! + raise_parsing_error("is empty duration") if parts.empty? + + # Mixing any of Y, M, D with W is invalid. + if parts.key?(:weeks) && (parts.keys & DATE_COMPONENTS).any? + raise_parsing_error("mixing weeks with other date parts not allowed") + end + + # Specifying an empty T part is invalid. + if mode == :time && (parts.keys & TIME_COMPONENTS).empty? + raise_parsing_error("time part marker is present but time part is empty") + end + + fractions = parts.values.reject(&:zero?).select { |a| (a % 1) != 0 } + unless fractions.empty? || (fractions.size == 1 && fractions.last == @parts.values.reject(&:zero?).last) + raise_parsing_error "(only last part can be fractional)" + end + + return true + end + end + end +end diff --git a/activesupport/lib/active_support/duration/iso8601_serializer.rb b/activesupport/lib/active_support/duration/iso8601_serializer.rb new file mode 100644 index 0000000000..542630b950 --- /dev/null +++ b/activesupport/lib/active_support/duration/iso8601_serializer.rb @@ -0,0 +1,53 @@ +require "active_support/core_ext/object/blank" +require "active_support/core_ext/hash/transform_values" + +module ActiveSupport + class Duration + # Serializes duration to string according to ISO 8601 Duration format. + class ISO8601Serializer + def initialize(duration, precision: nil) + @duration = duration + @precision = precision + end + + # Builds and returns output string. + def serialize + parts, sign = normalize + return "PT0S".freeze if parts.empty? + + output = "P" + output << "#{parts[:years]}Y" if parts.key?(:years) + output << "#{parts[:months]}M" if parts.key?(:months) + output << "#{parts[:weeks]}W" if parts.key?(:weeks) + output << "#{parts[:days]}D" if parts.key?(:days) + time = "" + time << "#{parts[:hours]}H" if parts.key?(:hours) + time << "#{parts[:minutes]}M" if parts.key?(:minutes) + if parts.key?(:seconds) + time << "#{sprintf(@precision ? "%0.0#{@precision}f" : '%g', parts[:seconds])}S" + end + output << "T#{time}" if time.present? + "#{sign}#{output}" + end + + private + + # Return pair of duration's parts and whole duration sign. + # Parts are summarized (as they can become repetitive due to addition, etc). + # Zero parts are removed as not significant. + # If all parts are negative it will negate all of them and return minus as a sign. + def normalize + parts = @duration.parts.each_with_object(Hash.new(0)) do |(k,v),p| + p[k] += v unless v.zero? + end + # If all parts are negative - let's make a negative duration + sign = "" + if parts.values.all? { |v| v < 0 } + sign = "-" + parts.transform_values!(&:-@) + end + [parts, sign] + end + end + end +end diff --git a/activesupport/lib/active_support/evented_file_update_checker.rb b/activesupport/lib/active_support/evented_file_update_checker.rb index 315be85fb3..f54f88eb0a 100644 --- a/activesupport/lib/active_support/evented_file_update_checker.rb +++ b/activesupport/lib/active_support/evented_file_update_checker.rb @@ -1,8 +1,35 @@ -require 'set' -require 'pathname' -require 'concurrent/atomic/atomic_boolean' +require "set" +require "pathname" +require "concurrent/atomic/atomic_boolean" module ActiveSupport + # Allows you to "listen" to changes in a file system. + # The evented file updater does not hit disk when checking for updates + # instead it uses platform specific file system events to trigger a change + # in state. + # + # The file checker takes an array of files to watch or a hash specifying directories + # and file extensions to watch. It also takes a block that is called when + # EventedFileUpdateChecker#execute is run or when EventedFileUpdateChecker#execute_if_updated + # is run and there have been changes to the file system. + # + # Note: Forking will cause the first call to `updated?` to return `true`. + # + # Example: + # + # checker = EventedFileUpdateChecker.new(["/tmp/foo"], -> { puts "changed" }) + # checker.updated? + # # => false + # checker.execute_if_updated + # # => nil + # + # FileUtils.touch("/tmp/foo") + # + # checker.updated? + # # => true + # checker.execute_if_updated + # # => "changed" + # class EventedFileUpdateChecker #:nodoc: all def initialize(files, dirs = {}, &block) @ph = PathHelper.new @@ -13,20 +40,35 @@ module ActiveSupport @dirs[@ph.xpath(dir)] = Array(exts).map { |ext| @ph.normalize_extension(ext) } end - @block = block - @updated = Concurrent::AtomicBoolean.new(false) - @lcsp = @ph.longest_common_subpath(@dirs.keys) + @block = block + @updated = Concurrent::AtomicBoolean.new(false) + @lcsp = @ph.longest_common_subpath(@dirs.keys) + @pid = Process.pid + @boot_mutex = Mutex.new - if (dtw = directories_to_watch).any? + if (@dtw = directories_to_watch).any? # Loading listen triggers warnings. These are originated by a legit # usage of attr_* macros for private attributes, but adds a lot of noise # to our test suite. Thus, we lazy load it and disable warnings locally. - silence_warnings { require 'listen' } - Listen.to(*dtw, &method(:changed)).start + silence_warnings do + begin + require "listen" + rescue LoadError => e + raise LoadError, "Could not load the 'listen' gem. Add `gem 'listen'` to the development group of your Gemfile", e.backtrace + end + end end + boot! end def updated? + @boot_mutex.synchronize do + if @pid != Process.pid + boot! + @pid = Process.pid + @updated.make_true + end + end @updated.true? end @@ -37,12 +79,16 @@ module ActiveSupport def execute_if_updated if updated? + yield if block_given? execute true end end private + def boot! + Listen.to(*@dtw, &method(:changed)).start + end def changed(modified, added, removed) unless updated? @@ -78,73 +124,71 @@ module ActiveSupport @ph.filter_out_descendants(dtw) end - class PathHelper - using Module.new { - refine Pathname do - def ascendant_of?(other) - self != other && other.ascend do |ascendant| - break true if self == ascendant - end - end + class PathHelper + def xpath(path) + Pathname.new(path).expand_path end - } - - def xpath(path) - Pathname.new(path).expand_path - end - def normalize_extension(ext) - ext.to_s.sub(/\A\./, '') - end + def normalize_extension(ext) + ext.to_s.sub(/\A\./, "") + end - # Given a collection of Pathname objects returns the longest subpath - # common to all of them, or +nil+ if there is none. - def longest_common_subpath(paths) - return if paths.empty? - - lcsp = Pathname.new(paths[0]) - - paths[1..-1].each do |path| - until lcsp.ascendant_of?(path) - if lcsp.root? - # If we get here a root directory is not an ascendant of path. - # This may happen if there are paths in different drives on - # Windows. - return - else - lcsp = lcsp.parent + # Given a collection of Pathname objects returns the longest subpath + # common to all of them, or +nil+ if there is none. + def longest_common_subpath(paths) + return if paths.empty? + + lcsp = Pathname.new(paths[0]) + + paths[1..-1].each do |path| + until ascendant_of?(lcsp, path) + if lcsp.root? + # If we get here a root directory is not an ascendant of path. + # This may happen if there are paths in different drives on + # Windows. + return + else + lcsp = lcsp.parent + end end end - end - lcsp - end + lcsp + end - # Returns the deepest existing ascendant, which could be the argument itself. - def existing_parent(dir) - dir.ascend do |ascendant| - break ascendant if ascendant.directory? + # Returns the deepest existing ascendant, which could be the argument itself. + def existing_parent(dir) + dir.ascend do |ascendant| + break ascendant if ascendant.directory? + end end - end - # Filters out directories which are descendants of others in the collection (stable). - def filter_out_descendants(dirs) - return dirs if dirs.length < 2 + # Filters out directories which are descendants of others in the collection (stable). + def filter_out_descendants(dirs) + return dirs if dirs.length < 2 - dirs_sorted_by_nparts = dirs.sort_by { |dir| dir.each_filename.to_a.length } - descendants = [] + dirs_sorted_by_nparts = dirs.sort_by { |dir| dir.each_filename.to_a.length } + descendants = [] - until dirs_sorted_by_nparts.empty? - dir = dirs_sorted_by_nparts.shift + until dirs_sorted_by_nparts.empty? + dir = dirs_sorted_by_nparts.shift - dirs_sorted_by_nparts.reject! do |possible_descendant| - dir.ascendant_of?(possible_descendant) && descendants << possible_descendant + dirs_sorted_by_nparts.reject! do |possible_descendant| + ascendant_of?(dir, possible_descendant) && descendants << possible_descendant + end end + + # Array#- preserves order. + dirs - descendants end - # Array#- preserves order. - dirs - descendants + private + + def ascendant_of?(base, other) + base != other && other.ascend do |ascendant| + break true if base == ascendant + end + end end - end end end diff --git a/activesupport/lib/active_support/execution_wrapper.rb b/activesupport/lib/active_support/execution_wrapper.rb new file mode 100644 index 0000000000..3384d12d5b --- /dev/null +++ b/activesupport/lib/active_support/execution_wrapper.rb @@ -0,0 +1,126 @@ +require "active_support/callbacks" + +module ActiveSupport + class ExecutionWrapper + include ActiveSupport::Callbacks + + Null = Object.new # :nodoc: + def Null.complete! # :nodoc: + end + + define_callbacks :run + define_callbacks :complete + + def self.to_run(*args, &block) + set_callback(:run, *args, &block) + end + + def self.to_complete(*args, &block) + set_callback(:complete, *args, &block) + end + + class RunHook < Struct.new(:hook) # :nodoc: + def before(target) + hook_state = target.send(:hook_state) + hook_state[hook] = hook.run + end + end + + class CompleteHook < Struct.new(:hook) # :nodoc: + def before(target) + hook_state = target.send(:hook_state) + if hook_state.key?(hook) + hook.complete hook_state[hook] + end + end + alias after before + end + + # Register an object to be invoked during both the +run+ and + # +complete+ steps. + # + # +hook.complete+ will be passed the value returned from +hook.run+, + # and will only be invoked if +run+ has previously been called. + # (Mostly, this means it won't be invoked if an exception occurs in + # a preceding +to_run+ block; all ordinary +to_complete+ blocks are + # invoked in that situation.) + def self.register_hook(hook, outer: false) + if outer + to_run RunHook.new(hook), prepend: true + to_complete :after, CompleteHook.new(hook) + else + to_run RunHook.new(hook) + to_complete CompleteHook.new(hook) + end + end + + # Run this execution. + # + # Returns an instance, whose +complete!+ method *must* be invoked + # after the work has been performed. + # + # Where possible, prefer +wrap+. + def self.run! + if active? + Null + else + new.tap do |instance| + success = nil + begin + instance.run! + success = true + ensure + instance.complete! unless success + end + end + end + end + + # Perform the work in the supplied block as an execution. + def self.wrap + return yield if active? + + instance = run! + begin + yield + ensure + instance.complete! + end + end + + class << self # :nodoc: + attr_accessor :active + end + + def self.inherited(other) # :nodoc: + super + other.active = Concurrent::Hash.new + end + + self.active = Concurrent::Hash.new + + def self.active? # :nodoc: + @active[Thread.current] + end + + def run! # :nodoc: + self.class.active[Thread.current] = true + run_callbacks(:run) + end + + # Complete this in-flight execution. This method *must* be called + # exactly once on the result of any call to +run!+. + # + # Where possible, prefer +wrap+. + def complete! + run_callbacks(:complete) + ensure + self.class.active.delete Thread.current + end + + private + def hook_state + @_hook_state ||= {} + end + end +end diff --git a/activesupport/lib/active_support/executor.rb b/activesupport/lib/active_support/executor.rb new file mode 100644 index 0000000000..a6400cae0a --- /dev/null +++ b/activesupport/lib/active_support/executor.rb @@ -0,0 +1,6 @@ +require "active_support/execution_wrapper" + +module ActiveSupport + class Executor < ExecutionWrapper + end +end diff --git a/activesupport/lib/active_support/file_update_checker.rb b/activesupport/lib/active_support/file_update_checker.rb index 1fa9335080..98aceabe21 100644 --- a/activesupport/lib/active_support/file_update_checker.rb +++ b/activesupport/lib/active_support/file_update_checker.rb @@ -1,3 +1,5 @@ +require "active_support/core_ext/time/calculations" + module ActiveSupport # FileUpdateChecker specifies the API used by Rails to watch files # and control reloading. The API depends on four methods: @@ -23,7 +25,7 @@ module ActiveSupport # I18n.reload! # end # - # ActionDispatch::Reloader.to_prepare do + # ActiveSupport::Reloader.to_prepare do # i18n_reloader.execute_if_updated # end class FileUpdateChecker @@ -81,6 +83,7 @@ module ActiveSupport # Execute the block given if updated. def execute_if_updated if updated? + yield if block_given? execute true else @@ -90,48 +93,65 @@ module ActiveSupport private - def watched - @watched || begin - all = @files.select { |f| File.exist?(f) } - all.concat(Dir[@glob]) if @glob - all + def watched + @watched || begin + all = @files.select { |f| File.exist?(f) } + all.concat(Dir[@glob]) if @glob + all + end end - end - def updated_at(paths) - @updated_at || max_mtime(paths) || Time.at(0) - end + def updated_at(paths) + @updated_at || max_mtime(paths) || Time.at(0) + end - # This method returns the maximum mtime of the files in +paths+, or +nil+ - # if the array is empty. - # - # Files with a mtime in the future are ignored. Such abnormal situation - # can happen for example if the user changes the clock by hand. It is - # healthy to consider this edge case because with mtimes in the future - # reloading is not triggered. - def max_mtime(paths) - time_now = Time.now - paths.map {|path| File.mtime(path)}.reject {|mtime| time_now < mtime}.max - end + # This method returns the maximum mtime of the files in +paths+, or +nil+ + # if the array is empty. + # + # Files with a mtime in the future are ignored. Such abnormal situation + # can happen for example if the user changes the clock by hand. It is + # healthy to consider this edge case because with mtimes in the future + # reloading is not triggered. + def max_mtime(paths) + time_now = Time.now + max_mtime = nil + + # Time comparisons are performed with #compare_without_coercion because + # AS redefines these operators in a way that is much slower and does not + # bring any benefit in this particular code. + # + # Read t1.compare_without_coercion(t2) < 0 as t1 < t2. + paths.each do |path| + mtime = File.mtime(path) - def compile_glob(hash) - hash.freeze # Freeze so changes aren't accidentally pushed - return if hash.empty? + next if time_now.compare_without_coercion(mtime) < 0 + + if max_mtime.nil? || max_mtime.compare_without_coercion(mtime) < 0 + max_mtime = mtime + end + end - globs = hash.map do |key, value| - "#{escape(key)}/**/*#{compile_ext(value)}" + max_mtime end - "{#{globs.join(",")}}" - end - def escape(key) - key.gsub(',','\,') - end + def compile_glob(hash) + hash.freeze # Freeze so changes aren't accidentally pushed + return if hash.empty? - def compile_ext(array) - array = Array(array) - return if array.empty? - ".{#{array.join(",")}}" - end + globs = hash.map do |key, value| + "#{escape(key)}/**/*#{compile_ext(value)}" + end + "{#{globs.join(",")}}" + end + + def escape(key) + key.gsub(",",'\,') + end + + def compile_ext(array) + array = Array(array) + return if array.empty? + ".{#{array.join(",")}}" + end end end diff --git a/activesupport/lib/active_support/gem_version.rb b/activesupport/lib/active_support/gem_version.rb index fc08273b6d..74f2d8dd4b 100644 --- a/activesupport/lib/active_support/gem_version.rb +++ b/activesupport/lib/active_support/gem_version.rb @@ -6,9 +6,9 @@ module ActiveSupport module VERSION MAJOR = 5 - MINOR = 0 + MINOR = 1 TINY = 0 - PRE = "beta2" + PRE = "alpha" STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".") end diff --git a/activesupport/lib/active_support/gzip.rb b/activesupport/lib/active_support/gzip.rb index b837c879bb..4aee8dddba 100644 --- a/activesupport/lib/active_support/gzip.rb +++ b/activesupport/lib/active_support/gzip.rb @@ -1,5 +1,5 @@ -require 'zlib' -require 'stringio' +require "zlib" +require "stringio" module ActiveSupport # A convenient wrapper for the zlib standard library that allows @@ -9,7 +9,7 @@ module ActiveSupport # # => "\x1F\x8B\b\x00o\x8D\xCDO\x00\x03K\xCE\xCF-(J-.V\xC8MU\x04\x00R>n\x83\f\x00\x00\x00" # # ActiveSupport::Gzip.decompress(gzip) - # # => "compress me!" + # # => "compress me!" module Gzip class Stream < StringIO def initialize(*) diff --git a/activesupport/lib/active_support/hash_with_indifferent_access.rb b/activesupport/lib/active_support/hash_with_indifferent_access.rb index 03770a197c..d3bb5496bf 100644 --- a/activesupport/lib/active_support/hash_with_indifferent_access.rb +++ b/activesupport/lib/active_support/hash_with_indifferent_access.rb @@ -1,5 +1,5 @@ -require 'active_support/core_ext/hash/keys' -require 'active_support/core_ext/hash/reverse_merge' +require "active_support/core_ext/hash/keys" +require "active_support/core_ext/hash/reverse_merge" module ActiveSupport # Implements a hash where keys <tt>:foo</tt> and <tt>"foo"</tt> are considered @@ -40,6 +40,12 @@ module ActiveSupport # rgb = { black: '#000000', white: '#FFFFFF' }.with_indifferent_access # # which may be handy. + # + # To access this class outside of Rails, require the core extension with: + # + # require "active_support/core_ext/hash/indifferent_access" + # + # which will, in turn, require this file. class HashWithIndifferentAccess < Hash # Returns +true+ so that <tt>Array#extract_options!</tt> finds members of # this class. @@ -161,7 +167,6 @@ module ActiveSupport alias_method :has_key?, :key? alias_method :member?, :key? - # Same as <tt>Hash#[]</tt> where the key passed as argument can be # either a string or a symbol: # @@ -217,7 +222,7 @@ module ActiveSupport # modify the receiver but rather returns a new hash with indifferent # access with the result of the merge. def merge(hash, &block) - self.dup.update(hash, &block) + dup.update(hash, &block) end # Like +merge+ but the other way around: Merges the receiver into the @@ -268,6 +273,11 @@ module ActiveSupport dup.tap { |hash| hash.reject!(*args, &block) } end + def transform_values(*args, &block) + return to_enum(:transform_values) unless block_given? + dup.tap { |hash| hash.transform_values!(*args, &block) } + end + # Convert to a regular hash with string keys. def to_hash _new_hash = Hash.new diff --git a/activesupport/lib/active_support/i18n.rb b/activesupport/lib/active_support/i18n.rb index 6cc98191d4..f0408f429c 100644 --- a/activesupport/lib/active_support/i18n.rb +++ b/activesupport/lib/active_support/i18n.rb @@ -1,13 +1,13 @@ -require 'active_support/core_ext/hash/deep_merge' -require 'active_support/core_ext/hash/except' -require 'active_support/core_ext/hash/slice' +require "active_support/core_ext/hash/deep_merge" +require "active_support/core_ext/hash/except" +require "active_support/core_ext/hash/slice" begin - require 'i18n' + require "i18n" rescue LoadError => e $stderr.puts "The i18n gem is not available. Please add it to your Gemfile and run bundle install" raise e end -require 'active_support/lazy_load_hooks' +require "active_support/lazy_load_hooks" ActiveSupport.run_load_hooks(:i18n) I18n.load_path << "#{File.dirname(__FILE__)}/locale/en.yml" diff --git a/activesupport/lib/active_support/i18n_railtie.rb b/activesupport/lib/active_support/i18n_railtie.rb index 82aacf3b24..08c9ef8f02 100644 --- a/activesupport/lib/active_support/i18n_railtie.rb +++ b/activesupport/lib/active_support/i18n_railtie.rb @@ -64,8 +64,8 @@ module I18n end app.reloaders << reloader - ActionDispatch::Reloader.to_prepare do - reloader.execute_if_updated + app.reloader.to_run do + reloader.execute_if_updated { require_unload_lock! } # TODO: remove the following line as soon as the return value of # callbacks is ignored, that is, returning `false` does not # display a deprecation warning or halts the callback chain. @@ -83,14 +83,15 @@ module I18n def self.init_fallbacks(fallbacks) include_fallbacks_module - args = case fallbacks - when ActiveSupport::OrderedOptions - [*(fallbacks[:defaults] || []) << fallbacks[:map]].compact - when Hash, Array - Array.wrap(fallbacks) - else # TrueClass - [] - end + args = \ + case fallbacks + when ActiveSupport::OrderedOptions + [*(fallbacks[:defaults] || []) << fallbacks[:map]].compact + when Hash, Array + Array.wrap(fallbacks) + else # TrueClass + [] + end I18n.fallbacks = I18n::Locale::Fallbacks.new(*args) end diff --git a/activesupport/lib/active_support/inflections.rb b/activesupport/lib/active_support/inflections.rb index 2ca1124e76..afa7d1f325 100644 --- a/activesupport/lib/active_support/inflections.rb +++ b/activesupport/lib/active_support/inflections.rb @@ -1,4 +1,4 @@ -require 'active_support/inflector/inflections' +require "active_support/inflector/inflections" #-- # Defines the standard inflection rules. These are the starting point for @@ -8,8 +8,8 @@ require 'active_support/inflector/inflections' #++ module ActiveSupport Inflector.inflections(:en) do |inflect| - inflect.plural(/$/, 's') - inflect.plural(/s$/i, 's') + inflect.plural(/$/, "s") + inflect.plural(/s$/i, "s") inflect.plural(/^(ax|test)is$/i, '\1es') inflect.plural(/(octop|vir)us$/i, '\1i') inflect.plural(/(octop|vir)i$/i, '\1i') @@ -18,7 +18,7 @@ module ActiveSupport inflect.plural(/(buffal|tomat)o$/i, '\1oes') inflect.plural(/([ti])um$/i, '\1a') inflect.plural(/([ti])a$/i, '\1a') - inflect.plural(/sis$/i, 'ses') + inflect.plural(/sis$/i, "ses") inflect.plural(/(?:([^f])fe|([lr])f)$/i, '\1\2ves') inflect.plural(/(hive)$/i, '\1s') inflect.plural(/([^aeiouy]|qu)y$/i, '\1ies') @@ -30,7 +30,7 @@ module ActiveSupport inflect.plural(/^(oxen)$/i, '\1') inflect.plural(/(quiz)$/i, '\1zes') - inflect.singular(/s$/i, '') + inflect.singular(/s$/i, "") inflect.singular(/(ss)$/i, '\1') inflect.singular(/(n)ews$/i, '\1ews') inflect.singular(/([ti])a$/i, '\1um') @@ -58,12 +58,12 @@ module ActiveSupport inflect.singular(/(quiz)zes$/i, '\1') inflect.singular(/(database)s$/i, '\1') - inflect.irregular('person', 'people') - inflect.irregular('man', 'men') - inflect.irregular('child', 'children') - inflect.irregular('sex', 'sexes') - inflect.irregular('move', 'moves') - inflect.irregular('zombie', 'zombies') + inflect.irregular("person", "people") + inflect.irregular("man", "men") + inflect.irregular("child", "children") + inflect.irregular("sex", "sexes") + inflect.irregular("move", "moves") + inflect.irregular("zombie", "zombies") inflect.uncountable(%w(equipment information rice money species series fish sheep jeans police)) end diff --git a/activesupport/lib/active_support/inflector.rb b/activesupport/lib/active_support/inflector.rb index 215a60eba7..48631b16a8 100644 --- a/activesupport/lib/active_support/inflector.rb +++ b/activesupport/lib/active_support/inflector.rb @@ -1,7 +1,7 @@ # in case active_support/inflector is required without the rest of active_support -require 'active_support/inflector/inflections' -require 'active_support/inflector/transliterate' -require 'active_support/inflector/methods' +require "active_support/inflector/inflections" +require "active_support/inflector/transliterate" +require "active_support/inflector/methods" -require 'active_support/inflections' -require 'active_support/core_ext/string/inflections' +require "active_support/inflections" +require "active_support/core_ext/string/inflections" diff --git a/activesupport/lib/active_support/inflector/inflections.rb b/activesupport/lib/active_support/inflector/inflections.rb index f3e52b48ac..aa68f9ec9e 100644 --- a/activesupport/lib/active_support/inflector/inflections.rb +++ b/activesupport/lib/active_support/inflector/inflections.rb @@ -1,6 +1,6 @@ -require 'concurrent/map' -require 'active_support/core_ext/array/prepend_and_append' -require 'active_support/i18n' +require "concurrent/map" +require "active_support/core_ext/array/prepend_and_append" +require "active_support/i18n" module ActiveSupport module Inflector @@ -43,8 +43,8 @@ module ActiveSupport end def add(words) - self.concat(words.flatten.map(&:downcase)) - @regex_array += self.map {|word| to_regex(word) } + concat(words.flatten.map(&:downcase)) + @regex_array += map { |word| to_regex(word) } self end @@ -215,10 +215,10 @@ module ActiveSupport # clear :plurals def clear(scope = :all) case scope - when :all - @plurals, @singulars, @uncountables, @humans = [], [], Uncountables.new, [] + when :all + @plurals, @singulars, @uncountables, @humans = [], [], Uncountables.new, [] else - instance_variable_set "@#{scope}", [] + instance_variable_set "@#{scope}", [] end end end diff --git a/activesupport/lib/active_support/inflector/methods.rb b/activesupport/lib/active_support/inflector/methods.rb index f741c0bfb8..c80243c40a 100644 --- a/activesupport/lib/active_support/inflector/methods.rb +++ b/activesupport/lib/active_support/inflector/methods.rb @@ -1,4 +1,5 @@ -require 'active_support/inflections' +require "active_support/inflections" +require "active_support/core_ext/regexp" module ActiveSupport # The Inflector transforms words from singular to plural, class names to table @@ -71,7 +72,7 @@ module ActiveSupport string = string.sub(/^(?:#{inflections.acronym_regex}(?=\b|[A-Z_])|\w)/) { |match| match.downcase } end string.gsub!(/(?:_|(\/))([a-z\d]*)/i) { "#{$1}#{inflections.acronyms[$2] || $2.capitalize}" } - string.gsub!('/'.freeze, '::'.freeze) + string.gsub!("/".freeze, "::".freeze) string end @@ -87,8 +88,8 @@ module ActiveSupport # # camelize(underscore('SSLError')) # => "SslError" def underscore(camel_cased_word) - return camel_cased_word unless camel_cased_word =~ /[A-Z-]|::/ - word = camel_cased_word.to_s.gsub('::'.freeze, '/'.freeze) + return camel_cased_word unless /[A-Z-]|::/.match?(camel_cased_word) + word = camel_cased_word.to_s.gsub("::".freeze, "/".freeze) word.gsub!(/(?:(?<=([A-Za-z\d]))|\b)(#{inflections.acronym_regex})(?=\b|[^a-z])/) { "#{$1 && '_'.freeze }#{$2.downcase}" } word.gsub!(/([A-Z\d]+)([A-Z][a-z])/, '\1_\2'.freeze) word.gsub!(/([a-z\d])([A-Z])/, '\1_\2'.freeze) @@ -125,9 +126,9 @@ module ActiveSupport inflections.humans.each { |(rule, replacement)| break if result.sub!(rule, replacement) } - result.sub!(/\A_+/, ''.freeze) - result.sub!(/_id\z/, ''.freeze) - result.tr!('_'.freeze, ' '.freeze) + result.sub!(/\A_+/, "".freeze) + result.sub!(/_id\z/, "".freeze) + result.tr!("_".freeze, " ".freeze) result.gsub!(/([a-z\d]*)/i) do |match| "#{inflections.acronyms[match] || match.downcase}" @@ -140,6 +141,15 @@ module ActiveSupport result end + # Converts just the first character to uppercase. + # + # upcase_first('what a Lovely Day') # => "What a Lovely Day" + # upcase_first('w') # => "W" + # upcase_first('') # => "" + def upcase_first(string) + string.length > 0 ? string[0].upcase.concat(string[1..-1]) : "" + end + # Capitalizes all the words and replaces some characters in the string to # create a nicer looking title. +titleize+ is meant for creating pretty # output. It is not used in the Rails internals. @@ -176,14 +186,14 @@ module ActiveSupport # classify('calculus') # => "Calculus" def classify(table_name) # strip out any leading schema name - camelize(singularize(table_name.to_s.sub(/.*\./, ''.freeze))) + camelize(singularize(table_name.to_s.sub(/.*\./, "".freeze))) end # Replaces underscores with dashes in the string. # # dasherize('puni_puni') # => "puni-puni" def dasherize(underscored_word) - underscored_word.tr('_'.freeze, '-'.freeze) + underscored_word.tr("_".freeze, "-".freeze) end # Removes the module part from the expression in the string. @@ -196,7 +206,7 @@ module ActiveSupport # See also #deconstantize. def demodulize(path) path = path.to_s - if i = path.rindex('::') + if i = path.rindex("::") path[(i+2)..-1] else path @@ -213,7 +223,7 @@ module ActiveSupport # # See also #demodulize. def deconstantize(path) - path.to_s[0, path.rindex('::') || 0] # implementation based on the one in facets' Module#spacename + path.to_s[0, path.rindex("::") || 0] # implementation based on the one in facets' Module#spacename end # Creates a foreign key name from a class name. @@ -229,8 +239,8 @@ module ActiveSupport # Tries to find a constant with the name specified in the argument string. # - # 'Module'.constantize # => Module - # 'Foo::Bar'.constantize # => Foo::Bar + # constantize('Module') # => Module + # constantize('Foo::Bar') # => Foo::Bar # # 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 @@ -239,14 +249,14 @@ module ActiveSupport # C = 'outside' # module M # C = 'inside' - # C # => 'inside' - # 'C'.constantize # => 'outside', same as ::C + # C # => 'inside' + # constantize('C') # => '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('::'.freeze) + names = camel_cased_word.split("::".freeze) # Trigger a built-in NameError exception including the ill-formed constant in the message. Object.const_get(camel_cased_word) if names.empty? @@ -304,7 +314,7 @@ module ActiveSupport raise if e.name && !(camel_cased_word.to_s.split("::").include?(e.name.to_s) || e.name.to_s == camel_cased_word.to_s) rescue ArgumentError => e - raise unless e.message =~ /not missing constant #{const_regexp(camel_cased_word)}\!$/ + raise unless /not missing constant #{const_regexp(camel_cased_word)}!$/.match?(e.message) end # Returns the suffix that should be added to a number to denote the position @@ -323,9 +333,9 @@ module ActiveSupport "th" else case abs_number % 10 - when 1; "st" - when 2; "nd" - when 3; "rd" + when 1; "st" + when 2; "nd" + when 3; "rd" else "th" end end @@ -346,36 +356,36 @@ module ActiveSupport private - # Mounts a regular expression, returned as a string to ease interpolation, - # that will match part by part the given constant. - # - # const_regexp("Foo::Bar::Baz") # => "Foo(::Bar(::Baz)?)?" - # const_regexp("::") # => "::" - def const_regexp(camel_cased_word) #:nodoc: - parts = camel_cased_word.split("::".freeze) + # Mounts a regular expression, returned as a string to ease interpolation, + # that will match part by part the given constant. + # + # const_regexp("Foo::Bar::Baz") # => "Foo(::Bar(::Baz)?)?" + # const_regexp("::") # => "::" + def const_regexp(camel_cased_word) #:nodoc: + parts = camel_cased_word.split("::".freeze) - return Regexp.escape(camel_cased_word) if parts.blank? + return Regexp.escape(camel_cased_word) if parts.blank? - last = parts.pop + last = parts.pop - parts.reverse.inject(last) do |acc, part| - part.empty? ? acc : "#{part}(::#{acc})?" + parts.reverse.inject(last) do |acc, part| + part.empty? ? acc : "#{part}(::#{acc})?" + end end - end - # Applies inflection rules for +singularize+ and +pluralize+. - # - # apply_inflections('post', inflections.plurals) # => "posts" - # apply_inflections('posts', inflections.singulars) # => "post" - def apply_inflections(word, rules) - result = word.to_s.dup + # Applies inflection rules for +singularize+ and +pluralize+. + # + # apply_inflections('post', inflections.plurals) # => "posts" + # apply_inflections('posts', inflections.singulars) # => "post" + def apply_inflections(word, rules) + result = word.to_s.dup - if word.empty? || inflections.uncountables.uncountable?(result) - result - else - rules.each { |(rule, replacement)| break if result.sub!(rule, replacement) } - result + if word.empty? || inflections.uncountables.uncountable?(result) + result + else + rules.each { |(rule, replacement)| break if result.sub!(rule, replacement) } + result + end end - end end end diff --git a/activesupport/lib/active_support/inflector/transliterate.rb b/activesupport/lib/active_support/inflector/transliterate.rb index 871cfb8a72..85fa83c803 100644 --- a/activesupport/lib/active_support/inflector/transliterate.rb +++ b/activesupport/lib/active_support/inflector/transliterate.rb @@ -1,9 +1,8 @@ -require 'active_support/core_ext/string/multibyte' -require 'active_support/i18n' +require "active_support/core_ext/string/multibyte" +require "active_support/i18n" module ActiveSupport module Inflector - # Replaces non-ASCII characters with an ASCII approximation, or if none # exists, a replacement character which defaults to "?". # @@ -60,7 +59,7 @@ module ActiveSupport def transliterate(string, replacement = "?".freeze) I18n.transliterate(ActiveSupport::Multibyte::Unicode.normalize( ActiveSupport::Multibyte::Unicode.tidy_bytes(string), :c), - :replacement => replacement) + replacement: replacement) end # Replaces special characters in a string so that it may be used as part of @@ -79,7 +78,7 @@ module ActiveSupport # parameterize("Donald E. Knuth", preserve_case: true) # => "Donald-E-Knuth" # parameterize("^trés|Jolie-- ", preserve_case: true) # => "tres-Jolie" # - def parameterize(string, sep = :unused, separator: '-', preserve_case: false) + def parameterize(string, sep = :unused, separator: "-", preserve_case: false) unless sep == :unused ActiveSupport::Deprecation.warn("Passing the separator argument as a positional parameter is deprecated and will soon be removed. Use `separator: '#{sep}'` instead.") separator = sep @@ -102,9 +101,9 @@ module ActiveSupport # No more than one of the separator in a row. parameterized_string.gsub!(re_duplicate_separator, separator) # Remove leading/trailing separator. - parameterized_string.gsub!(re_leading_trailing_separator, ''.freeze) + parameterized_string.gsub!(re_leading_trailing_separator, "".freeze) end - + parameterized_string.downcase! unless preserve_case parameterized_string end diff --git a/activesupport/lib/active_support/json.rb b/activesupport/lib/active_support/json.rb index 3e1d9b1d33..da938d1555 100644 --- a/activesupport/lib/active_support/json.rb +++ b/activesupport/lib/active_support/json.rb @@ -1,2 +1,2 @@ -require 'active_support/json/decoding' -require 'active_support/json/encoding' +require "active_support/json/decoding" +require "active_support/json/encoding" diff --git a/activesupport/lib/active_support/json/decoding.rb b/activesupport/lib/active_support/json/decoding.rb index 2932954f03..f487fa0c65 100644 --- a/activesupport/lib/active_support/json/decoding.rb +++ b/activesupport/lib/active_support/json/decoding.rb @@ -1,6 +1,6 @@ -require 'active_support/core_ext/module/attribute_accessors' -require 'active_support/core_ext/module/delegation' -require 'json' +require "active_support/core_ext/module/attribute_accessors" +require "active_support/core_ext/module/delegation" +require "json" module ActiveSupport # Look for and parse json strings that look like ISO 8601 times. @@ -8,7 +8,8 @@ module ActiveSupport module JSON # matches YAML-formatted dates - DATE_REGEX = /^(?:\d{4}-\d{2}-\d{2}|\d{4}-\d{1,2}-\d{1,2}[T \t]+\d{1,2}:\d{2}:\d{2}(\.[0-9]*)?(([ \t]*)Z|[-+]\d{2}?(:\d{2})?))$/ + DATE_REGEX = /^\d{4}-\d{2}-\d{2}$/ + DATETIME_REGEX = /^(?:\d{4}-\d{2}-\d{2}|\d{4}-\d{1,2}-\d{1,2}[T \t]+\d{1,2}:\d{2}:\d{2}(\.[0-9]*)?(([ \t]*)Z|[-+]\d{2}?(:\d{2})?)?)$/ class << self # Parses a JSON string (JavaScript Object Notation) into a hash. @@ -48,7 +49,13 @@ module ActiveSupport nil when DATE_REGEX begin - DateTime.parse(data) + Date.parse(data) + rescue ArgumentError + data + end + when DATETIME_REGEX + begin + Time.zone.parse(data) rescue ArgumentError data end diff --git a/activesupport/lib/active_support/json/encoding.rb b/activesupport/lib/active_support/json/encoding.rb index 031c5e9339..cee731417f 100644 --- a/activesupport/lib/active_support/json/encoding.rb +++ b/activesupport/lib/active_support/json/encoding.rb @@ -1,5 +1,5 @@ -require 'active_support/core_ext/object/json' -require 'active_support/core_ext/module/delegation' +require "active_support/core_ext/object/json" +require "active_support/core_ext/module/delegation" module ActiveSupport class << self @@ -7,7 +7,7 @@ module ActiveSupport :time_precision, :time_precision=, :escape_html_entities_in_json, :escape_html_entities_in_json=, :json_encoder, :json_encoder=, - :to => :'ActiveSupport::JSON::Encoding' + to: :'ActiveSupport::JSON::Encoding' end module JSON @@ -40,9 +40,9 @@ module ActiveSupport ESCAPED_CHARS = { "\u2028" => '\u2028', "\u2029" => '\u2029', - '>' => '\u003e', - '<' => '\u003c', - '&' => '\u0026', + ">" => '\u003e', + "<" => '\u003c', + "&" => '\u0026', } ESCAPE_REGEX_WITH_HTML_ENTITIES = /[\u2028\u2029><&]/u diff --git a/activesupport/lib/active_support/key_generator.rb b/activesupport/lib/active_support/key_generator.rb index 7f73f9ddfc..1064398d8c 100644 --- a/activesupport/lib/active_support/key_generator.rb +++ b/activesupport/lib/active_support/key_generator.rb @@ -1,5 +1,5 @@ -require 'concurrent/map' -require 'openssl' +require "concurrent/map" +require "openssl" module ActiveSupport # KeyGenerator is a simple wrapper around OpenSSL's implementation of PBKDF2. @@ -31,11 +31,9 @@ module ActiveSupport @cache_keys = Concurrent::Map.new end - # Returns a derived key suitable for use. The default key_size is chosen - # to be compatible with the default settings of ActiveSupport::MessageVerifier. - # i.e. OpenSSL::Digest::SHA1#block_length - def generate_key(salt, key_size=64) - @cache_keys["#{salt}#{key_size}"] ||= @key_generator.generate_key(salt, key_size) + # Returns a derived key suitable for use. + def generate_key(*args) + @cache_keys[args.join] ||= @key_generator.generate_key(*args) end end @@ -53,21 +51,21 @@ module ActiveSupport private - # To prevent users from using something insecure like "Password" we make sure that the - # secret they've provided is at least 30 characters in length. - def ensure_secret_secure(secret) - if secret.blank? - raise ArgumentError, "A secret is required to generate an integrity hash " \ - "for cookie session data. Set a secret_key_base of at least " \ - "#{SECRET_MIN_LENGTH} characters in config/secrets.yml." - end + # To prevent users from using something insecure like "Password" we make sure that the + # secret they've provided is at least 30 characters in length. + def ensure_secret_secure(secret) + if secret.blank? + raise ArgumentError, "A secret is required to generate an integrity hash " \ + "for cookie session data. Set a secret_key_base of at least " \ + "#{SECRET_MIN_LENGTH} characters in config/secrets.yml." + end - if secret.length < SECRET_MIN_LENGTH - raise ArgumentError, "Secret should be something secure, " \ - "like \"#{SecureRandom.hex(16)}\". The value you " \ - "provided, \"#{secret}\", is shorter than the minimum length " \ - "of #{SECRET_MIN_LENGTH} characters." + if secret.length < SECRET_MIN_LENGTH + raise ArgumentError, "Secret should be something secure, " \ + "like \"#{SecureRandom.hex(16)}\". The value you " \ + "provided, \"#{secret}\", is shorter than the minimum length " \ + "of #{SECRET_MIN_LENGTH} characters." + end end - end end end diff --git a/activesupport/lib/active_support/lazy_load_hooks.rb b/activesupport/lib/active_support/lazy_load_hooks.rb index e2b8f0f648..ae1897b886 100644 --- a/activesupport/lib/active_support/lazy_load_hooks.rb +++ b/activesupport/lib/active_support/lazy_load_hooks.rb @@ -15,34 +15,44 @@ module ActiveSupport # end # end # - # When the entirety of +activerecord/lib/active_record/base.rb+ has been + # When the entirety of +ActiveRecord::Base+ has been # evaluated then +run_load_hooks+ is invoked. The very last line of - # +activerecord/lib/active_record/base.rb+ is: + # +ActiveRecord::Base+ is: # # ActiveSupport.run_load_hooks(:active_record, ActiveRecord::Base) - @load_hooks = Hash.new { |h,k| h[k] = [] } - @loaded = Hash.new { |h,k| h[k] = [] } - - def self.on_load(name, options = {}, &block) - @loaded[name].each do |base| - execute_hook(base, options, block) + module LazyLoadHooks + def self.extended(base) # :nodoc: + base.class_eval do + @load_hooks = Hash.new { |h,k| h[k] = [] } + @loaded = Hash.new { |h,k| h[k] = [] } + end end - @load_hooks[name] << [block, options] - end + # Declares a block that will be executed when a Rails component is fully + # loaded. + def on_load(name, options = {}, &block) + @loaded[name].each do |base| + execute_hook(base, options, block) + end - def self.execute_hook(base, options, block) - if options[:yield] - block.call(base) - else - base.instance_eval(&block) + @load_hooks[name] << [block, options] end - end - def self.run_load_hooks(name, base = Object) - @loaded[name] << base - @load_hooks[name].each do |hook, options| - execute_hook(base, options, hook) + def execute_hook(base, options, block) + if options[:yield] + block.call(base) + else + base.instance_eval(&block) + end + end + + def run_load_hooks(name, base = Object) + @loaded[name] << base + @load_hooks[name].each do |hook, options| + execute_hook(base, options, hook) + end end end + + extend LazyLoadHooks end diff --git a/activesupport/lib/active_support/log_subscriber.rb b/activesupport/lib/active_support/log_subscriber.rb index e782cd2d4b..e5812d75d0 100644 --- a/activesupport/lib/active_support/log_subscriber.rb +++ b/activesupport/lib/active_support/log_subscriber.rb @@ -1,6 +1,6 @@ -require 'active_support/core_ext/module/attribute_accessors' -require 'active_support/core_ext/class/attribute' -require 'active_support/subscriber' +require "active_support/core_ext/module/attribute_accessors" +require "active_support/core_ext/class/attribute" +require "active_support/subscriber" module ActiveSupport # ActiveSupport::LogSubscriber is an object set to consume diff --git a/activesupport/lib/active_support/log_subscriber/test_helper.rb b/activesupport/lib/active_support/log_subscriber/test_helper.rb index 588ed67c81..a7e30632f6 100644 --- a/activesupport/lib/active_support/log_subscriber/test_helper.rb +++ b/activesupport/lib/active_support/log_subscriber/test_helper.rb @@ -1,6 +1,6 @@ -require 'active_support/log_subscriber' -require 'active_support/logger' -require 'active_support/notifications' +require "active_support/log_subscriber" +require "active_support/logger" +require "active_support/notifications" module ActiveSupport class LogSubscriber @@ -62,11 +62,11 @@ module ActiveSupport end def method_missing(level, message = nil) - if block_given? - @logged[level] << yield - else - @logged[level] << message - end + if block_given? + @logged[level] << yield + else + @logged[level] << message + end end def logged(level) diff --git a/activesupport/lib/active_support/logger.rb b/activesupport/lib/active_support/logger.rb index 7626b28108..3ba6461b57 100644 --- a/activesupport/lib/active_support/logger.rb +++ b/activesupport/lib/active_support/logger.rb @@ -1,8 +1,10 @@ -require 'active_support/logger_silence' -require 'logger' +require "active_support/logger_silence" +require "active_support/logger_thread_safe_level" +require "logger" module ActiveSupport class Logger < ::Logger + include ActiveSupport::LoggerThreadSafeLevel include LoggerSilence # Returns true if the logger destination matches one of the sources @@ -48,6 +50,29 @@ module ActiveSupport logger.level = level super(level) end + + define_method(:local_level=) do |level| + logger.local_level = level if logger.respond_to?(:local_level=) + super(level) if respond_to?(:local_level=) + end + + define_method(:silence) do |level = Logger::ERROR, &block| + if logger.respond_to?(:silence) + logger.silence(level) do + if respond_to?(:silence) + super(level, &block) + else + block.call(self) + end + end + else + if respond_to?(:silence) + super(level, &block) + else + block.call(self) + end + end + end end end diff --git a/activesupport/lib/active_support/logger_silence.rb b/activesupport/lib/active_support/logger_silence.rb index 125d81d973..632994cf50 100644 --- a/activesupport/lib/active_support/logger_silence.rb +++ b/activesupport/lib/active_support/logger_silence.rb @@ -1,45 +1,28 @@ -require 'active_support/concern' -require 'active_support/core_ext/module/attribute_accessors' -require 'concurrent' +require "active_support/concern" +require "active_support/core_ext/module/attribute_accessors" +require "concurrent" module LoggerSilence extend ActiveSupport::Concern included do cattr_accessor :silencer - attr_reader :local_levels self.silencer = true end - def after_initialize - @local_levels = Concurrent::Map.new(:initial_capacity => 2) - end - - def local_log_id - Thread.current.__id__ - end - - def level - local_levels[local_log_id] || super - end - # Silences the logger for the duration of the block. def silence(temporary_level = Logger::ERROR) if silencer begin - old_local_level = local_levels[local_log_id] - local_levels[local_log_id] = temporary_level + old_local_level = local_level + self.local_level = temporary_level yield self ensure - if old_local_level - local_levels[local_log_id] = old_local_level - else - local_levels.delete(local_log_id) - end + self.local_level = old_local_level end else yield self end end -end
\ No newline at end of file +end diff --git a/activesupport/lib/active_support/logger_thread_safe_level.rb b/activesupport/lib/active_support/logger_thread_safe_level.rb new file mode 100644 index 0000000000..7fb175dea6 --- /dev/null +++ b/activesupport/lib/active_support/logger_thread_safe_level.rb @@ -0,0 +1,31 @@ +require "active_support/concern" + +module ActiveSupport + module LoggerThreadSafeLevel # :nodoc: + extend ActiveSupport::Concern + + def after_initialize + @local_levels = Concurrent::Map.new(initial_capacity: 2) + end + + def local_log_id + Thread.current.__id__ + end + + def local_level + @local_levels[local_log_id] + end + + def local_level=(level) + if level + @local_levels[local_log_id] = level + else + @local_levels.delete(local_log_id) + end + end + + def level + local_level || super + end + end +end diff --git a/activesupport/lib/active_support/message_encryptor.rb b/activesupport/lib/active_support/message_encryptor.rb index 2dde01c844..7b33dc3481 100644 --- a/activesupport/lib/active_support/message_encryptor.rb +++ b/activesupport/lib/active_support/message_encryptor.rb @@ -1,6 +1,7 @@ -require 'openssl' -require 'base64' -require 'active_support/core_ext/array/extract_options' +require "openssl" +require "base64" +require "active_support/core_ext/array/extract_options" +require "active_support/message_verifier" module ActiveSupport # MessageEncryptor is a simple way to encrypt values which get stored @@ -18,6 +19,8 @@ module ActiveSupport # encrypted_data = crypt.encrypt_and_sign('my secret data') # => "NlFBTTMwOUV5UlA1QlNEN2xkY2d6eThYWWh..." # crypt.decrypt_and_verify(encrypted_data) # => "my secret data" class MessageEncryptor + DEFAULT_CIPHER = "aes-256-cbc" + module NullSerializer #:nodoc: def self.load(value) value @@ -28,6 +31,16 @@ module ActiveSupport end end + module NullVerifier #:nodoc: + def self.verify(value) + value + end + + def self.generate(value) + value + end + end + class InvalidMessage < StandardError; end OpenSSLCipherError = OpenSSL::Cipher::CipherError @@ -40,15 +53,17 @@ module ActiveSupport # Options: # * <tt>:cipher</tt> - Cipher to use. Can be any cipher returned by # <tt>OpenSSL::Cipher.ciphers</tt>. Default is 'aes-256-cbc'. - # * <tt>:digest</tt> - String of digest to use for signing. Default is +SHA1+. + # * <tt>:digest</tt> - String of digest to use for signing. Default is + # +SHA1+. Ignored when using an AEAD cipher like 'aes-256-gcm'. # * <tt>:serializer</tt> - Object serializer to use. Default is +Marshal+. def initialize(secret, *signature_key_or_options) options = signature_key_or_options.extract_options! sign_secret = signature_key_or_options.first @secret = secret @sign_secret = sign_secret - @cipher = options[:cipher] || 'aes-256-cbc' - @verifier = MessageVerifier.new(@sign_secret || @secret, digest: options[:digest] || 'SHA1', serializer: NullSerializer) + @cipher = options[:cipher] || "aes-256-cbc" + @digest = options[:digest] || "SHA1" unless aead_mode? + @verifier = resolve_verifier @serializer = options[:serializer] || Marshal end @@ -64,44 +79,73 @@ module ActiveSupport _decrypt(verifier.verify(value)) end + # Given a cipher, returns the key length of the cipher to help generate the key of desired size + def self.key_len(cipher = DEFAULT_CIPHER) + OpenSSL::Cipher.new(cipher).key_len + end + private - def _encrypt(value) - cipher = new_cipher - cipher.encrypt - cipher.key = @secret + def _encrypt(value) + cipher = new_cipher + cipher.encrypt + cipher.key = @secret - # Rely on OpenSSL for the initialization vector - iv = cipher.random_iv + # Rely on OpenSSL for the initialization vector + iv = cipher.random_iv + cipher.auth_data = "" if aead_mode? - encrypted_data = cipher.update(@serializer.dump(value)) - encrypted_data << cipher.final + encrypted_data = cipher.update(@serializer.dump(value)) + encrypted_data << cipher.final - "#{::Base64.strict_encode64 encrypted_data}--#{::Base64.strict_encode64 iv}" - end - - def _decrypt(encrypted_message) - cipher = new_cipher - encrypted_data, iv = encrypted_message.split("--".freeze).map {|v| ::Base64.strict_decode64(v)} + blob = "#{::Base64.strict_encode64 encrypted_data}--#{::Base64.strict_encode64 iv}" + blob << "--#{::Base64.strict_encode64 cipher.auth_tag}" if aead_mode? + blob + end - cipher.decrypt - cipher.key = @secret - cipher.iv = iv + def _decrypt(encrypted_message) + cipher = new_cipher + encrypted_data, iv, auth_tag = encrypted_message.split("--".freeze).map { |v| ::Base64.strict_decode64(v) } + + # Currently the OpenSSL bindings do not raise an error if auth_tag is + # truncated, which would allow an attacker to easily forge it. See + # https://github.com/ruby/openssl/issues/63 + raise InvalidMessage if aead_mode? && auth_tag.bytes.length != 16 + + cipher.decrypt + cipher.key = @secret + cipher.iv = iv + if aead_mode? + cipher.auth_tag = auth_tag + cipher.auth_data = "" + end + + decrypted_data = cipher.update(encrypted_data) + decrypted_data << cipher.final + + @serializer.load(decrypted_data) + rescue OpenSSLCipherError, TypeError, ArgumentError + raise InvalidMessage + end - decrypted_data = cipher.update(encrypted_data) - decrypted_data << cipher.final + def new_cipher + OpenSSL::Cipher.new(@cipher) + end - @serializer.load(decrypted_data) - rescue OpenSSLCipherError, TypeError, ArgumentError - raise InvalidMessage - end + def verifier + @verifier + end - def new_cipher - OpenSSL::Cipher::Cipher.new(@cipher) - end + def aead_mode? + @aead_mode ||= new_cipher.authenticated? + end - def verifier - @verifier - end + def resolve_verifier + if aead_mode? + NullVerifier + else + MessageVerifier.new(@sign_secret || @secret, digest: @digest, serializer: NullSerializer) + end + end end end diff --git a/activesupport/lib/active_support/message_verifier.rb b/activesupport/lib/active_support/message_verifier.rb index 854029bf83..8419e858c6 100644 --- a/activesupport/lib/active_support/message_verifier.rb +++ b/activesupport/lib/active_support/message_verifier.rb @@ -1,6 +1,6 @@ -require 'base64' -require 'active_support/core_ext/object/blank' -require 'active_support/security_utils' +require "base64" +require "active_support/core_ext/object/blank" +require "active_support/security_utils" module ActiveSupport # +MessageVerifier+ makes it easy to generate and verify messages which are @@ -24,13 +24,19 @@ module ActiveSupport # hash upon initialization: # # @verifier = ActiveSupport::MessageVerifier.new('s3Krit', serializer: YAML) + # + # +MessageVerifier+ creates HMAC signatures using SHA1 hash algorithm by default. + # If you want to use a different hash algorithm, you can change it by providing + # `:digest` key as an option while initializing the verifier: + # + # @verifier = ActiveSupport::MessageVerifier.new('s3Krit', digest: 'SHA256') class MessageVerifier class InvalidSignature < StandardError; end def initialize(secret, options = {}) - raise ArgumentError, 'Secret should not be nil.' unless secret + raise ArgumentError, "Secret should not be nil." unless secret @secret = secret - @digest = options[:digest] || 'SHA1' + @digest = options[:digest] || "SHA1" @serializer = options[:serializer] || Marshal end @@ -77,7 +83,7 @@ module ActiveSupport data = signed_message.split("--".freeze)[0] @serializer.load(decode(data)) rescue ArgumentError => argument_error - return if argument_error.message =~ %r{invalid base64} + return if argument_error.message.include?("invalid base64") raise end end @@ -121,7 +127,7 @@ module ActiveSupport end def generate_digest(data) - require 'openssl' unless defined?(OpenSSL) + require "openssl" unless defined?(OpenSSL) OpenSSL::HMAC.hexdigest(OpenSSL::Digest.const_get(@digest).new, @secret, data) end end diff --git a/activesupport/lib/active_support/multibyte.rb b/activesupport/lib/active_support/multibyte.rb index ffebd9a60b..f7c7befee0 100644 --- a/activesupport/lib/active_support/multibyte.rb +++ b/activesupport/lib/active_support/multibyte.rb @@ -1,7 +1,7 @@ module ActiveSupport #:nodoc: module Multibyte - autoload :Chars, 'active_support/multibyte/chars' - autoload :Unicode, 'active_support/multibyte/unicode' + autoload :Chars, "active_support/multibyte/chars" + autoload :Unicode, "active_support/multibyte/unicode" # The proxy class returned when calling mb_chars. You can use this accessor # to configure your own proxy class so you can support other encodings. See diff --git a/activesupport/lib/active_support/multibyte/chars.rb b/activesupport/lib/active_support/multibyte/chars.rb index 707cf200b5..938e4ebb72 100644 --- a/activesupport/lib/active_support/multibyte/chars.rb +++ b/activesupport/lib/active_support/multibyte/chars.rb @@ -1,7 +1,8 @@ -require 'active_support/json' -require 'active_support/core_ext/string/access' -require 'active_support/core_ext/string/behavior' -require 'active_support/core_ext/module/delegation' +require "active_support/json" +require "active_support/core_ext/string/access" +require "active_support/core_ext/string/behavior" +require "active_support/core_ext/module/delegation" +require "active_support/core_ext/regexp" module ActiveSupport #:nodoc: module Multibyte #:nodoc: @@ -45,7 +46,7 @@ module ActiveSupport #:nodoc: alias to_s wrapped_string alias to_str wrapped_string - delegate :<=>, :=~, :acts_like_string?, :to => :wrapped_string + delegate :<=>, :=~, :acts_like_string?, to: :wrapped_string # Creates a new Chars instance by wrapping _string_. def initialize(string) @@ -56,7 +57,7 @@ module ActiveSupport #:nodoc: # Forward all undefined methods to the wrapped string. def method_missing(method, *args, &block) result = @wrapped_string.__send__(method, *args, &block) - if method.to_s =~ /!$/ + if /!$/.match?(method) self if result else result.kind_of?(String) ? chars(result) : result @@ -105,7 +106,7 @@ module ActiveSupport #:nodoc: # # 'Café'.mb_chars.reverse.to_s # => 'éfaC' def reverse - chars(Unicode.unpack_graphemes(@wrapped_string).reverse.flatten.pack('U*')) + chars(Unicode.unpack_graphemes(@wrapped_string).reverse.flatten.pack("U*")) end # Limits the byte size of the string to a number of bytes without breaking @@ -142,7 +143,7 @@ module ActiveSupport #:nodoc: # # 'über'.mb_chars.capitalize.to_s # => "Über" def capitalize - (slice(0) || chars('')).upcase + (slice(1..-1) || chars('')).downcase + (slice(0) || chars("")).upcase + (slice(1..-1) || chars("")).downcase end # Capitalizes the first letter of every word, when possible. @@ -150,7 +151,7 @@ module ActiveSupport #:nodoc: # "ÉL QUE SE ENTERÓ".mb_chars.titleize # => "Él Que Se Enteró" # "日本語".mb_chars.titleize # => "日本語" def titleize - chars(downcase.to_s.gsub(/\b('?\S)/u) { Unicode.upcase($1)}) + chars(downcase.to_s.gsub(/\b('?\S)/u) { Unicode.upcase($1) }) end alias_method :titlecase, :titleize @@ -170,7 +171,7 @@ module ActiveSupport #:nodoc: # 'é'.length # => 2 # 'é'.mb_chars.decompose.to_s.length # => 3 def decompose - chars(Unicode.decompose(:canonical, @wrapped_string.codepoints.to_a).pack('U*')) + chars(Unicode.decompose(:canonical, @wrapped_string.codepoints.to_a).pack("U*")) end # Performs composition on all the characters. @@ -178,7 +179,7 @@ module ActiveSupport #:nodoc: # 'é'.length # => 3 # 'é'.mb_chars.compose.to_s.length # => 2 def compose - chars(Unicode.compose(@wrapped_string.codepoints.to_a).pack('U*')) + chars(Unicode.compose(@wrapped_string.codepoints.to_a).pack("U*")) end # Returns the number of grapheme clusters in the string. @@ -213,10 +214,10 @@ module ActiveSupport #:nodoc: def translate_offset(byte_offset) #:nodoc: return nil if byte_offset.nil? - return 0 if @wrapped_string == '' + return 0 if @wrapped_string == "" begin - @wrapped_string.byteslice(0...byte_offset).unpack('U*').length + @wrapped_string.byteslice(0...byte_offset).unpack("U*").length rescue ArgumentError byte_offset -= 1 retry diff --git a/activesupport/lib/active_support/multibyte/unicode.rb b/activesupport/lib/active_support/multibyte/unicode.rb index 72b20fff06..217919ccb8 100644 --- a/activesupport/lib/active_support/multibyte/unicode.rb +++ b/activesupport/lib/active_support/multibyte/unicode.rb @@ -1,7 +1,6 @@ module ActiveSupport module Multibyte module Unicode - extend self # A list of all available normalization forms. @@ -10,7 +9,7 @@ module ActiveSupport NORMALIZATION_FORMS = [:c, :kc, :d, :kd] # The Unicode version that is supported by the implementation - UNICODE_VERSION = '8.0.0' + UNICODE_VERSION = "8.0.0" # The default normalization used for operations that require # normalization. It can be set to any of the normalizations @@ -31,36 +30,6 @@ module ActiveSupport HANGUL_NCOUNT = HANGUL_VCOUNT * HANGUL_TCOUNT HANGUL_SCOUNT = 11172 HANGUL_SLAST = HANGUL_SBASE + HANGUL_SCOUNT - HANGUL_JAMO_FIRST = 0x1100 - HANGUL_JAMO_LAST = 0x11FF - - # All the unicode whitespace - WHITESPACE = [ - (0x0009..0x000D).to_a, # White_Space # Cc [5] <control-0009>..<control-000D> - 0x0020, # White_Space # Zs SPACE - 0x0085, # White_Space # Cc <control-0085> - 0x00A0, # White_Space # Zs NO-BREAK SPACE - 0x1680, # White_Space # Zs OGHAM SPACE MARK - (0x2000..0x200A).to_a, # White_Space # Zs [11] EN QUAD..HAIR SPACE - 0x2028, # White_Space # Zl LINE SEPARATOR - 0x2029, # White_Space # Zp PARAGRAPH SEPARATOR - 0x202F, # White_Space # Zs NARROW NO-BREAK SPACE - 0x205F, # White_Space # Zs MEDIUM MATHEMATICAL SPACE - 0x3000, # White_Space # Zs IDEOGRAPHIC SPACE - ].flatten.freeze - - # BOM (byte order mark) can also be seen as whitespace, it's a - # non-rendering character used to distinguish between little and big - # endian. This is not an issue in utf-8, so it must be ignored. - LEADERS_AND_TRAILERS = WHITESPACE + [65279] # ZERO-WIDTH NO-BREAK SPACE aka BOM - - # Returns a regular expression pattern that matches the passed Unicode - # codepoints. - def self.codepoints_to_pattern(array_of_codepoints) #:nodoc: - array_of_codepoints.collect{ |e| [e].pack 'U*'.freeze }.join('|'.freeze) - end - TRAILERS_PAT = /(#{codepoints_to_pattern(LEADERS_AND_TRAILERS)})+\Z/u - LEADERS_PAT = /\A(#{codepoints_to_pattern(LEADERS_AND_TRAILERS)})+/u # Detect whether the codepoint is in a certain character class. Returns # +true+ when it's in the specified character class and +false+ otherwise. @@ -90,25 +59,25 @@ module ActiveSupport should_break = # GB3. CR X LF - if previous == database.boundary[:cr] and current == database.boundary[:lf] + if previous == database.boundary[:cr] && current == database.boundary[:lf] false # GB4. (Control|CR|LF) ÷ - elsif previous and in_char_class?(previous, [:control,:cr,:lf]) + elsif previous && in_char_class?(previous, [:control,:cr,:lf]) true # GB5. ÷ (Control|CR|LF) elsif in_char_class?(current, [:control,:cr,:lf]) true # GB6. L X (L|V|LV|LVT) - elsif database.boundary[:l] === previous and in_char_class?(current, [:l,:v,:lv,:lvt]) + elsif database.boundary[:l] === previous && in_char_class?(current, [:l,:v,:lv,:lvt]) false # GB7. (LV|V) X (V|T) - elsif in_char_class?(previous, [:lv,:v]) and in_char_class?(current, [:v,:t]) + elsif in_char_class?(previous, [:lv,:v]) && in_char_class?(current, [:v,:t]) false # GB8. (LVT|T) X (T) - elsif in_char_class?(previous, [:lvt,:t]) and database.boundary[:t] === current + elsif in_char_class?(previous, [:lvt,:t]) && database.boundary[:t] === current false # GB8a. Regional_Indicator X Regional_Indicator - elsif database.boundary[:regional_indicator] === previous and database.boundary[:regional_indicator] === current + elsif database.boundary[:regional_indicator] === previous && database.boundary[:regional_indicator] === current false # GB9. X Extend elsif database.boundary[:extend] === current @@ -136,7 +105,7 @@ module ActiveSupport # # Unicode.pack_graphemes(Unicode.unpack_graphemes('क्षि')) # => 'क्षि' def pack_graphemes(unpacked) - unpacked.flatten.pack('U*') + unpacked.flatten.pack("U*") end # Re-order codepoints so the string becomes canonical. @@ -159,7 +128,7 @@ module ActiveSupport def decompose(type, codepoints) codepoints.inject([]) do |decomposed, cp| # if it's a hangul syllable starter character - if HANGUL_SBASE <= cp and cp < HANGUL_SLAST + if HANGUL_SBASE <= cp && cp < HANGUL_SLAST sindex = cp - HANGUL_SBASE ncp = [] # new codepoints ncp << HANGUL_LBASE + sindex / HANGUL_NCOUNT @@ -168,7 +137,7 @@ module ActiveSupport ncp << (HANGUL_TBASE + tindex) unless tindex == 0 decomposed.concat ncp # if the codepoint is decomposable in with the current decomposition type - elsif (ncp = database.codepoints[cp].decomp_mapping) and (!database.codepoints[cp].decomp_type || type == :compatibility) + elsif (ncp = database.codepoints[cp].decomp_mapping) && (!database.codepoints[cp].decomp_type || type == :compatibility) decomposed.concat decompose(type, ncp.dup) else decomposed << cp @@ -187,11 +156,11 @@ module ActiveSupport pos += 1 lindex = starter_char - HANGUL_LBASE # -- Hangul - if 0 <= lindex and lindex < HANGUL_LCOUNT + if 0 <= lindex && lindex < HANGUL_LCOUNT vindex = codepoints[starter_pos+1] - HANGUL_VBASE rescue vindex = -1 - if 0 <= vindex and vindex < HANGUL_VCOUNT + if 0 <= vindex && vindex < HANGUL_VCOUNT tindex = codepoints[starter_pos+2] - HANGUL_TBASE rescue tindex = -1 - if 0 <= tindex and tindex < HANGUL_TCOUNT + if 0 <= tindex && tindex < HANGUL_TCOUNT j = starter_pos + 2 eoa -= 2 else @@ -259,7 +228,7 @@ module ActiveSupport reader = Encoding::Converter.new(Encoding::UTF_8, Encoding::UTF_16LE) source = string.dup - out = ''.force_encoding(Encoding::UTF_16LE) + out = "".force_encoding(Encoding::UTF_16LE) loop do reader.primitive_convert(source, out) @@ -287,17 +256,17 @@ module ActiveSupport # See http://www.unicode.org/reports/tr15, Table 1 codepoints = string.codepoints.to_a case form - when :d - reorder_characters(decompose(:canonical, codepoints)) - when :c - compose(reorder_characters(decompose(:canonical, codepoints))) - when :kd - reorder_characters(decompose(:compatibility, codepoints)) - when :kc - compose(reorder_characters(decompose(:compatibility, codepoints))) + when :d + reorder_characters(decompose(:canonical, codepoints)) + when :c + compose(reorder_characters(decompose(:canonical, codepoints))) + when :kd + reorder_characters(decompose(:compatibility, codepoints)) + when :kc + compose(reorder_characters(decompose(:compatibility, codepoints))) else - raise ArgumentError, "#{form} is not a valid normalization variant", caller - end.pack('U*'.freeze) + raise ArgumentError, "#{form} is not a valid normalization variant", caller + end.pack("U*".freeze) end def downcase(string) @@ -356,7 +325,7 @@ module ActiveSupport # UnicodeDatabase. def load begin - @codepoints, @composition_exclusion, @composition_map, @boundary, @cp1252 = File.open(self.class.filename, 'rb') { |f| Marshal.load f.read } + @codepoints, @composition_exclusion, @composition_map, @boundary, @cp1252 = File.open(self.class.filename, "rb") { |f| Marshal.load f.read } rescue => e raise IOError.new("Couldn't load the Unicode tables for UTF8Handler (#{e.message}), ActiveSupport::Multibyte is unusable") end @@ -378,7 +347,7 @@ module ActiveSupport # Returns the directory in which the data files are stored. def self.dirname - File.dirname(__FILE__) + '/../values/' + File.dirname(__FILE__) + "/../values/" end # Returns the filename for the data file for this version. @@ -389,25 +358,25 @@ module ActiveSupport private - def apply_mapping(string, mapping) #:nodoc: - database.codepoints - string.each_codepoint.map do |codepoint| - cp = database.codepoints[codepoint] - if cp and (ncp = cp.send(mapping)) and ncp > 0 - ncp - else - codepoint - end - end.pack('U*') - end + def apply_mapping(string, mapping) #:nodoc: + database.codepoints + string.each_codepoint.map do |codepoint| + cp = database.codepoints[codepoint] + if cp && (ncp = cp.send(mapping)) && ncp > 0 + ncp + else + codepoint + end + end.pack("U*") + end - def recode_windows1252_chars(string) - string.encode(Encoding::UTF_8, Encoding::Windows_1252, invalid: :replace, undef: :replace) - end + def recode_windows1252_chars(string) + string.encode(Encoding::UTF_8, Encoding::Windows_1252, invalid: :replace, undef: :replace) + end - def database - @database ||= UnicodeDatabase.new - end + def database + @database ||= UnicodeDatabase.new + end end end end diff --git a/activesupport/lib/active_support/notifications.rb b/activesupport/lib/active_support/notifications.rb index 823d68e507..bae5f067ae 100644 --- a/activesupport/lib/active_support/notifications.rb +++ b/activesupport/lib/active_support/notifications.rb @@ -1,6 +1,6 @@ -require 'active_support/notifications/instrumenter' -require 'active_support/notifications/fanout' -require 'active_support/per_thread_registry' +require "active_support/notifications/instrumenter" +require "active_support/notifications/fanout" +require "active_support/per_thread_registry" module ActiveSupport # = Notifications diff --git a/activesupport/lib/active_support/notifications/fanout.rb b/activesupport/lib/active_support/notifications/fanout.rb index c53f9c1039..9da115f552 100644 --- a/activesupport/lib/active_support/notifications/fanout.rb +++ b/activesupport/lib/active_support/notifications/fanout.rb @@ -1,5 +1,5 @@ -require 'mutex_m' -require 'concurrent/map' +require "mutex_m" +require "concurrent/map" module ActiveSupport module Notifications @@ -68,7 +68,7 @@ module ActiveSupport module Subscribers # :nodoc: def self.new(pattern, listener) - if listener.respond_to?(:start) and listener.respond_to?(:finish) + if listener.respond_to?(:start) && listener.respond_to?(:finish) subscriber = Evented.new pattern, listener else subscriber = Timed.new pattern, listener diff --git a/activesupport/lib/active_support/notifications/instrumenter.rb b/activesupport/lib/active_support/notifications/instrumenter.rb index 91f94cb2d7..23262d5398 100644 --- a/activesupport/lib/active_support/notifications/instrumenter.rb +++ b/activesupport/lib/active_support/notifications/instrumenter.rb @@ -1,4 +1,4 @@ -require 'securerandom' +require "securerandom" module ActiveSupport module Notifications @@ -44,9 +44,9 @@ module ActiveSupport private - def unique_id - SecureRandom.hex(10) - end + def unique_id + SecureRandom.hex(10) + end end class Event diff --git a/activesupport/lib/active_support/number_helper.rb b/activesupport/lib/active_support/number_helper.rb index 64d9e71f37..7a49bbb960 100644 --- a/activesupport/lib/active_support/number_helper.rb +++ b/activesupport/lib/active_support/number_helper.rb @@ -15,7 +15,7 @@ module ActiveSupport extend self - # Formats a +number+ into a US phone number (e.g., (555) + # Formats a +number+ into a phone number (US by default e.g., (555) # 123-9876). You can customize the format in the +options+ hash. # # ==== Options @@ -27,19 +27,26 @@ module ActiveSupport # end of the generated number. # * <tt>:country_code</tt> - Sets the country code for the phone # number. + # * <tt>:pattern</tt> - Specifies how the number is divided into three + # groups with the custom regexp to override the default format. # ==== Examples # - # number_to_phone(5551234) # => 555-1234 - # number_to_phone('5551234') # => 555-1234 - # number_to_phone(1235551234) # => 123-555-1234 - # number_to_phone(1235551234, area_code: true) # => (123) 555-1234 - # number_to_phone(1235551234, delimiter: ' ') # => 123 555 1234 - # number_to_phone(1235551234, area_code: true, extension: 555) # => (123) 555-1234 x 555 - # number_to_phone(1235551234, country_code: 1) # => +1-123-555-1234 - # number_to_phone('123a456') # => 123a456 + # number_to_phone(5551234) # => "555-1234" + # number_to_phone('5551234') # => "555-1234" + # number_to_phone(1235551234) # => "123-555-1234" + # number_to_phone(1235551234, area_code: true) # => "(123) 555-1234" + # number_to_phone(1235551234, delimiter: ' ') # => "123 555 1234" + # number_to_phone(1235551234, area_code: true, extension: 555) # => "(123) 555-1234 x 555" + # number_to_phone(1235551234, country_code: 1) # => "+1-123-555-1234" + # number_to_phone('123a456') # => "123a456" # # number_to_phone(1235551234, country_code: 1, extension: 1343, delimiter: '.') - # # => +1.123.555.1234 x 1343 + # # => "+1.123.555.1234 x 1343" + # + # number_to_phone(75561234567, pattern: /(\d{1,4})(\d{4})(\d{4})$/, area_code: true) + # # => "(755) 6123-4567" + # number_to_phone(13312345678, pattern: /(\d{3})(\d{4})(\d{4})$/)) + # # => "133-1234-5678" def number_to_phone(number, options = {}) NumberToPhoneConverter.convert(number, options) end @@ -78,18 +85,18 @@ module ActiveSupport # # ==== Examples # - # number_to_currency(1234567890.50) # => $1,234,567,890.50 - # number_to_currency(1234567890.506) # => $1,234,567,890.51 - # number_to_currency(1234567890.506, precision: 3) # => $1,234,567,890.506 - # number_to_currency(1234567890.506, locale: :fr) # => 1 234 567 890,51 € - # number_to_currency('123a456') # => $123a456 + # number_to_currency(1234567890.50) # => "$1,234,567,890.50" + # number_to_currency(1234567890.506) # => "$1,234,567,890.51" + # number_to_currency(1234567890.506, precision: 3) # => "$1,234,567,890.506" + # number_to_currency(1234567890.506, locale: :fr) # => "1 234 567 890,51 €" + # number_to_currency('123a456') # => "$123a456" # # number_to_currency(-1234567890.50, negative_format: '(%u%n)') - # # => ($1,234,567,890.50) + # # => "($1,234,567,890.50)" # number_to_currency(1234567890.50, unit: '£', separator: ',', delimiter: '') - # # => £1234567890,50 + # # => "£1234567890,50" # number_to_currency(1234567890.50, unit: '£', separator: ',', delimiter: '', format: '%n %u') - # # => 1234567890,50 £ + # # => "1234567890,50 £" def number_to_currency(number, options = {}) NumberToCurrencyConverter.convert(number, options) end @@ -118,15 +125,15 @@ module ActiveSupport # # ==== Examples # - # number_to_percentage(100) # => 100.000% - # number_to_percentage('98') # => 98.000% - # number_to_percentage(100, precision: 0) # => 100% - # number_to_percentage(1000, delimiter: '.', separator: ',') # => 1.000,000% - # number_to_percentage(302.24398923423, precision: 5) # => 302.24399% - # number_to_percentage(1000, locale: :fr) # => 1000,000% - # number_to_percentage(1000, precision: nil) # => 1000% - # number_to_percentage('98a') # => 98a% - # number_to_percentage(100, format: '%n %') # => 100.000 % + # number_to_percentage(100) # => "100.000%" + # number_to_percentage('98') # => "98.000%" + # number_to_percentage(100, precision: 0) # => "100%" + # number_to_percentage(1000, delimiter: '.', separator: ',') # => "1.000,000%" + # number_to_percentage(302.24398923423, precision: 5) # => "302.24399%" + # number_to_percentage(1000, locale: :fr) # => "1000,000%" + # number_to_percentage(1000, precision: nil) # => "1000%" + # number_to_percentage('98a') # => "98a%" + # number_to_percentage(100, format: '%n %') # => "100.000 %" def number_to_percentage(number, options = {}) NumberToPercentageConverter.convert(number, options) end @@ -149,19 +156,19 @@ module ActiveSupport # # ==== Examples # - # number_to_delimited(12345678) # => 12,345,678 - # number_to_delimited('123456') # => 123,456 - # number_to_delimited(12345678.05) # => 12,345,678.05 - # number_to_delimited(12345678, delimiter: '.') # => 12.345.678 - # number_to_delimited(12345678, delimiter: ',') # => 12,345,678 - # number_to_delimited(12345678.05, separator: ' ') # => 12,345,678 05 - # number_to_delimited(12345678.05, locale: :fr) # => 12 345 678,05 - # number_to_delimited('112a') # => 112a + # number_to_delimited(12345678) # => "12,345,678" + # number_to_delimited('123456') # => "123,456" + # number_to_delimited(12345678.05) # => "12,345,678.05" + # number_to_delimited(12345678, delimiter: '.') # => "12.345.678" + # number_to_delimited(12345678, delimiter: ',') # => "12,345,678" + # number_to_delimited(12345678.05, separator: ' ') # => "12,345,678 05" + # number_to_delimited(12345678.05, locale: :fr) # => "12 345 678,05" + # number_to_delimited('112a') # => "112a" # number_to_delimited(98765432.98, delimiter: ' ', separator: ',') - # # => 98 765 432,98 + # # => "98 765 432,98" # number_to_delimited("123456.78", # delimiter_pattern: /(\d+?)(?=(\d\d)+(\d)(?!\d))/) - # # => 1,23,456.78 + # # => "1,23,456.78" def number_to_delimited(number, options = {}) NumberToDelimitedConverter.convert(number, options) end @@ -190,22 +197,22 @@ module ActiveSupport # # ==== Examples # - # number_to_rounded(111.2345) # => 111.235 - # number_to_rounded(111.2345, precision: 2) # => 111.23 - # number_to_rounded(13, precision: 5) # => 13.00000 - # number_to_rounded(389.32314, precision: 0) # => 389 - # number_to_rounded(111.2345, significant: true) # => 111 - # number_to_rounded(111.2345, precision: 1, significant: true) # => 100 - # number_to_rounded(13, precision: 5, significant: true) # => 13.000 - # number_to_rounded(13, precision: nil) # => 13 - # number_to_rounded(111.234, locale: :fr) # => 111,234 + # number_to_rounded(111.2345) # => "111.235" + # number_to_rounded(111.2345, precision: 2) # => "111.23" + # number_to_rounded(13, precision: 5) # => "13.00000" + # number_to_rounded(389.32314, precision: 0) # => "389" + # number_to_rounded(111.2345, significant: true) # => "111" + # number_to_rounded(111.2345, precision: 1, significant: true) # => "100" + # number_to_rounded(13, precision: 5, significant: true) # => "13.000" + # number_to_rounded(13, precision: nil) # => "13" + # number_to_rounded(111.234, locale: :fr) # => "111,234" # # number_to_rounded(13, precision: 5, significant: true, strip_insignificant_zeros: true) - # # => 13 + # # => "13" # - # number_to_rounded(389.32314, precision: 4, significant: true) # => 389.3 + # number_to_rounded(389.32314, precision: 4, significant: true) # => "389.3" # number_to_rounded(1111.2345, precision: 2, separator: ',', delimiter: '.') - # # => 1.111,23 + # # => "1.111,23" def number_to_rounded(number, options = {}) NumberToRoundedConverter.convert(number, options) end @@ -237,17 +244,17 @@ module ActiveSupport # # ==== Examples # - # number_to_human_size(123) # => 123 Bytes - # number_to_human_size(1234) # => 1.21 KB - # number_to_human_size(12345) # => 12.1 KB - # number_to_human_size(1234567) # => 1.18 MB - # number_to_human_size(1234567890) # => 1.15 GB - # number_to_human_size(1234567890123) # => 1.12 TB - # number_to_human_size(1234567890123456) # => 1.1 PB - # number_to_human_size(1234567890123456789) # => 1.07 EB - # number_to_human_size(1234567, precision: 2) # => 1.2 MB - # number_to_human_size(483989, precision: 2) # => 470 KB - # number_to_human_size(1234567, precision: 2, separator: ',') # => 1,2 MB + # number_to_human_size(123) # => "123 Bytes" + # number_to_human_size(1234) # => "1.21 KB" + # number_to_human_size(12345) # => "12.1 KB" + # number_to_human_size(1234567) # => "1.18 MB" + # number_to_human_size(1234567890) # => "1.15 GB" + # number_to_human_size(1234567890123) # => "1.12 TB" + # number_to_human_size(1234567890123456) # => "1.1 PB" + # number_to_human_size(1234567890123456789) # => "1.07 EB" + # number_to_human_size(1234567, precision: 2) # => "1.2 MB" + # number_to_human_size(483989, precision: 2) # => "470 KB" + # number_to_human_size(1234567, precision: 2, separator: ',') # => "1,2 MB" # number_to_human_size(1234567890123, precision: 5) # => "1.1228 TB" # number_to_human_size(524288000, precision: 5) # => "500 MB" def number_to_human_size(number, options = {}) diff --git a/activesupport/lib/active_support/number_helper/number_converter.rb b/activesupport/lib/active_support/number_helper/number_converter.rb index 9d976f1831..c485a6af63 100644 --- a/activesupport/lib/active_support/number_helper/number_converter.rb +++ b/activesupport/lib/active_support/number_helper/number_converter.rb @@ -1,8 +1,8 @@ -require 'active_support/core_ext/big_decimal/conversions' -require 'active_support/core_ext/object/blank' -require 'active_support/core_ext/hash/keys' -require 'active_support/i18n' -require 'active_support/core_ext/class/attribute' +require "active_support/core_ext/big_decimal/conversions" +require "active_support/core_ext/object/blank" +require "active_support/core_ext/hash/keys" +require "active_support/i18n" +require "active_support/core_ext/class/attribute" module ActiveSupport module NumberHelper @@ -169,7 +169,7 @@ module ActiveSupport end def default_value(key) - key.split('.').reduce(DEFAULTS) { |defaults, k| defaults[k.to_sym] } + key.split(".").reduce(DEFAULTS) { |defaults, k| defaults[k.to_sym] } end def valid_float? #:nodoc: diff --git a/activesupport/lib/active_support/number_helper/number_to_currency_converter.rb b/activesupport/lib/active_support/number_helper/number_to_currency_converter.rb index 57f40f33bf..0f9dce722f 100644 --- a/activesupport/lib/active_support/number_helper/number_to_currency_converter.rb +++ b/activesupport/lib/active_support/number_helper/number_to_currency_converter.rb @@ -1,4 +1,4 @@ -require 'active_support/core_ext/numeric/inquiry' +require "active_support/core_ext/numeric/inquiry" module ActiveSupport module NumberHelper @@ -15,13 +15,13 @@ module ActiveSupport end rounded_number = NumberToRoundedConverter.convert(number, options) - format.gsub('%n'.freeze, rounded_number).gsub('%u'.freeze, options[:unit]) + format.gsub("%n".freeze, rounded_number).gsub("%u".freeze, options[:unit]) end private def absolute_value(number) - number.respond_to?(:abs) ? number.abs : number.sub(/\A-/, '') + number.respond_to?(:abs) ? number.abs : number.sub(/\A-/, "") end def options diff --git a/activesupport/lib/active_support/number_helper/number_to_delimited_converter.rb b/activesupport/lib/active_support/number_helper/number_to_delimited_converter.rb index 45ae8f1a93..e3b35531b1 100644 --- a/activesupport/lib/active_support/number_helper/number_to_delimited_converter.rb +++ b/activesupport/lib/active_support/number_helper/number_to_delimited_converter.rb @@ -12,7 +12,7 @@ module ActiveSupport private def parts - left, right = number.to_s.split('.') + left, right = number.to_s.split(".".freeze) left.gsub!(delimiter_pattern) do |digit_to_delimit| "#{digit_to_delimit}#{options[:delimiter]}" end @@ -22,7 +22,6 @@ module ActiveSupport def delimiter_pattern options.fetch(:delimiter_pattern, DEFAULT_DELIMITER_REGEX) end - end end end diff --git a/activesupport/lib/active_support/number_helper/number_to_human_converter.rb b/activesupport/lib/active_support/number_helper/number_to_human_converter.rb index 7a1f8171c0..695ee1dad3 100644 --- a/activesupport/lib/active_support/number_helper/number_to_human_converter.rb +++ b/activesupport/lib/active_support/number_helper/number_to_human_converter.rb @@ -25,22 +25,22 @@ module ActiveSupport exponent += 3 end unit = determine_unit(units, exponent) - format.gsub('%n'.freeze, rounded_number).gsub('%u'.freeze, unit).strip + format.gsub("%n".freeze, rounded_number).gsub("%u".freeze, unit).strip end private def format - options[:format] || translate_in_locale('human.decimal_units.format') + options[:format] || translate_in_locale("human.decimal_units.format") end def determine_unit(units, exponent) exp = DECIMAL_UNITS[exponent] case units when Hash - units[exp] || '' + units[exp] || "" when String, Symbol - I18n.translate("#{units}.#{exp}", :locale => options[:locale], :count => number.to_i) + I18n.translate("#{units}.#{exp}", locale: options[:locale], count: number.to_i) else translate_in_locale("human.decimal_units.units.#{exp}", count: number.to_i) end @@ -56,7 +56,7 @@ module ActiveSupport when Hash units when String, Symbol - I18n.translate(units.to_s, :locale => options[:locale], :raise => true) + I18n.translate(units.to_s, locale: options[:locale], raise: true) when nil translate_in_locale("human.decimal_units.units", raise: true) else diff --git a/activesupport/lib/active_support/number_helper/number_to_human_size_converter.rb b/activesupport/lib/active_support/number_helper/number_to_human_size_converter.rb index a83b368b7f..78cb33aa62 100644 --- a/activesupport/lib/active_support/number_helper/number_to_human_size_converter.rb +++ b/activesupport/lib/active_support/number_helper/number_to_human_size_converter.rb @@ -8,7 +8,7 @@ module ActiveSupport def convert if opts.key?(:prefix) - ActiveSupport::Deprecation.warn('The :prefix option of `number_to_human_size` is deprecated and will be removed in Rails 5.1 with no replacement.') + ActiveSupport::Deprecation.warn("The :prefix option of `number_to_human_size` is deprecated and will be removed in Rails 5.1 with no replacement.") end @number = Float(number) @@ -24,21 +24,21 @@ module ActiveSupport human_size = number / (base ** exponent) number_to_format = NumberToRoundedConverter.convert(human_size, options) end - conversion_format.gsub('%n'.freeze, number_to_format).gsub('%u'.freeze, unit) + conversion_format.gsub("%n".freeze, number_to_format).gsub("%u".freeze, unit) end private def conversion_format - translate_number_value_with_default('human.storage_units.format', :locale => options[:locale], :raise => true) + translate_number_value_with_default("human.storage_units.format", locale: options[:locale], raise: true) end def unit - translate_number_value_with_default(storage_unit_key, :locale => options[:locale], :count => number.to_i, :raise => true) + translate_number_value_with_default(storage_unit_key, locale: options[:locale], count: number.to_i, raise: true) end def storage_unit_key - key_end = smaller_than_base? ? 'byte' : STORAGE_UNITS[exponent] + key_end = smaller_than_base? ? "byte" : STORAGE_UNITS[exponent] "human.storage_units.units.#{key_end}" end @@ -59,4 +59,3 @@ module ActiveSupport end end end - diff --git a/activesupport/lib/active_support/number_helper/number_to_percentage_converter.rb b/activesupport/lib/active_support/number_helper/number_to_percentage_converter.rb index 4c04d40c19..ac647ca9b7 100644 --- a/activesupport/lib/active_support/number_helper/number_to_percentage_converter.rb +++ b/activesupport/lib/active_support/number_helper/number_to_percentage_converter.rb @@ -5,7 +5,7 @@ module ActiveSupport def convert rounded_number = NumberToRoundedConverter.convert(number, options) - options[:format].gsub('%n'.freeze, rounded_number) + options[:format].gsub("%n".freeze, rounded_number) end end end diff --git a/activesupport/lib/active_support/number_helper/number_to_phone_converter.rb b/activesupport/lib/active_support/number_helper/number_to_phone_converter.rb index af2ee56d91..c2612f9a9b 100644 --- a/activesupport/lib/active_support/number_helper/number_to_phone_converter.rb +++ b/activesupport/lib/active_support/number_helper/number_to_phone_converter.rb @@ -18,12 +18,16 @@ module ActiveSupport end def convert_with_area_code(number) - number.gsub!(/(\d{1,3})(\d{3})(\d{4}$)/,"(\\1) \\2#{delimiter}\\3") + default_pattern = /(\d{1,3})(\d{3})(\d{4}$)/ + number.gsub!(regexp_pattern(default_pattern), + "(\\1) \\2#{delimiter}\\3") number end def convert_without_area_code(number) - number.gsub!(/(\d{0,3})(\d{3})(\d{4})$/,"\\1#{delimiter}\\2#{delimiter}\\3") + default_pattern = /(\d{0,3})(\d{3})(\d{4})$/ + number.gsub!(regexp_pattern(default_pattern), + "\\1#{delimiter}\\2#{delimiter}\\3") number.slice!(0, 1) if start_with_delimiter?(number) number end @@ -43,7 +47,10 @@ module ActiveSupport def phone_ext(ext) ext.blank? ? "" : " x #{ext}" end + + def regexp_pattern(default_pattern) + opts.fetch :pattern, default_pattern + end end end end - diff --git a/activesupport/lib/active_support/number_helper/number_to_rounded_converter.rb b/activesupport/lib/active_support/number_helper/number_to_rounded_converter.rb index 981c562551..cfcb0045fb 100644 --- a/activesupport/lib/active_support/number_helper/number_to_rounded_converter.rb +++ b/activesupport/lib/active_support/number_helper/number_to_rounded_converter.rb @@ -29,9 +29,11 @@ module ActiveSupport formatted_string = if BigDecimal === rounded_number && rounded_number.finite? - s = rounded_number.to_s('F') + '0'*precision - a, b = s.split('.', 2) - a + '.' + b[0, precision] + s = rounded_number.to_s("F") + s << "0".freeze * precision + a, b = s.split(".".freeze, 2) + a << ".".freeze + a << b[0, precision] else "%00.#{precision}f" % rounded_number end @@ -72,7 +74,7 @@ module ActiveSupport def format_number(number) if strip_insignificant_zeros escaped_separator = Regexp.escape(options[:separator]) - number.sub(/(#{escaped_separator})(\d*[1-9])?0+\z/, '\1\2').sub(/#{escaped_separator}\z/, '') + number.sub(/(#{escaped_separator})(\d*[1-9])?0+\z/, '\1\2').sub(/#{escaped_separator}\z/, "") else number end diff --git a/activesupport/lib/active_support/option_merger.rb b/activesupport/lib/active_support/option_merger.rb index dea84e437f..0f2caa98f2 100644 --- a/activesupport/lib/active_support/option_merger.rb +++ b/activesupport/lib/active_support/option_merger.rb @@ -1,4 +1,4 @@ -require 'active_support/core_ext/hash/deep_merge' +require "active_support/core_ext/hash/deep_merge" module ActiveSupport class OptionMerger #:nodoc: diff --git a/activesupport/lib/active_support/ordered_hash.rb b/activesupport/lib/active_support/ordered_hash.rb index b1658f0f27..793bc9e22d 100644 --- a/activesupport/lib/active_support/ordered_hash.rb +++ b/activesupport/lib/active_support/ordered_hash.rb @@ -1,7 +1,7 @@ -require 'yaml' +require "yaml" YAML.add_builtin_type("omap") do |type, val| - ActiveSupport::OrderedHash[val.map{ |v| v.to_a.first }] + ActiveSupport::OrderedHash[val.map { |v| v.to_a.first }] end module ActiveSupport @@ -25,7 +25,7 @@ module ActiveSupport end def encode_with(coder) - coder.represent_seq '!omap', map { |k,v| { k => v } } + coder.represent_seq "!omap", map { |k,v| { k => v } } end def select(*args, &block) diff --git a/activesupport/lib/active_support/ordered_options.rb b/activesupport/lib/active_support/ordered_options.rb index 53a55bd986..14ed9049be 100644 --- a/activesupport/lib/active_support/ordered_options.rb +++ b/activesupport/lib/active_support/ordered_options.rb @@ -1,3 +1,5 @@ +require "active_support/core_ext/object/blank" + module ActiveSupport # Usually key value pairs are handled something like this: # @@ -36,10 +38,10 @@ module ActiveSupport def method_missing(name, *args) name_string = name.to_s - if name_string.chomp!('=') + if name_string.chomp!("=") self[name_string] = args.first else - bangs = name_string.chomp!('!') + bangs = name_string.chomp!("!") if bangs fetch(name_string.to_sym).presence || raise(KeyError.new("#{name_string} is blank.")) diff --git a/activesupport/lib/active_support/per_thread_registry.rb b/activesupport/lib/active_support/per_thread_registry.rb index 88e2b12cc7..9e6d8d4fd8 100644 --- a/activesupport/lib/active_support/per_thread_registry.rb +++ b/activesupport/lib/active_support/per_thread_registry.rb @@ -1,7 +1,7 @@ -require 'active_support/core_ext/module/delegation' +require "active_support/core_ext/module/delegation" module ActiveSupport - # NOTE: This approach has been deprecated for end-user code in favor of thread_mattr_accessor and friends. + # NOTE: This approach has been deprecated for end-user code in favor of {thread_mattr_accessor}[rdoc-ref:Module#thread_mattr_accessor] and friends. # Please use that approach instead. # # This module is used to encapsulate access to thread local variables. @@ -38,7 +38,7 @@ module ActiveSupport # If the class has an initializer, it must accept no arguments. module PerThreadRegistry def self.extended(object) - object.instance_variable_set '@per_thread_registry_key', object.name.freeze + object.instance_variable_set "@per_thread_registry_key", object.name.freeze end def instance diff --git a/activesupport/lib/active_support/rails.rb b/activesupport/lib/active_support/rails.rb index c8e3a4bf53..f6b018f0d3 100644 --- a/activesupport/lib/active_support/rails.rb +++ b/activesupport/lib/active_support/rails.rb @@ -9,19 +9,25 @@ # Rails and can change anytime. # Defines Object#blank? and Object#present?. -require 'active_support/core_ext/object/blank' +require "active_support/core_ext/object/blank" # Rails own autoload, eager_load, etc. -require 'active_support/dependencies/autoload' +require "active_support/dependencies/autoload" # Support for ClassMethods and the included macro. -require 'active_support/concern' +require "active_support/concern" # Defines Class#class_attribute. -require 'active_support/core_ext/class/attribute' +require "active_support/core_ext/class/attribute" # Defines Module#delegate. -require 'active_support/core_ext/module/delegation' +require "active_support/core_ext/module/delegation" # Defines ActiveSupport::Deprecation. -require 'active_support/deprecation' +require "active_support/deprecation" + +# Defines Regexp#match?. +# +# This should be removed when Rails needs Ruby 2.4 or later, and the require +# added where other Regexp extensions are being used (easy to grep). +require "active_support/core_ext/regexp" diff --git a/activesupport/lib/active_support/railtie.rb b/activesupport/lib/active_support/railtie.rb index 845788b669..b875875afe 100644 --- a/activesupport/lib/active_support/railtie.rb +++ b/activesupport/lib/active_support/railtie.rb @@ -21,11 +21,11 @@ module ActiveSupport rescue TZInfo::DataSourceNotFound => e raise e.exception "tzinfo-data is not present. Please add gem 'tzinfo-data' to your Gemfile and run bundle install" end - require 'active_support/core_ext/time/zones' + require "active_support/core_ext/time/zones" zone_default = Time.find_zone!(app.config.time_zone) unless zone_default - raise 'Value assigned to config.time_zone not recognized. ' \ + raise "Value assigned to config.time_zone not recognized. " \ 'Run "rake time:zones:all" for a time zone names list.' end @@ -35,7 +35,7 @@ module ActiveSupport # Sets the default week start # If assigned value is not a valid day symbol (e.g. :sunday, :monday, ...), an exception will be raised. initializer "active_support.initialize_beginning_of_week" do |app| - require 'active_support/core_ext/date/calculations' + require "active_support/core_ext/date/calculations" beginning_of_week_default = Date.find_beginning_of_week!(app.config.beginning_of_week) Date.beginning_of_week_default = beginning_of_week_default diff --git a/activesupport/lib/active_support/reloader.rb b/activesupport/lib/active_support/reloader.rb new file mode 100644 index 0000000000..121c621751 --- /dev/null +++ b/activesupport/lib/active_support/reloader.rb @@ -0,0 +1,129 @@ +require "active_support/execution_wrapper" + +module ActiveSupport + #-- + # This class defines several callbacks: + # + # to_prepare -- Run once at application startup, and also from + # +to_run+. + # + # to_run -- Run before a work run that is reloading. If + # +reload_classes_only_on_change+ is true (the default), the class + # unload will have already occurred. + # + # to_complete -- Run after a work run that has reloaded. If + # +reload_classes_only_on_change+ is false, the class unload will + # have occurred after the work run, but before this callback. + # + # before_class_unload -- Run immediately before the classes are + # unloaded. + # + # after_class_unload -- Run immediately after the classes are + # unloaded. + # + class Reloader < ExecutionWrapper + define_callbacks :prepare + + define_callbacks :class_unload + + def self.to_prepare(*args, &block) + set_callback(:prepare, *args, &block) + end + + def self.before_class_unload(*args, &block) + set_callback(:class_unload, *args, &block) + end + + def self.after_class_unload(*args, &block) + set_callback(:class_unload, :after, *args, &block) + end + + to_run(:after) { self.class.prepare! } + + # Initiate a manual reload + def self.reload! + executor.wrap do + new.tap do |instance| + begin + instance.run! + ensure + instance.complete! + end + end + end + prepare! + end + + def self.run! # :nodoc: + if check! + super + else + Null + end + end + + # Run the supplied block as a work unit, reloading code as needed + def self.wrap + executor.wrap do + super + end + end + + class_attribute :executor + class_attribute :check + + self.executor = Executor + self.check = lambda { false } + + def self.check! # :nodoc: + @should_reload ||= check.call + end + + def self.reloaded! # :nodoc: + @should_reload = false + end + + def self.prepare! # :nodoc: + new.run_callbacks(:prepare) + end + + def initialize + super + @locked = false + end + + # Acquire the ActiveSupport::Dependencies::Interlock unload lock, + # ensuring it will be released automatically + def require_unload_lock! + unless @locked + ActiveSupport::Dependencies.interlock.start_unloading + @locked = true + end + end + + # Release the unload lock if it has been previously obtained + def release_unload_lock! + if @locked + @locked = false + ActiveSupport::Dependencies.interlock.done_unloading + end + end + + def run! # :nodoc: + super + release_unload_lock! + end + + def class_unload!(&block) # :nodoc: + require_unload_lock! + run_callbacks(:class_unload, &block) + end + + def complete! # :nodoc: + super + self.class.reloaded! + ensure + release_unload_lock! + end + end +end diff --git a/activesupport/lib/active_support/rescuable.rb b/activesupport/lib/active_support/rescuable.rb index fcf5553061..dc3f27a16d 100644 --- a/activesupport/lib/active_support/rescuable.rb +++ b/activesupport/lib/active_support/rescuable.rb @@ -1,7 +1,6 @@ -require 'active_support/concern' -require 'active_support/core_ext/class/attribute' -require 'active_support/core_ext/string/inflections' -require 'active_support/core_ext/array/extract_options' +require "active_support/concern" +require "active_support/core_ext/class/attribute" +require "active_support/core_ext/string/inflections" module ActiveSupport # Rescuable module adds support for easier exception handling. @@ -48,14 +47,12 @@ module ActiveSupport # end # # Exceptions raised inside exception handlers are not propagated up. - def rescue_from(*klasses, &block) - options = klasses.extract_options! - - unless options.has_key?(:with) + def rescue_from(*klasses, with: nil, &block) + unless with if block_given? - options[:with] = block + with = block else - raise ArgumentError, "Need a handler. Supply an options hash that has a :with key as the last argument." + raise ArgumentError, "Need a handler. Pass the with: keyword argument or provide a block." end end @@ -65,55 +62,104 @@ module ActiveSupport elsif klass.is_a?(String) klass else - raise ArgumentError, "#{klass} is neither an Exception nor a String" + raise ArgumentError, "#{klass.inspect} must be an Exception class or a String referencing an Exception class" end # Put the new handler at the end because the list is read in reverse. - self.rescue_handlers += [[key, options[:with]]] + self.rescue_handlers += [[key, with]] end end - end - # Tries to rescue the exception by looking up and calling a registered handler. - def rescue_with_handler(exception) - if handler = handler_for_rescue(exception) - handler.arity != 0 ? handler.call(exception) : handler.call - true # don't rely on the return value of the handler + # Matches an exception to a handler based on the exception class. + # + # If no handler matches the exception, check for a handler matching the + # (optional) exception.cause. If no handler matches the exception or its + # cause, this returns nil so you can deal with unhandled exceptions. + # Be sure to re-raise unhandled exceptions if this is what you expect. + # + # begin + # … + # rescue => exception + # rescue_with_handler(exception) || raise + # end + # + # Returns the exception if it was handled and nil if it was not. + def rescue_with_handler(exception, object: self) + if handler = handler_for_rescue(exception, object: object) + handler.call exception + exception + end end - end - def handler_for_rescue(exception) - # We go from right to left because pairs are pushed onto rescue_handlers - # as rescue_from declarations are found. - _, rescuer = self.class.rescue_handlers.reverse.detect do |klass_name, handler| - # The purpose of allowing strings in rescue_from is to support the - # declaration of handler associations for exception classes whose - # definition is yet unknown. - # - # Since this loop needs the constants it would be inconsistent to - # assume they should exist at this point. An early raised exception - # could trigger some other handler and the array could include - # precisely a string whose corresponding constant has not yet been - # seen. This is why we are tolerant to unknown constants. - # - # Note that this tolerance only matters if the exception was given as - # a string, otherwise a NameError will be raised by the interpreter - # itself when rescue_from CONSTANT is executed. - klass = self.class.const_get(klass_name) rescue nil - klass ||= (klass_name.constantize rescue nil) - klass === exception if klass + def handler_for_rescue(exception, object: self) #:nodoc: + case rescuer = find_rescue_handler(exception) + when Symbol + method = object.method(rescuer) + if method.arity == 0 + -> e { method.call } + else + method + end + when Proc + if rescuer.arity == 0 + -> e { object.instance_exec(&rescuer) } + else + -> e { object.instance_exec(e, &rescuer) } + end + end end - case rescuer - when Symbol - method(rescuer) - when Proc - if rescuer.arity == 0 - Proc.new { instance_exec(&rescuer) } - else - Proc.new { |_exception| instance_exec(_exception, &rescuer) } + private + def find_rescue_handler(exception) + if exception + # Handlers are in order of declaration but the most recently declared + # is the highest priority match, so we search for matching handlers + # in reverse. + _, handler = rescue_handlers.reverse_each.detect do |class_or_name, _| + if klass = constantize_rescue_handler_class(class_or_name) + klass === exception + end + end + + handler || find_rescue_handler(exception.cause) + end end - end + + def constantize_rescue_handler_class(class_or_name) + case class_or_name + when String, Symbol + begin + # Try a lexical lookup first since we support + # + # class Super + # rescue_from 'Error', with: … + # end + # + # class Sub + # class Error < StandardError; end + # end + # + # so an Error raised in Sub will hit the 'Error' handler. + const_get class_or_name + rescue NameError + class_or_name.safe_constantize + end + else + class_or_name + end + end + end + + # Delegates to the class method, but uses the instance as the subject for + # rescue_from handlers (method calls, instance_exec blocks). + def rescue_with_handler(exception) + self.class.rescue_with_handler exception, object: self + end + + # Internal handler lookup. Delegates to class method. Some libraries call + # this directly, so keeping it around for compatibility. + def handler_for_rescue(exception) #:nodoc: + self.class.handler_for_rescue exception, object: self end end end diff --git a/activesupport/lib/active_support/security_utils.rb b/activesupport/lib/active_support/security_utils.rb index 9be8613ada..b655d64449 100644 --- a/activesupport/lib/active_support/security_utils.rb +++ b/activesupport/lib/active_support/security_utils.rb @@ -1,4 +1,4 @@ -require 'digest' +require "digest" module ActiveSupport module SecurityUtils diff --git a/activesupport/lib/active_support/string_inquirer.rb b/activesupport/lib/active_support/string_inquirer.rb index bc673150d0..09e1cbb28d 100644 --- a/activesupport/lib/active_support/string_inquirer.rb +++ b/activesupport/lib/active_support/string_inquirer.rb @@ -8,15 +8,21 @@ module ActiveSupport # you can call this: # # Rails.env.production? + # + # == Instantiating a new StringInquirer + # + # vehicle = ActiveSupport::StringInquirer.new('car') + # vehicle.car? # => true + # vehicle.bike? # => false class StringInquirer < String private def respond_to_missing?(method_name, include_private = false) - method_name[-1] == '?' + method_name[-1] == "?" end def method_missing(method_name, *arguments) - if method_name[-1] == '?' + if method_name[-1] == "?" self == method_name[0..-2] else super diff --git a/activesupport/lib/active_support/subscriber.rb b/activesupport/lib/active_support/subscriber.rb index 1cd4b807ad..0f09f1eb63 100644 --- a/activesupport/lib/active_support/subscriber.rb +++ b/activesupport/lib/active_support/subscriber.rb @@ -1,4 +1,4 @@ -require 'active_support/per_thread_registry' +require "active_support/per_thread_registry" module ActiveSupport # ActiveSupport::Subscriber is an object set to consume @@ -23,7 +23,6 @@ module ActiveSupport # the +sql+ method. class Subscriber class << self - # Attach the subscriber to a namespace. def attach_to(namespace, subscriber=new, notifier=ActiveSupport::Notifications) @namespace = namespace @@ -91,7 +90,7 @@ module ActiveSupport event.end = finished event.payload.merge!(payload) - method = name.split('.'.freeze).first + method = name.split(".".freeze).first send(method, event) end diff --git a/activesupport/lib/active_support/tagged_logging.rb b/activesupport/lib/active_support/tagged_logging.rb index bcd7bf74c0..6836378943 100644 --- a/activesupport/lib/active_support/tagged_logging.rb +++ b/activesupport/lib/active_support/tagged_logging.rb @@ -1,7 +1,7 @@ -require 'active_support/core_ext/module/delegation' -require 'active_support/core_ext/object/blank' -require 'logger' -require 'active_support/logger' +require "active_support/core_ext/module/delegation" +require "active_support/core_ext/object/blank" +require "logger" +require "active_support/logger" module ActiveSupport # Wraps any standard Logger object to provide tagging capabilities. diff --git a/activesupport/lib/active_support/test_case.rb b/activesupport/lib/active_support/test_case.rb index d9a668c0ea..3de4ccc1da 100644 --- a/activesupport/lib/active_support/test_case.rb +++ b/activesupport/lib/active_support/test_case.rb @@ -1,15 +1,15 @@ -gem 'minitest' # make sure we get the gem, not stdlib -require 'minitest' -require 'active_support/testing/tagged_logging' -require 'active_support/testing/setup_and_teardown' -require 'active_support/testing/assertions' -require 'active_support/testing/deprecation' -require 'active_support/testing/declarative' -require 'active_support/testing/isolation' -require 'active_support/testing/constant_lookup' -require 'active_support/testing/time_helpers' -require 'active_support/testing/file_fixtures' -require 'active_support/core_ext/kernel/reporting' +gem "minitest" # make sure we get the gem, not stdlib +require "minitest" +require "active_support/testing/tagged_logging" +require "active_support/testing/setup_and_teardown" +require "active_support/testing/assertions" +require "active_support/testing/deprecation" +require "active_support/testing/declarative" +require "active_support/testing/isolation" +require "active_support/testing/constant_lookup" +require "active_support/testing/time_helpers" +require "active_support/testing/file_fixtures" +require "active_support/core_ext/kernel/reporting" module ActiveSupport class TestCase < ::Minitest::Test @@ -66,13 +66,6 @@ module ActiveSupport alias :assert_not_respond_to :refute_respond_to alias :assert_not_same :refute_same - # Reveals the intention that the block should not raise any exception. - # - # assert_nothing_raised do - # ... - # end - def assert_nothing_raised(*args) - yield - end + ActiveSupport.run_load_hooks(:active_support_test_case, self) end end diff --git a/activesupport/lib/active_support/testing/assertions.rb b/activesupport/lib/active_support/testing/assertions.rb index 29305e0082..28cf2953bf 100644 --- a/activesupport/lib/active_support/testing/assertions.rb +++ b/activesupport/lib/active_support/testing/assertions.rb @@ -1,8 +1,8 @@ -require 'active_support/core_ext/object/blank' - module ActiveSupport module Testing module Assertions + UNTRACKED = Object.new # :nodoc: + # Asserts that an expression is not truthy. Passes if <tt>object</tt> is # +nil+ or +false+. "Truthy" means "considered true in a conditional" # like <tt>if foo</tt>. @@ -19,6 +19,17 @@ module ActiveSupport assert !object, message end + # Assertion that the block should not raise an exception. + # + # Passes if evaluated code in the yielded block raises no exception. + # + # assert_nothing_raised do + # perform_service(param: 'no_exception') + # end + def assert_nothing_raised + yield + end + # Test numeric difference between the return value of an expression as a # result of what is evaluated in the yielded block. # @@ -94,6 +105,93 @@ module ActiveSupport def assert_no_difference(expression, message = nil, &block) assert_difference expression, 0, message, &block end + + # Assertion that the result of evaluating an expression is changed before + # and after invoking the passed in block. + # + # assert_changes 'Status.all_good?' do + # post :create, params: { status: { ok: false } } + # end + # + # You can pass the block as a string to be evaluated in the context of + # the block. A lambda can be passed for the block as well. + # + # assert_changes -> { Status.all_good? } do + # post :create, params: { status: { ok: false } } + # end + # + # The assertion is useful to test side effects. The passed block can be + # anything that can be converted to string with #to_s. + # + # assert_changes :@object do + # @object = 42 + # end + # + # The keyword arguments :from and :to can be given to specify the + # expected initial value and the expected value after the block was + # executed. + # + # assert_changes :@object, from: nil, to: :foo do + # @object = :foo + # end + # + # An error message can be specified. + # + # assert_changes -> { Status.all_good? }, 'Expected the status to be bad' do + # post :create, params: { status: { incident: true } } + # end + def assert_changes(expression, message = nil, from: UNTRACKED, to: UNTRACKED, &block) + exp = expression.respond_to?(:call) ? expression : -> { eval(expression.to_s, block.binding) } + + before = exp.call + retval = yield + + unless from == UNTRACKED + error = "#{expression.inspect} isn't #{from.inspect}" + error = "#{message}.\n#{error}" if message + assert from === before, error + end + + after = exp.call + + if to == UNTRACKED + error = "#{expression.inspect} didn't changed" + error = "#{message}.\n#{error}" if message + assert_not_equal before, after, error + else + error = "#{expression.inspect} didn't change to #{to}" + error = "#{message}.\n#{error}" if message + assert to === after, error + end + + retval + end + + # Assertion that the result of evaluating an expression is changed before + # and after invoking the passed in block. + # + # assert_no_changes 'Status.all_good?' do + # post :create, params: { status: { ok: true } } + # end + # + # An error message can be specified. + # + # assert_no_changes -> { Status.all_good? }, 'Expected the status to be good' do + # post :create, params: { status: { ok: false } } + # end + def assert_no_changes(expression, message = nil, &block) + exp = expression.respond_to?(:call) ? expression : -> { eval(expression.to_s, block.binding) } + + before = exp.call + retval = yield + after = exp.call + + error = "#{expression.inspect} did change to #{after}" + error = "#{message}.\n#{error}" if message + assert_equal before, after, error + + retval + end end end end diff --git a/activesupport/lib/active_support/testing/autorun.rb b/activesupport/lib/active_support/testing/autorun.rb index 84c6b89340..3108e3e549 100644 --- a/activesupport/lib/active_support/testing/autorun.rb +++ b/activesupport/lib/active_support/testing/autorun.rb @@ -1,12 +1,9 @@ -gem 'minitest' +gem "minitest" -require 'minitest' +require "minitest" -if Minitest.respond_to?(:run_with_rails_extension) - unless Minitest.run_with_rails_extension - Minitest.run_with_autorun = true - Minitest.autorun - end -else - Minitest.autorun +if Minitest.respond_to?(:run_via) && !Minitest.run_via[:rails] + Minitest.run_via[:ruby] = true end + +Minitest.autorun diff --git a/activesupport/lib/active_support/testing/constant_lookup.rb b/activesupport/lib/active_support/testing/constant_lookup.rb index 07d477c0db..647395d2b3 100644 --- a/activesupport/lib/active_support/testing/constant_lookup.rb +++ b/activesupport/lib/active_support/testing/constant_lookup.rb @@ -44,7 +44,6 @@ module ActiveSupport end end end - end end end diff --git a/activesupport/lib/active_support/testing/deprecation.rb b/activesupport/lib/active_support/testing/deprecation.rb index 5dfa14eeba..58911570e8 100644 --- a/activesupport/lib/active_support/testing/deprecation.rb +++ b/activesupport/lib/active_support/testing/deprecation.rb @@ -1,4 +1,5 @@ -require 'active_support/deprecation' +require "active_support/deprecation" +require "active_support/core_ext/regexp" module ActiveSupport module Testing @@ -8,7 +9,7 @@ module ActiveSupport assert !warnings.empty?, "Expected a deprecation warning within the block but received none" if match match = Regexp.new(Regexp.escape(match)) unless match.is_a?(Regexp) - assert warnings.any? { |w| w =~ match }, "No deprecation warning matched #{match}: #{warnings.join(', ')}" + assert warnings.any? { |w| match.match?(w) }, "No deprecation warning matched #{match}: #{warnings.join(', ')}" end result end diff --git a/activesupport/lib/active_support/testing/isolation.rb b/activesupport/lib/active_support/testing/isolation.rb index edf8b30a0a..d30b34ecd6 100644 --- a/activesupport/lib/active_support/testing/isolation.rb +++ b/activesupport/lib/active_support/testing/isolation.rb @@ -1,7 +1,7 @@ module ActiveSupport module Testing module Isolation - require 'thread' + require "thread" def self.included(klass) #:nodoc: klass.class_eval do @@ -13,17 +13,6 @@ module ActiveSupport !ENV["NO_FORK"] && Process.respond_to?(:fork) end - @@class_setup_mutex = Mutex.new - - def _run_class_setup # class setup method should only happen in parent - @@class_setup_mutex.synchronize do - unless defined?(@@ran_class_setup) || ENV['ISOLATION_TEST'] - self.class.setup if self.class.respond_to?(:setup) - @@ran_class_setup = true - end - end - end - def run serialized = run_in_isolation do super @@ -79,17 +68,17 @@ module ActiveSupport if ENV["ISOLATION_TEST"] yield File.open(ENV["ISOLATION_OUTPUT"], "w") do |file| - file.puts [Marshal.dump(self.dup)].pack("m") + file.puts [Marshal.dump(dup)].pack("m") end exit! else Tempfile.open("isolation") do |tmpfile| env = { - 'ISOLATION_TEST' => self.class.name, - 'ISOLATION_OUTPUT' => tmpfile.path + "ISOLATION_TEST" => self.class.name, + "ISOLATION_OUTPUT" => tmpfile.path } - load_paths = $-I.map {|p| "-I\"#{File.expand_path(p)}\"" }.join(" ") + load_paths = $-I.map { |p| "-I\"#{File.expand_path(p)}\"" }.join(" ") orig_args = ORIG_ARGV.join(" ") test_opts = "-n#{self.class.name}##{self.name}" command = "#{Gem.ruby} #{load_paths} #{$0} '#{orig_args}' #{test_opts}" diff --git a/activesupport/lib/active_support/testing/method_call_assertions.rb b/activesupport/lib/active_support/testing/method_call_assertions.rb index fccaa54f40..6b07416fdc 100644 --- a/activesupport/lib/active_support/testing/method_call_assertions.rb +++ b/activesupport/lib/active_support/testing/method_call_assertions.rb @@ -1,4 +1,4 @@ -require 'minitest/mock' +require "minitest/mock" module ActiveSupport module Testing diff --git a/activesupport/lib/active_support/testing/setup_and_teardown.rb b/activesupport/lib/active_support/testing/setup_and_teardown.rb index 33f2b8dc9b..358c79c321 100644 --- a/activesupport/lib/active_support/testing/setup_and_teardown.rb +++ b/activesupport/lib/active_support/testing/setup_and_teardown.rb @@ -1,5 +1,5 @@ -require 'active_support/concern' -require 'active_support/callbacks' +require "active_support/concern" +require "active_support/callbacks" module ActiveSupport module Testing diff --git a/activesupport/lib/active_support/testing/stream.rb b/activesupport/lib/active_support/testing/stream.rb index 895192ad05..1d06b94559 100644 --- a/activesupport/lib/active_support/testing/stream.rb +++ b/activesupport/lib/active_support/testing/stream.rb @@ -3,40 +3,40 @@ module ActiveSupport module Stream #:nodoc: private - def silence_stream(stream) - old_stream = stream.dup - stream.reopen(IO::NULL) - stream.sync = true - yield - ensure - stream.reopen(old_stream) - old_stream.close - end + def silence_stream(stream) + old_stream = stream.dup + stream.reopen(IO::NULL) + stream.sync = true + yield + ensure + stream.reopen(old_stream) + old_stream.close + end - def quietly - silence_stream(STDOUT) do - silence_stream(STDERR) do - yield + def quietly + silence_stream(STDOUT) do + silence_stream(STDERR) do + yield + end end end - end - def capture(stream) - stream = stream.to_s - captured_stream = Tempfile.new(stream) - stream_io = eval("$#{stream}") - origin_stream = stream_io.dup - stream_io.reopen(captured_stream) + def capture(stream) + stream = stream.to_s + captured_stream = Tempfile.new(stream) + stream_io = eval("$#{stream}") + origin_stream = stream_io.dup + stream_io.reopen(captured_stream) - yield + yield - stream_io.rewind - return captured_stream.read - ensure - captured_stream.close - captured_stream.unlink - stream_io.reopen(origin_stream) - end + stream_io.rewind + return captured_stream.read + ensure + captured_stream.close + captured_stream.unlink + stream_io.reopen(origin_stream) + end end end end diff --git a/activesupport/lib/active_support/testing/tagged_logging.rb b/activesupport/lib/active_support/testing/tagged_logging.rb index 843ce4a867..afdff87b45 100644 --- a/activesupport/lib/active_support/testing/tagged_logging.rb +++ b/activesupport/lib/active_support/testing/tagged_logging.rb @@ -8,7 +8,7 @@ module ActiveSupport def before_setup if tagged_logger && tagged_logger.info? heading = "#{self.class}: #{name}" - divider = '-' * heading.size + divider = "-" * heading.size tagged_logger.info divider tagged_logger.info heading tagged_logger.info divider diff --git a/activesupport/lib/active_support/testing/time_helpers.rb b/activesupport/lib/active_support/testing/time_helpers.rb index fca0947c5b..e2f008b4b7 100644 --- a/activesupport/lib/active_support/testing/time_helpers.rb +++ b/activesupport/lib/active_support/testing/time_helpers.rb @@ -1,32 +1,39 @@ +require "active_support/core_ext/string/strip" # for strip_heredoc +require "concurrent/map" + module ActiveSupport module Testing class SimpleStubs # :nodoc: Stub = Struct.new(:object, :method_name, :original_method) def initialize - @stubs = {} + @stubs = Concurrent::Map.new { |h, k| h[k] = {} } end def stub_object(object, method_name, return_value) - key = [object.object_id, method_name] - - if stub = @stubs[key] + if stub = stubbing(object, method_name) unstub_object(stub) end new_name = "__simple_stub__#{method_name}" - @stubs[key] = Stub.new(object, method_name, new_name) + @stubs[object.object_id][method_name] = Stub.new(object, method_name, new_name) object.singleton_class.send :alias_method, new_name, method_name object.define_singleton_method(method_name) { return_value } end def unstub_all! - @stubs.each_value do |stub| - unstub_object(stub) + @stubs.each_value do |object_stubs| + object_stubs.each_value do |stub| + unstub_object(stub) + end end - @stubs = {} + @stubs.clear + end + + def stubbing(object, method_name) + @stubs[object.object_id][method_name] end private @@ -66,7 +73,7 @@ module ActiveSupport # +Date.today+, and +DateTime.now+ to return the time or date passed into this method. # # Time.current # => Sat, 09 Nov 2013 15:34:49 EST -05:00 - # travel_to Time.new(2004, 11, 24, 01, 04, 44) + # travel_to Time.zone.local(2004, 11, 24, 01, 04, 44) # Time.current # => Wed, 24 Nov 2004 01:04:44 EST -05:00 # Date.current # => Wed, 24 Nov 2004 # DateTime.current # => Wed, 24 Nov 2004 01:04:44 -0500 @@ -88,11 +95,39 @@ module ActiveSupport # state at the end of the block: # # Time.current # => Sat, 09 Nov 2013 15:34:49 EST -05:00 - # travel_to Time.new(2004, 11, 24, 01, 04, 44) do + # travel_to Time.zone.local(2004, 11, 24, 01, 04, 44) do # Time.current # => Wed, 24 Nov 2004 01:04:44 EST -05:00 # end # Time.current # => Sat, 09 Nov 2013 15:34:49 EST -05:00 def travel_to(date_or_time) + if block_given? && simple_stubs.stubbing(Time, :now) + travel_to_nested_block_call = <<-MSG.strip_heredoc + + Calling `travel_to` with a block, when we have previously already made a call to `travel_to`, can lead to confusing time stubbing. + + Instead of: + + travel_to 2.days.from_now do + # 2 days from today + travel_to 3.days.from_now do + # 5 days from today + end + end + + preferred way to achieve above is: + + travel 2.days do + # 2 days from today + end + + travel 5.days do + # 5 days from today + end + + MSG + raise travel_to_nested_block_call + end + if date_or_time.is_a?(Date) && !date_or_time.is_a?(DateTime) now = date_or_time.midnight.to_time else @@ -116,7 +151,7 @@ module ActiveSupport # `travel` and `travel_to`. # # Time.current # => Sat, 09 Nov 2013 15:34:49 EST -05:00 - # travel_to Time.new(2004, 11, 24, 01, 04, 44) + # travel_to Time.zone.local(2004, 11, 24, 01, 04, 44) # Time.current # => Wed, 24 Nov 2004 01:04:44 EST -05:00 # travel_back # Time.current # => Sat, 09 Nov 2013 15:34:49 EST -05:00 diff --git a/activesupport/lib/active_support/time.rb b/activesupport/lib/active_support/time.rb index ea2d3391bd..7658228ca6 100644 --- a/activesupport/lib/active_support/time.rb +++ b/activesupport/lib/active_support/time.rb @@ -1,18 +1,18 @@ module ActiveSupport - autoload :Duration, 'active_support/duration' - autoload :TimeWithZone, 'active_support/time_with_zone' - autoload :TimeZone, 'active_support/values/time_zone' + autoload :Duration, "active_support/duration" + autoload :TimeWithZone, "active_support/time_with_zone" + autoload :TimeZone, "active_support/values/time_zone" end -require 'date' -require 'time' +require "date" +require "time" -require 'active_support/core_ext/time' -require 'active_support/core_ext/date' -require 'active_support/core_ext/date_time' +require "active_support/core_ext/time" +require "active_support/core_ext/date" +require "active_support/core_ext/date_time" -require 'active_support/core_ext/integer/time' -require 'active_support/core_ext/numeric/time' +require "active_support/core_ext/integer/time" +require "active_support/core_ext/numeric/time" -require 'active_support/core_ext/string/conversions' -require 'active_support/core_ext/string/zones' +require "active_support/core_ext/string/conversions" +require "active_support/core_ext/string/zones" diff --git a/activesupport/lib/active_support/time_with_zone.rb b/activesupport/lib/active_support/time_with_zone.rb index 79cc748cf5..889f71c4f3 100644 --- a/activesupport/lib/active_support/time_with_zone.rb +++ b/activesupport/lib/active_support/time_with_zone.rb @@ -1,6 +1,7 @@ -require 'active_support/duration' -require 'active_support/values/time_zone' -require 'active_support/core_ext/object/acts_like' +require "active_support/duration" +require "active_support/values/time_zone" +require "active_support/core_ext/object/acts_like" +require "active_support/core_ext/date_and_time/compatibility" module ActiveSupport # A Time-like class that can represent a time in any time zone. Necessary @@ -35,29 +36,29 @@ module ActiveSupport # t.is_a?(Time) # => true # t.is_a?(ActiveSupport::TimeWithZone) # => true class TimeWithZone - # Report class name as 'Time' to thwart type checking. def self.name - 'Time' + "Time" end PRECISIONS = Hash.new { |h, n| h[n] = "%FT%T.%#{n}N".freeze } - PRECISIONS[0] = '%FT%T'.freeze + PRECISIONS[0] = "%FT%T".freeze - include Comparable + include Comparable, DateAndTime::Compatibility attr_reader :time_zone def initialize(utc_time, time_zone, local_time = nil, period = nil) - @utc, @time_zone, @time = utc_time, time_zone, local_time + @utc = utc_time ? transfer_time_values_to_utc_constructor(utc_time) : nil + @time_zone, @time = time_zone, local_time @period = @utc ? period : get_period_and_ensure_valid_local_time(period) end - # Returns a Time or DateTime instance that represents the time in +time_zone+. + # Returns a <tt>Time</tt> instance that represents the time in +time_zone+. def time @time ||= period.to_local(@utc) end - # Returns a Time or DateTime instance that represents the time in UTC. + # Returns a <tt>Time</tt> instance of the simultaneous time in the UTC timezone. def utc @utc ||= period.to_utc(@time) end @@ -77,10 +78,9 @@ module ActiveSupport utc.in_time_zone(new_zone) end - # Returns a <tt>Time.local()</tt> instance of the simultaneous time in your - # system's <tt>ENV['TZ']</tt> zone. + # Returns a <tt>Time</tt> instance of the simultaneous time in the system timezone. def localtime(utc_offset = nil) - utc.respond_to?(:getlocal) ? utc.getlocal(utc_offset) : utc.to_time.getlocal(utc_offset) + utc.getlocal(utc_offset) end alias_method :getlocal, :localtime @@ -133,7 +133,7 @@ module ActiveSupport period.zone_identifier.to_s end - # Returns a string of the object's date, time, zone and offset from UTC. + # Returns a string of the object's date, time, zone, and offset from UTC. # # Time.zone.now.inspect # => "Thu, 04 Dec 2014 11:00:25 EST -05:00" def inspect @@ -170,12 +170,12 @@ module ActiveSupport end def init_with(coder) #:nodoc: - initialize(coder['utc'], coder['zone'], coder['time']) + initialize(coder["utc"], coder["zone"], coder["time"]) end def encode_with(coder) #:nodoc: - coder.tag = '!ruby/object:ActiveSupport::TimeWithZone' - coder.map = { 'utc' => utc, 'zone' => time_zone, 'time' => time } + coder.tag = "!ruby/object:ActiveSupport::TimeWithZone" + coder.map = { "utc" => utc, "zone" => time_zone, "time" => time } end # Returns a string of the object's date and time in the format used by @@ -279,6 +279,7 @@ module ActiveSupport end end alias_method :since, :+ + alias_method :in, :+ # Returns a new TimeWithZone object that represents the difference between # the current object's time and the +other+ time. @@ -401,17 +402,12 @@ module ActiveSupport utc.to_r end - # Returns an instance of Time in the system timezone. - def to_time - utc.to_time - end - # Returns an instance of DateTime with the timezone's UTC offset # # Time.zone.now.to_datetime # => Tue, 18 Aug 2015 02:32:20 +0000 # Time.current.in_time_zone('Hawaii').to_datetime # => Mon, 17 Aug 2015 16:32:20 -1000 def to_datetime - utc.to_datetime.new_offset(Rational(utc_offset, 86_400)) + @to_datetime ||= utc.to_datetime.new_offset(Rational(utc_offset, 86_400)) end # So that +self+ <tt>acts_like?(:time)</tt>. @@ -454,7 +450,6 @@ module ActiveSupport # Ensure proxy class responds to all methods that underlying time instance # responds to. def respond_to_missing?(sym, include_priv) - # consistently respond false to acts_like?(:date), regardless of whether #time is a Time or DateTime return false if sym.to_sym == :acts_like_date? time.respond_to?(sym, include_priv) end @@ -464,7 +459,7 @@ module ActiveSupport def method_missing(sym, *args, &block) wrap_with_time_zone time.__send__(sym, *args, &block) rescue NoMethodError => e - raise e, e.message.sub(time.inspect, self.inspect), e.backtrace + raise e, e.message.sub(time.inspect, inspect), e.backtrace end private @@ -482,11 +477,13 @@ module ActiveSupport end def transfer_time_values_to_utc_constructor(time) - ::Time.utc(time.year, time.month, time.day, time.hour, time.min, time.sec, Rational(time.nsec, 1000)) + # avoid creating another Time object if possible + return time if time.instance_of?(::Time) && time.utc? + ::Time.utc(time.year, time.month, time.day, time.hour, time.min, time.sec + time.subsec) end def duration_of_variable_length?(obj) - ActiveSupport::Duration === obj && obj.parts.any? {|p| [:years, :months, :days].include?(p[0]) } + ActiveSupport::Duration === obj && obj.parts.any? { |p| [:years, :months, :weeks, :days].include?(p[0]) } end def wrap_with_time_zone(time) diff --git a/activesupport/lib/active_support/values/time_zone.rb b/activesupport/lib/active_support/values/time_zone.rb index 7ca3592520..a562f33420 100644 --- a/activesupport/lib/active_support/values/time_zone.rb +++ b/activesupport/lib/active_support/values/time_zone.rb @@ -1,7 +1,6 @@ -require 'tzinfo' -require 'concurrent/map' -require 'active_support/core_ext/object/blank' -require 'active_support/core_ext/object/try' +require "tzinfo" +require "concurrent/map" +require "active_support/core_ext/object/blank" module ActiveSupport # The TimeZone class serves as a wrapper around TZInfo::Timezone instances. @@ -181,10 +180,11 @@ module ActiveSupport "Samoa" => "Pacific/Apia" } - UTC_OFFSET_WITH_COLON = '%s%02d:%02d' - UTC_OFFSET_WITHOUT_COLON = UTC_OFFSET_WITH_COLON.tr(':', '') + UTC_OFFSET_WITH_COLON = "%s%02d:%02d" + UTC_OFFSET_WITHOUT_COLON = UTC_OFFSET_WITH_COLON.tr(":", "") @lazy_zones_map = Concurrent::Map.new + @country_zones = Concurrent::Map.new class << self # Assumes self represents an offset from UTC in seconds (as returned from @@ -193,7 +193,7 @@ module ActiveSupport # ActiveSupport::TimeZone.seconds_to_utc_offset(-21_600) # => "-06:00" def seconds_to_utc_offset(seconds, colon = true) format = colon ? UTC_OFFSET_WITH_COLON : UTC_OFFSET_WITHOUT_COLON - sign = (seconds < 0 ? '-' : '+') + sign = (seconds < 0 ? "-" : "+") hours = seconds.abs / 3600 minutes = (seconds.abs % 3600) / 60 format % [sign, hours, minutes] @@ -226,30 +226,41 @@ module ActiveSupport # Returns +nil+ if no such time zone is known to the system. def [](arg) case arg - when String + when String begin @lazy_zones_map[arg] ||= create(arg) rescue TZInfo::InvalidTimezoneIdentifier nil end - when Numeric, ActiveSupport::Duration - arg *= 3600 if arg.abs <= 13 - all.find { |z| z.utc_offset == arg.to_i } + when Numeric, ActiveSupport::Duration + arg *= 3600 if arg.abs <= 13 + all.find { |z| z.utc_offset == arg.to_i } else - raise ArgumentError, "invalid argument to TimeZone[]: #{arg.inspect}" + raise ArgumentError, "invalid argument to TimeZone[]: #{arg.inspect}" end end # A convenience method for returning a collection of TimeZone objects # for time zones in the USA. def us_zones - @us_zones ||= all.find_all { |z| z.name =~ /US|Arizona|Indiana|Hawaii|Alaska/ } + country_zones(:us) + end + + # A convenience method for returning a collection of TimeZone objects + # for time zones in the country specified by its ISO 3166-1 Alpha2 code. + def country_zones(country_code) + code = country_code.to_s.upcase + @country_zones[code] ||= + TZInfo::Country.get(code).zone_identifiers.map do |tz_id| + name = MAPPING.key(tz_id) + name && self[name] + end.compact.sort! end private def zones_map @zones_map ||= begin - MAPPING.each_key {|place| self[place]} # load all the zones + MAPPING.each_key { |place| self[place] } # load all the zones @lazy_zones_map end end @@ -267,7 +278,6 @@ module ActiveSupport @name = name @utc_offset = utc_offset @tzinfo = tzinfo || TimeZone.find_tzinfo(name) - @current_period = nil end # Returns the offset of this time zone from UTC in seconds. @@ -275,8 +285,7 @@ module ActiveSupport if @utc_offset @utc_offset else - @current_period ||= tzinfo.current_period if tzinfo - @current_period.utc_offset if @current_period + tzinfo.current_period.utc_offset if tzinfo && tzinfo.current_period end end @@ -428,29 +437,34 @@ module ActiveSupport end def init_with(coder) #:nodoc: - initialize(coder['name']) + initialize(coder["name"]) end def encode_with(coder) #:nodoc: coder.tag ="!ruby/object:#{self.class}" - coder.map = { 'name' => tzinfo.name } + coder.map = { "name" => tzinfo.name } end private def parts_to_time(parts, now) + raise ArgumentError, "invalid date" if parts.nil? return if parts.empty? - time = Time.new( - parts.fetch(:year, now.year), - parts.fetch(:mon, now.month), - parts.fetch(:mday, parts[:year] || parts[:mon] ? 1 : now.day), - parts.fetch(:hour, 0), - parts.fetch(:min, 0), - parts.fetch(:sec, 0) + parts.fetch(:sec_fraction, 0), - parts.fetch(:offset, 0) - ) - - if parts[:offset] + if parts[:seconds] + time = Time.at(parts[:seconds]) + else + time = Time.new( + parts.fetch(:year, now.year), + parts.fetch(:mon, now.month), + parts.fetch(:mday, parts[:year] || parts[:mon] ? 1 : now.day), + parts.fetch(:hour, 0), + parts.fetch(:min, 0), + parts.fetch(:sec, 0) + parts.fetch(:sec_fraction, 0), + parts.fetch(:offset, 0) + ) + end + + if parts[:offset] || parts[:seconds] TimeWithZone.new(time.utc, self) else TimeWithZone.new(nil, self, time) diff --git a/activesupport/lib/active_support/version.rb b/activesupport/lib/active_support/version.rb index fe03984546..20b91ac911 100644 --- a/activesupport/lib/active_support/version.rb +++ b/activesupport/lib/active_support/version.rb @@ -1,4 +1,4 @@ -require_relative 'gem_version' +require_relative "gem_version" module ActiveSupport # Returns the version of the currently loaded ActiveSupport as a <tt>Gem::Version</tt> diff --git a/activesupport/lib/active_support/xml_mini.rb b/activesupport/lib/active_support/xml_mini.rb index df7b081993..921a3447d0 100644 --- a/activesupport/lib/active_support/xml_mini.rb +++ b/activesupport/lib/active_support/xml_mini.rb @@ -1,9 +1,9 @@ -require 'time' -require 'base64' -require 'bigdecimal' -require 'active_support/core_ext/module/delegation' -require 'active_support/core_ext/string/inflections' -require 'active_support/core_ext/date_time/calculations' +require "time" +require "base64" +require "bigdecimal" +require "active_support/core_ext/module/delegation" +require "active_support/core_ext/string/inflections" +require "active_support/core_ext/date_time/calculations" module ActiveSupport # = XmlMini @@ -20,11 +20,11 @@ module ActiveSupport attr_writer :original_filename, :content_type def original_filename - @original_filename || 'untitled' + @original_filename || "untitled" end def content_type - @content_type || 'application/octet-stream' + @content_type || "application/octet-stream" end end @@ -32,20 +32,25 @@ module ActiveSupport "binary" => "base64" } unless defined?(DEFAULT_ENCODINGS) - TYPE_NAMES = { - "Symbol" => "symbol", - "Fixnum" => "integer", - "Bignum" => "integer", - "BigDecimal" => "decimal", - "Float" => "float", - "TrueClass" => "boolean", - "FalseClass" => "boolean", - "Date" => "date", - "DateTime" => "dateTime", - "Time" => "dateTime", - "Array" => "array", - "Hash" => "hash" - } unless defined?(TYPE_NAMES) + unless defined?(TYPE_NAMES) + TYPE_NAMES = { + "Symbol" => "symbol", + "Integer" => "integer", + "BigDecimal" => "decimal", + "Float" => "float", + "TrueClass" => "boolean", + "FalseClass" => "boolean", + "Date" => "date", + "DateTime" => "dateTime", + "Time" => "dateTime", + "Array" => "array", + "Hash" => "hash" + } + + # No need to map these on Ruby 2.4+ + TYPE_NAMES["Fixnum"] = "integer" unless 0.class == Integer + TYPE_NAMES["Bignum"] = "integer" unless 0.class == Integer + end FORMATTING = { "symbol" => Proc.new { |symbol| symbol.to_s }, @@ -81,7 +86,7 @@ module ActiveSupport attr_accessor :depth self.depth = 100 - delegate :parse, :to => :backend + delegate :parse, to: :backend def backend current_thread_backend || @backend @@ -103,7 +108,7 @@ module ActiveSupport def to_tag(key, value, options) type_name = options.delete(:type) - merged_options = options.merge(:root => key, :skip_instruct => true) + merged_options = options.merge(root: key, skip_instruct: true) if value.is_a?(::Method) || value.is_a?(::Proc) if value.arity == 1 @@ -121,7 +126,7 @@ module ActiveSupport key = rename_key(key.to_s, options) - attributes = options[:skip_types] || type_name.nil? ? { } : { :type => type_name } + attributes = options[:skip_types] || type_name.nil? ? {} : { type: type_name } attributes[:nil] = true if value.nil? encoding = options[:encoding] || DEFAULT_ENCODINGS[type_name] @@ -146,29 +151,29 @@ module ActiveSupport protected - def _dasherize(key) - # $2 must be a non-greedy regex for this to work - left, middle, right = /\A(_*)(.*?)(_*)\Z/.match(key.strip)[1,3] - "#{left}#{middle.tr('_ ', '--')}#{right}" - end + def _dasherize(key) + # $2 must be a non-greedy regex for this to work + left, middle, right = /\A(_*)(.*?)(_*)\Z/.match(key.strip)[1,3] + "#{left}#{middle.tr('_ ', '--')}#{right}" + end - # TODO: Add support for other encodings - def _parse_binary(bin, entity) #:nodoc: - case entity['encoding'] - when 'base64' - ::Base64.decode64(bin) - else - bin + # TODO: Add support for other encodings + def _parse_binary(bin, entity) #:nodoc: + case entity["encoding"] + when "base64" + ::Base64.decode64(bin) + else + bin + end end - end - def _parse_file(file, entity) - f = StringIO.new(::Base64.decode64(file)) - f.extend(FileLike) - f.original_filename = entity['name'] - f.content_type = entity['content_type'] - f - end + def _parse_file(file, entity) + f = StringIO.new(::Base64.decode64(file)) + f.extend(FileLike) + f.original_filename = entity["name"] + f.content_type = entity["content_type"] + f + end private @@ -190,5 +195,5 @@ module ActiveSupport end end - XmlMini.backend = 'REXML' + XmlMini.backend = "REXML" end diff --git a/activesupport/lib/active_support/xml_mini/jdom.rb b/activesupport/lib/active_support/xml_mini/jdom.rb index 94751bbc04..10498c9be0 100644 --- a/activesupport/lib/active_support/xml_mini/jdom.rb +++ b/activesupport/lib/active_support/xml_mini/jdom.rb @@ -1,9 +1,9 @@ -raise "JRuby is required to use the JDOM backend for XmlMini" unless RUBY_PLATFORM =~ /java/ +raise "JRuby is required to use the JDOM backend for XmlMini" unless RUBY_PLATFORM.include?("java") -require 'jruby' +require "jruby" include Java -require 'active_support/core_ext/object/blank' +require "active_support/core_ext/object/blank" java_import javax.xml.parsers.DocumentBuilder unless defined? DocumentBuilder java_import javax.xml.parsers.DocumentBuilderFactory unless defined? DocumentBuilderFactory @@ -16,7 +16,7 @@ module ActiveSupport module XmlMini_JDOM #:nodoc: extend self - CONTENT_KEY = '__content__'.freeze + CONTENT_KEY = "__content__".freeze NODE_TYPE_NAMES = %w{ATTRIBUTE_NODE CDATA_SECTION_NODE COMMENT_NODE DOCUMENT_FRAGMENT_NODE DOCUMENT_NODE DOCUMENT_TYPE_NODE ELEMENT_NODE ENTITY_NODE ENTITY_REFERENCE_NODE NOTATION_NODE @@ -46,136 +46,136 @@ module ActiveSupport xml_string_reader = StringReader.new(data) xml_input_source = InputSource.new(xml_string_reader) doc = @dbf.new_document_builder.parse(xml_input_source) - merge_element!({CONTENT_KEY => ''}, doc.document_element, XmlMini.depth) + merge_element!({ CONTENT_KEY => "" }, doc.document_element, XmlMini.depth) end end private - # Convert an XML element and merge into the hash - # - # hash:: - # Hash to merge the converted element into. - # element:: - # XML element to merge into hash - def merge_element!(hash, element, depth) - raise 'Document too deep!' if depth == 0 - delete_empty(hash) - merge!(hash, element.tag_name, collapse(element, depth)) - end - - def delete_empty(hash) - hash.delete(CONTENT_KEY) if hash[CONTENT_KEY] == '' - end + # Convert an XML element and merge into the hash + # + # hash:: + # Hash to merge the converted element into. + # element:: + # XML element to merge into hash + def merge_element!(hash, element, depth) + raise "Document too deep!" if depth == 0 + delete_empty(hash) + merge!(hash, element.tag_name, collapse(element, depth)) + end - # Actually converts an XML document element into a data structure. - # - # element:: - # The document element to be collapsed. - def collapse(element, depth) - hash = get_attributes(element) + def delete_empty(hash) + hash.delete(CONTENT_KEY) if hash[CONTENT_KEY] == "" + end - child_nodes = element.child_nodes - if child_nodes.length > 0 - (0...child_nodes.length).each do |i| - child = child_nodes.item(i) - merge_element!(hash, child, depth - 1) unless child.node_type == Node.TEXT_NODE + # Actually converts an XML document element into a data structure. + # + # element:: + # The document element to be collapsed. + def collapse(element, depth) + hash = get_attributes(element) + + child_nodes = element.child_nodes + if child_nodes.length > 0 + (0...child_nodes.length).each do |i| + child = child_nodes.item(i) + merge_element!(hash, child, depth - 1) unless child.node_type == Node.TEXT_NODE + end + merge_texts!(hash, element) unless empty_content?(element) + hash + else + merge_texts!(hash, element) end - merge_texts!(hash, element) unless empty_content?(element) - hash - else - merge_texts!(hash, element) end - end - # Merge all the texts of an element into the hash - # - # hash:: - # Hash to add the converted element to. - # element:: - # XML element whose texts are to me merged into the hash - def merge_texts!(hash, element) - delete_empty(hash) - text_children = texts(element) - if text_children.join.empty? - hash - else - # must use value to prevent double-escaping - merge!(hash, CONTENT_KEY, text_children.join) + # Merge all the texts of an element into the hash + # + # hash:: + # Hash to add the converted element to. + # element:: + # XML element whose texts are to me merged into the hash + def merge_texts!(hash, element) + delete_empty(hash) + text_children = texts(element) + if text_children.join.empty? + hash + else + # must use value to prevent double-escaping + merge!(hash, CONTENT_KEY, text_children.join) + end end - end - # Adds a new key/value pair to an existing Hash. If the key to be added - # already exists and the existing value associated with key is not - # an Array, it will be wrapped in an Array. Then the new value is - # appended to that Array. - # - # hash:: - # Hash to add key/value pair to. - # key:: - # Key to be added. - # value:: - # Value to be associated with key. - def merge!(hash, key, value) - if hash.has_key?(key) - if hash[key].instance_of?(Array) - hash[key] << value + # Adds a new key/value pair to an existing Hash. If the key to be added + # already exists and the existing value associated with key is not + # an Array, it will be wrapped in an Array. Then the new value is + # appended to that Array. + # + # hash:: + # Hash to add key/value pair to. + # key:: + # Key to be added. + # value:: + # Value to be associated with key. + def merge!(hash, key, value) + if hash.has_key?(key) + if hash[key].instance_of?(Array) + hash[key] << value + else + hash[key] = [hash[key], value] + end + elsif value.instance_of?(Array) + hash[key] = [value] else - hash[key] = [hash[key], value] + hash[key] = value end - elsif value.instance_of?(Array) - hash[key] = [value] - else - hash[key] = value + hash end - hash - end - # Converts the attributes array of an XML element into a hash. - # Returns an empty Hash if node has no attributes. - # - # element:: - # XML element to extract attributes from. - def get_attributes(element) - attribute_hash = {} - attributes = element.attributes - (0...attributes.length).each do |i| - attribute_hash[CONTENT_KEY] ||= '' - attribute_hash[attributes.item(i).name] = attributes.item(i).value + # Converts the attributes array of an XML element into a hash. + # Returns an empty Hash if node has no attributes. + # + # element:: + # XML element to extract attributes from. + def get_attributes(element) + attribute_hash = {} + attributes = element.attributes + (0...attributes.length).each do |i| + attribute_hash[CONTENT_KEY] ||= "" + attribute_hash[attributes.item(i).name] = attributes.item(i).value + end + attribute_hash end - attribute_hash - end - # Determines if a document element has text content - # - # element:: - # XML element to be checked. - def texts(element) - texts = [] - child_nodes = element.child_nodes - (0...child_nodes.length).each do |i| - item = child_nodes.item(i) - if item.node_type == Node.TEXT_NODE - texts << item.get_data + # Determines if a document element has text content + # + # element:: + # XML element to be checked. + def texts(element) + texts = [] + child_nodes = element.child_nodes + (0...child_nodes.length).each do |i| + item = child_nodes.item(i) + if item.node_type == Node.TEXT_NODE + texts << item.get_data + end end + texts end - texts - end - # Determines if a document element has text content - # - # element:: - # XML element to be checked. - def empty_content?(element) - text = '' - child_nodes = element.child_nodes - (0...child_nodes.length).each do |i| - item = child_nodes.item(i) - if item.node_type == Node.TEXT_NODE - text << item.get_data.strip + # Determines if a document element has text content + # + # element:: + # XML element to be checked. + def empty_content?(element) + text = "" + child_nodes = element.child_nodes + (0...child_nodes.length).each do |i| + item = child_nodes.item(i) + if item.node_type == Node.TEXT_NODE + text << item.get_data.strip + end end + text.strip.length == 0 end - text.strip.length == 0 - end end end diff --git a/activesupport/lib/active_support/xml_mini/libxml.rb b/activesupport/lib/active_support/xml_mini/libxml.rb index bb0ea9c582..8a4aa03963 100644 --- a/activesupport/lib/active_support/xml_mini/libxml.rb +++ b/activesupport/lib/active_support/xml_mini/libxml.rb @@ -1,6 +1,6 @@ -require 'libxml' -require 'active_support/core_ext/object/blank' -require 'stringio' +require "libxml" +require "active_support/core_ext/object/blank" +require "stringio" module ActiveSupport module XmlMini_LibXML #:nodoc: @@ -11,7 +11,7 @@ module ActiveSupport # XML Document string or IO to parse def parse(data) if !data.respond_to?(:read) - data = StringIO.new(data || '') + data = StringIO.new(data || "") end char = data.getc @@ -22,7 +22,6 @@ module ActiveSupport LibXML::XML::Parser.io(data).parse.to_hash end end - end end @@ -35,7 +34,7 @@ module LibXML #:nodoc: end module Node #:nodoc: - CONTENT_ROOT = '__content__'.freeze + CONTENT_ROOT = "__content__".freeze # Convert XML document to hash. # @@ -46,9 +45,9 @@ module LibXML #:nodoc: # Insert node hash into parent hash correctly. case hash[name] - when Array then hash[name] << node_hash - when Hash then hash[name] = [hash[name], node_hash] - when nil then hash[name] = node_hash + when Array then hash[name] << node_hash + when Hash then hash[name] = [hash[name], node_hash] + when nil then hash[name] = node_hash end # Handle child elements @@ -56,7 +55,7 @@ module LibXML #:nodoc: if c.element? c.to_hash(node_hash) elsif c.text? || c.cdata? - node_hash[CONTENT_ROOT] ||= '' + node_hash[CONTENT_ROOT] ||= "" node_hash[CONTENT_ROOT] << c.content end end diff --git a/activesupport/lib/active_support/xml_mini/libxmlsax.rb b/activesupport/lib/active_support/xml_mini/libxmlsax.rb index 70a95299ec..4edb0bd2b1 100644 --- a/activesupport/lib/active_support/xml_mini/libxmlsax.rb +++ b/activesupport/lib/active_support/xml_mini/libxmlsax.rb @@ -1,6 +1,6 @@ -require 'libxml' -require 'active_support/core_ext/object/blank' -require 'stringio' +require "libxml" +require "active_support/core_ext/object/blank" +require "stringio" module ActiveSupport module XmlMini_LibXMLSAX #:nodoc: @@ -9,11 +9,10 @@ module ActiveSupport # Class that will build the hash while the XML document # is being parsed using SAX events. class HashBuilder - include LibXML::XML::SaxParser::Callbacks - CONTENT_KEY = '__content__'.freeze - HASH_SIZE_KEY = '__hash_size__'.freeze + CONTENT_KEY = "__content__".freeze + HASH_SIZE_KEY = "__hash_size__".freeze attr_reader :hash @@ -22,7 +21,7 @@ module ActiveSupport end def on_start_document - @hash = { CONTENT_KEY => '' } + @hash = { CONTENT_KEY => "" } @hash_stack = [@hash] end @@ -32,20 +31,20 @@ module ActiveSupport end def on_start_element(name, attrs = {}) - new_hash = { CONTENT_KEY => '' }.merge!(attrs) + new_hash = { CONTENT_KEY => "" }.merge!(attrs) new_hash[HASH_SIZE_KEY] = new_hash.size + 1 case current_hash[name] - when Array then current_hash[name] << new_hash - when Hash then current_hash[name] = [current_hash[name], new_hash] - when nil then current_hash[name] = new_hash + when Array then current_hash[name] << new_hash + when Hash then current_hash[name] = [current_hash[name], new_hash] + when nil then current_hash[name] = new_hash end @hash_stack.push(new_hash) end def on_end_element(name) - if current_hash.length > current_hash.delete(HASH_SIZE_KEY) && current_hash[CONTENT_KEY].blank? || current_hash[CONTENT_KEY] == '' + if current_hash.length > current_hash.delete(HASH_SIZE_KEY) && current_hash[CONTENT_KEY].blank? || current_hash[CONTENT_KEY] == "" current_hash.delete(CONTENT_KEY) end @hash_stack.pop @@ -63,7 +62,7 @@ module ActiveSupport def parse(data) if !data.respond_to?(:read) - data = StringIO.new(data || '') + data = StringIO.new(data || "") end char = data.getc diff --git a/activesupport/lib/active_support/xml_mini/nokogiri.rb b/activesupport/lib/active_support/xml_mini/nokogiri.rb index 619cc7522d..b92fa7ea7c 100644 --- a/activesupport/lib/active_support/xml_mini/nokogiri.rb +++ b/activesupport/lib/active_support/xml_mini/nokogiri.rb @@ -1,11 +1,11 @@ begin - require 'nokogiri' + require "nokogiri" rescue LoadError => e $stderr.puts "You don't have nokogiri installed in your application. Please add it to your Gemfile and run bundle install" raise e end -require 'active_support/core_ext/object/blank' -require 'stringio' +require "active_support/core_ext/object/blank" +require "stringio" module ActiveSupport module XmlMini_Nokogiri #:nodoc: @@ -16,7 +16,7 @@ module ActiveSupport # XML Document string or IO to parse def parse(data) if !data.respond_to?(:read) - data = StringIO.new(data || '') + data = StringIO.new(data || "") end char = data.getc @@ -38,7 +38,7 @@ module ActiveSupport end module Node #:nodoc: - CONTENT_ROOT = '__content__'.freeze + CONTENT_ROOT = "__content__".freeze # Convert XML document to hash. # @@ -49,9 +49,9 @@ module ActiveSupport # Insert node hash into parent hash correctly. case hash[name] - when Array then hash[name] << node_hash - when Hash then hash[name] = [hash[name], node_hash] - when nil then hash[name] = node_hash + when Array then hash[name] << node_hash + when Hash then hash[name] = [hash[name], node_hash] + when nil then hash[name] = node_hash end # Handle child elements @@ -59,7 +59,7 @@ module ActiveSupport if c.element? c.to_hash(node_hash) elsif c.text? || c.cdata? - node_hash[CONTENT_ROOT] ||= '' + node_hash[CONTENT_ROOT] ||= "" node_hash[CONTENT_ROOT] << c.content end end diff --git a/activesupport/lib/active_support/xml_mini/nokogirisax.rb b/activesupport/lib/active_support/xml_mini/nokogirisax.rb index be2d6a4cb1..b8b85146c5 100644 --- a/activesupport/lib/active_support/xml_mini/nokogirisax.rb +++ b/activesupport/lib/active_support/xml_mini/nokogirisax.rb @@ -1,11 +1,11 @@ begin - require 'nokogiri' + require "nokogiri" rescue LoadError => e $stderr.puts "You don't have nokogiri installed in your application. Please add it to your Gemfile and run bundle install" raise e end -require 'active_support/core_ext/object/blank' -require 'stringio' +require "active_support/core_ext/object/blank" +require "stringio" module ActiveSupport module XmlMini_NokogiriSAX #:nodoc: @@ -14,9 +14,8 @@ module ActiveSupport # Class that will build the hash while the XML document # is being parsed using SAX events. class HashBuilder < Nokogiri::XML::SAX::Document - - CONTENT_KEY = '__content__'.freeze - HASH_SIZE_KEY = '__hash_size__'.freeze + CONTENT_KEY = "__content__".freeze + HASH_SIZE_KEY = "__hash_size__".freeze attr_reader :hash @@ -38,20 +37,20 @@ module ActiveSupport end def start_element(name, attrs = []) - new_hash = { CONTENT_KEY => '' }.merge!(Hash[attrs]) + new_hash = { CONTENT_KEY => "" }.merge!(Hash[attrs]) new_hash[HASH_SIZE_KEY] = new_hash.size + 1 case current_hash[name] - when Array then current_hash[name] << new_hash - when Hash then current_hash[name] = [current_hash[name], new_hash] - when nil then current_hash[name] = new_hash + when Array then current_hash[name] << new_hash + when Hash then current_hash[name] = [current_hash[name], new_hash] + when nil then current_hash[name] = new_hash end @hash_stack.push(new_hash) end def end_element(name) - if current_hash.length > current_hash.delete(HASH_SIZE_KEY) && current_hash[CONTENT_KEY].blank? || current_hash[CONTENT_KEY] == '' + if current_hash.length > current_hash.delete(HASH_SIZE_KEY) && current_hash[CONTENT_KEY].blank? || current_hash[CONTENT_KEY] == "" current_hash.delete(CONTENT_KEY) end @hash_stack.pop @@ -69,7 +68,7 @@ module ActiveSupport def parse(data) if !data.respond_to?(:read) - data = StringIO.new(data || '') + data = StringIO.new(data || "") end char = data.getc diff --git a/activesupport/lib/active_support/xml_mini/rexml.rb b/activesupport/lib/active_support/xml_mini/rexml.rb index 924ed72345..091a15294c 100644 --- a/activesupport/lib/active_support/xml_mini/rexml.rb +++ b/activesupport/lib/active_support/xml_mini/rexml.rb @@ -1,12 +1,12 @@ -require 'active_support/core_ext/kernel/reporting' -require 'active_support/core_ext/object/blank' -require 'stringio' +require "active_support/core_ext/kernel/reporting" +require "active_support/core_ext/object/blank" +require "stringio" module ActiveSupport module XmlMini_REXML #:nodoc: extend self - CONTENT_KEY = '__content__'.freeze + CONTENT_KEY = "__content__".freeze # Parse an XML Document string or IO into a simple hash. # @@ -17,15 +17,13 @@ module ActiveSupport # XML Document string or IO to parse def parse(data) if !data.respond_to?(:read) - data = StringIO.new(data || '') + data = StringIO.new(data || "") end - char = data.getc - if char.nil? + if data.eof? {} else - data.ungetc(char) - silence_warnings { require 'rexml/document' } unless defined?(REXML::Document) + silence_warnings { require "rexml/document" } unless defined?(REXML::Document) doc = REXML::Document.new(data) if doc.root @@ -57,7 +55,7 @@ module ActiveSupport hash = get_attributes(element) if element.has_elements? - element.each_element {|child| merge_element!(hash, child, depth - 1) } + element.each_element { |child| merge_element!(hash, child, depth - 1) } merge_texts!(hash, element) unless empty_content?(element) hash else @@ -76,7 +74,7 @@ module ActiveSupport hash else # must use value to prevent double-escaping - texts = '' + texts = "" element.texts.each { |t| texts << t.value } merge!(hash, CONTENT_KEY, texts) end diff --git a/activesupport/test/abstract_unit.rb b/activesupport/test/abstract_unit.rb index c0e23e89f7..4e564591b4 100644 --- a/activesupport/test/abstract_unit.rb +++ b/activesupport/test/abstract_unit.rb @@ -1,40 +1,36 @@ ORIG_ARGV = ARGV.dup -begin - old, $VERBOSE = $VERBOSE, nil - require File.expand_path('../../../load_paths', __FILE__) -ensure - $VERBOSE = old -end - -require 'active_support/core_ext/kernel/reporting' +require "active_support/core_ext/kernel/reporting" silence_warnings do Encoding.default_internal = "UTF-8" Encoding.default_external = "UTF-8" end -require 'active_support/testing/autorun' -require 'active_support/testing/method_call_assertions' +require "active_support/testing/autorun" +require "active_support/testing/method_call_assertions" -ENV['NO_RELOAD'] = '1' -require 'active_support' +ENV["NO_RELOAD"] = "1" +require "active_support" Thread.abort_on_exception = true # Show backtraces for deprecated behavior for quicker cleanup. ActiveSupport::Deprecation.debug = true +# Default to old to_time behavior but allow running tests with new behavior +ActiveSupport.to_time_preserves_timezone = ENV["PRESERVE_TIMEZONES"] == "1" + # Disable available locale checks to avoid warnings running the test suite. I18n.enforce_available_locales = false # Skips the current run on Rubinius using Minitest::Assertions#skip -def rubinius_skip(message = '') - skip message if RUBY_ENGINE == 'rbx' +def rubinius_skip(message = "") + skip message if RUBY_ENGINE == "rbx" end # Skips the current run on JRuby using Minitest::Assertions#skip -def jruby_skip(message = '') +def jruby_skip(message = "") skip message if defined?(JRUBY_VERSION) end diff --git a/activesupport/test/array_inquirer_test.rb b/activesupport/test/array_inquirer_test.rb index 263ab3802b..4d3f5b001c 100644 --- a/activesupport/test/array_inquirer_test.rb +++ b/activesupport/test/array_inquirer_test.rb @@ -1,9 +1,9 @@ -require 'abstract_unit' -require 'active_support/core_ext/array' +require "abstract_unit" +require "active_support/core_ext/array" class ArrayInquirerTest < ActiveSupport::TestCase def setup - @array_inquirer = ActiveSupport::ArrayInquirer.new([:mobile, :tablet, 'api']) + @array_inquirer = ActiveSupport::ArrayInquirer.new([:mobile, :tablet, "api"]) end def test_individual @@ -19,7 +19,7 @@ class ArrayInquirerTest < ActiveSupport::TestCase end def test_any_string_symbol_mismatch - assert @array_inquirer.any?('mobile') + assert @array_inquirer.any?("mobile") assert @array_inquirer.any?(:api) end @@ -33,7 +33,7 @@ class ArrayInquirerTest < ActiveSupport::TestCase end def test_inquiry - result = [:mobile, :tablet, 'api'].inquiry + result = [:mobile, :tablet, "api"].inquiry assert_instance_of ActiveSupport::ArrayInquirer, result assert_equal @array_inquirer, result diff --git a/activesupport/test/autoload_test.rb b/activesupport/test/autoload_test.rb index c18b007612..6c8aa3e055 100644 --- a/activesupport/test/autoload_test.rb +++ b/activesupport/test/autoload_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" class TestAutoloadModule < ActiveSupport::TestCase include ActiveSupport::Testing::Isolation @@ -31,7 +31,7 @@ class TestAutoloadModule < ActiveSupport::TestCase end end - assert !$LOADED_FEATURES.include?(@some_class_path) + assert_not_includes $LOADED_FEATURES, @some_class_path assert_nothing_raised { ::Fixtures::Autoload::SomeClass } end @@ -40,7 +40,7 @@ class TestAutoloadModule < ActiveSupport::TestCase autoload :SomeClass end - assert !$LOADED_FEATURES.include?(@some_class_path) + assert_not_includes $LOADED_FEATURES, @some_class_path assert_nothing_raised { ::Fixtures::Autoload::SomeClass } end @@ -51,9 +51,9 @@ class TestAutoloadModule < ActiveSupport::TestCase end end - assert !$LOADED_FEATURES.include?(@some_class_path) + assert_not_includes $LOADED_FEATURES, @some_class_path ::Fixtures::Autoload.eager_load! - assert $LOADED_FEATURES.include?(@some_class_path) + assert_includes $LOADED_FEATURES, @some_class_path assert_nothing_raised { ::Fixtures::Autoload::SomeClass } end @@ -64,7 +64,7 @@ class TestAutoloadModule < ActiveSupport::TestCase end end - assert !$LOADED_FEATURES.include?(@another_class_path) + assert_not_includes $LOADED_FEATURES, @another_class_path assert_nothing_raised { ::Fixtures::AnotherClass } end @@ -75,7 +75,7 @@ class TestAutoloadModule < ActiveSupport::TestCase end end - assert !$LOADED_FEATURES.include?(@another_class_path) + assert_not_includes $LOADED_FEATURES, @another_class_path assert_nothing_raised { ::Fixtures::AnotherClass } end -end
\ No newline at end of file +end diff --git a/activesupport/test/autoloading_fixtures/a/b.rb b/activesupport/test/autoloading_fixtures/a/b.rb index 9c9e6454cf..0dbbbbd181 100644 --- a/activesupport/test/autoloading_fixtures/a/b.rb +++ b/activesupport/test/autoloading_fixtures/a/b.rb @@ -1,2 +1,2 @@ class A::B -end
\ No newline at end of file +end diff --git a/activesupport/test/autoloading_fixtures/a/c/d.rb b/activesupport/test/autoloading_fixtures/a/c/d.rb index 0f40d6fbc4..2c0ec5f182 100644 --- a/activesupport/test/autoloading_fixtures/a/c/d.rb +++ b/activesupport/test/autoloading_fixtures/a/c/d.rb @@ -1,2 +1,2 @@ class A::C::D -end
\ No newline at end of file +end diff --git a/activesupport/test/autoloading_fixtures/a/c/em/f.rb b/activesupport/test/autoloading_fixtures/a/c/em/f.rb index 8b28e19148..3ff1b7efa0 100644 --- a/activesupport/test/autoloading_fixtures/a/c/em/f.rb +++ b/activesupport/test/autoloading_fixtures/a/c/em/f.rb @@ -1,2 +1,2 @@ class A::C::EM::F -end
\ No newline at end of file +end diff --git a/activesupport/test/autoloading_fixtures/class_folder.rb b/activesupport/test/autoloading_fixtures/class_folder.rb index ad2b27be61..6ee8182214 100644 --- a/activesupport/test/autoloading_fixtures/class_folder.rb +++ b/activesupport/test/autoloading_fixtures/class_folder.rb @@ -1,3 +1,3 @@ class ClassFolder - ConstantInClassFolder = 'indeed' + ConstantInClassFolder = "indeed" end diff --git a/activesupport/test/autoloading_fixtures/class_folder/class_folder_subclass.rb b/activesupport/test/autoloading_fixtures/class_folder/class_folder_subclass.rb index 402609c583..4df069cab6 100644 --- a/activesupport/test/autoloading_fixtures/class_folder/class_folder_subclass.rb +++ b/activesupport/test/autoloading_fixtures/class_folder/class_folder_subclass.rb @@ -1,3 +1,3 @@ class ClassFolder::ClassFolderSubclass < ClassFolder - ConstantInClassFolder = 'indeed' + ConstantInClassFolder = "indeed" end diff --git a/activesupport/test/autoloading_fixtures/conflict.rb b/activesupport/test/autoloading_fixtures/conflict.rb index 4ac6201902..d7f42b5d5f 100644 --- a/activesupport/test/autoloading_fixtures/conflict.rb +++ b/activesupport/test/autoloading_fixtures/conflict.rb @@ -1 +1 @@ -Conflict = 2
\ No newline at end of file +Conflict = 2 diff --git a/activesupport/test/autoloading_fixtures/cross_site_dependency.rb b/activesupport/test/autoloading_fixtures/cross_site_dependency.rb index 21ee554e92..de941bf271 100644 --- a/activesupport/test/autoloading_fixtures/cross_site_dependency.rb +++ b/activesupport/test/autoloading_fixtures/cross_site_dependency.rb @@ -1,2 +1,2 @@ class CrossSiteDependency -end
\ No newline at end of file +end diff --git a/activesupport/test/autoloading_fixtures/d.rb b/activesupport/test/autoloading_fixtures/d.rb index 45c794d4ca..52850e1e1a 100644 --- a/activesupport/test/autoloading_fixtures/d.rb +++ b/activesupport/test/autoloading_fixtures/d.rb @@ -1,2 +1,2 @@ class D -end
\ No newline at end of file +end diff --git a/activesupport/test/autoloading_fixtures/em.rb b/activesupport/test/autoloading_fixtures/em.rb index 16a1838667..e47024999e 100644 --- a/activesupport/test/autoloading_fixtures/em.rb +++ b/activesupport/test/autoloading_fixtures/em.rb @@ -1,2 +1,2 @@ class EM -end
\ No newline at end of file +end diff --git a/activesupport/test/autoloading_fixtures/load_path/loaded_constant.rb b/activesupport/test/autoloading_fixtures/load_path/loaded_constant.rb index e3d1218c96..d2c4f6b0c5 100644 --- a/activesupport/test/autoloading_fixtures/load_path/loaded_constant.rb +++ b/activesupport/test/autoloading_fixtures/load_path/loaded_constant.rb @@ -1,3 +1,2 @@ module LoadedConstant end - diff --git a/activesupport/test/autoloading_fixtures/module_folder/nested_sibling.rb b/activesupport/test/autoloading_fixtures/module_folder/nested_sibling.rb index 80244b8bab..04c426833e 100644 --- a/activesupport/test/autoloading_fixtures/module_folder/nested_sibling.rb +++ b/activesupport/test/autoloading_fixtures/module_folder/nested_sibling.rb @@ -1,2 +1,2 @@ class ModuleFolder::NestedSibling -end
\ No newline at end of file +end diff --git a/activesupport/test/autoloading_fixtures/module_with_custom_const_missing/a/b.rb b/activesupport/test/autoloading_fixtures/module_with_custom_const_missing/a/b.rb index d12d02f3aa..4f2020c503 100644 --- a/activesupport/test/autoloading_fixtures/module_with_custom_const_missing/a/b.rb +++ b/activesupport/test/autoloading_fixtures/module_with_custom_const_missing/a/b.rb @@ -1 +1 @@ -ModuleWithCustomConstMissing::A::B = "10"
\ No newline at end of file +ModuleWithCustomConstMissing::A::B = "10" diff --git a/activesupport/test/autoloading_fixtures/raises_arbitrary_exception.rb b/activesupport/test/autoloading_fixtures/raises_arbitrary_exception.rb new file mode 100644 index 0000000000..829ee917d2 --- /dev/null +++ b/activesupport/test/autoloading_fixtures/raises_arbitrary_exception.rb @@ -0,0 +1,4 @@ +RaisesArbitraryException = 1 +_ = A::B # Autoloading recursion, also expected to be watched and discarded. + +raise Exception, "arbitray exception message" diff --git a/activesupport/test/autoloading_fixtures/requires_constant.rb b/activesupport/test/autoloading_fixtures/requires_constant.rb index 14804a0de0..f04dcc4091 100644 --- a/activesupport/test/autoloading_fixtures/requires_constant.rb +++ b/activesupport/test/autoloading_fixtures/requires_constant.rb @@ -2,4 +2,3 @@ require "loaded_constant" module RequiresConstant end - diff --git a/activesupport/test/autoloading_fixtures/throws.rb b/activesupport/test/autoloading_fixtures/throws.rb new file mode 100644 index 0000000000..e1d96cc512 --- /dev/null +++ b/activesupport/test/autoloading_fixtures/throws.rb @@ -0,0 +1,4 @@ +Throws = 1 +_ = A::B # Autoloading recursion, expected to be discarded. + +throw :t diff --git a/activesupport/test/autoloading_fixtures/typo.rb b/activesupport/test/autoloading_fixtures/typo.rb index 8e047f5fd4..0ffe07c2b3 100644 --- a/activesupport/test/autoloading_fixtures/typo.rb +++ b/activesupport/test/autoloading_fixtures/typo.rb @@ -1,2 +1 @@ TypO = 1 - diff --git a/activesupport/test/benchmarkable_test.rb b/activesupport/test/benchmarkable_test.rb index 04d4f5e503..210b9cb9fd 100644 --- a/activesupport/test/benchmarkable_test.rb +++ b/activesupport/test/benchmarkable_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" class BenchmarkableTest < ActiveSupport::TestCase include ActiveSupport::Benchmarkable @@ -36,27 +36,41 @@ class BenchmarkableTest < ActiveSupport::TestCase def test_with_message i_was_run = false - benchmark('test_run') { i_was_run = true } + benchmark("test_run") { i_was_run = true } assert i_was_run - assert_last_logged 'test_run' + assert_last_logged "test_run" + end + + def test_with_silence + assert_difference "buffer.count", +2 do + benchmark("test_run") do + logger.info "SOMETHING" + end + end + + assert_difference "buffer.count", +1 do + benchmark("test_run", silence: true) do + logger.info "NOTHING" + end + end end def test_within_level logger.level = ActiveSupport::Logger::DEBUG - benchmark('included_debug_run', :level => :debug) { } - assert_last_logged 'included_debug_run' + benchmark("included_debug_run", level: :debug) {} + assert_last_logged "included_debug_run" end def test_outside_level logger.level = ActiveSupport::Logger::ERROR - benchmark('skipped_debug_run', :level => :debug) { } + benchmark("skipped_debug_run", level: :debug) {} assert_no_match(/skipped_debug_run/, buffer.last) ensure logger.level = ActiveSupport::Logger::DEBUG end private - def assert_last_logged(message = 'Benchmarking') + def assert_last_logged(message = "Benchmarking") assert_match(/^#{message} \(.*\)$/, buffer.last) end end diff --git a/activesupport/test/broadcast_logger_test.rb b/activesupport/test/broadcast_logger_test.rb index 6d4e3b74f7..4b74f1313e 100644 --- a/activesupport/test/broadcast_logger_test.rb +++ b/activesupport/test/broadcast_logger_test.rb @@ -1,77 +1,149 @@ -require 'abstract_unit' +require "abstract_unit" module ActiveSupport class BroadcastLoggerTest < TestCase attr_reader :logger, :log1, :log2 - def setup + + setup do @log1 = FakeLogger.new @log2 = FakeLogger.new @log1.extend Logger.broadcast @log2 @logger = @log1 end - def test_debug - logger.debug "foo" - assert_equal 'foo', log1.adds.first[2] - assert_equal 'foo', log2.adds.first[2] + Logger::Severity.constants.each do |level_name| + method = level_name.downcase + level = Logger::Severity.const_get(level_name) + + test "##{method} adds the message to all loggers" do + logger.send(method, "msg") + + assert_equal [level, "msg", nil], log1.adds.first + assert_equal [level, "msg", nil], log2.adds.first + end end - def test_close + test "#close broadcasts to all loggers" do logger.close - assert log1.closed, 'should be closed' - assert log2.closed, 'should be closed' + + assert log1.closed, "should be closed" + assert log2.closed, "should be closed" end - def test_chevrons + test "#<< shovels the value into all loggers" do logger << "foo" + assert_equal %w{ foo }, log1.chevrons assert_equal %w{ foo }, log2.chevrons end - def test_level - assert_nil logger.level - logger.level = 10 - assert_equal 10, log1.level - assert_equal 10, log2.level + test "#level= assigns the level to all loggers" do + assert_equal ::Logger::DEBUG, logger.level + logger.level = ::Logger::FATAL + + assert_equal ::Logger::FATAL, log1.level + assert_equal ::Logger::FATAL, log2.level end - def test_progname + test "#progname= assigns to all the loggers" do assert_nil logger.progname - logger.progname = 10 - assert_equal 10, log1.progname - assert_equal 10, log2.progname + logger.progname = ::Logger::FATAL + + assert_equal ::Logger::FATAL, log1.progname + assert_equal ::Logger::FATAL, log2.progname end - def test_formatter + test "#formatter= assigns to all the loggers" do assert_nil logger.formatter - logger.formatter = 10 - assert_equal 10, log1.formatter - assert_equal 10, log2.formatter + logger.formatter = ::Logger::FATAL + + assert_equal ::Logger::FATAL, log1.formatter + assert_equal ::Logger::FATAL, log2.formatter + end + + test "#local_level= assigns the local_level to all loggers" do + assert_equal ::Logger::DEBUG, logger.local_level + logger.local_level = ::Logger::FATAL + + assert_equal ::Logger::FATAL, log1.local_level + assert_equal ::Logger::FATAL, log2.local_level + end + + test "#silence silences all loggers below the default level of ERROR" do + logger.silence do + logger.debug "test" + end + + assert_equal [], log1.adds + assert_equal [], log2.adds + end + + test "#silence does not silence at or above ERROR" do + logger.silence do + logger.error "from error" + logger.unknown "from unknown" + end + + assert_equal [[::Logger::ERROR, "from error", nil], [::Logger::UNKNOWN, "from unknown", nil]], log1.adds + assert_equal [[::Logger::ERROR, "from error", nil], [::Logger::UNKNOWN, "from unknown", nil]], log2.adds + end + + test "#silence allows you to override the silence level" do + logger.silence(::Logger::FATAL) do + logger.error "unseen" + logger.fatal "seen" + end + + assert_equal [[::Logger::FATAL, "seen", nil]], log1.adds + assert_equal [[::Logger::FATAL, "seen", nil]], log2.adds end class FakeLogger + include LoggerSilence + attr_reader :adds, :closed, :chevrons - attr_accessor :level, :progname, :formatter + attr_accessor :level, :progname, :formatter, :local_level def initialize - @adds = [] - @closed = false - @chevrons = [] - @level = nil - @progname = nil - @formatter = nil + @adds = [] + @closed = false + @chevrons = [] + @level = ::Logger::DEBUG + @local_level = ::Logger::DEBUG + @progname = nil + @formatter = nil + end + + def debug(message, &block) + add(::Logger::DEBUG, message, &block) + end + + def info(message, &block) + add(::Logger::INFO, message, &block) + end + + def warn(message, &block) + add(::Logger::WARN, message, &block) + end + + def error(message, &block) + add(::Logger::ERROR, message, &block) + end + + def fatal(message, &block) + add(::Logger::FATAL, message, &block) end - def debug msg, &block - add(:omg, nil, msg, &block) + def unknown(message, &block) + add(::Logger::UNKNOWN, message, &block) end - def << x + def <<(x) @chevrons << x end - def add(*args) - @adds << args + def add(message_level, message=nil, progname=nil, &block) + @adds << [message_level, message, progname] if message_level >= local_level end def close diff --git a/activesupport/test/caching_test.rb b/activesupport/test/caching_test.rb index 4a299429f3..0df4173a1a 100644 --- a/activesupport/test/caching_test.rb +++ b/activesupport/test/caching_test.rb @@ -1,7 +1,9 @@ -require 'logger' -require 'abstract_unit' -require 'active_support/cache' -require 'dependencies_test_helpers' +require "logger" +require "abstract_unit" +require "active_support/cache" +require "dependencies_test_helpers" + +require "pathname" module ActiveSupport module Cache @@ -11,23 +13,35 @@ module ActiveSupport def test_local_cache_cleared_on_close key = "super awesome key" assert_nil LocalCacheRegistry.cache_for key - middleware = Middleware.new('<3', key).new(->(env) { - assert LocalCacheRegistry.cache_for(key), 'should have a cache' + middleware = Middleware.new("<3", key).new(->(env) { + assert LocalCacheRegistry.cache_for(key), "should have a cache" [200, {}, []] }) _, _, body = middleware.call({}) - assert LocalCacheRegistry.cache_for(key), 'should still have a cache' - body.each { } - assert LocalCacheRegistry.cache_for(key), 'should still have a cache' + assert LocalCacheRegistry.cache_for(key), "should still have a cache" + body.each {} + assert LocalCacheRegistry.cache_for(key), "should still have a cache" body.close assert_nil LocalCacheRegistry.cache_for(key) end + def test_local_cache_cleared_and_response_should_be_present_on_invalid_parameters_error + key = "super awesome key" + assert_nil LocalCacheRegistry.cache_for key + middleware = Middleware.new("<3", key).new(->(env) { + assert LocalCacheRegistry.cache_for(key), "should have a cache" + raise Rack::Utils::InvalidParameterError + }) + response = middleware.call({}) + assert response, "response should exist" + assert_nil LocalCacheRegistry.cache_for(key) + end + def test_local_cache_cleared_on_exception key = "super awesome key" assert_nil LocalCacheRegistry.cache_for key - middleware = Middleware.new('<3', key).new(->(env) { - assert LocalCacheRegistry.cache_for(key), 'should have a cache' + middleware = Middleware.new("<3", key).new(->(env) { + assert LocalCacheRegistry.cache_for(key), "should have a cache" raise }) assert_raises(RuntimeError) { middleware.call({}) } @@ -50,82 +64,92 @@ class CacheKeyTest < ActiveSupport::TestCase end end - entry = legacy.new 'foo' - assert_equal 'foo', entry.value + entry = legacy.new "foo" + assert_equal "foo", entry.value end def test_expand_cache_key - assert_equal '1/2/true', ActiveSupport::Cache.expand_cache_key([1, '2', true]) - assert_equal 'name/1/2/true', ActiveSupport::Cache.expand_cache_key([1, '2', true], :name) + assert_equal "1/2/true", ActiveSupport::Cache.expand_cache_key([1, "2", true]) + assert_equal "name/1/2/true", ActiveSupport::Cache.expand_cache_key([1, "2", true], :name) end def test_expand_cache_key_with_rails_cache_id - with_env('RAILS_CACHE_ID' => 'c99') do - assert_equal 'c99/foo', ActiveSupport::Cache.expand_cache_key(:foo) - assert_equal 'c99/foo', ActiveSupport::Cache.expand_cache_key([:foo]) - assert_equal 'c99/foo/bar', ActiveSupport::Cache.expand_cache_key([:foo, :bar]) - assert_equal 'nm/c99/foo', ActiveSupport::Cache.expand_cache_key(:foo, :nm) - assert_equal 'nm/c99/foo', ActiveSupport::Cache.expand_cache_key([:foo], :nm) - assert_equal 'nm/c99/foo/bar', ActiveSupport::Cache.expand_cache_key([:foo, :bar], :nm) + with_env("RAILS_CACHE_ID" => "c99") do + assert_equal "c99/foo", ActiveSupport::Cache.expand_cache_key(:foo) + assert_equal "c99/foo", ActiveSupport::Cache.expand_cache_key([:foo]) + assert_equal "c99/foo/bar", ActiveSupport::Cache.expand_cache_key([:foo, :bar]) + assert_equal "nm/c99/foo", ActiveSupport::Cache.expand_cache_key(:foo, :nm) + assert_equal "nm/c99/foo", ActiveSupport::Cache.expand_cache_key([:foo], :nm) + assert_equal "nm/c99/foo/bar", ActiveSupport::Cache.expand_cache_key([:foo, :bar], :nm) end end def test_expand_cache_key_with_rails_app_version - with_env('RAILS_APP_VERSION' => 'rails3') do - assert_equal 'rails3/foo', ActiveSupport::Cache.expand_cache_key(:foo) + with_env("RAILS_APP_VERSION" => "rails3") do + assert_equal "rails3/foo", ActiveSupport::Cache.expand_cache_key(:foo) end end def test_expand_cache_key_rails_cache_id_should_win_over_rails_app_version - with_env('RAILS_CACHE_ID' => 'c99', 'RAILS_APP_VERSION' => 'rails3') do - assert_equal 'c99/foo', ActiveSupport::Cache.expand_cache_key(:foo) + with_env("RAILS_CACHE_ID" => "c99", "RAILS_APP_VERSION" => "rails3") do + assert_equal "c99/foo", ActiveSupport::Cache.expand_cache_key(:foo) end end def test_expand_cache_key_respond_to_cache_key - key = 'foo' + key = "foo" def key.cache_key :foo_key end - assert_equal 'foo_key', ActiveSupport::Cache.expand_cache_key(key) + assert_equal "foo_key", ActiveSupport::Cache.expand_cache_key(key) end def test_expand_cache_key_array_with_something_that_responds_to_cache_key - key = 'foo' + key = "foo" def key.cache_key :foo_key end - assert_equal 'foo_key', ActiveSupport::Cache.expand_cache_key([key]) + assert_equal "foo_key", ActiveSupport::Cache.expand_cache_key([key]) end def test_expand_cache_key_of_nil - assert_equal '', ActiveSupport::Cache.expand_cache_key(nil) + assert_equal "", ActiveSupport::Cache.expand_cache_key(nil) end def test_expand_cache_key_of_false - assert_equal 'false', ActiveSupport::Cache.expand_cache_key(false) + assert_equal "false", ActiveSupport::Cache.expand_cache_key(false) end def test_expand_cache_key_of_true - assert_equal 'true', ActiveSupport::Cache.expand_cache_key(true) + assert_equal "true", ActiveSupport::Cache.expand_cache_key(true) end def test_expand_cache_key_of_array_like_object - assert_equal 'foo/bar/baz', ActiveSupport::Cache.expand_cache_key(%w{foo bar baz}.to_enum) + assert_equal "foo/bar/baz", ActiveSupport::Cache.expand_cache_key(%w{foo bar baz}.to_enum) end private - def with_env(kv) - old_values = {} - kv.each { |key, value| old_values[key], ENV[key] = ENV[key], value } - yield - ensure - old_values.each { |key, value| ENV[key] = value} - end + def with_env(kv) + old_values = {} + kv.each { |key, value| old_values[key], ENV[key] = ENV[key], value } + yield + ensure + old_values.each { |key, value| ENV[key] = value } + end end class CacheStoreSettingTest < ActiveSupport::TestCase + def test_memory_store_gets_created_if_no_arguments_passed_to_lookup_store_method + store = ActiveSupport::Cache.lookup_store + assert_kind_of(ActiveSupport::Cache::MemoryStore, store) + end + + def test_memory_store + store = ActiveSupport::Cache.lookup_store :memory_store + assert_kind_of(ActiveSupport::Cache::MemoryStore, store) + end + def test_file_fragment_cache_store store = ActiveSupport::Cache.lookup_store :file_store, "/path/to/cache/directory" assert_kind_of(ActiveSupport::Cache::FileStore, store) @@ -158,16 +182,16 @@ class CacheStoreSettingTest < ActiveSupport::TestCase def test_mem_cache_fragment_cache_store_with_multiple_servers assert_called_with(Dalli::Client, :new, [%w[localhost 192.168.1.1], {}]) do - store = ActiveSupport::Cache.lookup_store :mem_cache_store, "localhost", '192.168.1.1' + store = ActiveSupport::Cache.lookup_store :mem_cache_store, "localhost", "192.168.1.1" assert_kind_of(ActiveSupport::Cache::MemCacheStore, store) end end def test_mem_cache_fragment_cache_store_with_options - assert_called_with(Dalli::Client, :new, [%w[localhost 192.168.1.1], { :timeout => 10 }]) do - store = ActiveSupport::Cache.lookup_store :mem_cache_store, "localhost", '192.168.1.1', :namespace => 'foo', :timeout => 10 + assert_called_with(Dalli::Client, :new, [%w[localhost 192.168.1.1], { timeout: 10 }]) do + store = ActiveSupport::Cache.lookup_store :mem_cache_store, "localhost", "192.168.1.1", namespace: "foo", timeout: 10 assert_kind_of(ActiveSupport::Cache::MemCacheStore, store) - assert_equal 'foo', store.options[:namespace] + assert_equal "foo", store.options[:namespace] end end @@ -180,7 +204,7 @@ end class CacheStoreNamespaceTest < ActiveSupport::TestCase def test_static_namespace - cache = ActiveSupport::Cache.lookup_store(:memory_store, :namespace => "tester") + cache = ActiveSupport::Cache.lookup_store(:memory_store, namespace: "tester") cache.write("foo", "bar") assert_equal "bar", cache.read("foo") assert_equal "bar", cache.instance_variable_get(:@data)["tester:foo"].value @@ -188,15 +212,15 @@ class CacheStoreNamespaceTest < ActiveSupport::TestCase def test_proc_namespace test_val = "tester" - proc = lambda{test_val} - cache = ActiveSupport::Cache.lookup_store(:memory_store, :namespace => proc) + proc = lambda { test_val } + cache = ActiveSupport::Cache.lookup_store(:memory_store, namespace: proc) cache.write("foo", "bar") assert_equal "bar", cache.read("foo") assert_equal "bar", cache.instance_variable_get(:@data)["tester:foo"].value end def test_delete_matched_key_start - cache = ActiveSupport::Cache.lookup_store(:memory_store, :namespace => "tester") + cache = ActiveSupport::Cache.lookup_store(:memory_store, namespace: "tester") cache.write("foo", "bar") cache.write("fu", "baz") cache.delete_matched(/^fo/) @@ -205,7 +229,7 @@ class CacheStoreNamespaceTest < ActiveSupport::TestCase end def test_delete_matched_key - cache = ActiveSupport::Cache.lookup_store(:memory_store, :namespace => "foo") + cache = ActiveSupport::Cache.lookup_store(:memory_store, namespace: "foo") cache.write("foo", "bar") cache.write("fu", "baz") cache.delete_matched(/OO/i) @@ -217,127 +241,147 @@ end # Tests the base functionality that should be identical across all cache stores. module CacheStoreBehavior def test_should_read_and_write_strings - assert @cache.write('foo', 'bar') - assert_equal 'bar', @cache.read('foo') + assert @cache.write("foo", "bar") + assert_equal "bar", @cache.read("foo") end def test_should_overwrite - @cache.write('foo', 'bar') - @cache.write('foo', 'baz') - assert_equal 'baz', @cache.read('foo') + @cache.write("foo", "bar") + @cache.write("foo", "baz") + assert_equal "baz", @cache.read("foo") end def test_fetch_without_cache_miss - @cache.write('foo', 'bar') + @cache.write("foo", "bar") assert_not_called(@cache, :write) do - assert_equal 'bar', @cache.fetch('foo') { 'baz' } + assert_equal "bar", @cache.fetch("foo") { "baz" } end end def test_fetch_with_cache_miss - assert_called_with(@cache, :write, ['foo', 'baz', @cache.options]) do - assert_equal 'baz', @cache.fetch('foo') { 'baz' } + assert_called_with(@cache, :write, ["foo", "baz", @cache.options]) do + assert_equal "baz", @cache.fetch("foo") { "baz" } end end def test_fetch_with_cache_miss_passes_key_to_block cache_miss = false - assert_equal 3, @cache.fetch('foo') { |key| cache_miss = true; key.length } + assert_equal 3, @cache.fetch("foo") { |key| cache_miss = true; key.length } assert cache_miss cache_miss = false - assert_equal 3, @cache.fetch('foo') { |key| cache_miss = true; key.length } + assert_equal 3, @cache.fetch("foo") { |key| cache_miss = true; key.length } assert !cache_miss end def test_fetch_with_forced_cache_miss - @cache.write('foo', 'bar') + @cache.write("foo", "bar") assert_not_called(@cache, :read) do - assert_called_with(@cache, :write, ['foo', 'bar', @cache.options.merge(:force => true)]) do - @cache.fetch('foo', :force => true) { 'bar' } + assert_called_with(@cache, :write, ["foo", "bar", @cache.options.merge(force: true)]) do + @cache.fetch("foo", force: true) { "bar" } end end end def test_fetch_with_cached_nil - @cache.write('foo', nil) + @cache.write("foo", nil) assert_not_called(@cache, :write) do - assert_nil @cache.fetch('foo') { 'baz' } + assert_nil @cache.fetch("foo") { "baz" } end end + def test_fetch_with_forced_cache_miss_with_block + @cache.write("foo", "bar") + assert_equal "foo_bar", @cache.fetch("foo", force: true) { "foo_bar" } + end + + def test_fetch_with_forced_cache_miss_without_block + @cache.write("foo", "bar") + assert_raises(ArgumentError) do + @cache.fetch("foo", force: true) + end + + assert_equal "bar", @cache.read("foo") + end + def test_should_read_and_write_hash - assert @cache.write('foo', {:a => "b"}) - assert_equal({:a => "b"}, @cache.read('foo')) + assert @cache.write("foo", a: "b") + assert_equal({ a: "b" }, @cache.read("foo")) end def test_should_read_and_write_integer - assert @cache.write('foo', 1) - assert_equal 1, @cache.read('foo') + assert @cache.write("foo", 1) + assert_equal 1, @cache.read("foo") end def test_should_read_and_write_nil - assert @cache.write('foo', nil) - assert_equal nil, @cache.read('foo') + assert @cache.write("foo", nil) + assert_equal nil, @cache.read("foo") end def test_should_read_and_write_false - assert @cache.write('foo', false) - assert_equal false, @cache.read('foo') + assert @cache.write("foo", false) + assert_equal false, @cache.read("foo") end def test_read_multi - @cache.write('foo', 'bar') - @cache.write('fu', 'baz') - @cache.write('fud', 'biz') - assert_equal({"foo" => "bar", "fu" => "baz"}, @cache.read_multi('foo', 'fu')) + @cache.write("foo", "bar") + @cache.write("fu", "baz") + @cache.write("fud", "biz") + assert_equal({ "foo" => "bar", "fu" => "baz" }, @cache.read_multi("foo", "fu")) end def test_read_multi_with_expires time = Time.now - @cache.write('foo', 'bar', :expires_in => 10) - @cache.write('fu', 'baz') - @cache.write('fud', 'biz') + @cache.write("foo", "bar", expires_in: 10) + @cache.write("fu", "baz") + @cache.write("fud", "biz") Time.stub(:now, time + 11) do - assert_equal({"fu" => "baz"}, @cache.read_multi('foo', 'fu')) + assert_equal({ "fu" => "baz" }, @cache.read_multi("foo", "fu")) end end def test_fetch_multi - @cache.write('foo', 'bar') - @cache.write('fud', 'biz') + @cache.write("foo", "bar") + @cache.write("fud", "biz") - values = @cache.fetch_multi('foo', 'fu', 'fud') { |value| value * 2 } + values = @cache.fetch_multi("foo", "fu", "fud") { |value| value * 2 } - assert_equal({ 'foo' => 'bar', 'fu' => 'fufu', 'fud' => 'biz' }, values) - assert_equal('fufu', @cache.read('fu')) + assert_equal({ "foo" => "bar", "fu" => "fufu", "fud" => "biz" }, values) + assert_equal("fufu", @cache.read("fu")) end def test_multi_with_objects cache_struct = Struct.new(:cache_key, :title) - foo = cache_struct.new('foo', 'FOO!') - bar = cache_struct.new('bar') + foo = cache_struct.new("foo", "FOO!") + bar = cache_struct.new("bar") - @cache.write('bar', 'BAM!') + @cache.write("bar", "BAM!") values = @cache.fetch_multi(foo, bar) { |object| object.title } - assert_equal({ foo => 'FOO!', bar => 'BAM!' }, values) + assert_equal({ foo => "FOO!", bar => "BAM!" }, values) + end + + def test_fetch_multi_without_block + assert_raises(ArgumentError) do + @cache.fetch_multi("foo") + end end def test_read_and_write_compressed_small_data - @cache.write('foo', 'bar', :compress => true) - assert_equal 'bar', @cache.read('foo') + @cache.write("foo", "bar", compress: true) + assert_equal "bar", @cache.read("foo") end def test_read_and_write_compressed_large_data - @cache.write('foo', 'bar', :compress => true, :compress_threshold => 2) - assert_equal 'bar', @cache.read('foo') + @cache.write("foo", "bar", compress: true, compress_threshold: 2) + assert_equal "bar", @cache.read("foo") end def test_read_and_write_compressed_nil - @cache.write('foo', nil, :compress => true) - assert_nil @cache.read('foo') + @cache.write("foo", nil, compress: true) + assert_nil @cache.read("foo") end def test_cache_key @@ -364,7 +408,7 @@ module CacheStoreBehavior end def test_hash_as_cache_key - @cache.write({:foo => 1, :fu => 2}, "bar") + @cache.write({ foo: 1, fu: 2 }, "bar") assert_equal "bar", @cache.read("foo=1/fu=2") end @@ -374,65 +418,65 @@ module CacheStoreBehavior end def test_exist - @cache.write('foo', 'bar') - assert_equal true, @cache.exist?('foo') - assert_equal false, @cache.exist?('bar') + @cache.write("foo", "bar") + assert_equal true, @cache.exist?("foo") + assert_equal false, @cache.exist?("bar") end def test_nil_exist - @cache.write('foo', nil) - assert @cache.exist?('foo') + @cache.write("foo", nil) + assert @cache.exist?("foo") end def test_delete - @cache.write('foo', 'bar') - assert @cache.exist?('foo') - assert @cache.delete('foo') - assert !@cache.exist?('foo') + @cache.write("foo", "bar") + assert @cache.exist?("foo") + assert @cache.delete("foo") + assert !@cache.exist?("foo") end def test_original_store_objects_should_not_be_immutable - bar = 'bar' - @cache.write('foo', bar) - assert_nothing_raised { bar.gsub!(/.*/, 'baz') } + bar = "bar" + @cache.write("foo", bar) + assert_nothing_raised { bar.gsub!(/.*/, "baz") } end def test_expires_in time = Time.local(2008, 4, 24) Time.stub(:now, time) do - @cache.write('foo', 'bar') - assert_equal 'bar', @cache.read('foo') + @cache.write("foo", "bar") + assert_equal "bar", @cache.read("foo") end Time.stub(:now, time + 30) do - assert_equal 'bar', @cache.read('foo') + assert_equal "bar", @cache.read("foo") end Time.stub(:now, time + 61) do - assert_nil @cache.read('foo') + assert_nil @cache.read("foo") end end def test_race_condition_protection_skipped_if_not_defined - @cache.write('foo', 'bar') - time = @cache.send(:read_entry, @cache.send(:normalize_key, 'foo', {}), {}).expires_at + @cache.write("foo", "bar") + time = @cache.send(:read_entry, @cache.send(:normalize_key, "foo", {}), {}).expires_at Time.stub(:now, Time.at(time)) do - result = @cache.fetch('foo') do - assert_equal nil, @cache.read('foo') - 'baz' + result = @cache.fetch("foo") do + assert_equal nil, @cache.read("foo") + "baz" end - assert_equal 'baz', result + assert_equal "baz", result end end def test_race_condition_protection_is_limited time = Time.now - @cache.write('foo', 'bar', :expires_in => 60) + @cache.write("foo", "bar", expires_in: 60) Time.stub(:now, time + 71) do - result = @cache.fetch('foo', :race_condition_ttl => 10) do - assert_equal nil, @cache.read('foo') + result = @cache.fetch("foo", race_condition_ttl: 10) do + assert_equal nil, @cache.read("foo") "baz" end assert_equal "baz", result @@ -441,28 +485,28 @@ module CacheStoreBehavior def test_race_condition_protection_is_safe time = Time.now - @cache.write('foo', 'bar', :expires_in => 60) + @cache.write("foo", "bar", expires_in: 60) Time.stub(:now, time + 61) do begin - @cache.fetch('foo', :race_condition_ttl => 10) do - assert_equal 'bar', @cache.read('foo') + @cache.fetch("foo", race_condition_ttl: 10) do + assert_equal "bar", @cache.read("foo") raise ArgumentError.new end rescue ArgumentError end - assert_equal "bar", @cache.read('foo') + assert_equal "bar", @cache.read("foo") end Time.stub(:now, time + 91) do - assert_nil @cache.read('foo') + assert_nil @cache.read("foo") end end def test_race_condition_protection time = Time.now - @cache.write('foo', 'bar', :expires_in => 60) + @cache.write("foo", "bar", expires_in: 60) Time.stub(:now, time + 61) do - result = @cache.fetch('foo', :race_condition_ttl => 10) do - assert_equal 'bar', @cache.read('foo') + result = @cache.fetch("foo", race_condition_ttl: 10) do + assert_equal "bar", @cache.read("foo") "baz" end assert_equal "baz", result @@ -471,23 +515,23 @@ module CacheStoreBehavior def test_crazy_key_characters crazy_key = "#/:*(<+=> )&$%@?;'\"\'`~-" - assert @cache.write(crazy_key, "1", :raw => true) + assert @cache.write(crazy_key, "1", raw: true) assert_equal "1", @cache.read(crazy_key) assert_equal "1", @cache.fetch(crazy_key) assert @cache.delete(crazy_key) - assert_equal "2", @cache.fetch(crazy_key, :raw => true) { "2" } + assert_equal "2", @cache.fetch(crazy_key, raw: true) { "2" } assert_equal 3, @cache.increment(crazy_key) assert_equal 2, @cache.decrement(crazy_key) end def test_really_long_keys key = "" - 900.times{key << "x"} + 900.times { key << "x" } assert @cache.write(key, "bar") assert_equal "bar", @cache.read(key) assert_equal "bar", @cache.fetch(key) assert_nil @cache.read("#{key}x") - assert_equal({key => "bar"}, @cache.read_multi(key)) + assert_equal({ key => "bar" }, @cache.read_multi(key)) assert @cache.delete(key) end @@ -497,10 +541,10 @@ module CacheStoreBehavior ActiveSupport::Notifications.subscribe "cache_read.active_support" do |*args| @events << ActiveSupport::Notifications::Event.new(*args) end - assert @cache.write(key, "1", :raw => true) + assert @cache.write(key, "1", raw: true) assert @cache.fetch(key) {} assert_equal 1, @events.length - assert_equal 'cache_read.active_support', @events[0].name + assert_equal "cache_read.active_support", @events[0].name assert_equal :fetch, @events[0].payload[:super_operation] assert @events[0].payload[:hit] ensure @@ -514,9 +558,9 @@ module CacheStoreBehavior end assert_not @cache.fetch("bad_key") {} assert_equal 3, @events.length - assert_equal 'cache_read.active_support', @events[0].name - assert_equal 'cache_generate.active_support', @events[1].name - assert_equal 'cache_write.active_support', @events[2].name + assert_equal "cache_read.active_support", @events[0].name + assert_equal "cache_generate.active_support", @events[1].name + assert_equal "cache_write.active_support", @events[2].name assert_equal :fetch, @events[0].payload[:super_operation] assert_not @events[0].payload[:hit] ensure @@ -537,11 +581,11 @@ module EncodedKeyCacheBehavior Encoding.list.each do |encoding| define_method "test_#{encoding.name.underscore}_encoded_values" do key = "foo".force_encoding(encoding) - assert @cache.write(key, "1", :raw => true) + assert @cache.write(key, "1", raw: true) assert_equal "1", @cache.read(key) assert_equal "1", @cache.fetch(key) assert @cache.delete(key) - assert_equal "2", @cache.fetch(key, :raw => true) { "2" } + assert_equal "2", @cache.fetch(key, raw: true) { "2" } assert_equal 3, @cache.increment(key) assert_equal 2, @cache.decrement(key) end @@ -549,18 +593,18 @@ module EncodedKeyCacheBehavior def test_common_utf8_values key = "\xC3\xBCmlaut".force_encoding(Encoding::UTF_8) - assert @cache.write(key, "1", :raw => true) + assert @cache.write(key, "1", raw: true) assert_equal "1", @cache.read(key) assert_equal "1", @cache.fetch(key) assert @cache.delete(key) - assert_equal "2", @cache.fetch(key, :raw => true) { "2" } + assert_equal "2", @cache.fetch(key, raw: true) { "2" } assert_equal 3, @cache.increment(key) assert_equal 2, @cache.decrement(key) end def test_retains_encoding key = "\xC3\xBCmlaut".force_encoding(Encoding::UTF_8) - assert @cache.write(key, "1", :raw => true) + assert @cache.write(key, "1", raw: true) assert_equal Encoding::UTF_8, key.encoding end end @@ -581,122 +625,122 @@ end module CacheIncrementDecrementBehavior def test_increment - @cache.write('foo', 1, :raw => true) - assert_equal 1, @cache.read('foo').to_i - assert_equal 2, @cache.increment('foo') - assert_equal 2, @cache.read('foo').to_i - assert_equal 3, @cache.increment('foo') - assert_equal 3, @cache.read('foo').to_i - assert_nil @cache.increment('bar') + @cache.write("foo", 1, raw: true) + assert_equal 1, @cache.read("foo").to_i + assert_equal 2, @cache.increment("foo") + assert_equal 2, @cache.read("foo").to_i + assert_equal 3, @cache.increment("foo") + assert_equal 3, @cache.read("foo").to_i + assert_nil @cache.increment("bar") end def test_decrement - @cache.write('foo', 3, :raw => true) - assert_equal 3, @cache.read('foo').to_i - assert_equal 2, @cache.decrement('foo') - assert_equal 2, @cache.read('foo').to_i - assert_equal 1, @cache.decrement('foo') - assert_equal 1, @cache.read('foo').to_i - assert_nil @cache.decrement('bar') + @cache.write("foo", 3, raw: true) + assert_equal 3, @cache.read("foo").to_i + assert_equal 2, @cache.decrement("foo") + assert_equal 2, @cache.read("foo").to_i + assert_equal 1, @cache.decrement("foo") + assert_equal 1, @cache.read("foo").to_i + assert_nil @cache.decrement("bar") end end module LocalCacheBehavior def test_local_writes_are_persistent_on_the_remote_cache retval = @cache.with_local_cache do - @cache.write('foo', 'bar') + @cache.write("foo", "bar") end assert retval - assert_equal 'bar', @cache.read('foo') + assert_equal "bar", @cache.read("foo") end def test_clear_also_clears_local_cache @cache.with_local_cache do - @cache.write('foo', 'bar') + @cache.write("foo", "bar") @cache.clear - assert_nil @cache.read('foo') + assert_nil @cache.read("foo") end - assert_nil @cache.read('foo') + assert_nil @cache.read("foo") end def test_local_cache_of_write @cache.with_local_cache do - @cache.write('foo', 'bar') - @peek.delete('foo') - assert_equal 'bar', @cache.read('foo') + @cache.write("foo", "bar") + @peek.delete("foo") + assert_equal "bar", @cache.read("foo") end end def test_local_cache_of_read - @cache.write('foo', 'bar') + @cache.write("foo", "bar") @cache.with_local_cache do - assert_equal 'bar', @cache.read('foo') + assert_equal "bar", @cache.read("foo") end end def test_local_cache_of_read_nil @cache.with_local_cache do - assert_equal nil, @cache.read('foo') - @cache.send(:bypass_local_cache) { @cache.write 'foo', 'bar' } - assert_equal nil, @cache.read('foo') + assert_equal nil, @cache.read("foo") + @cache.send(:bypass_local_cache) { @cache.write "foo", "bar" } + assert_equal nil, @cache.read("foo") end end def test_local_cache_fetch @cache.with_local_cache do - @cache.send(:local_cache).write 'foo', 'bar' - assert_equal 'bar', @cache.send(:local_cache).fetch('foo') + @cache.send(:local_cache).write "foo", "bar" + assert_equal "bar", @cache.send(:local_cache).fetch("foo") end end def test_local_cache_of_write_nil @cache.with_local_cache do - assert @cache.write('foo', nil) - assert_nil @cache.read('foo') - @peek.write('foo', 'bar') - assert_nil @cache.read('foo') + assert @cache.write("foo", nil) + assert_nil @cache.read("foo") + @peek.write("foo", "bar") + assert_nil @cache.read("foo") end end def test_local_cache_of_delete @cache.with_local_cache do - @cache.write('foo', 'bar') - @cache.delete('foo') - assert_nil @cache.read('foo') + @cache.write("foo", "bar") + @cache.delete("foo") + assert_nil @cache.read("foo") end end def test_local_cache_of_exist @cache.with_local_cache do - @cache.write('foo', 'bar') - @peek.delete('foo') - assert @cache.exist?('foo') + @cache.write("foo", "bar") + @peek.delete("foo") + assert @cache.exist?("foo") end end def test_local_cache_of_increment @cache.with_local_cache do - @cache.write('foo', 1, :raw => true) - @peek.write('foo', 2, :raw => true) - @cache.increment('foo') - assert_equal 3, @cache.read('foo') + @cache.write("foo", 1, raw: true) + @peek.write("foo", 2, raw: true) + @cache.increment("foo") + assert_equal 3, @cache.read("foo") end end def test_local_cache_of_decrement @cache.with_local_cache do - @cache.write('foo', 1, :raw => true) - @peek.write('foo', 3, :raw => true) - @cache.decrement('foo') - assert_equal 2, @cache.read('foo') + @cache.write("foo", 1, raw: true) + @peek.write("foo", 3, raw: true) + @cache.decrement("foo") + assert_equal 2, @cache.read("foo") end end def test_middleware app = lambda { |env| - result = @cache.write('foo', 'bar') - assert_equal 'bar', @cache.read('foo') # make sure 'foo' was written + result = @cache.write("foo", "bar") + assert_equal "bar", @cache.read("foo") # make sure 'foo' was written assert result [200, {}, []] } @@ -707,9 +751,9 @@ module LocalCacheBehavior def test_can_call_deprecated_set_cache_value @cache.with_local_cache do assert_deprecated "`set_cache_value` is deprecated" do - @cache.send(:set_cache_value, 1, 'foo', :ignored, {}) + @cache.send(:set_cache_value, 1, "foo", :ignored, {}) end - assert_equal 1, @cache.read('foo') + assert_equal 1, @cache.read("foo") end end end @@ -718,14 +762,14 @@ module AutoloadingCacheBehavior include DependenciesTestHelpers def test_simple_autoloading with_autoloading_fixtures do - @cache.write('foo', EM.new) + @cache.write("foo", EM.new) end remove_constants(:EM) ActiveSupport::Dependencies.clear with_autoloading_fixtures do - assert_kind_of EM, @cache.read('foo') + assert_kind_of EM, @cache.read("foo") end remove_constants(:EM) @@ -734,14 +778,14 @@ module AutoloadingCacheBehavior def test_two_classes_autoloading with_autoloading_fixtures do - @cache.write('foo', [EM.new, ClassFolder.new]) + @cache.write("foo", [EM.new, ClassFolder.new]) end remove_constants(:EM, :ClassFolder) ActiveSupport::Dependencies.clear with_autoloading_fixtures do - loaded = @cache.read('foo') + loaded = @cache.read("foo") assert_kind_of Array, loaded assert_equal 2, loaded.size assert_kind_of EM, loaded[0] @@ -756,9 +800,9 @@ end class FileStoreTest < ActiveSupport::TestCase def setup Dir.mkdir(cache_dir) unless File.exist?(cache_dir) - @cache = ActiveSupport::Cache.lookup_store(:file_store, cache_dir, :expires_in => 60) - @peek = ActiveSupport::Cache.lookup_store(:file_store, cache_dir, :expires_in => 60) - @cache_with_pathname = ActiveSupport::Cache.lookup_store(:file_store, Pathname.new(cache_dir), :expires_in => 60) + @cache = ActiveSupport::Cache.lookup_store(:file_store, cache_dir, expires_in: 60) + @peek = ActiveSupport::Cache.lookup_store(:file_store, cache_dir, expires_in: 60) + @cache_with_pathname = ActiveSupport::Cache.lookup_store(:file_store, Pathname.new(cache_dir), expires_in: 60) @buffer = StringIO.new @cache.logger = ActiveSupport::Logger.new(@buffer) @@ -770,7 +814,7 @@ class FileStoreTest < ActiveSupport::TestCase end def cache_dir - File.join(Dir.pwd, 'tmp_cache') + File.join(Dir.pwd, "tmp_cache") end include CacheStoreBehavior @@ -793,11 +837,6 @@ class FileStoreTest < ActiveSupport::TestCase @cache.clear end - def test_long_keys - @cache.write("a"*10000, 1) - assert_equal 1, @cache.read("a"*10000) - end - def test_long_uri_encoded_keys @cache.write("%"*870, 1) assert_equal 1, @cache.read("%"*870) @@ -820,7 +859,7 @@ class FileStoreTest < ActiveSupport::TestCase key = "#{'A' * ActiveSupport::Cache::FileStore::FILENAME_MAX_SIZE}" path = @cache.send(:normalize_key, key, {}) Dir::Tmpname.create(path) do |tmpname, n, opts| - assert File.basename(tmpname+'.lock').length <= 255, "Temp filename too long: #{File.basename(tmpname+'.lock').length}" + assert File.basename(tmpname+".lock").length <= 255, "Temp filename too long: #{File.basename(tmpname+'.lock').length}" end end @@ -829,28 +868,28 @@ class FileStoreTest < ActiveSupport::TestCase def test_key_transformation_max_filename_size key = "#{'A' * ActiveSupport::Cache::FileStore::FILENAME_MAX_SIZE}B" path = @cache.send(:normalize_key, key, {}) - assert path.split('/').all? { |dir_name| dir_name.size <= ActiveSupport::Cache::FileStore::FILENAME_MAX_SIZE} - assert_equal 'B', File.basename(path) + assert path.split("/").all? { |dir_name| dir_name.size <= ActiveSupport::Cache::FileStore::FILENAME_MAX_SIZE } + assert_equal "B", File.basename(path) end # If nothing has been stored in the cache, there is a chance the cache directory does not yet exist # Ensure delete_matched gracefully handles this case def test_delete_matched_when_cache_directory_does_not_exist - assert_nothing_raised(Exception) do - ActiveSupport::Cache::FileStore.new('/test/cache/directory').delete_matched(/does_not_exist/) + assert_nothing_raised do + ActiveSupport::Cache::FileStore.new("/test/cache/directory").delete_matched(/does_not_exist/) end end def test_delete_does_not_delete_empty_parent_dir - sub_cache_dir = File.join(cache_dir, 'subdir/') + sub_cache_dir = File.join(cache_dir, "subdir/") sub_cache_store = ActiveSupport::Cache::FileStore.new(sub_cache_dir) - assert_nothing_raised(Exception) do - assert sub_cache_store.write('foo', 'bar') - assert sub_cache_store.delete('foo') + assert_nothing_raised do + assert sub_cache_store.write("foo", "bar") + assert sub_cache_store.delete("foo") end assert File.exist?(cache_dir), "Parent of top level cache dir was deleted!" assert File.exist?(sub_cache_dir), "Top level cache dir was deleted!" - assert Dir.entries(sub_cache_dir).reject {|f| ActiveSupport::Cache::FileStore::EXCLUDED_DIRS.include?(f)}.empty? + assert Dir.entries(sub_cache_dir).reject { |f| ActiveSupport::Cache::FileStore::EXCLUDED_DIRS.include?(f) }.empty? end def test_log_exception_when_cache_read_fails @@ -862,14 +901,14 @@ class FileStoreTest < ActiveSupport::TestCase def test_cleanup_removes_all_expired_entries time = Time.now - @cache.write('foo', 'bar', expires_in: 10) - @cache.write('baz', 'qux') - @cache.write('quux', 'corge', expires_in: 20) + @cache.write("foo", "bar", expires_in: 10) + @cache.write("baz", "qux") + @cache.write("quux", "corge", expires_in: 20) Time.stub(:now, time + 15) do @cache.cleanup - assert_not @cache.exist?('foo') - assert @cache.exist?('baz') - assert @cache.exist?('quux') + assert_not @cache.exist?("foo") + assert @cache.exist?("baz") + assert @cache.exist?("quux") end end @@ -890,7 +929,7 @@ end class MemoryStoreTest < ActiveSupport::TestCase def setup @record_size = ActiveSupport::Cache.lookup_store(:memory_store).send(:cached_size, 1, ActiveSupport::Cache::Entry.new("aaaaaaaaaa")) - @cache = ActiveSupport::Cache.lookup_store(:memory_store, :expires_in => 60, :size => @record_size * 10 + 1) + @cache = ActiveSupport::Cache.lookup_store(:memory_store, expires_in: 60, size: @record_size * 10 + 1) end include CacheStoreBehavior @@ -950,7 +989,7 @@ class MemoryStoreTest < ActiveSupport::TestCase @cache.write(7, "gggggggggg") && sleep(0.001) @cache.write(8, "hhhhhhhhhh") && sleep(0.001) @cache.write(9, "iiiiiiiiii") && sleep(0.001) - long_key = '*' * 2 * @record_size + long_key = "*" * 2 * @record_size @cache.write(long_key, "llllllllll") assert @cache.exist?(long_key) assert @cache.exist?(9) @@ -984,18 +1023,18 @@ class MemoryStoreTest < ActiveSupport::TestCase def test_write_with_unless_exist assert_equal true, @cache.write(1, "aaaaaaaaaa") - assert_equal false, @cache.write(1, "aaaaaaaaaa", :unless_exist => true) + assert_equal false, @cache.write(1, "aaaaaaaaaa", unless_exist: true) @cache.write(1, nil) - assert_equal false, @cache.write(1, "aaaaaaaaaa", :unless_exist => true) + assert_equal false, @cache.write(1, "aaaaaaaaaa", unless_exist: true) end end class MemCacheStoreTest < ActiveSupport::TestCase - require 'dalli' + require "dalli" begin - ss = Dalli::Client.new('localhost:11211').stats - raise Dalli::DalliError unless ss['localhost:11211'] + ss = Dalli::Client.new("localhost:11211").stats + raise Dalli::DalliError unless ss["localhost:11211"] MEMCACHE_UP = true rescue Dalli::DalliError @@ -1006,7 +1045,7 @@ class MemCacheStoreTest < ActiveSupport::TestCase def setup skip "memcache server is not up" unless MEMCACHE_UP - @cache = ActiveSupport::Cache.lookup_store(:mem_cache_store, :expires_in => 60) + @cache = ActiveSupport::Cache.lookup_store(:mem_cache_store, expires_in: 60) @peek = ActiveSupport::Cache.lookup_store(:mem_cache_store) @data = @cache.instance_variable_get(:@data) @cache.clear @@ -1021,21 +1060,21 @@ class MemCacheStoreTest < ActiveSupport::TestCase include AutoloadingCacheBehavior def test_raw_values - cache = ActiveSupport::Cache.lookup_store(:mem_cache_store, :raw => true) + cache = ActiveSupport::Cache.lookup_store(:mem_cache_store, raw: true) cache.clear cache.write("foo", 2) assert_equal "2", cache.read("foo") end def test_raw_values_with_marshal - cache = ActiveSupport::Cache.lookup_store(:mem_cache_store, :raw => true) + cache = ActiveSupport::Cache.lookup_store(:mem_cache_store, raw: true) cache.clear cache.write("foo", Marshal.dump([])) assert_equal [], cache.read("foo") end def test_local_cache_raw_values - cache = ActiveSupport::Cache.lookup_store(:mem_cache_store, :raw => true) + cache = ActiveSupport::Cache.lookup_store(:mem_cache_store, raw: true) cache.clear cache.with_local_cache do cache.write("foo", 2) @@ -1044,7 +1083,7 @@ class MemCacheStoreTest < ActiveSupport::TestCase end def test_local_cache_raw_values_with_marshal - cache = ActiveSupport::Cache.lookup_store(:mem_cache_store, :raw => true) + cache = ActiveSupport::Cache.lookup_store(:mem_cache_store, raw: true) cache.clear cache.with_local_cache do cache.write("foo", Marshal.dump([])) @@ -1053,11 +1092,11 @@ class MemCacheStoreTest < ActiveSupport::TestCase end def test_read_should_return_a_different_object_id_each_time_it_is_called - @cache.write('foo', 'bar') - value = @cache.read('foo') - assert_not_equal value.object_id, @cache.read('foo').object_id - value << 'bingo' - assert_not_equal value, @cache.read('foo') + @cache.write("foo", "bar") + value = @cache.read("foo") + assert_not_equal value.object_id, @cache.read("foo").object_id + value << "bingo" + assert_not_equal value, @cache.read("foo") end def test_can_call_deprecated_escape_key @@ -1095,12 +1134,12 @@ class NullStoreTest < ActiveSupport::TestCase end def test_increment - @cache.write("name", 1, :raw => true) + @cache.write("name", 1, raw: true) assert_nil @cache.increment("name") end def test_decrement - @cache.write("name", 1, :raw => true) + @cache.write("name", 1, raw: true) assert_nil @cache.increment("name") end @@ -1130,12 +1169,12 @@ class CacheStoreLoggerTest < ActiveSupport::TestCase end def test_logging - @cache.fetch('foo') { 'bar' } + @cache.fetch("foo") { "bar" } assert @buffer.string.present? end def test_log_with_string_namespace - @cache.fetch('foo', {namespace: 'string_namespace'}) { 'bar' } + @cache.fetch("foo", namespace: "string_namespace") { "bar" } assert_match %r{string_namespace:foo}, @buffer.string end @@ -1143,39 +1182,30 @@ class CacheStoreLoggerTest < ActiveSupport::TestCase proc = Proc.new do "proc_namespace" end - @cache.fetch('foo', {:namespace => proc}) { 'bar' } + @cache.fetch("foo", namespace: proc) { "bar" } assert_match %r{proc_namespace:foo}, @buffer.string end def test_mute_logging - @cache.mute { @cache.fetch('foo') { 'bar' } } + @cache.mute { @cache.fetch("foo") { "bar" } } assert @buffer.string.blank? end - - def test_multi_read_loggin - @cache.write 'hello', 'goodbye' - @cache.write 'world', 'earth' - - @cache.read_multi('hello', 'world') - - assert_match "Caches multi read:\n- hello\n- world", @buffer.string - end end class CacheEntryTest < ActiveSupport::TestCase def test_expired entry = ActiveSupport::Cache::Entry.new("value") - assert !entry.expired?, 'entry not expired' - entry = ActiveSupport::Cache::Entry.new("value", :expires_in => 60) - assert !entry.expired?, 'entry not expired' + assert !entry.expired?, "entry not expired" + entry = ActiveSupport::Cache::Entry.new("value", expires_in: 60) + assert !entry.expired?, "entry not expired" Time.stub(:now, Time.now + 61) do - assert entry.expired?, 'entry is expired' + assert entry.expired?, "entry is expired" end end def test_compress_values value = "value" * 100 - entry = ActiveSupport::Cache::Entry.new(value, :compress => true, :compress_threshold => 1) + entry = ActiveSupport::Cache::Entry.new(value, compress: true, compress_threshold: 1) assert_equal value, entry.value assert(value.bytesize > entry.size, "value is compressed") end diff --git a/activesupport/test/callback_inheritance_test.rb b/activesupport/test/callback_inheritance_test.rb index 1adfe4edf4..9e2f7527e0 100644 --- a/activesupport/test/callback_inheritance_test.rb +++ b/activesupport/test/callback_inheritance_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" class GrandParent include ActiveSupport::Callbacks @@ -9,8 +9,8 @@ class GrandParent end define_callbacks :dispatch - set_callback :dispatch, :before, :before1, :before2, :if => proc {|c| c.action_name == "index" || c.action_name == "update" } - set_callback :dispatch, :after, :after1, :after2, :if => proc {|c| c.action_name == "update" || c.action_name == "delete" } + set_callback :dispatch, :before, :before1, :before2, if: proc { |c| c.action_name == "index" || c.action_name == "update" } + set_callback :dispatch, :after, :after1, :after2, if: proc { |c| c.action_name == "update" || c.action_name == "delete" } def before1 @log << "before1" @@ -37,12 +37,12 @@ class GrandParent end class Parent < GrandParent - skip_callback :dispatch, :before, :before2, :unless => proc {|c| c.action_name == "update" } - skip_callback :dispatch, :after, :after2, :unless => proc {|c| c.action_name == "delete" } + skip_callback :dispatch, :before, :before2, unless: proc { |c| c.action_name == "update" } + skip_callback :dispatch, :after, :after2, unless: proc { |c| c.action_name == "delete" } end class Child < GrandParent - skip_callback :dispatch, :before, :before2, :unless => proc {|c| c.action_name == "update" }, :if => :state_open? + skip_callback :dispatch, :before, :before2, unless: proc { |c| c.action_name == "update" }, if: :state_open? def state_open? @state == :open diff --git a/activesupport/test/callbacks_test.rb b/activesupport/test/callbacks_test.rb index a624473f46..783952c8c7 100644 --- a/activesupport/test/callbacks_test.rb +++ b/activesupport/test/callbacks_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" module CallbacksTest class Record @@ -56,27 +56,31 @@ module CallbacksTest end class Person < Record + attr_accessor :save_fails + [:before_save, :after_save].each do |callback_method| callback_method_sym = callback_method.to_sym send(callback_method, callback_symbol(callback_method_sym)) ActiveSupport::Deprecation.silence { send(callback_method, callback_string(callback_method_sym)) } send(callback_method, callback_proc(callback_method_sym)) - send(callback_method, callback_object(callback_method_sym.to_s.gsub(/_save/, ''))) + send(callback_method, callback_object(callback_method_sym.to_s.gsub(/_save/, ""))) send(callback_method, CallbackClass) send(callback_method) { |model| model.history << [callback_method_sym, :block] } end def save - run_callbacks :save + run_callbacks :save do + raise "inside save" if save_fails + end end end class PersonSkipper < Person - skip_callback :save, :before, :before_save_method, :if => :yes - skip_callback :save, :after, :after_save_method, :unless => :yes - skip_callback :save, :after, :after_save_method, :if => :no - skip_callback :save, :before, :before_save_method, :unless => :no - skip_callback :save, :before, CallbackClass , :if => :yes + skip_callback :save, :before, :before_save_method, if: :yes + skip_callback :save, :after, :after_save_method, unless: :yes + skip_callback :save, :after, :after_save_method, if: :no + skip_callback :save, :before, :before_save_method, unless: :no + skip_callback :save, :before, CallbackClass , if: :yes def yes; true; end def no; false; end end @@ -89,7 +93,7 @@ module CallbacksTest define_callbacks :dispatch - set_callback :dispatch, :before, :log, :unless => proc {|c| c.action_name == :index || c.action_name == :show } + set_callback :dispatch, :before, :log, unless: proc { |c| c.action_name == :index || c.action_name == :show } set_callback :dispatch, :after, :log2 attr_reader :action_name, :logger @@ -114,7 +118,7 @@ module CallbacksTest end class Child < ParentController - skip_callback :dispatch, :before, :log, :if => proc {|c| c.action_name == :update} + skip_callback :dispatch, :before, :log, if: proc { |c| c.action_name == :update } skip_callback :dispatch, :after, :log2 end @@ -125,10 +129,10 @@ module CallbacksTest super end - before_save Proc.new {|r| r.history << [:before_save, :starts_true, :if] }, :if => :starts_true - before_save Proc.new {|r| r.history << [:before_save, :starts_false, :if] }, :if => :starts_false - before_save Proc.new {|r| r.history << [:before_save, :starts_true, :unless] }, :unless => :starts_true - before_save Proc.new {|r| r.history << [:before_save, :starts_false, :unless] }, :unless => :starts_false + before_save Proc.new { |r| r.history << [:before_save, :starts_true, :if] }, if: :starts_true + before_save Proc.new { |r| r.history << [:before_save, :starts_false, :if] }, if: :starts_false + before_save Proc.new { |r| r.history << [:before_save, :starts_true, :unless] }, unless: :starts_true + before_save Proc.new { |r| r.history << [:before_save, :starts_false, :unless] }, unless: :starts_false def starts_true if @@starts_true @@ -181,27 +185,25 @@ module CallbacksTest end end - - class ConditionalPerson < Record # proc - before_save Proc.new { |r| r.history << [:before_save, :proc] }, :if => Proc.new { |r| true } - before_save Proc.new { |r| r.history << "b00m" }, :if => Proc.new { |r| false } - before_save Proc.new { |r| r.history << [:before_save, :proc] }, :unless => Proc.new { |r| false } - before_save Proc.new { |r| r.history << "b00m" }, :unless => Proc.new { |r| true } + before_save Proc.new { |r| r.history << [:before_save, :proc] }, if: Proc.new { |r| true } + before_save Proc.new { |r| r.history << "b00m" }, if: Proc.new { |r| false } + before_save Proc.new { |r| r.history << [:before_save, :proc] }, unless: Proc.new { |r| false } + before_save Proc.new { |r| r.history << "b00m" }, unless: Proc.new { |r| true } # symbol - before_save Proc.new { |r| r.history << [:before_save, :symbol] }, :if => :yes - before_save Proc.new { |r| r.history << "b00m" }, :if => :no - before_save Proc.new { |r| r.history << [:before_save, :symbol] }, :unless => :no - before_save Proc.new { |r| r.history << "b00m" }, :unless => :yes + before_save Proc.new { |r| r.history << [:before_save, :symbol] }, if: :yes + before_save Proc.new { |r| r.history << "b00m" }, if: :no + before_save Proc.new { |r| r.history << [:before_save, :symbol] }, unless: :no + before_save Proc.new { |r| r.history << "b00m" }, unless: :yes # string - before_save Proc.new { |r| r.history << [:before_save, :string] }, :if => 'yes' - before_save Proc.new { |r| r.history << "b00m" }, :if => 'no' - before_save Proc.new { |r| r.history << [:before_save, :string] }, :unless => 'no' - before_save Proc.new { |r| r.history << "b00m" }, :unless => 'yes' + before_save Proc.new { |r| r.history << [:before_save, :string] }, if: "yes" + before_save Proc.new { |r| r.history << "b00m" }, if: "no" + before_save Proc.new { |r| r.history << [:before_save, :string] }, unless: "no" + before_save Proc.new { |r| r.history << "b00m" }, unless: "yes" # Combined if and unless - before_save Proc.new { |r| r.history << [:before_save, :combined_symbol] }, :if => :yes, :unless => :no - before_save Proc.new { |r| r.history << "b00m" }, :if => :yes, :unless => :yes + before_save Proc.new { |r| r.history << [:before_save, :combined_symbol] }, if: :yes, unless: :no + before_save Proc.new { |r| r.history << "b00m" }, if: :yes, unless: :yes def yes; true; end def other_yes; true; end @@ -224,19 +226,20 @@ module CallbacksTest class AroundPerson < MySuper attr_reader :history + attr_accessor :save_fails - set_callback :save, :before, :nope, :if => :no - set_callback :save, :before, :nope, :unless => :yes + set_callback :save, :before, :nope, if: :no + set_callback :save, :before, :nope, unless: :yes set_callback :save, :after, :tweedle ActiveSupport::Deprecation.silence { set_callback :save, :before, "tweedle_dee" } - set_callback :save, :before, proc {|m| m.history << "yup" } - set_callback :save, :before, :nope, :if => proc { false } - set_callback :save, :before, :nope, :unless => proc { true } - set_callback :save, :before, :yup, :if => proc { true } - set_callback :save, :before, :yup, :unless => proc { false } + set_callback :save, :before, proc { |m| m.history << "yup" } + set_callback :save, :before, :nope, if: proc { false } + set_callback :save, :before, :nope, unless: proc { true } + set_callback :save, :before, :yup, if: proc { true } + set_callback :save, :before, :yup, unless: proc { false } set_callback :save, :around, :tweedle_dum - set_callback :save, :around, :w0tyes, :if => :yes - set_callback :save, :around, :w0tno, :if => :no + set_callback :save, :around, :w0tyes, if: :yes + set_callback :save, :around, :w0tno, if: :no set_callback :save, :around, :tweedle_deedle def no; false; end @@ -287,6 +290,7 @@ module CallbacksTest def save run_callbacks :save do + raise "inside save" if save_fails @history << "running" end end @@ -323,7 +327,7 @@ module CallbacksTest define_callbacks :save attr_reader :stuff - set_callback :save, :before, :action, :if => :yes + set_callback :save, :before, :action, if: :yes def yes() true end @@ -361,7 +365,6 @@ module CallbacksTest end class ExtendCallbacks - include ActiveSupport::Callbacks define_callbacks :save @@ -405,6 +408,71 @@ module CallbacksTest end end + class CallStackTest < ActiveSupport::TestCase + def test_tidy_call_stack + around = AroundPerson.new + around.save_fails = true + + exception = (around.save rescue $!) + + # Make sure we have the exception we're expecting + assert_equal "inside save", exception.message + + call_stack = exception.backtrace_locations + call_stack.pop caller_locations(0).size + + # Yes, this looks like an implementation test, but it's the least + # obtuse way of asserting that there aren't a load of entries in + # the call stack for each callback. + # + # If you've renamed a method, or squeezed more lines out, go ahead + # and update this assertion. But if you're here because a + # refactoring added new lines, please reconsider. + + # As shown here, our current budget is one line for run_callbacks + # itself, plus N+1 lines where N is the number of :around + # callbacks that have been invoked, if there are any (plus + # whatever the callbacks do themselves, of course). + + assert_equal [ + "block in save", + "block in run_callbacks", + "tweedle_deedle", + "block in run_callbacks", + "w0tyes", + "block in run_callbacks", + "tweedle_dum", + "block in run_callbacks", + ("call" if RUBY_VERSION < "2.3"), + "run_callbacks", + "save" + ].compact, call_stack.map(&:label) + end + + def test_short_call_stack + person = Person.new + person.save_fails = true + + exception = (person.save rescue $!) + + # Make sure we have the exception we're expecting + assert_equal "inside save", exception.message + + call_stack = exception.backtrace_locations + call_stack.pop caller_locations(0).size + + # This budget much simpler: with no :around callbacks invoked, + # there should be just one line. run_callbacks yields directly + # back to its caller. + + assert_equal [ + "block in save", + "run_callbacks", + "save" + ], call_stack.map(&:label) + end + end + class AroundCallbackResultTest < ActiveSupport::TestCase def test_save_around around = AroundPersonResult.new @@ -453,7 +521,6 @@ module CallbacksTest end class CallbacksTest < ActiveSupport::TestCase - def test_save_person person = Person.new assert_equal [], person.history @@ -491,8 +558,6 @@ module CallbacksTest end end - - class ResetCallbackTest < ActiveSupport::TestCase def test_save_conditional_person person = CleanPerson.new @@ -637,7 +702,7 @@ module CallbacksTest class CustomScopeObject include ActiveSupport::Callbacks - define_callbacks :save, :scope => [:kind, :name] + define_callbacks :save, scope: [:kind, :name] set_callback :save, :before, CallbackObject.new attr_accessor :record @@ -810,7 +875,7 @@ module CallbacksTest class WriterSkipper < Person attr_accessor :age - skip_callback :save, :before, :before_save_method, :if => lambda {self.age > 21} + skip_callback :save, :before, :before_save_method, if: -> { age > 21 } end class WriterCallbacksTest < ActiveSupport::TestCase @@ -885,7 +950,7 @@ module CallbacksTest def test_proc_arity_2 assert_raises(ArgumentError) do - klass = build_class(->(x,y) { }) + klass = build_class(->(x,y) {}) klass.new.run end end @@ -903,7 +968,7 @@ module CallbacksTest Class.new { include ActiveSupport::Callbacks define_callbacks :foo - set_callback :foo, :before, :foo, :if => callback + set_callback :foo, :before, :foo, if: callback def foo; end def run; run_callbacks :foo; end } @@ -918,8 +983,8 @@ module CallbacksTest } klass = Class.new { include ActiveSupport::Callbacks - define_callbacks :foo, :scope => [:name] - set_callback :foo, :before, :foo, :if => callback + define_callbacks :foo, scope: [:name] + set_callback :foo, :before, :foo, if: callback def run; run_callbacks :foo; end private def foo; end @@ -964,7 +1029,7 @@ module CallbacksTest def test_proc_arity2 assert_raises(ArgumentError) do - object = build_class(->(a,b) { }).new + object = build_class(->(a,b) {}).new object.run end end diff --git a/activesupport/test/class_cache_test.rb b/activesupport/test/class_cache_test.rb index b96f476ce6..c618fea81a 100644 --- a/activesupport/test/class_cache_test.rb +++ b/activesupport/test/class_cache_test.rb @@ -1,5 +1,5 @@ -require 'abstract_unit' -require 'active_support/dependencies' +require "abstract_unit" +require "active_support/dependencies" module ActiveSupport module Dependencies diff --git a/activesupport/test/clean_backtrace_test.rb b/activesupport/test/clean_backtrace_test.rb index 05580352a9..5ed518cdb0 100644 --- a/activesupport/test/clean_backtrace_test.rb +++ b/activesupport/test/clean_backtrace_test.rb @@ -1,9 +1,9 @@ -require 'abstract_unit' +require "abstract_unit" class BacktraceCleanerFilterTest < ActiveSupport::TestCase def setup @bc = ActiveSupport::BacktraceCleaner.new - @bc.add_filter { |line| line.gsub("/my/prefix", '') } + @bc.add_filter { |line| line.gsub("/my/prefix", "") } end test "backtrace should filter all lines in a backtrace, removing prefixes" do @@ -20,13 +20,12 @@ class BacktraceCleanerFilterTest < ActiveSupport::TestCase test "backtrace should contain unaltered lines if they dont match a filter" do assert_equal "/my/other_prefix/my/class.rb", @bc.clean([ "/my/other_prefix/my/class.rb" ]).first end - end class BacktraceCleanerSilencerTest < ActiveSupport::TestCase def setup @bc = ActiveSupport::BacktraceCleaner.new - @bc.add_silencer { |line| line =~ /mongrel/ } + @bc.add_silencer { |line| line.include?("mongrel") } end test "backtrace should not contain lines that match the silencer" do @@ -44,8 +43,8 @@ end class BacktraceCleanerMultipleSilencersTest < ActiveSupport::TestCase def setup @bc = ActiveSupport::BacktraceCleaner.new - @bc.add_silencer { |line| line =~ /mongrel/ } - @bc.add_silencer { |line| line =~ /yolo/ } + @bc.add_silencer { |line| line.include?("mongrel") } + @bc.add_silencer { |line| line.include?("yolo") } end test "backtrace should not contain lines that match the silencers" do @@ -66,7 +65,7 @@ class BacktraceCleanerFilterAndSilencerTest < ActiveSupport::TestCase def setup @bc = ActiveSupport::BacktraceCleaner.new @bc.add_filter { |line| line.gsub("/mongrel", "") } - @bc.add_silencer { |line| line =~ /mongrel/ } + @bc.add_silencer { |line| line.include?("mongrel") } end test "backtrace should not silence lines that has first had their silence hook filtered out" do diff --git a/activesupport/test/clean_logger_test.rb b/activesupport/test/clean_logger_test.rb index 02693a97dc..cf37fc5639 100644 --- a/activesupport/test/clean_logger_test.rb +++ b/activesupport/test/clean_logger_test.rb @@ -1,6 +1,6 @@ -require 'abstract_unit' -require 'stringio' -require 'active_support/logger' +require "abstract_unit" +require "stringio" +require "active_support/logger" class CleanLoggerTest < ActiveSupport::TestCase def setup @@ -9,14 +9,14 @@ class CleanLoggerTest < ActiveSupport::TestCase end def test_format_message - @logger.error 'error' + @logger.error "error" assert_equal "error\n", @out.string end def test_datetime_format @logger.formatter = Logger::Formatter.new @logger.formatter.datetime_format = "%Y-%m-%d" - @logger.debug 'debug' + @logger.debug "debug" assert_equal "%Y-%m-%d", @logger.formatter.datetime_format assert_match(/D, \[\d\d\d\d-\d\d-\d\d#\d+\] DEBUG -- : debug/, @out.string) end diff --git a/activesupport/test/concern_test.rb b/activesupport/test/concern_test.rb index 8ea701cfb7..95507c815d 100644 --- a/activesupport/test/concern_test.rb +++ b/activesupport/test/concern_test.rb @@ -1,5 +1,5 @@ -require 'abstract_unit' -require 'active_support/concern' +require "abstract_unit" +require "active_support/concern" class ConcernTest < ActiveSupport::TestCase module Baz @@ -66,13 +66,13 @@ class ConcernTest < ActiveSupport::TestCase def test_module_is_included_normally @klass.include(Baz) assert_equal "baz", @klass.new.baz - assert @klass.included_modules.include?(ConcernTest::Baz) + assert_includes @klass.included_modules, ConcernTest::Baz end def test_class_methods_are_extended @klass.include(Baz) assert_equal "baz", @klass.baz - assert_equal ConcernTest::Baz::ClassMethods, (class << @klass; self.included_modules; end)[0] + assert_equal ConcernTest::Baz::ClassMethods, (class << @klass; included_modules; end)[0] end def test_class_methods_are_extended_only_on_expected_objects @@ -105,7 +105,7 @@ class ConcernTest < ActiveSupport::TestCase assert_equal "bar", @klass.new.bar assert_equal "bar+baz", @klass.new.baz assert_equal "bar's baz + baz", @klass.baz - assert @klass.included_modules.include?(ConcernTest::Bar) + assert_includes @klass.included_modules, ConcernTest::Bar end def test_dependencies_with_multiple_modules diff --git a/activesupport/test/configurable_test.rb b/activesupport/test/configurable_test.rb index 5d22ded2de..3cd6d2d4d0 100644 --- a/activesupport/test/configurable_test.rb +++ b/activesupport/test/configurable_test.rb @@ -1,5 +1,5 @@ -require 'abstract_unit' -require 'active_support/configurable' +require "abstract_unit" +require "active_support/configurable" class ConfigurableActiveSupport < ActiveSupport::TestCase class Parent @@ -111,7 +111,7 @@ class ConfigurableActiveSupport < ActiveSupport::TestCase end end - test 'the config_accessor method should not be publicly callable' do + test "the config_accessor method should not be publicly callable" do assert_raises NoMethodError do Class.new { include ActiveSupport::Configurable @@ -121,11 +121,11 @@ class ConfigurableActiveSupport < ActiveSupport::TestCase def assert_method_defined(object, method) methods = object.public_methods.map(&:to_s) - assert methods.include?(method.to_s), "Expected #{methods.inspect} to include #{method.to_s.inspect}" + assert_includes methods, method.to_s, "Expected #{methods.inspect} to include #{method.to_s.inspect}" end def assert_method_not_defined(object, method) methods = object.public_methods.map(&:to_s) - assert !methods.include?(method.to_s), "Expected #{methods.inspect} to not include #{method.to_s.inspect}" + assert_not_includes methods, method.to_s, "Expected #{methods.inspect} to not include #{method.to_s.inspect}" end end diff --git a/activesupport/test/constantize_test_cases.rb b/activesupport/test/constantize_test_cases.rb index 1115bc0fd8..af2db8c991 100644 --- a/activesupport/test/constantize_test_cases.rb +++ b/activesupport/test/constantize_test_cases.rb @@ -1,4 +1,4 @@ -require 'dependencies_test_helpers' +require "dependencies_test_helpers" module Ace module Base @@ -100,10 +100,10 @@ module ConstantizeTestCases assert_nil yield("Ace::Gas::ConstantizeTestCases") assert_nil yield("#<Class:0x7b8b718b>::Nested_1") assert_nil yield("Ace::gas") - assert_nil yield('Object::ABC') - assert_nil yield('Object::Object::Object::ABC') - assert_nil yield('A::Object::B') - assert_nil yield('A::Object::Object::Object::B') + assert_nil yield("Object::ABC") + assert_nil yield("Object::Object::Object::ABC") + assert_nil yield("A::Object::B") + assert_nil yield("A::Object::Object::Object::B") assert_raises(NameError) do with_autoloading_fixtures do diff --git a/activesupport/test/core_ext/array/access_test.rb b/activesupport/test/core_ext/array/access_test.rb index 1d834667f0..a38ea36d00 100644 --- a/activesupport/test/core_ext/array/access_test.rb +++ b/activesupport/test/core_ext/array/access_test.rb @@ -1,5 +1,5 @@ -require 'abstract_unit' -require 'active_support/core_ext/array' +require "abstract_unit" +require "active_support/core_ext/array" class AccessTest < ActiveSupport::TestCase def test_from diff --git a/activesupport/test/core_ext/array/conversions_test.rb b/activesupport/test/core_ext/array/conversions_test.rb index 507e13f968..469efcd934 100644 --- a/activesupport/test/core_ext/array/conversions_test.rb +++ b/activesupport/test/core_ext/array/conversions_test.rb @@ -1,37 +1,42 @@ -require 'abstract_unit' -require 'active_support/core_ext/array' -require 'active_support/core_ext/big_decimal' -require 'active_support/core_ext/hash' -require 'active_support/core_ext/string' +require "abstract_unit" +require "active_support/core_ext/array" +require "active_support/core_ext/big_decimal" +require "active_support/core_ext/hash" +require "active_support/core_ext/string" class ToSentenceTest < ActiveSupport::TestCase def test_plain_array_to_sentence assert_equal "", [].to_sentence - assert_equal "one", ['one'].to_sentence - assert_equal "one and two", ['one', 'two'].to_sentence - assert_equal "one, two, and three", ['one', 'two', 'three'].to_sentence + assert_equal "one", ["one"].to_sentence + assert_equal "one and two", ["one", "two"].to_sentence + assert_equal "one, two, and three", ["one", "two", "three"].to_sentence end def test_to_sentence_with_words_connector - assert_equal "one two, and three", ['one', 'two', 'three'].to_sentence(words_connector: ' ') - assert_equal "one & two, and three", ['one', 'two', 'three'].to_sentence(words_connector: ' & ') - assert_equal "onetwo, and three", ['one', 'two', 'three'].to_sentence(words_connector: nil) + assert_equal "one two, and three", ["one", "two", "three"].to_sentence(words_connector: " ") + assert_equal "one & two, and three", ["one", "two", "three"].to_sentence(words_connector: " & ") + assert_equal "onetwo, and three", ["one", "two", "three"].to_sentence(words_connector: nil) end def test_to_sentence_with_last_word_connector - assert_equal "one, two, and also three", ['one', 'two', 'three'].to_sentence(last_word_connector: ', and also ') - assert_equal "one, twothree", ['one', 'two', 'three'].to_sentence(last_word_connector: nil) - assert_equal "one, two three", ['one', 'two', 'three'].to_sentence(last_word_connector: ' ') - assert_equal "one, two and three", ['one', 'two', 'three'].to_sentence(last_word_connector: ' and ') + assert_equal "one, two, and also three", ["one", "two", "three"].to_sentence(last_word_connector: ", and also ") + assert_equal "one, twothree", ["one", "two", "three"].to_sentence(last_word_connector: nil) + assert_equal "one, two three", ["one", "two", "three"].to_sentence(last_word_connector: " ") + assert_equal "one, two and three", ["one", "two", "three"].to_sentence(last_word_connector: " and ") + end + + def test_to_sentence_with_fallback_string + assert_equal "none", [].to_sentence(fallback_string: "none") + assert_equal "one, two, and three", ["one", "two", "three"].to_sentence(fallback_string: "none") end def test_two_elements - assert_equal "one and two", ['one', 'two'].to_sentence - assert_equal "one two", ['one', 'two'].to_sentence(two_words_connector: ' ') + assert_equal "one and two", ["one", "two"].to_sentence + assert_equal "one two", ["one", "two"].to_sentence(two_words_connector: " ") end def test_one_element - assert_equal "one", ['one'].to_sentence + assert_equal "one", ["one"].to_sentence end def test_one_element_not_same_object @@ -40,31 +45,31 @@ class ToSentenceTest < ActiveSupport::TestCase end def test_one_non_string_element - assert_equal '1', [1].to_sentence + assert_equal "1", [1].to_sentence end def test_does_not_modify_given_hash - options = { words_connector: ' ' } - assert_equal "one two, and three", ['one', 'two', 'three'].to_sentence(options) - assert_equal({ words_connector: ' ' }, options) + options = { words_connector: " " } + assert_equal "one two, and three", ["one", "two", "three"].to_sentence(options) + assert_equal({ words_connector: " " }, options) end def test_with_blank_elements - assert_equal ", one, , two, and three", [nil, 'one', '', 'two', 'three'].to_sentence + assert_equal ", one, , two, and three", [nil, "one", "", "two", "three"].to_sentence end def test_with_invalid_options exception = assert_raise ArgumentError do - ['one', 'two'].to_sentence(passing: 'invalid option') + ["one", "two"].to_sentence(passing: "invalid option") end - assert_equal exception.message, "Unknown key: :passing. Valid keys are: :words_connector, :two_words_connector, :last_word_connector, :locale" + assert_equal exception.message, "Unknown key: :passing. Valid keys are: :words_connector, :two_words_connector, :last_word_connector, :locale, :fallback_string" end def test_always_returns_string - assert_instance_of String, [ActiveSupport::SafeBuffer.new('one')].to_sentence - assert_instance_of String, [ActiveSupport::SafeBuffer.new('one'), 'two'].to_sentence - assert_instance_of String, [ActiveSupport::SafeBuffer.new('one'), 'two', 'three'].to_sentence + assert_instance_of String, [ActiveSupport::SafeBuffer.new("one")].to_sentence + assert_instance_of String, [ActiveSupport::SafeBuffer.new("one"), "two"].to_sentence + assert_instance_of String, [ActiveSupport::SafeBuffer.new("one"), "two", "three"].to_sentence end end @@ -88,32 +93,32 @@ class ToXmlTest < ActiveSupport::TestCase def test_to_xml_with_hash_elements xml = [ { name: "David", age: 26, age_in_millis: 820497600000 }, - { name: "Jason", age: 31, age_in_millis: BigDecimal.new('1.0') } + { name: "Jason", age: 31, age_in_millis: BigDecimal.new("1.0") } ].to_xml(skip_instruct: true, indent: 0) assert_equal '<objects type="array"><object>', xml.first(30) - assert xml.include?(%(<age type="integer">26</age>)), xml - assert xml.include?(%(<age-in-millis type="integer">820497600000</age-in-millis>)), xml - assert xml.include?(%(<name>David</name>)), xml - assert xml.include?(%(<age type="integer">31</age>)), xml - assert xml.include?(%(<age-in-millis type="decimal">1.0</age-in-millis>)), xml - assert xml.include?(%(<name>Jason</name>)), xml + assert_includes xml, %(<age type="integer">26</age>), xml + assert_includes xml, %(<age-in-millis type="integer">820497600000</age-in-millis>), xml + assert_includes xml, %(<name>David</name>), xml + assert_includes xml, %(<age type="integer">31</age>), xml + assert_includes xml, %(<age-in-millis type="decimal">1.0</age-in-millis>), xml + assert_includes xml, %(<name>Jason</name>), xml end def test_to_xml_with_non_hash_elements - xml = [1, 2, 3].to_xml(skip_instruct: true, indent: 0) + xml = %w[1 2 3].to_xml(skip_instruct: true, indent: 0) - assert_equal '<fixnums type="array"><fixnum', xml.first(29) - assert xml.include?(%(<fixnum type="integer">2</fixnum>)), xml + assert_equal '<strings type="array"><string', xml.first(29) + assert_includes xml, %(<string>2</string>), xml end def test_to_xml_with_non_hash_different_type_elements - xml = [1, 2.0, '3'].to_xml(skip_instruct: true, indent: 0) + xml = [1, 2.0, "3"].to_xml(skip_instruct: true, indent: 0) assert_equal '<objects type="array"><object', xml.first(29) - assert xml.include?(%(<object type="integer">1</object>)), xml - assert xml.include?(%(<object type="float">2.0</object>)), xml - assert xml.include?(%(object>3</object>)), xml + assert_includes xml, %(<object type="integer">1</object>), xml + assert_includes xml, %(<object type="float">2.0</object>), xml + assert_includes xml, %(object>3</object>), xml end def test_to_xml_with_dedicated_name @@ -130,10 +135,10 @@ class ToXmlTest < ActiveSupport::TestCase ].to_xml(skip_instruct: true, skip_types: true, indent: 0) assert_equal "<objects><object>", xml.first(17) - assert xml.include?(%(<street-address>Paulina</street-address>)) - assert xml.include?(%(<name>David</name>)) - assert xml.include?(%(<street-address>Evergreen</street-address>)) - assert xml.include?(%(<name>Jason</name>)) + assert_includes xml, %(<street-address>Paulina</street-address>) + assert_includes xml, %(<name>David</name>) + assert_includes xml, %(<street-address>Evergreen</street-address>) + assert_includes xml, %(<name>Jason</name>) end def test_to_xml_with_indent_set @@ -142,10 +147,10 @@ class ToXmlTest < ActiveSupport::TestCase ].to_xml(skip_instruct: true, skip_types: true, indent: 4) assert_equal "<objects>\n <object>", xml.first(22) - assert xml.include?(%(\n <street-address>Paulina</street-address>)) - assert xml.include?(%(\n <name>David</name>)) - assert xml.include?(%(\n <street-address>Evergreen</street-address>)) - assert xml.include?(%(\n <name>Jason</name>)) + assert_includes xml, %(\n <street-address>Paulina</street-address>) + assert_includes xml, %(\n <name>David</name>) + assert_includes xml, %(\n <street-address>Evergreen</street-address>) + assert_includes xml, %(\n <name>Jason</name>) end def test_to_xml_with_dasherize_false @@ -154,8 +159,8 @@ class ToXmlTest < ActiveSupport::TestCase ].to_xml(skip_instruct: true, skip_types: true, indent: 0, dasherize: false) assert_equal "<objects><object>", xml.first(17) - assert xml.include?(%(<street_address>Paulina</street_address>)) - assert xml.include?(%(<street_address>Evergreen</street_address>)) + assert_includes xml, %(<street_address>Paulina</street_address>) + assert_includes xml, %(<street_address>Evergreen</street_address>) end def test_to_xml_with_dasherize_true @@ -164,14 +169,14 @@ class ToXmlTest < ActiveSupport::TestCase ].to_xml(skip_instruct: true, skip_types: true, indent: 0, dasherize: true) assert_equal "<objects><object>", xml.first(17) - assert xml.include?(%(<street-address>Paulina</street-address>)) - assert xml.include?(%(<street-address>Evergreen</street-address>)) + assert_includes xml, %(<street-address>Paulina</street-address>) + assert_includes xml, %(<street-address>Evergreen</street-address>) end def test_to_xml_with_instruct xml = [ { name: "David", age: 26, age_in_millis: 820497600000 }, - { name: "Jason", age: 31, age_in_millis: BigDecimal.new('1.0') } + { name: "Jason", age: 31, age_in_millis: BigDecimal.new("1.0") } ].to_xml(skip_instruct: false, indent: 0) assert_match(/^<\?xml [^>]*/, xml) @@ -181,12 +186,12 @@ class ToXmlTest < ActiveSupport::TestCase def test_to_xml_with_block xml = [ { name: "David", age: 26, age_in_millis: 820497600000 }, - { name: "Jason", age: 31, age_in_millis: BigDecimal.new('1.0') } + { name: "Jason", age: 31, age_in_millis: BigDecimal.new("1.0") } ].to_xml(skip_instruct: true, indent: 0) do |builder| builder.count 2 end - assert xml.include?(%(<count>2</count>)), xml + assert_includes xml, %(<count>2</count>), xml end def test_to_xml_with_empty diff --git a/activesupport/test/core_ext/array/extract_options_test.rb b/activesupport/test/core_ext/array/extract_options_test.rb index 0481a507cf..1651bee0f6 100644 --- a/activesupport/test/core_ext/array/extract_options_test.rb +++ b/activesupport/test/core_ext/array/extract_options_test.rb @@ -1,6 +1,6 @@ -require 'abstract_unit' -require 'active_support/core_ext/array' -require 'active_support/core_ext/hash' +require "abstract_unit" +require "active_support/core_ext/array" +require "active_support/core_ext/hash" class ExtractOptionsTest < ActiveSupport::TestCase class HashSubclass < Hash diff --git a/activesupport/test/core_ext/array/grouping_test.rb b/activesupport/test/core_ext/array/grouping_test.rb index 2eb0f05141..b06f87c008 100644 --- a/activesupport/test/core_ext/array/grouping_test.rb +++ b/activesupport/test/core_ext/array/grouping_test.rb @@ -1,38 +1,39 @@ -require 'abstract_unit' -require 'active_support/core_ext/array' +require "abstract_unit" +require "active_support/core_ext/array" class GroupingTest < ActiveSupport::TestCase def setup - Fixnum.send :private, :/ # test we avoid Integer#/ (redefined by mathn) + # In Ruby < 2.4, test we avoid Integer#/ (redefined by mathn) + Fixnum.send :private, :/ unless 0.class == Integer end def teardown - Fixnum.send :public, :/ + Fixnum.send :public, :/ unless 0.class == Integer end def test_in_groups_of_with_perfect_fit groups = [] - ('a'..'i').to_a.in_groups_of(3) do |group| + ("a".."i").to_a.in_groups_of(3) do |group| groups << group end assert_equal [%w(a b c), %w(d e f), %w(g h i)], groups - assert_equal [%w(a b c), %w(d e f), %w(g h i)], ('a'..'i').to_a.in_groups_of(3) + assert_equal [%w(a b c), %w(d e f), %w(g h i)], ("a".."i").to_a.in_groups_of(3) end def test_in_groups_of_with_padding groups = [] - ('a'..'g').to_a.in_groups_of(3) do |group| + ("a".."g").to_a.in_groups_of(3) do |group| groups << group end - assert_equal [%w(a b c), %w(d e f), ['g', nil, nil]], groups + assert_equal [%w(a b c), %w(d e f), ["g", nil, nil]], groups end def test_in_groups_of_pads_with_specified_values groups = [] - ('a'..'g').to_a.in_groups_of(3, 'foo') do |group| + ("a".."g").to_a.in_groups_of(3, "foo") do |group| groups << group end @@ -42,7 +43,7 @@ class GroupingTest < ActiveSupport::TestCase def test_in_groups_of_without_padding groups = [] - ('a'..'g').to_a.in_groups_of(3, false) do |group| + ("a".."g").to_a.in_groups_of(3, false) do |group| groups << group end @@ -82,8 +83,8 @@ class GroupingTest < ActiveSupport::TestCase assert_equal [[1, 2, 3], [4, 5, nil], [6, 7, nil]], array.in_groups(3) - assert_equal [[1, 2, 3], [4, 5, 'foo'], [6, 7, 'foo']], - array.in_groups(3, 'foo') + assert_equal [[1, 2, 3], [4, 5, "foo"], [6, 7, "foo"]], + array.in_groups(3, "foo") end def test_in_groups_without_padding @@ -123,4 +124,12 @@ class SplitTest < ActiveSupport::TestCase assert_equal [[], [2, 3, 4], []], a.split { |i| i == 1 || i == 5 } assert_equal [1, 2, 3, 4, 5], a end + + def test_split_with_repeated_values + a = [1, 2, 3, 5, 5, 3, 4, 6, 2, 1, 3] + assert_equal [[1, 2], [5, 5], [4, 6, 2, 1], []], a.split(3) + assert_equal [[1, 2, 3], [], [3, 4, 6, 2, 1, 3]], a.split(5) + assert_equal [[1, 2], [], [], [], [4, 6, 2, 1], []], a.split { |i| i == 3 || i == 5 } + assert_equal [1, 2, 3, 5, 5, 3, 4, 6, 2, 1, 3], a + end end diff --git a/activesupport/test/core_ext/array/prepend_append_test.rb b/activesupport/test/core_ext/array/prepend_append_test.rb index 762aa69b2b..763e26191d 100644 --- a/activesupport/test/core_ext/array/prepend_append_test.rb +++ b/activesupport/test/core_ext/array/prepend_append_test.rb @@ -1,5 +1,5 @@ -require 'abstract_unit' -require 'active_support/core_ext/array' +require "abstract_unit" +require "active_support/core_ext/array" class PrependAppendTest < ActiveSupport::TestCase def test_append diff --git a/activesupport/test/core_ext/array/wrap_test.rb b/activesupport/test/core_ext/array/wrap_test.rb index baf426506f..ae846cb3f2 100644 --- a/activesupport/test/core_ext/array/wrap_test.rb +++ b/activesupport/test/core_ext/array/wrap_test.rb @@ -1,5 +1,5 @@ -require 'abstract_unit' -require 'active_support/core_ext/array' +require "abstract_unit" +require "active_support/core_ext/array" class WrapTest < ActiveSupport::TestCase class FakeCollection diff --git a/activesupport/test/core_ext/bigdecimal_test.rb b/activesupport/test/core_ext/bigdecimal_test.rb index 423a3f2e9d..43b659546f 100644 --- a/activesupport/test/core_ext/bigdecimal_test.rb +++ b/activesupport/test/core_ext/bigdecimal_test.rb @@ -1,9 +1,11 @@ -require 'abstract_unit' -require 'active_support/core_ext/big_decimal' +require "abstract_unit" +require "active_support/core_ext/big_decimal" class BigDecimalTest < ActiveSupport::TestCase def test_to_s - bd = BigDecimal.new '0.01' - assert_equal '0.01', bd.to_s + bd = BigDecimal.new "0.01" + assert_equal "0.01", bd.to_s + assert_equal "+0.01", bd.to_s("+F") + assert_equal "+0.0 1", bd.to_s("+1F") end end diff --git a/activesupport/test/core_ext/class/attribute_test.rb b/activesupport/test/core_ext/class/attribute_test.rb index e7a1334db3..5a9ec78cc1 100644 --- a/activesupport/test/core_ext/class/attribute_test.rb +++ b/activesupport/test/core_ext/class/attribute_test.rb @@ -1,5 +1,5 @@ -require 'abstract_unit' -require 'active_support/core_ext/class/attribute' +require "abstract_unit" +require "active_support/core_ext/class/attribute" class ClassAttributeTest < ActiveSupport::TestCase def setup @@ -7,17 +7,17 @@ class ClassAttributeTest < ActiveSupport::TestCase @sub = Class.new(@klass) end - test 'defaults to nil' do + test "defaults to nil" do assert_nil @klass.setting assert_nil @sub.setting end - test 'inheritable' do + test "inheritable" do @klass.setting = 1 assert_equal 1, @sub.setting end - test 'overridable' do + test "overridable" do @sub.setting = 1 assert_nil @klass.setting @@ -27,20 +27,20 @@ class ClassAttributeTest < ActiveSupport::TestCase assert_equal 1, Class.new(@sub).setting end - test 'predicate method' do + test "predicate method" do assert_equal false, @klass.setting? @klass.setting = 1 assert_equal true, @klass.setting? end - test 'instance reader delegates to class' do + test "instance reader delegates to class" do assert_nil @klass.new.setting @klass.setting = 1 assert_equal 1, @klass.new.setting end - test 'instance override' do + test "instance override" do object = @klass.new object.setting = 1 assert_nil @klass.setting @@ -48,43 +48,43 @@ class ClassAttributeTest < ActiveSupport::TestCase assert_equal 1, object.setting end - test 'instance predicate' do + test "instance predicate" do object = @klass.new assert_equal false, object.setting? object.setting = 1 assert_equal true, object.setting? end - test 'disabling instance writer' do - object = Class.new { class_attribute :setting, :instance_writer => false }.new - assert_raise(NoMethodError) { object.setting = 'boom' } + test "disabling instance writer" do + object = Class.new { class_attribute :setting, instance_writer: false }.new + assert_raise(NoMethodError) { object.setting = "boom" } end - test 'disabling instance reader' do - object = Class.new { class_attribute :setting, :instance_reader => false }.new + test "disabling instance reader" do + object = Class.new { class_attribute :setting, instance_reader: false }.new assert_raise(NoMethodError) { object.setting } assert_raise(NoMethodError) { object.setting? } end - test 'disabling both instance writer and reader' do - object = Class.new { class_attribute :setting, :instance_accessor => false }.new + test "disabling both instance writer and reader" do + object = Class.new { class_attribute :setting, instance_accessor: false }.new assert_raise(NoMethodError) { object.setting } assert_raise(NoMethodError) { object.setting? } - assert_raise(NoMethodError) { object.setting = 'boom' } + assert_raise(NoMethodError) { object.setting = "boom" } end - test 'disabling instance predicate' do + test "disabling instance predicate" do object = Class.new { class_attribute :setting, instance_predicate: false }.new assert_raise(NoMethodError) { object.setting? } end - test 'works well with singleton classes' do + test "works well with singleton classes" do object = @klass.new - object.singleton_class.setting = 'foo' - assert_equal 'foo', object.setting + object.singleton_class.setting = "foo" + assert_equal "foo", object.setting end - test 'setter returns set value' do + test "setter returns set value" do val = @klass.send(:setting=, 1) assert_equal 1, val end diff --git a/activesupport/test/core_ext/class_test.rb b/activesupport/test/core_ext/class_test.rb index 9c6c579ef7..a9c44907cc 100644 --- a/activesupport/test/core_ext/class_test.rb +++ b/activesupport/test/core_ext/class_test.rb @@ -1,6 +1,6 @@ -require 'abstract_unit' -require 'active_support/core_ext/class' -require 'set' +require "abstract_unit" +require "active_support/core_ext/class" +require "set" class ClassTest < ActiveSupport::TestCase class Parent; end diff --git a/activesupport/test/core_ext/date_and_time_behavior.rb b/activesupport/test/core_ext/date_and_time_behavior.rb index 784547bdf8..6cc9781e02 100644 --- a/activesupport/test/core_ext/date_and_time_behavior.rb +++ b/activesupport/test/core_ext/date_and_time_behavior.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" module DateAndTimeBehavior def test_yesterday @@ -126,7 +126,9 @@ module DateAndTimeBehavior end def test_next_week_at_same_time - assert_equal date_time_init(2005,2,28,15,15,10), date_time_init(2005,2,22,15,15,10).next_week(:monday, same_time: true) + assert_equal date_time_init(2005,2,28,15,15,10), date_time_init(2005,2,22,15,15,10).next_week(:monday, same_time: true) + assert_equal date_time_init(2005,2,28,15,15,10,999999), date_time_init(2005,2,22,15,15,10,999999).next_week(:monday, same_time: true) + assert_equal date_time_init(2005,2,28,15,15,10,Rational(999999999, 1000)), date_time_init(2005,2,22,15,15,10,Rational(999999999, 1000)).next_week(:monday, same_time: true) assert_equal date_time_init(2005,3,4,15,15,10), date_time_init(2005,2,22,15,15,10).next_week(:friday, same_time: true) assert_equal date_time_init(2006,10,30,0,0,0), date_time_init(2006,10,23,0,0,0).next_week(:monday, same_time: true) assert_equal date_time_init(2006,11,1,0,0,0), date_time_init(2006,10,23,0,0,0).next_week(:wednesday, same_time: true) @@ -301,6 +303,16 @@ module DateAndTimeBehavior assert_not date_time_init(2015,1,5,15,15,10).on_weekend? end + def test_on_weekday_on_sunday + assert_not date_time_init(2015,1,4,0,0,0).on_weekday? + assert_not date_time_init(2015,1,4,15,15,10).on_weekday? + end + + def test_on_weekday_on_monday + assert date_time_init(2015,1,5,0,0,0).on_weekday? + assert date_time_init(2015,1,5,15,15,10).on_weekday? + end + def with_bw_default(bw = :monday) old_bw = Date.beginning_of_week Date.beginning_of_week = bw diff --git a/activesupport/test/core_ext/date_and_time_compatibility_test.rb b/activesupport/test/core_ext/date_and_time_compatibility_test.rb new file mode 100644 index 0000000000..180b3e12aa --- /dev/null +++ b/activesupport/test/core_ext/date_and_time_compatibility_test.rb @@ -0,0 +1,127 @@ +require "abstract_unit" +require "active_support/time" +require "time_zone_test_helpers" + +class DateAndTimeCompatibilityTest < ActiveSupport::TestCase + include TimeZoneTestHelpers + + def setup + @utc_time = Time.utc(2016, 4, 23, 14, 11, 12) + @date_time = DateTime.new(2016, 4, 23, 14, 11, 12, 0) + @utc_offset = 3600 + @system_offset = -14400 + @zone = ActiveSupport::TimeZone["London"] + end + + def test_time_to_time_preserves_timezone + with_preserve_timezone(true) do + with_env_tz "US/Eastern" do + time = Time.new(2016, 4, 23, 15, 11, 12, 3600).to_time + + assert_instance_of Time, time + assert_equal @utc_time, time.getutc + assert_equal @utc_offset, time.utc_offset + end + end + end + + def test_time_to_time_does_not_preserve_time_zone + with_preserve_timezone(false) do + with_env_tz "US/Eastern" do + time = Time.new(2016, 4, 23, 15, 11, 12, 3600).to_time + + assert_instance_of Time, time + assert_equal @utc_time, time.getutc + assert_equal @system_offset, time.utc_offset + end + end + end + + def test_datetime_to_time_preserves_timezone + with_preserve_timezone(true) do + with_env_tz "US/Eastern" do + time = DateTime.new(2016, 4, 23, 15, 11, 12, Rational(1,24)).to_time + + assert_instance_of Time, time + assert_equal @utc_time, time.getutc + assert_equal @utc_offset, time.utc_offset + end + end + end + + def test_datetime_to_time_does_not_preserve_time_zone + with_preserve_timezone(false) do + with_env_tz "US/Eastern" do + time = DateTime.new(2016, 4, 23, 15, 11, 12, Rational(1,24)).to_time + + assert_instance_of Time, time + assert_equal @utc_time, time.getutc + assert_equal @system_offset, time.utc_offset + end + end + end + + def test_twz_to_time_preserves_timezone + with_preserve_timezone(true) do + with_env_tz "US/Eastern" do + time = ActiveSupport::TimeWithZone.new(@utc_time, @zone).to_time + + assert_instance_of Time, time + assert_equal @utc_time, time.getutc + assert_instance_of Time, time.getutc + assert_equal @utc_offset, time.utc_offset + + time = ActiveSupport::TimeWithZone.new(@date_time, @zone).to_time + + assert_instance_of Time, time + assert_equal @date_time, time.getutc + assert_instance_of Time, time.getutc + assert_equal @utc_offset, time.utc_offset + end + end + end + + def test_twz_to_time_does_not_preserve_time_zone + with_preserve_timezone(false) do + with_env_tz "US/Eastern" do + time = ActiveSupport::TimeWithZone.new(@utc_time, @zone).to_time + + assert_instance_of Time, time + assert_equal @utc_time, time.getutc + assert_instance_of Time, time.getutc + assert_equal @system_offset, time.utc_offset + + time = ActiveSupport::TimeWithZone.new(@date_time, @zone).to_time + + assert_instance_of Time, time + assert_equal @date_time, time.getutc + assert_instance_of Time, time.getutc + assert_equal @system_offset, time.utc_offset + end + end + end + + def test_string_to_time_preserves_timezone + with_preserve_timezone(true) do + with_env_tz "US/Eastern" do + time = "2016-04-23T15:11:12+01:00".to_time + + assert_instance_of Time, time + assert_equal @utc_time, time.getutc + assert_equal @utc_offset, time.utc_offset + end + end + end + + def test_string_to_time_does_not_preserve_time_zone + with_preserve_timezone(false) do + with_env_tz "US/Eastern" do + time = "2016-04-23T15:11:12+01:00".to_time + + assert_instance_of Time, time + assert_equal @utc_time, time.getutc + assert_equal @system_offset, time.utc_offset + end + end + end +end diff --git a/activesupport/test/core_ext/date_ext_test.rb b/activesupport/test/core_ext/date_ext_test.rb index 0fc3f765f5..0655197335 100644 --- a/activesupport/test/core_ext/date_ext_test.rb +++ b/activesupport/test/core_ext/date_ext_test.rb @@ -1,7 +1,7 @@ -require 'abstract_unit' -require 'active_support/time' -require 'core_ext/date_and_time_behavior' -require 'time_zone_test_helpers' +require "abstract_unit" +require "active_support/time" +require "core_ext/date_and_time_behavior" +require "time_zone_test_helpers" class DateExtCalculationsTest < ActiveSupport::TestCase def date_time_init(year,month,day,*args) @@ -30,13 +30,24 @@ class DateExtCalculationsTest < ActiveSupport::TestCase assert_equal "2005-02-21", date.to_s(:iso8601) end + def test_to_s_with_single_digit_day + date = Date.new(2005, 2, 1) + assert_equal "2005-02-01", date.to_s + assert_equal "01 Feb", date.to_s(:short) + assert_equal "February 01, 2005", date.to_s(:long) + assert_equal "February 1st, 2005", date.to_s(:long_ordinal) + assert_equal "2005-02-01", date.to_s(:db) + assert_equal "01 Feb 2005", date.to_s(:rfc822) + assert_equal "2005-02-01", date.to_s(:iso8601) + end + def test_readable_inspect assert_equal "Mon, 21 Feb 2005", Date.new(2005, 2, 21).readable_inspect assert_equal Date.new(2005, 2, 21).readable_inspect, Date.new(2005, 2, 21).inspect end def test_to_time - with_env_tz 'US/Eastern' do + with_env_tz "US/Eastern" do assert_equal Time, Date.new(2005, 2, 21).to_time.class assert_equal Time.local(2005, 2, 21), Date.new(2005, 2, 21).to_time assert_equal Time.local(2005, 2, 21).utc_offset, Date.new(2005, 2, 21).to_time.utc_offset @@ -49,6 +60,10 @@ class DateExtCalculationsTest < ActiveSupport::TestCase end end end + + assert_raise(ArgumentError) do + Date.new(2005, 2, 21).to_time(:tokyo) + end end def test_compare_to_time @@ -66,10 +81,10 @@ class DateExtCalculationsTest < ActiveSupport::TestCase end def test_change - assert_equal Date.new(2005, 2, 21), Date.new(2005, 2, 11).change(:day => 21) - assert_equal Date.new(2007, 5, 11), Date.new(2005, 2, 11).change(:year => 2007, :month => 5) - assert_equal Date.new(2006,2,22), Date.new(2005,2,22).change(:year => 2006) - assert_equal Date.new(2005,6,22), Date.new(2005,2,22).change(:month => 6) + assert_equal Date.new(2005, 2, 21), Date.new(2005, 2, 11).change(day: 21) + assert_equal Date.new(2007, 5, 11), Date.new(2005, 2, 11).change(year: 2007, month: 5) + assert_equal Date.new(2006,2,22), Date.new(2005,2,22).change(year: 2006) + assert_equal Date.new(2005,6,22), Date.new(2005,2,22).change(month: 6) end def test_sunday @@ -124,34 +139,34 @@ class DateExtCalculationsTest < ActiveSupport::TestCase end def test_advance - assert_equal Date.new(2006,2,28), Date.new(2005,2,28).advance(:years => 1) - assert_equal Date.new(2005,6,28), Date.new(2005,2,28).advance(:months => 4) - assert_equal Date.new(2005,3,21), Date.new(2005,2,28).advance(:weeks => 3) - assert_equal Date.new(2005,3,5), Date.new(2005,2,28).advance(:days => 5) - assert_equal Date.new(2012,9,28), Date.new(2005,2,28).advance(:years => 7, :months => 7) - assert_equal Date.new(2013,10,3), Date.new(2005,2,28).advance(:years => 7, :months => 19, :days => 5) - assert_equal Date.new(2013,10,17), Date.new(2005,2,28).advance(:years => 7, :months => 19, :weeks => 2, :days => 5) - assert_equal Date.new(2005,2,28), Date.new(2004,2,29).advance(:years => 1) #leap day plus one year + assert_equal Date.new(2006,2,28), Date.new(2005,2,28).advance(years: 1) + assert_equal Date.new(2005,6,28), Date.new(2005,2,28).advance(months: 4) + assert_equal Date.new(2005,3,21), Date.new(2005,2,28).advance(weeks: 3) + assert_equal Date.new(2005,3,5), Date.new(2005,2,28).advance(days: 5) + assert_equal Date.new(2012,9,28), Date.new(2005,2,28).advance(years: 7, months: 7) + assert_equal Date.new(2013,10,3), Date.new(2005,2,28).advance(years: 7, months: 19, days: 5) + assert_equal Date.new(2013,10,17), Date.new(2005,2,28).advance(years: 7, months: 19, weeks: 2, days: 5) + assert_equal Date.new(2005,2,28), Date.new(2004,2,29).advance(years: 1) #leap day plus one year end def test_advance_does_first_years_and_then_days - assert_equal Date.new(2012, 2, 29), Date.new(2011, 2, 28).advance(:years => 1, :days => 1) + assert_equal Date.new(2012, 2, 29), Date.new(2011, 2, 28).advance(years: 1, days: 1) # If day was done first we would jump to 2012-03-01 instead. end def test_advance_does_first_months_and_then_days - assert_equal Date.new(2010, 3, 29), Date.new(2010, 2, 28).advance(:months => 1, :days => 1) + assert_equal Date.new(2010, 3, 29), Date.new(2010, 2, 28).advance(months: 1, days: 1) # If day was done first we would jump to 2010-04-01 instead. end def test_advance_in_calendar_reform - assert_equal Date.new(1582,10,15), Date.new(1582,10,4).advance(:days => 1) - assert_equal Date.new(1582,10,4), Date.new(1582,10,15).advance(:days => -1) + assert_equal Date.new(1582,10,15), Date.new(1582,10,4).advance(days: 1) + assert_equal Date.new(1582,10,4), Date.new(1582,10,15).advance(days: -1) 5.upto(14) do |day| - assert_equal Date.new(1582,10,4), Date.new(1582,9,day).advance(:months => 1) - assert_equal Date.new(1582,10,4), Date.new(1582,11,day).advance(:months => -1) - assert_equal Date.new(1582,10,4), Date.new(1581,10,day).advance(:years => 1) - assert_equal Date.new(1582,10,4), Date.new(1583,10,day).advance(:years => -1) + assert_equal Date.new(1582,10,4), Date.new(1582,9,day).advance(months: 1) + assert_equal Date.new(1582,10,4), Date.new(1582,11,day).advance(months: -1) + assert_equal Date.new(1582,10,4), Date.new(1581,10,day).advance(years: 1) + assert_equal Date.new(1582,10,4), Date.new(1583,10,day).advance(years: -1) end end @@ -181,7 +196,7 @@ class DateExtCalculationsTest < ActiveSupport::TestCase end def test_yesterday_constructor_when_zone_is_not_set - with_env_tz 'UTC' do + with_env_tz "UTC" do with_tz_default do assert_equal(Date.today - 1, Date.yesterday) end @@ -189,8 +204,8 @@ class DateExtCalculationsTest < ActiveSupport::TestCase end def test_yesterday_constructor_when_zone_is_set - with_env_tz 'UTC' do - with_tz_default ActiveSupport::TimeZone['Eastern Time (US & Canada)'] do # UTC -5 + with_env_tz "UTC" do + with_tz_default ActiveSupport::TimeZone["Eastern Time (US & Canada)"] do # UTC -5 Time.stub(:now, Time.local(2000, 1, 1)) do assert_equal Date.new(1999, 12, 30), Date.yesterday end @@ -203,7 +218,7 @@ class DateExtCalculationsTest < ActiveSupport::TestCase end def test_tomorrow_constructor_when_zone_is_not_set - with_env_tz 'UTC' do + with_env_tz "UTC" do with_tz_default do assert_equal(Date.today + 1, Date.tomorrow) end @@ -211,8 +226,8 @@ class DateExtCalculationsTest < ActiveSupport::TestCase end def test_tomorrow_constructor_when_zone_is_set - with_env_tz 'UTC' do - with_tz_default ActiveSupport::TimeZone['Europe/Paris'] do # UTC +1 + with_env_tz "UTC" do + with_tz_default ActiveSupport::TimeZone["Europe/Paris"] do # UTC +1 Time.stub(:now, Time.local(1999, 12, 31, 23)) do assert_equal Date.new(2000, 1, 2), Date.tomorrow end @@ -225,8 +240,8 @@ class DateExtCalculationsTest < ActiveSupport::TestCase end def test_since_when_zone_is_set - zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)'] - with_env_tz 'UTC' do + zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"] + with_env_tz "UTC" do with_tz_default zone do assert_equal zone.local(2005,2,21,0,0,45), Date.new(2005,2,21).since(45) assert_equal zone, Date.new(2005,2,21).since(45).time_zone @@ -239,8 +254,8 @@ class DateExtCalculationsTest < ActiveSupport::TestCase end def test_ago_when_zone_is_set - zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)'] - with_env_tz 'UTC' do + zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"] + with_env_tz "UTC" do with_tz_default zone do assert_equal zone.local(2005,2,20,23,59,15), Date.new(2005,2,21).ago(45) assert_equal zone, Date.new(2005,2,21).ago(45).time_zone @@ -257,8 +272,8 @@ class DateExtCalculationsTest < ActiveSupport::TestCase end def test_beginning_of_day_when_zone_is_set - zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)'] - with_env_tz 'UTC' do + zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"] + with_env_tz "UTC" do with_tz_default zone do assert_equal zone.local(2005,2,21,0,0,0), Date.new(2005,2,21).beginning_of_day assert_equal zone, Date.new(2005,2,21).beginning_of_day.time_zone @@ -271,8 +286,8 @@ class DateExtCalculationsTest < ActiveSupport::TestCase end def test_end_of_day_when_zone_is_set - zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)'] - with_env_tz 'UTC' do + zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"] + with_env_tz "UTC" do with_tz_default zone do assert_equal zone.local(2005,2,21,23,59,59,Rational(999999999, 1000)), Date.new(2005,2,21).end_of_day assert_equal zone, Date.new(2005,2,21).end_of_day.time_zone @@ -280,6 +295,23 @@ class DateExtCalculationsTest < ActiveSupport::TestCase end end + def test_all_day + beginning_of_day = Time.local(2011,6,7,0,0,0) + end_of_day = Time.local(2011,6,7,23,59,59,Rational(999999999, 1000)) + assert_equal beginning_of_day..end_of_day, Date.new(2011,6,7).all_day + end + + def test_all_day_when_zone_is_set + zone = ActiveSupport::TimeZone["Hawaii"] + with_env_tz "UTC" do + with_tz_default zone do + beginning_of_day = zone.local(2011,6,7,0,0,0) + end_of_day = zone.local(2011,6,7,23,59,59,Rational(999999999, 1000)) + assert_equal beginning_of_day..end_of_day, Date.new(2011,6,7).all_day + end + end + end + def test_all_week assert_equal Date.new(2011,6,6)..Date.new(2011,6,12), Date.new(2011,6,7).all_week assert_equal Date.new(2011,6,5)..Date.new(2011,6,11), Date.new(2011,6,7).all_week(:sunday) @@ -298,7 +330,7 @@ class DateExtCalculationsTest < ActiveSupport::TestCase end def test_xmlschema - with_env_tz 'US/Eastern' do + with_env_tz "US/Eastern" do assert_match(/^1980-02-28T00:00:00-05:?00$/, Date.new(1980, 2, 28).xmlschema) assert_match(/^1980-06-28T00:00:00-04:?00$/, Date.new(1980, 6, 28).xmlschema) # these tests are only of interest on platforms where older dates #to_time fail over to DateTime @@ -310,8 +342,8 @@ class DateExtCalculationsTest < ActiveSupport::TestCase end def test_xmlschema_when_zone_is_set - with_env_tz 'UTC' do - with_tz_default ActiveSupport::TimeZone['Eastern Time (US & Canada)'] do # UTC -5 + with_env_tz "UTC" do + with_tz_default ActiveSupport::TimeZone["Eastern Time (US & Canada)"] do # UTC -5 assert_match(/^1980-02-28T00:00:00-05:?00$/, Date.new(1980, 2, 28).xmlschema) assert_match(/^1980-06-28T00:00:00-04:?00$/, Date.new(1980, 6, 28).xmlschema) end @@ -335,7 +367,7 @@ class DateExtCalculationsTest < ActiveSupport::TestCase end def test_current_returns_date_today_when_zone_not_set - with_env_tz 'US/Central' do + with_env_tz "US/Central" do Time.stub(:now, Time.local(1999, 12, 31, 23)) do assert_equal Date.today, Date.current end @@ -343,8 +375,8 @@ class DateExtCalculationsTest < ActiveSupport::TestCase end def test_current_returns_time_zone_today_when_zone_is_set - Time.zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)'] - with_env_tz 'US/Central' do + Time.zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"] + with_env_tz "US/Central" do assert_equal ::Time.zone.today, Date.current end ensure @@ -352,9 +384,9 @@ class DateExtCalculationsTest < ActiveSupport::TestCase end def test_date_advance_should_not_change_passed_options_hash - options = { :years => 3, :months => 11, :days => 2 } + options = { years: 3, months: 11, days: 2 } Date.new(2005,2,28).advance(options) - assert_equal({ :years => 3, :months => 11, :days => 2 }, options) + assert_equal({ years: 3, months: 11, days: 2 }, options) end end @@ -375,4 +407,3 @@ class DateExtBehaviorTest < ActiveSupport::TestCase end end end - diff --git a/activesupport/test/core_ext/date_time_ext_test.rb b/activesupport/test/core_ext/date_time_ext_test.rb index 6fe38c45ec..f2a50f4693 100644 --- a/activesupport/test/core_ext/date_time_ext_test.rb +++ b/activesupport/test/core_ext/date_time_ext_test.rb @@ -1,7 +1,7 @@ -require 'abstract_unit' -require 'active_support/time' -require 'core_ext/date_and_time_behavior' -require 'time_zone_test_helpers' +require "abstract_unit" +require "active_support/time" +require "core_ext/date_and_time_behavior" +require "time_zone_test_helpers" class DateTimeExtCalculationsTest < ActiveSupport::TestCase def date_time_init(year,month,day,hour,minute,second,*args) @@ -35,11 +35,29 @@ class DateTimeExtCalculationsTest < ActiveSupport::TestCase end def test_custom_date_format - Time::DATE_FORMATS[:custom] = '%Y%m%d%H%M%S' - assert_equal '20050221143000', DateTime.new(2005, 2, 21, 14, 30, 0).to_s(:custom) + Time::DATE_FORMATS[:custom] = "%Y%m%d%H%M%S" + assert_equal "20050221143000", DateTime.new(2005, 2, 21, 14, 30, 0).to_s(:custom) Time::DATE_FORMATS.delete(:custom) end + def test_localtime + with_env_tz "US/Eastern" do + assert_instance_of Time, DateTime.new(2016, 3, 11, 15, 11, 12, 0).localtime + assert_equal Time.local(2016, 3, 11, 10, 11, 12), DateTime.new(2016, 3, 11, 15, 11, 12, 0).localtime + assert_equal Time.local(2016, 3, 21, 11, 11, 12), DateTime.new(2016, 3, 21, 15, 11, 12, 0).localtime + assert_equal Time.local(2016, 4, 1, 11, 11, 12), DateTime.new(2016, 4, 1, 16, 11, 12, Rational(1,24)).localtime + end + end + + def test_getlocal + with_env_tz "US/Eastern" do + assert_instance_of Time, DateTime.new(2016, 3, 11, 15, 11, 12, 0).getlocal + assert_equal Time.local(2016, 3, 11, 10, 11, 12), DateTime.new(2016, 3, 11, 15, 11, 12, 0).getlocal + assert_equal Time.local(2016, 3, 21, 11, 11, 12), DateTime.new(2016, 3, 21, 15, 11, 12, 0).getlocal + assert_equal Time.local(2016, 4, 1, 11, 11, 12), DateTime.new(2016, 4, 1, 16, 11, 12, Rational(1,24)).getlocal + end + end + def test_to_date assert_equal Date.new(2005, 2, 21), DateTime.new(2005, 2, 21, 14, 30, 0).to_date end @@ -49,10 +67,16 @@ class DateTimeExtCalculationsTest < ActiveSupport::TestCase end def test_to_time - with_env_tz 'US/Eastern' do - assert_equal Time, DateTime.new(2005, 2, 21, 10, 11, 12, 0).to_time.class - assert_equal Time.local(2005, 2, 21, 5, 11, 12), DateTime.new(2005, 2, 21, 10, 11, 12, 0).to_time - assert_equal Time.local(2005, 2, 21, 5, 11, 12).utc_offset, DateTime.new(2005, 2, 21, 10, 11, 12, 0).to_time.utc_offset + with_env_tz "US/Eastern" do + assert_instance_of Time, DateTime.new(2005, 2, 21, 10, 11, 12, 0).to_time + + if ActiveSupport.to_time_preserves_timezone + assert_equal Time.local(2005, 2, 21, 5, 11, 12).getlocal(0), DateTime.new(2005, 2, 21, 10, 11, 12, 0).to_time + assert_equal Time.local(2005, 2, 21, 5, 11, 12).getlocal(0).utc_offset, DateTime.new(2005, 2, 21, 10, 11, 12, 0).to_time.utc_offset + else + assert_equal Time.local(2005, 2, 21, 5, 11, 12), DateTime.new(2005, 2, 21, 10, 11, 12, 0).to_time + assert_equal Time.local(2005, 2, 21, 5, 11, 12).utc_offset, DateTime.new(2005, 2, 21, 10, 11, 12, 0).to_time.utc_offset + end end end @@ -135,47 +159,47 @@ class DateTimeExtCalculationsTest < ActiveSupport::TestCase end def test_change - assert_equal DateTime.civil(2006,2,22,15,15,10), DateTime.civil(2005,2,22,15,15,10).change(:year => 2006) - assert_equal DateTime.civil(2005,6,22,15,15,10), DateTime.civil(2005,2,22,15,15,10).change(:month => 6) - assert_equal DateTime.civil(2012,9,22,15,15,10), DateTime.civil(2005,2,22,15,15,10).change(:year => 2012, :month => 9) - assert_equal DateTime.civil(2005,2,22,16), DateTime.civil(2005,2,22,15,15,10).change(:hour => 16) - assert_equal DateTime.civil(2005,2,22,16,45), DateTime.civil(2005,2,22,15,15,10).change(:hour => 16, :min => 45) - assert_equal DateTime.civil(2005,2,22,15,45), DateTime.civil(2005,2,22,15,15,10).change(:min => 45) + assert_equal DateTime.civil(2006,2,22,15,15,10), DateTime.civil(2005,2,22,15,15,10).change(year: 2006) + assert_equal DateTime.civil(2005,6,22,15,15,10), DateTime.civil(2005,2,22,15,15,10).change(month: 6) + assert_equal DateTime.civil(2012,9,22,15,15,10), DateTime.civil(2005,2,22,15,15,10).change(year: 2012, month: 9) + assert_equal DateTime.civil(2005,2,22,16), DateTime.civil(2005,2,22,15,15,10).change(hour: 16) + assert_equal DateTime.civil(2005,2,22,16,45), DateTime.civil(2005,2,22,15,15,10).change(hour: 16, min: 45) + assert_equal DateTime.civil(2005,2,22,15,45), DateTime.civil(2005,2,22,15,15,10).change(min: 45) # datetime with fractions of a second - assert_equal DateTime.civil(2005,2,1,15,15,10.7), DateTime.civil(2005,2,22,15,15,10.7).change(:day => 1) + assert_equal DateTime.civil(2005,2,1,15,15,10.7), DateTime.civil(2005,2,22,15,15,10.7).change(day: 1) end def test_advance - assert_equal DateTime.civil(2006,2,28,15,15,10), DateTime.civil(2005,2,28,15,15,10).advance(:years => 1) - assert_equal DateTime.civil(2005,6,28,15,15,10), DateTime.civil(2005,2,28,15,15,10).advance(:months => 4) - assert_equal DateTime.civil(2005,3,21,15,15,10), DateTime.civil(2005,2,28,15,15,10).advance(:weeks => 3) - assert_equal DateTime.civil(2005,3,5,15,15,10), DateTime.civil(2005,2,28,15,15,10).advance(:days => 5) - assert_equal DateTime.civil(2012,9,28,15,15,10), DateTime.civil(2005,2,28,15,15,10).advance(:years => 7, :months => 7) - assert_equal DateTime.civil(2013,10,3,15,15,10), DateTime.civil(2005,2,28,15,15,10).advance(:years => 7, :months => 19, :days => 5) - assert_equal DateTime.civil(2013,10,17,15,15,10), DateTime.civil(2005,2,28,15,15,10).advance(:years => 7, :months => 19, :weeks => 2, :days => 5) - assert_equal DateTime.civil(2001,12,27,15,15,10), DateTime.civil(2005,2,28,15,15,10).advance(:years => -3, :months => -2, :days => -1) - assert_equal DateTime.civil(2005,2,28,15,15,10), DateTime.civil(2004,2,29,15,15,10).advance(:years => 1) #leap day plus one year - assert_equal DateTime.civil(2005,2,28,20,15,10), DateTime.civil(2005,2,28,15,15,10).advance(:hours => 5) - assert_equal DateTime.civil(2005,2,28,15,22,10), DateTime.civil(2005,2,28,15,15,10).advance(:minutes => 7) - assert_equal DateTime.civil(2005,2,28,15,15,19), DateTime.civil(2005,2,28,15,15,10).advance(:seconds => 9) - assert_equal DateTime.civil(2005,2,28,20,22,19), DateTime.civil(2005,2,28,15,15,10).advance(:hours => 5, :minutes => 7, :seconds => 9) - assert_equal DateTime.civil(2005,2,28,10,8,1), DateTime.civil(2005,2,28,15,15,10).advance(:hours => -5, :minutes => -7, :seconds => -9) - assert_equal DateTime.civil(2013,10,17,20,22,19), DateTime.civil(2005,2,28,15,15,10).advance(:years => 7, :months => 19, :weeks => 2, :days => 5, :hours => 5, :minutes => 7, :seconds => 9) + assert_equal DateTime.civil(2006,2,28,15,15,10), DateTime.civil(2005,2,28,15,15,10).advance(years: 1) + assert_equal DateTime.civil(2005,6,28,15,15,10), DateTime.civil(2005,2,28,15,15,10).advance(months: 4) + assert_equal DateTime.civil(2005,3,21,15,15,10), DateTime.civil(2005,2,28,15,15,10).advance(weeks: 3) + assert_equal DateTime.civil(2005,3,5,15,15,10), DateTime.civil(2005,2,28,15,15,10).advance(days: 5) + assert_equal DateTime.civil(2012,9,28,15,15,10), DateTime.civil(2005,2,28,15,15,10).advance(years: 7, months: 7) + assert_equal DateTime.civil(2013,10,3,15,15,10), DateTime.civil(2005,2,28,15,15,10).advance(years: 7, months: 19, days: 5) + assert_equal DateTime.civil(2013,10,17,15,15,10), DateTime.civil(2005,2,28,15,15,10).advance(years: 7, months: 19, weeks: 2, days: 5) + assert_equal DateTime.civil(2001,12,27,15,15,10), DateTime.civil(2005,2,28,15,15,10).advance(years: -3, months: -2, days: -1) + assert_equal DateTime.civil(2005,2,28,15,15,10), DateTime.civil(2004,2,29,15,15,10).advance(years: 1) #leap day plus one year + assert_equal DateTime.civil(2005,2,28,20,15,10), DateTime.civil(2005,2,28,15,15,10).advance(hours: 5) + assert_equal DateTime.civil(2005,2,28,15,22,10), DateTime.civil(2005,2,28,15,15,10).advance(minutes: 7) + assert_equal DateTime.civil(2005,2,28,15,15,19), DateTime.civil(2005,2,28,15,15,10).advance(seconds: 9) + assert_equal DateTime.civil(2005,2,28,20,22,19), DateTime.civil(2005,2,28,15,15,10).advance(hours: 5, minutes: 7, seconds: 9) + assert_equal DateTime.civil(2005,2,28,10,8,1), DateTime.civil(2005,2,28,15,15,10).advance(hours: -5, minutes: -7, seconds: -9) + assert_equal DateTime.civil(2013,10,17,20,22,19), DateTime.civil(2005,2,28,15,15,10).advance(years: 7, months: 19, weeks: 2, days: 5, hours: 5, minutes: 7, seconds: 9) end def test_advance_partial_days - assert_equal DateTime.civil(2012,9,29,13,15,10), DateTime.civil(2012,9,28,1,15,10).advance(:days => 1.5) - assert_equal DateTime.civil(2012,9,28,13,15,10), DateTime.civil(2012,9,28,1,15,10).advance(:days => 0.5) - assert_equal DateTime.civil(2012,10,29,13,15,10), DateTime.civil(2012,9,28,1,15,10).advance(:days => 1.5, :months => 1) + assert_equal DateTime.civil(2012,9,29,13,15,10), DateTime.civil(2012,9,28,1,15,10).advance(days: 1.5) + assert_equal DateTime.civil(2012,9,28,13,15,10), DateTime.civil(2012,9,28,1,15,10).advance(days: 0.5) + assert_equal DateTime.civil(2012,10,29,13,15,10), DateTime.civil(2012,9,28,1,15,10).advance(days: 1.5, months: 1) end def test_advanced_processes_first_the_date_deltas_and_then_the_time_deltas # If the time deltas were processed first, the following datetimes would be advanced to 2010/04/01 instead. - assert_equal DateTime.civil(2010, 3, 29), DateTime.civil(2010, 2, 28, 23, 59, 59).advance(:months => 1, :seconds => 1) - assert_equal DateTime.civil(2010, 3, 29), DateTime.civil(2010, 2, 28, 23, 59).advance(:months => 1, :minutes => 1) - assert_equal DateTime.civil(2010, 3, 29), DateTime.civil(2010, 2, 28, 23).advance(:months => 1, :hours => 1) - assert_equal DateTime.civil(2010, 3, 29), DateTime.civil(2010, 2, 28, 22, 58, 59).advance(:months => 1, :hours => 1, :minutes => 1, :seconds => 1) + assert_equal DateTime.civil(2010, 3, 29), DateTime.civil(2010, 2, 28, 23, 59, 59).advance(months: 1, seconds: 1) + assert_equal DateTime.civil(2010, 3, 29), DateTime.civil(2010, 2, 28, 23, 59).advance(months: 1, minutes: 1) + assert_equal DateTime.civil(2010, 3, 29), DateTime.civil(2010, 2, 28, 23).advance(months: 1, hours: 1) + assert_equal DateTime.civil(2010, 3, 29), DateTime.civil(2010, 2, 28, 22, 58, 59).advance(months: 1, hours: 1, minutes: 1, seconds: 1) end def test_last_week @@ -186,6 +210,10 @@ class DateTimeExtCalculationsTest < ActiveSupport::TestCase assert_equal DateTime.civil(2006,11,15), DateTime.civil(2006,11,23,0,0,0).last_week(:wednesday) end + def test_date_time_should_have_correct_last_week_for_leap_year + assert_equal DateTime.civil(2016, 2, 29), DateTime.civil(2016, 3, 7).last_week + end + def test_last_month_on_31st assert_equal DateTime.civil(2004, 2, 29), DateTime.civil(2004, 3, 31).last_month end @@ -254,7 +282,7 @@ class DateTimeExtCalculationsTest < ActiveSupport::TestCase end def test_current_returns_date_today_when_zone_is_not_set - with_env_tz 'US/Eastern' do + with_env_tz "US/Eastern" do Time.stub(:now, Time.local(1999, 12, 31, 23, 59, 59)) do assert_equal DateTime.new(1999, 12, 31, 23, 59, 59, Rational(-18000, 86400)), DateTime.current end @@ -262,8 +290,8 @@ class DateTimeExtCalculationsTest < ActiveSupport::TestCase end def test_current_returns_time_zone_today_when_zone_is_set - Time.zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)'] - with_env_tz 'US/Eastern' do + Time.zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"] + with_env_tz "US/Eastern" do Time.stub(:now, Time.local(1999, 12, 31, 23, 59, 59)) do assert_equal DateTime.new(1999, 12, 31, 23, 59, 59, Rational(-18000, 86400)), DateTime.current end @@ -277,7 +305,7 @@ class DateTimeExtCalculationsTest < ActiveSupport::TestCase end def test_current_with_time_zone - with_env_tz 'US/Eastern' do + with_env_tz "US/Eastern" do assert_kind_of DateTime, DateTime.current end end @@ -306,6 +334,7 @@ class DateTimeExtCalculationsTest < ActiveSupport::TestCase end def test_utc + assert_instance_of Time, DateTime.civil(2005, 2, 21, 10, 11, 12, Rational(-6, 24)).utc assert_equal DateTime.civil(2005, 2, 21, 16, 11, 12, 0), DateTime.civil(2005, 2, 21, 10, 11, 12, Rational(-6, 24)).utc assert_equal DateTime.civil(2005, 2, 21, 15, 11, 12, 0), DateTime.civil(2005, 2, 21, 10, 11, 12, Rational(-5, 24)).utc assert_equal DateTime.civil(2005, 2, 21, 10, 11, 12, 0), DateTime.civil(2005, 2, 21, 10, 11, 12, 0).utc @@ -314,15 +343,15 @@ class DateTimeExtCalculationsTest < ActiveSupport::TestCase end def test_formatted_offset_with_utc - assert_equal '+00:00', DateTime.civil(2000).formatted_offset - assert_equal '+0000', DateTime.civil(2000).formatted_offset(false) - assert_equal 'UTC', DateTime.civil(2000).formatted_offset(true, 'UTC') + assert_equal "+00:00", DateTime.civil(2000).formatted_offset + assert_equal "+0000", DateTime.civil(2000).formatted_offset(false) + assert_equal "UTC", DateTime.civil(2000).formatted_offset(true, "UTC") end def test_formatted_offset_with_local dt = DateTime.civil(2005, 2, 21, 10, 11, 12, Rational(-5, 24)) - assert_equal '-05:00', dt.formatted_offset - assert_equal '-0500', dt.formatted_offset(false) + assert_equal "-05:00", dt.formatted_offset + assert_equal "-0500", dt.formatted_offset(false) end def test_compare_with_time @@ -338,9 +367,9 @@ class DateTimeExtCalculationsTest < ActiveSupport::TestCase end def test_compare_with_time_with_zone - assert_equal 1, DateTime.civil(2000) <=> ActiveSupport::TimeWithZone.new( Time.utc(1999, 12, 31, 23, 59, 59), ActiveSupport::TimeZone['UTC'] ) - assert_equal 0, DateTime.civil(2000) <=> ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 1, 0, 0, 0), ActiveSupport::TimeZone['UTC'] ) - assert_equal(-1, DateTime.civil(2000) <=> ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 1, 0, 0, 1), ActiveSupport::TimeZone['UTC'] )) + assert_equal 1, DateTime.civil(2000) <=> ActiveSupport::TimeWithZone.new( Time.utc(1999, 12, 31, 23, 59, 59), ActiveSupport::TimeZone["UTC"] ) + assert_equal 0, DateTime.civil(2000) <=> ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 1, 0, 0, 0), ActiveSupport::TimeZone["UTC"] ) + assert_equal(-1, DateTime.civil(2000) <=> ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 1, 0, 0, 1), ActiveSupport::TimeZone["UTC"] )) end def test_compare_with_string @@ -350,6 +379,24 @@ class DateTimeExtCalculationsTest < ActiveSupport::TestCase assert_equal nil, DateTime.civil(2000) <=> "Invalid as Time" end + def test_compare_with_integer + assert_equal 1, DateTime.civil(1970, 1, 1, 12, 0, 0) <=> 2440587 + assert_equal 0, DateTime.civil(1970, 1, 1, 12, 0, 0) <=> 2440588 + assert_equal(-1, DateTime.civil(1970, 1, 1, 12, 0, 0) <=> 2440589) + end + + def test_compare_with_float + assert_equal 1, DateTime.civil(1970) <=> 2440586.5 + assert_equal 0, DateTime.civil(1970) <=> 2440587.5 + assert_equal(-1, DateTime.civil(1970) <=> 2440588.5) + end + + def test_compare_with_rational + assert_equal 1, DateTime.civil(1970) <=> Rational(4881173, 2) + assert_equal 0, DateTime.civil(1970) <=> Rational(4881175, 2) + assert_equal(-1, DateTime.civil(1970) <=> Rational(4881177, 2)) + end + def test_to_f assert_equal 946684800.0, DateTime.civil(2000).to_f assert_equal 946684800.0, DateTime.civil(1999,12,31,19,0,0,Rational(-5,24)).to_f @@ -370,4 +417,9 @@ class DateTimeExtCalculationsTest < ActiveSupport::TestCase assert_equal 0, DateTime.civil(2000).nsec assert_equal 500000000, DateTime.civil(2000, 1, 1, 0, 0, Rational(1,2)).nsec end + + def test_subsec + assert_equal 0, DateTime.civil(2000).subsec + assert_equal Rational(1,2), DateTime.civil(2000, 1, 1, 0, 0, Rational(1,2)).subsec + end end diff --git a/activesupport/test/core_ext/digest/uuid_test.rb b/activesupport/test/core_ext/digest/uuid_test.rb index 08e0a1d6e1..866a03259a 100644 --- a/activesupport/test/core_ext/digest/uuid_test.rb +++ b/activesupport/test/core_ext/digest/uuid_test.rb @@ -1,5 +1,5 @@ -require 'abstract_unit' -require 'active_support/core_ext/digest/uuid' +require "abstract_unit" +require "active_support/core_ext/digest/uuid" class DigestUUIDExt < ActiveSupport::TestCase def test_v3_uuids @@ -18,7 +18,7 @@ class DigestUUIDExt < ActiveSupport::TestCase def test_invalid_hash_class assert_raise ArgumentError do - Digest::UUID.uuid_from_hash(Digest::SHA2, Digest::UUID::OID_NAMESPACE, '1.2.3') + Digest::UUID.uuid_from_hash(Digest::SHA2, Digest::UUID::OID_NAMESPACE, "1.2.3") end end end diff --git a/activesupport/test/core_ext/duration_test.rb b/activesupport/test/core_ext/duration_test.rb index 9e97acaffb..a881768470 100644 --- a/activesupport/test/core_ext/duration_test.rb +++ b/activesupport/test/core_ext/duration_test.rb @@ -1,8 +1,8 @@ -require 'abstract_unit' -require 'active_support/inflector' -require 'active_support/time' -require 'active_support/json' -require 'time_zone_test_helpers' +require "abstract_unit" +require "active_support/inflector" +require "active_support/time" +require "active_support/json" +require "time_zone_test_helpers" class DurationTest < ActiveSupport::TestCase include TimeZoneTestHelpers @@ -12,7 +12,7 @@ class DurationTest < ActiveSupport::TestCase assert d.is_a?(ActiveSupport::Duration) assert_kind_of ActiveSupport::Duration, d assert_kind_of Numeric, d - assert_kind_of Fixnum, d + assert_kind_of Integer, d assert !d.is_a?(Hash) k = Class.new @@ -29,14 +29,14 @@ class DurationTest < ActiveSupport::TestCase def test_threequals assert ActiveSupport::Duration === 1.day assert !(ActiveSupport::Duration === 1.day.to_i) - assert !(ActiveSupport::Duration === 'foo') + assert !(ActiveSupport::Duration === "foo") end def test_equals assert 1.day == 1.day assert 1.day == 1.day.to_i assert 1.day.to_i == 1.day - assert !(1.day == 'foo') + assert !(1.day == "foo") end def test_to_s @@ -54,27 +54,28 @@ class DurationTest < ActiveSupport::TestCase assert !1.eql?(1.second) assert 1.minute.eql?(180.seconds - 2.minutes) assert !1.minute.eql?(60) - assert !1.minute.eql?('foo') + assert !1.minute.eql?("foo") end def test_inspect - assert_equal '0 seconds', 0.seconds.inspect - assert_equal '1 month', 1.month.inspect - assert_equal '1 month and 1 day', (1.month + 1.day).inspect - assert_equal '6 months and -2 days', (6.months - 2.days).inspect - assert_equal '10 seconds', 10.seconds.inspect - assert_equal '10 years, 2 months, and 1 day', (10.years + 2.months + 1.day).inspect - assert_equal '10 years, 2 months, and 1 day', (10.years + 1.month + 1.day + 1.month).inspect - assert_equal '10 years, 2 months, and 1 day', (1.day + 10.years + 2.months).inspect - assert_equal '7 days', 1.week.inspect - assert_equal '14 days', 1.fortnight.inspect + assert_equal "0 seconds", 0.seconds.inspect + assert_equal "1 month", 1.month.inspect + assert_equal "1 month and 1 day", (1.month + 1.day).inspect + assert_equal "6 months and -2 days", (6.months - 2.days).inspect + assert_equal "10 seconds", 10.seconds.inspect + assert_equal "10 years, 2 months, and 1 day", (10.years + 2.months + 1.day).inspect + assert_equal "10 years, 2 months, and 1 day", (10.years + 1.month + 1.day + 1.month).inspect + assert_equal "10 years, 2 months, and 1 day", (1.day + 10.years + 2.months).inspect + assert_equal "7 days", 7.days.inspect + assert_equal "1 week", 1.week.inspect + assert_equal "2 weeks", 1.fortnight.inspect end def test_inspect_locale current_locale = I18n.default_locale I18n.default_locale = :de - I18n.backend.store_translations(:de, { support: { array: { last_word_connector: ' und ' } } }) - assert_equal '10 years, 1 month und 1 day', (10.years + 1.month + 1.day).inspect + I18n.backend.store_translations(:de, support: { array: { last_word_connector: " und " } }) + assert_equal "10 years, 1 month und 1 day", (10.years + 1.month + 1.day).inspect ensure I18n.default_locale = current_locale end @@ -87,9 +88,18 @@ class DurationTest < ActiveSupport::TestCase assert_equal 1 + 1.second, 1.second + 1, "Duration + Numeric should == Numeric + Duration" end + def test_time_plus_duration_returns_same_time_datatype + twz = ActiveSupport::TimeWithZone.new(nil, ActiveSupport::TimeZone["Moscow"] , Time.utc(2016,4,28,00,45)) + now = Time.now.utc + %w( second minute hour day week month year ).each do |unit| + assert_equal((now + 1.send(unit)).class, Time, "Time + 1.#{unit} must be Time") + assert_equal((twz + 1.send(unit)).class, ActiveSupport::TimeWithZone, "TimeWithZone + 1.#{unit} must be TimeWithZone") + end + end + def test_argument_error e = assert_raise ArgumentError do - 1.second.ago('') + 1.second.ago("") end assert_equal 'expected a time or date, got ""', e.message, "ensure ArgumentError is not being raised by dependencies.rb" end @@ -139,7 +149,7 @@ class DurationTest < ActiveSupport::TestCase def test_since_and_ago_anchored_to_time_now_when_time_zone_is_not_set Time.zone = nil - with_env_tz 'US/Eastern' do + with_env_tz "US/Eastern" do Time.stub(:now, Time.local(2000)) do # since assert_not_instance_of ActiveSupport::TimeWithZone, 5.seconds.since @@ -152,17 +162,17 @@ class DurationTest < ActiveSupport::TestCase end def test_since_and_ago_anchored_to_time_zone_now_when_time_zone_is_set - Time.zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)'] - with_env_tz 'US/Eastern' do + Time.zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"] + with_env_tz "US/Eastern" do Time.stub(:now, Time.local(2000)) do # since assert_instance_of ActiveSupport::TimeWithZone, 5.seconds.since assert_equal Time.utc(2000,1,1,0,0,5), 5.seconds.since.time - assert_equal 'Eastern Time (US & Canada)', 5.seconds.since.time_zone.name + assert_equal "Eastern Time (US & Canada)", 5.seconds.since.time_zone.name # ago assert_instance_of ActiveSupport::TimeWithZone, 5.seconds.ago assert_equal Time.utc(1999,12,31,23,59,55), 5.seconds.ago.time - assert_equal 'Eastern Time (US & Canada)', 5.seconds.ago.time_zone.name + assert_equal "Eastern Time (US & Canada)", 5.seconds.ago.time_zone.name end end ensure @@ -170,13 +180,13 @@ class DurationTest < ActiveSupport::TestCase end def test_adding_hours_across_dst_boundary - with_env_tz 'CET' do + with_env_tz "CET" do assert_equal Time.local(2009,3,29,0,0,0) + 24.hours, Time.local(2009,3,30,1,0,0) end end def test_adding_day_across_dst_boundary - with_env_tz 'CET' do + with_env_tz "CET" do assert_equal Time.local(2009,3,29,0,0,0) + 1.day, Time.local(2009,3,30,0,0,0) end end @@ -184,7 +194,7 @@ class DurationTest < ActiveSupport::TestCase def test_delegation_with_block_works counter = 0 assert_nothing_raised do - 1.minute.times {counter += 1} + 1.minute.times { counter += 1 } end assert_equal counter, 60 end @@ -194,11 +204,15 @@ class DurationTest < ActiveSupport::TestCase end def test_to_json - assert_equal '172800', 2.days.to_json + assert_equal "172800", 2.days.to_json end def test_case_when - cased = case 1.day when 1.day then "ok" end + cased = \ + case 1.day + when 1.day + "ok" + end assert_equal cased, "ok" end @@ -222,4 +236,90 @@ class DurationTest < ActiveSupport::TestCase assert_equal(1, (1.minute <=> 1.second)) assert_equal(1, (61 <=> 1.minute)) end + + # ISO8601 string examples are taken from ISO8601 gem at https://github.com/arnau/ISO8601/blob/b93d466840/spec/iso8601/duration_spec.rb + # published under the conditions of MIT license at https://github.com/arnau/ISO8601/blob/b93d466840/LICENSE + # + # Copyright (c) 2012-2014 Arnau Siches + # + # MIT License + # + # 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. + + def test_iso8601_parsing_wrong_patterns_with_raise + invalid_patterns = ["", "P", "PT", "P1YT", "T", "PW", "P1Y1W", "~P1Y", ".P1Y", "P1.5Y0.5M", "P1.5Y1M", "P1.5MT10.5S"] + invalid_patterns.each do |pattern| + assert_raise ActiveSupport::Duration::ISO8601Parser::ParsingError, pattern.inspect do + ActiveSupport::Duration.parse(pattern) + end + end + end + + def test_iso8601_output + expectations = [ + ["P1Y", 1.year ], + ["P1W", 1.week ], + ["P1Y1M", 1.year + 1.month ], + ["P1Y1M1D", 1.year + 1.month + 1.day ], + ["-P1Y1D", -1.year - 1.day ], + ["P1Y-1DT-1S", 1.year - 1.day - 1.second ], # Parts with different signs are exists in PostgreSQL interval datatype. + ["PT1S", 1.second ], + ["PT1.4S", (1.4).seconds ], + ["P1Y1M1DT1H", 1.year + 1.month + 1.day + 1.hour], + ["PT0S", 0.minutes ], + ] + expectations.each do |expected_output, duration| + assert_equal expected_output, duration.iso8601, expected_output.inspect + end + end + + def test_iso8601_output_precision + expectations = [ + [nil, "P1Y1MT5.55S", 1.year + 1.month + (5.55).seconds ], + [0, "P1Y1MT6S", 1.year + 1.month + (5.55).seconds ], + [1, "P1Y1MT5.5S", 1.year + 1.month + (5.55).seconds ], + [2, "P1Y1MT5.55S", 1.year + 1.month + (5.55).seconds ], + [3, "P1Y1MT5.550S", 1.year + 1.month + (5.55).seconds ], + [nil, "PT1S", 1.second ], + [2, "PT1.00S", 1.second ], + [nil, "PT1.4S", (1.4).seconds ], + [0, "PT1S", (1.4).seconds ], + [1, "PT1.4S", (1.4).seconds ], + [5, "PT1.40000S", (1.4).seconds ], + ] + expectations.each do |precision, expected_output, duration| + assert_equal expected_output, duration.iso8601(precision: precision), expected_output.inspect + end + end + + def test_iso8601_output_and_reparsing + patterns = %w[ + P1Y P0.5Y P0,5Y P1Y1M P1Y0.5M P1Y0,5M P1Y1M1D P1Y1M0.5D P1Y1M0,5D P1Y1M1DT1H P1Y1M1DT0.5H P1Y1M1DT0,5H P1W +P1Y -P1Y + P1Y1M1DT1H1M P1Y1M1DT1H0.5M P1Y1M1DT1H0,5M P1Y1M1DT1H1M1S P1Y1M1DT1H1M1.0S P1Y1M1DT1H1M1,0S P-1Y-2M3DT-4H-5M-6S + ] + # That could be weird, but if we parse P1Y1M0.5D and output it to ISO 8601, we'll get P1Y1MT12.0H. + # So we check that initially parsed and reparsed duration added to time will result in the same time. + time = Time.current + patterns.each do |pattern| + duration = ActiveSupport::Duration.parse(pattern) + assert_equal time+duration, time+ActiveSupport::Duration.parse(duration.iso8601), pattern.inspect + end + end end diff --git a/activesupport/test/core_ext/enumerable_test.rb b/activesupport/test/core_ext/enumerable_test.rb index f09b7d8850..9072957e0e 100644 --- a/activesupport/test/core_ext/enumerable_test.rb +++ b/activesupport/test/core_ext/enumerable_test.rb @@ -1,6 +1,6 @@ -require 'abstract_unit' -require 'active_support/core_ext/array' -require 'active_support/core_ext/enumerable' +require "abstract_unit" +require "active_support/core_ext/array" +require "active_support/core_ext/enumerable" Payment = Struct.new(:price) ExpandedPayment = Struct.new(:dollars, :cents) @@ -10,26 +10,31 @@ class SummablePayment < Payment end class EnumerableTests < ActiveSupport::TestCase - class GenericEnumerable include Enumerable + def initialize(values = [1, 2, 3]) @values = values end def each - @values.each{|v| yield v} + @values.each { |v| yield v } end end + def assert_typed_equal(e, v, cls, msg=nil) + assert_kind_of(cls, v, msg) + assert_equal(e, v, msg) + end + def test_sums enum = GenericEnumerable.new([5, 15, 10]) assert_equal 30, enum.sum - assert_equal 60, enum.sum { |i| i * 2} + assert_equal 60, enum.sum { |i| i * 2 } enum = GenericEnumerable.new(%w(a b c)) - assert_equal 'abc', enum.sum - assert_equal 'aabbcc', enum.sum { |i| i * 2 } + assert_equal "abc", enum.sum + assert_equal "aabbcc", enum.sum { |i| i * 2 } payments = GenericEnumerable.new([ Payment.new(5), Payment.new(15), Payment.new(10) ]) assert_equal 30, payments.sum(&:price) @@ -38,6 +43,40 @@ class EnumerableTests < ActiveSupport::TestCase payments = GenericEnumerable.new([ SummablePayment.new(5), SummablePayment.new(15) ]) assert_equal SummablePayment.new(20), payments.sum assert_equal SummablePayment.new(20), payments.sum { |p| p } + + sum = GenericEnumerable.new([3, 5.quo(1)]).sum + assert_typed_equal(8, sum, Rational) + + sum = GenericEnumerable.new([3, 5.quo(1)]).sum(0.0) + assert_typed_equal(8.0, sum, Float) + + sum = GenericEnumerable.new([3, 5.quo(1), 7.0]).sum + assert_typed_equal(15.0, sum, Float) + + sum = GenericEnumerable.new([3, 5.quo(1), Complex(7)]).sum + assert_typed_equal(Complex(15), sum, Complex) + assert_typed_equal(15, sum.real, Rational) + assert_typed_equal(0, sum.imag, Integer) + + sum = GenericEnumerable.new([3.5, 5]).sum + assert_typed_equal(8.5, sum, Float) + + sum = GenericEnumerable.new([2, 8.5]).sum + assert_typed_equal(10.5, sum, Float) + + sum = GenericEnumerable.new([1.quo(2), 1]).sum + assert_typed_equal(3.quo(2), sum, Rational) + + sum = GenericEnumerable.new([1.quo(2), 1.quo(3)]).sum + assert_typed_equal(5.quo(6), sum, Rational) + + sum = GenericEnumerable.new([2.0, 3.0*Complex::I]).sum + assert_typed_equal(Complex(2.0, 3.0), sum, Complex) + assert_typed_equal(2.0, sum.real, Float) + assert_typed_equal(3.0, sum.imag, Float) + + sum = GenericEnumerable.new([1, 2]).sum(10) { |v| v * 2 } + assert_typed_equal(16, sum, Integer) end def test_nil_sums @@ -55,6 +94,7 @@ class EnumerableTests < ActiveSupport::TestCase assert_equal 0, GenericEnumerable.new([]).sum assert_equal 0, GenericEnumerable.new([]).sum { |i| i + 10 } assert_equal Payment.new(0), GenericEnumerable.new([]).sum(Payment.new(0)) + assert_typed_equal 0.0, GenericEnumerable.new([]).sum(0.0), Float end def test_range_sums @@ -62,12 +102,68 @@ class EnumerableTests < ActiveSupport::TestCase assert_equal 10, (1..4).sum assert_equal 10, (1..4.5).sum assert_equal 6, (1...4).sum - assert_equal 'abc', ('a'..'c').sum + assert_equal "abc", ("a".."c").sum assert_equal 50_000_005_000_000, (0..10_000_000).sum assert_equal 0, (10..0).sum assert_equal 5, (10..0).sum(5) assert_equal 10, (10..10).sum assert_equal 42, (10...10).sum(42) + assert_typed_equal 20.0, (1..4).sum(0.0) { |i| i * 2 }, Float + assert_typed_equal 10.0, (1..4).sum(0.0), Float + assert_typed_equal 20.0, (1..4).sum(10.0), Float + assert_typed_equal 5.0, (10..0).sum(5.0), Float + end + + def test_array_sums + enum = [5, 15, 10] + assert_equal 30, enum.sum + assert_equal 60, enum.sum { |i| i * 2 } + + enum = %w(a b c) + assert_equal "abc", enum.sum + assert_equal "aabbcc", enum.sum { |i| i * 2 } + + payments = [ Payment.new(5), Payment.new(15), Payment.new(10) ] + assert_equal 30, payments.sum(&:price) + assert_equal 60, payments.sum { |p| p.price * 2 } + + payments = [ SummablePayment.new(5), SummablePayment.new(15) ] + assert_equal SummablePayment.new(20), payments.sum + assert_equal SummablePayment.new(20), payments.sum { |p| p } + + sum = [3, 5.quo(1)].sum + assert_typed_equal(8, sum, Rational) + + sum = [3, 5.quo(1)].sum(0.0) + assert_typed_equal(8.0, sum, Float) + + sum = [3, 5.quo(1), 7.0].sum + assert_typed_equal(15.0, sum, Float) + + sum = [3, 5.quo(1), Complex(7)].sum + assert_typed_equal(Complex(15), sum, Complex) + assert_typed_equal(15, sum.real, Rational) + assert_typed_equal(0, sum.imag, Integer) + + sum = [3.5, 5].sum + assert_typed_equal(8.5, sum, Float) + + sum = [2, 8.5].sum + assert_typed_equal(10.5, sum, Float) + + sum = [1.quo(2), 1].sum + assert_typed_equal(3.quo(2), sum, Rational) + + sum = [1.quo(2), 1.quo(3)].sum + assert_typed_equal(5.quo(6), sum, Rational) + + sum = [2.0, 3.0*Complex::I].sum + assert_typed_equal(Complex(2.0, 3.0), sum, Complex) + assert_typed_equal(2.0, sum.real, Float) + assert_typed_equal(3.0, sum.imag, Float) + + sum = [1, 2].sum(10) { |v| v * 2 } + assert_typed_equal(16, sum, Integer) end def test_index_by @@ -88,17 +184,17 @@ class EnumerableTests < ActiveSupport::TestCase assert_equal false, GenericEnumerable.new([ 1 ] ).many? assert_equal true, GenericEnumerable.new([ 1, 2 ] ).many? - assert_equal false, GenericEnumerable.new([] ).many? {|x| x > 1 } - assert_equal false, GenericEnumerable.new([ 2 ] ).many? {|x| x > 1 } - assert_equal false, GenericEnumerable.new([ 1, 2 ] ).many? {|x| x > 1 } - assert_equal true, GenericEnumerable.new([ 1, 2, 2 ]).many? {|x| x > 1 } + assert_equal false, GenericEnumerable.new([] ).many? { |x| x > 1 } + assert_equal false, GenericEnumerable.new([ 2 ] ).many? { |x| x > 1 } + assert_equal false, GenericEnumerable.new([ 1, 2 ] ).many? { |x| x > 1 } + assert_equal true, GenericEnumerable.new([ 1, 2, 2 ]).many? { |x| x > 1 } end def test_many_iterates_only_on_what_is_needed infinity = 1.0/0.0 very_long_enum = 0..infinity assert_equal true, very_long_enum.many? - assert_equal true, very_long_enum.many?{|x| x > 100} + assert_equal true, very_long_enum.many? { |x| x > 100 } end def test_exclude? @@ -110,7 +206,7 @@ class EnumerableTests < ActiveSupport::TestCase assert_equal [1, 2, 4], GenericEnumerable.new((1..5).to_a).without(3, 5) assert_equal [1, 2, 4], (1..5).to_a.without(3, 5) assert_equal [1, 2, 4], (1..5).to_set.without(3, 5) - assert_equal({foo: 1, baz: 3}, {foo: 1, bar: 2, baz: 3}.without(:bar)) + assert_equal({ foo: 1, baz: 3 }, { foo: 1, bar: 2, baz: 3 }.without(:bar)) end def test_pluck diff --git a/activesupport/test/core_ext/file_test.rb b/activesupport/test/core_ext/file_test.rb index cde0132b97..df5d09acd0 100644 --- a/activesupport/test/core_ext/file_test.rb +++ b/activesupport/test/core_ext/file_test.rb @@ -1,5 +1,5 @@ -require 'abstract_unit' -require 'active_support/core_ext/file' +require "abstract_unit" +require "active_support/core_ext/file" class AtomicWriteTest < ActiveSupport::TestCase def test_atomic_write_without_errors diff --git a/activesupport/test/core_ext/hash/transform_keys_test.rb b/activesupport/test/core_ext/hash/transform_keys_test.rb index 99af274614..7a11d827f8 100644 --- a/activesupport/test/core_ext/hash/transform_keys_test.rb +++ b/activesupport/test/core_ext/hash/transform_keys_test.rb @@ -1,46 +1,62 @@ -require 'abstract_unit' -require 'active_support/core_ext/hash/keys' +require "abstract_unit" +require "active_support/core_ext/hash/keys" class TransformKeysTest < ActiveSupport::TestCase test "transform_keys returns a new hash with the keys computed from the block" do - original = { a: 'a', b: 'b' } + original = { a: "a", b: "b" } mapped = original.transform_keys { |k| "#{k}!".to_sym } - assert_equal({ a: 'a', b: 'b' }, original) - assert_equal({ a!: 'a', b!: 'b' }, mapped) + assert_equal({ a: "a", b: "b" }, original) + assert_equal({ a!: "a", b!: "b" }, mapped) end test "transform_keys! modifies the keys of the original" do - original = { a: 'a', b: 'b' } + original = { a: "a", b: "b" } mapped = original.transform_keys! { |k| "#{k}!".to_sym } - assert_equal({ a!: 'a', b!: 'b' }, original) + assert_equal({ a!: "a", b!: "b" }, original) assert_same original, mapped end test "transform_keys returns a sized Enumerator if no block is given" do - original = { a: 'a', b: 'b' } + original = { a: "a", b: "b" } enumerator = original.transform_keys assert_equal original.size, enumerator.size assert_equal Enumerator, enumerator.class end test "transform_keys! returns a sized Enumerator if no block is given" do - original = { a: 'a', b: 'b' } + original = { a: "a", b: "b" } enumerator = original.transform_keys! assert_equal original.size, enumerator.size assert_equal Enumerator, enumerator.class end test "transform_keys is chainable with Enumerable methods" do - original = { a: 'a', b: 'b' } + original = { a: "a", b: "b" } mapped = original.transform_keys.with_index { |k, i| [k, i].join.to_sym } - assert_equal({ a0: 'a', b1: 'b' }, mapped) + assert_equal({ a0: "a", b1: "b" }, mapped) end test "transform_keys! is chainable with Enumerable methods" do - original = { a: 'a', b: 'b' } + original = { a: "a", b: "b" } original.transform_keys!.with_index { |k, i| [k, i].join.to_sym } - assert_equal({ a0: 'a', b1: 'b' }, original) + assert_equal({ a0: "a", b1: "b" }, original) + end + + test "transform_keys returns a Hash instance when self is inherited from Hash" do + class HashDescendant < ::Hash + def initialize(elements = nil) + super(elements) + (elements || {}).each_pair { |key, value| self[key] = value } + end + end + + original = HashDescendant.new(a: "a", b: "b") + mapped = original.transform_keys { |k| "#{k}!".to_sym } + + assert_equal({ a: "a", b: "b" }, original) + assert_equal({ a!: "a", b!: "b" }, mapped) + assert_equal(::Hash, mapped.class) end end diff --git a/activesupport/test/core_ext/hash/transform_values_test.rb b/activesupport/test/core_ext/hash/transform_values_test.rb index 114022fbaf..f2ac4ce6ce 100644 --- a/activesupport/test/core_ext/hash/transform_values_test.rb +++ b/activesupport/test/core_ext/hash/transform_values_test.rb @@ -1,75 +1,75 @@ -require 'abstract_unit' -require 'active_support/core_ext/hash/indifferent_access' -require 'active_support/core_ext/hash/transform_values' +require "abstract_unit" +require "active_support/core_ext/hash/indifferent_access" +require "active_support/core_ext/hash/transform_values" class TransformValuesTest < ActiveSupport::TestCase test "transform_values returns a new hash with the values computed from the block" do - original = { a: 'a', b: 'b' } - mapped = original.transform_values { |v| v + '!' } + original = { a: "a", b: "b" } + mapped = original.transform_values { |v| v + "!" } - assert_equal({ a: 'a', b: 'b' }, original) - assert_equal({ a: 'a!', b: 'b!' }, mapped) + assert_equal({ a: "a", b: "b" }, original) + assert_equal({ a: "a!", b: "b!" }, mapped) end test "transform_values! modifies the values of the original" do - original = { a: 'a', b: 'b' } - mapped = original.transform_values! { |v| v + '!' } + original = { a: "a", b: "b" } + mapped = original.transform_values! { |v| v + "!" } - assert_equal({ a: 'a!', b: 'b!' }, original) + assert_equal({ a: "a!", b: "b!" }, original) assert_same original, mapped end test "indifferent access is still indifferent after mapping values" do - original = { a: 'a', b: 'b' }.with_indifferent_access - mapped = original.transform_values { |v| v + '!' } + original = { a: "a", b: "b" }.with_indifferent_access + mapped = original.transform_values { |v| v + "!" } - assert_equal 'a!', mapped[:a] - assert_equal 'a!', mapped['a'] + assert_equal "a!", mapped[:a] + assert_equal "a!", mapped["a"] end # This is to be consistent with the behavior of Ruby's built in methods # (e.g. #select, #reject) as of 2.2 test "default values do not persist during mapping" do - original = Hash.new('foo') - original[:a] = 'a' - mapped = original.transform_values { |v| v + '!' } + original = Hash.new("foo") + original[:a] = "a" + mapped = original.transform_values { |v| v + "!" } - assert_equal 'a!', mapped[:a] + assert_equal "a!", mapped[:a] assert_nil mapped[:b] end test "default procs do not persist after mapping" do - original = Hash.new { 'foo' } - original[:a] = 'a' - mapped = original.transform_values { |v| v + '!' } + original = Hash.new { "foo" } + original[:a] = "a" + mapped = original.transform_values { |v| v + "!" } - assert_equal 'a!', mapped[:a] + assert_equal "a!", mapped[:a] assert_nil mapped[:b] end test "transform_values returns a sized Enumerator if no block is given" do - original = { a: 'a', b: 'b' } + original = { a: "a", b: "b" } enumerator = original.transform_values assert_equal original.size, enumerator.size assert_equal Enumerator, enumerator.class end test "transform_values! returns a sized Enumerator if no block is given" do - original = { a: 'a', b: 'b' } + original = { a: "a", b: "b" } enumerator = original.transform_values! assert_equal original.size, enumerator.size assert_equal Enumerator, enumerator.class end test "transform_values is chainable with Enumerable methods" do - original = { a: 'a', b: 'b' } + original = { a: "a", b: "b" } mapped = original.transform_values.with_index { |v, i| [v, i].join } - assert_equal({ a: 'a0', b: 'b1' }, mapped) + assert_equal({ a: "a0", b: "b1" }, mapped) end test "transform_values! is chainable with Enumerable methods" do - original = { a: 'a', b: 'b' } + original = { a: "a", b: "b" } original.transform_values!.with_index { |v, i| [v, i].join } - assert_equal({ a: 'a0', b: 'b1' }, original) + assert_equal({ a: "a0", b: "b1" }, original) end end diff --git a/activesupport/test/core_ext/hash_ext_test.rb b/activesupport/test/core_ext/hash_ext_test.rb index be8583e704..ae35adb19b 100644 --- a/activesupport/test/core_ext/hash_ext_test.rb +++ b/activesupport/test/core_ext/hash_ext_test.rb @@ -1,11 +1,11 @@ -require 'abstract_unit' -require 'active_support/core_ext/hash' -require 'bigdecimal' -require 'active_support/core_ext/string/access' -require 'active_support/ordered_hash' -require 'active_support/core_ext/object/conversions' -require 'active_support/core_ext/object/deep_dup' -require 'active_support/inflections' +require "abstract_unit" +require "active_support/core_ext/hash" +require "bigdecimal" +require "active_support/core_ext/string/access" +require "active_support/ordered_hash" +require "active_support/core_ext/object/conversions" +require "active_support/core_ext/object/deep_dup" +require "active_support/inflections" class HashExtTest < ActiveSupport::TestCase class IndifferentHash < ActiveSupport::HashWithIndifferentAccess @@ -34,22 +34,22 @@ class HashExtTest < ActiveSupport::TestCase end def setup - @strings = { 'a' => 1, 'b' => 2 } - @nested_strings = { 'a' => { 'b' => { 'c' => 3 } } } - @symbols = { :a => 1, :b => 2 } - @nested_symbols = { :a => { :b => { :c => 3 } } } - @mixed = { :a => 1, 'b' => 2 } - @nested_mixed = { 'a' => { :b => { 'c' => 3 } } } - @fixnums = { 0 => 1, 1 => 2 } - @nested_fixnums = { 0 => { 1 => { 2 => 3} } } + @strings = { "a" => 1, "b" => 2 } + @nested_strings = { "a" => { "b" => { "c" => 3 } } } + @symbols = { a: 1, b: 2 } + @nested_symbols = { a: { b: { c: 3 } } } + @mixed = { :a => 1, "b" => 2 } + @nested_mixed = { "a" => { b: { "c" => 3 } } } + @integers = { 0 => 1, 1 => 2 } + @nested_integers = { 0 => { 1 => { 2 => 3 } } } @illegal_symbols = { [] => 3 } - @nested_illegal_symbols = { [] => { [] => 3} } - @upcase_strings = { 'A' => 1, 'B' => 2 } - @nested_upcase_strings = { 'A' => { 'B' => { 'C' => 3 } } } - @string_array_of_hashes = { 'a' => [ { 'b' => 2 }, { 'c' => 3 }, 4 ] } - @symbol_array_of_hashes = { :a => [ { :b => 2 }, { :c => 3 }, 4 ] } - @mixed_array_of_hashes = { :a => [ { :b => 2 }, { 'c' => 3 }, 4 ] } - @upcase_array_of_hashes = { 'A' => [ { 'B' => 2 }, { 'C' => 3 }, 4 ] } + @nested_illegal_symbols = { [] => { [] => 3 } } + @upcase_strings = { "A" => 1, "B" => 2 } + @nested_upcase_strings = { "A" => { "B" => { "C" => 3 } } } + @string_array_of_hashes = { "a" => [ { "b" => 2 }, { "c" => 3 }, 4 ] } + @symbol_array_of_hashes = { a: [ { b: 2 }, { c: 3 }, 4 ] } + @mixed_array_of_hashes = { a: [ { b: 2 }, { "c" => 3 }, 4 ] } + @upcase_array_of_hashes = { "A" => [ { "B" => 2 }, { "C" => 3 }, 4 ] } end def test_methods @@ -75,59 +75,59 @@ class HashExtTest < ActiveSupport::TestCase end def test_transform_keys - assert_equal @upcase_strings, @strings.transform_keys{ |key| key.to_s.upcase } - assert_equal @upcase_strings, @symbols.transform_keys{ |key| key.to_s.upcase } - assert_equal @upcase_strings, @mixed.transform_keys{ |key| key.to_s.upcase } + assert_equal @upcase_strings, @strings.transform_keys { |key| key.to_s.upcase } + assert_equal @upcase_strings, @symbols.transform_keys { |key| key.to_s.upcase } + assert_equal @upcase_strings, @mixed.transform_keys { |key| key.to_s.upcase } end def test_transform_keys_not_mutates transformed_hash = @mixed.dup - transformed_hash.transform_keys{ |key| key.to_s.upcase } + transformed_hash.transform_keys { |key| key.to_s.upcase } assert_equal @mixed, transformed_hash end def test_deep_transform_keys - assert_equal @nested_upcase_strings, @nested_symbols.deep_transform_keys{ |key| key.to_s.upcase } - assert_equal @nested_upcase_strings, @nested_strings.deep_transform_keys{ |key| key.to_s.upcase } - assert_equal @nested_upcase_strings, @nested_mixed.deep_transform_keys{ |key| key.to_s.upcase } - assert_equal @upcase_array_of_hashes, @string_array_of_hashes.deep_transform_keys{ |key| key.to_s.upcase } - assert_equal @upcase_array_of_hashes, @symbol_array_of_hashes.deep_transform_keys{ |key| key.to_s.upcase } - assert_equal @upcase_array_of_hashes, @mixed_array_of_hashes.deep_transform_keys{ |key| key.to_s.upcase } + assert_equal @nested_upcase_strings, @nested_symbols.deep_transform_keys { |key| key.to_s.upcase } + assert_equal @nested_upcase_strings, @nested_strings.deep_transform_keys { |key| key.to_s.upcase } + assert_equal @nested_upcase_strings, @nested_mixed.deep_transform_keys { |key| key.to_s.upcase } + assert_equal @upcase_array_of_hashes, @string_array_of_hashes.deep_transform_keys { |key| key.to_s.upcase } + assert_equal @upcase_array_of_hashes, @symbol_array_of_hashes.deep_transform_keys { |key| key.to_s.upcase } + assert_equal @upcase_array_of_hashes, @mixed_array_of_hashes.deep_transform_keys { |key| key.to_s.upcase } end def test_deep_transform_keys_not_mutates transformed_hash = @nested_mixed.deep_dup - transformed_hash.deep_transform_keys{ |key| key.to_s.upcase } + transformed_hash.deep_transform_keys { |key| key.to_s.upcase } assert_equal @nested_mixed, transformed_hash end def test_transform_keys! - assert_equal @upcase_strings, @symbols.dup.transform_keys!{ |key| key.to_s.upcase } - assert_equal @upcase_strings, @strings.dup.transform_keys!{ |key| key.to_s.upcase } - assert_equal @upcase_strings, @mixed.dup.transform_keys!{ |key| key.to_s.upcase } + assert_equal @upcase_strings, @symbols.dup.transform_keys! { |key| key.to_s.upcase } + assert_equal @upcase_strings, @strings.dup.transform_keys! { |key| key.to_s.upcase } + assert_equal @upcase_strings, @mixed.dup.transform_keys! { |key| key.to_s.upcase } end def test_transform_keys_with_bang_mutates transformed_hash = @mixed.dup - transformed_hash.transform_keys!{ |key| key.to_s.upcase } + transformed_hash.transform_keys! { |key| key.to_s.upcase } assert_equal @upcase_strings, transformed_hash - assert_equal @mixed, { :a => 1, "b" => 2 } + assert_equal @mixed, :a => 1, "b" => 2 end def test_deep_transform_keys! - assert_equal @nested_upcase_strings, @nested_symbols.deep_dup.deep_transform_keys!{ |key| key.to_s.upcase } - assert_equal @nested_upcase_strings, @nested_strings.deep_dup.deep_transform_keys!{ |key| key.to_s.upcase } - assert_equal @nested_upcase_strings, @nested_mixed.deep_dup.deep_transform_keys!{ |key| key.to_s.upcase } - assert_equal @upcase_array_of_hashes, @string_array_of_hashes.deep_dup.deep_transform_keys!{ |key| key.to_s.upcase } - assert_equal @upcase_array_of_hashes, @symbol_array_of_hashes.deep_dup.deep_transform_keys!{ |key| key.to_s.upcase } - assert_equal @upcase_array_of_hashes, @mixed_array_of_hashes.deep_dup.deep_transform_keys!{ |key| key.to_s.upcase } + assert_equal @nested_upcase_strings, @nested_symbols.deep_dup.deep_transform_keys! { |key| key.to_s.upcase } + assert_equal @nested_upcase_strings, @nested_strings.deep_dup.deep_transform_keys! { |key| key.to_s.upcase } + assert_equal @nested_upcase_strings, @nested_mixed.deep_dup.deep_transform_keys! { |key| key.to_s.upcase } + assert_equal @upcase_array_of_hashes, @string_array_of_hashes.deep_dup.deep_transform_keys! { |key| key.to_s.upcase } + assert_equal @upcase_array_of_hashes, @symbol_array_of_hashes.deep_dup.deep_transform_keys! { |key| key.to_s.upcase } + assert_equal @upcase_array_of_hashes, @mixed_array_of_hashes.deep_dup.deep_transform_keys! { |key| key.to_s.upcase } end def test_deep_transform_keys_with_bang_mutates transformed_hash = @nested_mixed.deep_dup - transformed_hash.deep_transform_keys!{ |key| key.to_s.upcase } + transformed_hash.deep_transform_keys! { |key| key.to_s.upcase } assert_equal @nested_upcase_strings, transformed_hash - assert_equal @nested_mixed, { 'a' => { :b => { 'c' => 3 } } } + assert_equal @nested_mixed, "a" => { b: { "c" => 3 } } end def test_symbolize_keys @@ -167,7 +167,7 @@ class HashExtTest < ActiveSupport::TestCase transformed_hash = @mixed.dup transformed_hash.deep_symbolize_keys! assert_equal @symbols, transformed_hash - assert_equal @mixed, { :a => 1, "b" => 2 } + assert_equal @mixed, :a => 1, "b" => 2 end def test_deep_symbolize_keys! @@ -183,7 +183,7 @@ class HashExtTest < ActiveSupport::TestCase transformed_hash = @nested_mixed.deep_dup transformed_hash.deep_symbolize_keys! assert_equal @nested_symbols, transformed_hash - assert_equal @nested_mixed, { 'a' => { :b => { 'c' => 3 } } } + assert_equal @nested_mixed, "a" => { b: { "c" => 3 } } end def test_symbolize_keys_preserves_keys_that_cant_be_symbolized @@ -196,14 +196,14 @@ class HashExtTest < ActiveSupport::TestCase assert_equal @nested_illegal_symbols, @nested_illegal_symbols.deep_dup.deep_symbolize_keys! end - def test_symbolize_keys_preserves_fixnum_keys - assert_equal @fixnums, @fixnums.symbolize_keys - assert_equal @fixnums, @fixnums.dup.symbolize_keys! + def test_symbolize_keys_preserves_integer_keys + assert_equal @integers, @integers.symbolize_keys + assert_equal @integers, @integers.dup.symbolize_keys! end - def test_deep_symbolize_keys_preserves_fixnum_keys - assert_equal @nested_fixnums, @nested_fixnums.deep_symbolize_keys - assert_equal @nested_fixnums, @nested_fixnums.deep_dup.deep_symbolize_keys! + def test_deep_symbolize_keys_preserves_integer_keys + assert_equal @nested_integers, @nested_integers.deep_symbolize_keys + assert_equal @nested_integers, @nested_integers.deep_dup.deep_symbolize_keys! end def test_stringify_keys @@ -243,7 +243,7 @@ class HashExtTest < ActiveSupport::TestCase transformed_hash = @mixed.dup transformed_hash.stringify_keys! assert_equal @strings, transformed_hash - assert_equal @mixed, { :a => 1, "b" => 2 } + assert_equal @mixed, :a => 1, "b" => 2 end def test_deep_stringify_keys! @@ -259,7 +259,7 @@ class HashExtTest < ActiveSupport::TestCase transformed_hash = @nested_mixed.deep_dup transformed_hash.deep_stringify_keys! assert_equal @nested_strings, transformed_hash - assert_equal @nested_mixed, { 'a' => { :b => { 'c' => 3 } } } + assert_equal @nested_mixed, "a" => { b: { "c" => 3 } } end def test_symbolize_keys_for_hash_with_indifferent_access @@ -276,7 +276,6 @@ class HashExtTest < ActiveSupport::TestCase assert_equal @nested_symbols, @nested_mixed.with_indifferent_access.deep_symbolize_keys end - def test_symbolize_keys_bang_for_hash_with_indifferent_access assert_raise(NoMethodError) { @symbols.with_indifferent_access.dup.symbolize_keys! } assert_raise(NoMethodError) { @strings.with_indifferent_access.dup.symbolize_keys! } @@ -299,14 +298,14 @@ class HashExtTest < ActiveSupport::TestCase assert_raise(NoMethodError) { @nested_illegal_symbols.with_indifferent_access.deep_dup.deep_symbolize_keys! } end - def test_symbolize_keys_preserves_fixnum_keys_for_hash_with_indifferent_access - assert_equal @fixnums, @fixnums.with_indifferent_access.symbolize_keys - assert_raise(NoMethodError) { @fixnums.with_indifferent_access.dup.symbolize_keys! } + def test_symbolize_keys_preserves_integer_keys_for_hash_with_indifferent_access + assert_equal @integers, @integers.with_indifferent_access.symbolize_keys + assert_raise(NoMethodError) { @integers.with_indifferent_access.dup.symbolize_keys! } end - def test_deep_symbolize_keys_preserves_fixnum_keys_for_hash_with_indifferent_access - assert_equal @nested_fixnums, @nested_fixnums.with_indifferent_access.deep_symbolize_keys - assert_raise(NoMethodError) { @nested_fixnums.with_indifferent_access.deep_dup.deep_symbolize_keys! } + def test_deep_symbolize_keys_preserves_integer_keys_for_hash_with_indifferent_access + assert_equal @nested_integers, @nested_integers.with_indifferent_access.deep_symbolize_keys + assert_raise(NoMethodError) { @nested_integers.with_indifferent_access.deep_dup.deep_symbolize_keys! } end def test_stringify_keys_for_hash_with_indifferent_access @@ -353,31 +352,31 @@ class HashExtTest < ActiveSupport::TestCase @symbols = @symbols.with_indifferent_access @mixed = @mixed.with_indifferent_access - assert_equal 'a', @strings.__send__(:convert_key, :a) + assert_equal "a", @strings.__send__(:convert_key, :a) - assert_equal 1, @strings.fetch('a') + assert_equal 1, @strings.fetch("a") assert_equal 1, @strings.fetch(:a.to_s) assert_equal 1, @strings.fetch(:a) hashes = { :@strings => @strings, :@symbols => @symbols, :@mixed => @mixed } - method_map = { :'[]' => 1, :fetch => 1, :values_at => [1], - :has_key? => true, :include? => true, :key? => true, - :member? => true } + method_map = { '[]': 1, fetch: 1, values_at: [1], + has_key?: true, include?: true, key?: true, + member?: true } hashes.each do |name, hash| method_map.sort_by(&:to_s).each do |meth, expected| - assert_equal(expected, hash.__send__(meth, 'a'), + assert_equal(expected, hash.__send__(meth, "a"), "Calling #{name}.#{meth} 'a'") assert_equal(expected, hash.__send__(meth, :a), "Calling #{name}.#{meth} :a") end end - assert_equal [1, 2], @strings.values_at('a', 'b') + assert_equal [1, 2], @strings.values_at("a", "b") assert_equal [1, 2], @strings.values_at(:a, :b) - assert_equal [1, 2], @symbols.values_at('a', 'b') + assert_equal [1, 2], @symbols.values_at("a", "b") assert_equal [1, 2], @symbols.values_at(:a, :b) - assert_equal [1, 2], @mixed.values_at('a', 'b') + assert_equal [1, 2], @mixed.values_at("a", "b") assert_equal [1, 2], @mixed.values_at(:a, :b) end @@ -412,11 +411,11 @@ class HashExtTest < ActiveSupport::TestCase def test_indifferent_writing hash = HashWithIndifferentAccess.new hash[:a] = 1 - hash['b'] = 2 + hash["b"] = 2 hash[3] = 3 - assert_equal hash['a'], 1 - assert_equal hash['b'], 2 + assert_equal hash["a"], 1 + assert_equal hash["b"], 2 assert_equal hash[:a], 1 assert_equal hash[:b], 2 assert_equal hash[3], 3 @@ -424,56 +423,56 @@ class HashExtTest < ActiveSupport::TestCase def test_indifferent_update hash = HashWithIndifferentAccess.new - hash[:a] = 'a' - hash['b'] = 'b' + hash[:a] = "a" + hash["b"] = "b" updated_with_strings = hash.update(@strings) updated_with_symbols = hash.update(@symbols) updated_with_mixed = hash.update(@mixed) assert_equal updated_with_strings[:a], 1 - assert_equal updated_with_strings['a'], 1 - assert_equal updated_with_strings['b'], 2 + assert_equal updated_with_strings["a"], 1 + assert_equal updated_with_strings["b"], 2 assert_equal updated_with_symbols[:a], 1 - assert_equal updated_with_symbols['b'], 2 + assert_equal updated_with_symbols["b"], 2 assert_equal updated_with_symbols[:b], 2 assert_equal updated_with_mixed[:a], 1 - assert_equal updated_with_mixed['b'], 2 + assert_equal updated_with_mixed["b"], 2 assert [updated_with_strings, updated_with_symbols, updated_with_mixed].all? { |h| h.keys.size == 2 } end def test_update_with_to_hash_conversion hash = HashWithIndifferentAccess.new - hash.update HashByConversion.new({ :a => 1 }) - assert_equal hash['a'], 1 + hash.update HashByConversion.new(a: 1) + assert_equal hash["a"], 1 end def test_indifferent_merging hash = HashWithIndifferentAccess.new - hash[:a] = 'failure' - hash['b'] = 'failure' + hash[:a] = "failure" + hash["b"] = "failure" - other = { 'a' => 1, :b => 2 } + other = { "a" => 1, :b => 2 } merged = hash.merge(other) assert_equal HashWithIndifferentAccess, merged.class assert_equal 1, merged[:a] - assert_equal 2, merged['b'] + assert_equal 2, merged["b"] hash.update(other) assert_equal 1, hash[:a] - assert_equal 2, hash['b'] + assert_equal 2, hash["b"] end def test_merge_with_to_hash_conversion hash = HashWithIndifferentAccess.new - merged = hash.merge HashByConversion.new({ :a => 1 }) - assert_equal merged['a'], 1 + merged = hash.merge HashByConversion.new(a: 1) + assert_equal merged["a"], 1 end def test_indifferent_replace @@ -482,7 +481,7 @@ class HashExtTest < ActiveSupport::TestCase replaced = hash.replace(b: 12) - assert hash.key?('b') + assert hash.key?("b") assert !hash.key?(:a) assert_equal 12, hash[:b] assert_same hash, replaced @@ -494,7 +493,7 @@ class HashExtTest < ActiveSupport::TestCase replaced = hash.replace(HashByConversion.new(b: 12)) - assert hash.key?('b') + assert hash.key?("b") assert !hash.key?(:a) assert_equal 12, hash[:b] assert_same hash, replaced @@ -503,18 +502,18 @@ class HashExtTest < ActiveSupport::TestCase def test_indifferent_merging_with_block hash = HashWithIndifferentAccess.new hash[:a] = 1 - hash['b'] = 3 + hash["b"] = 3 - other = { 'a' => 4, :b => 2, 'c' => 10 } + other = { "a" => 4, :b => 2, "c" => 10 } merged = hash.merge(other) { |key, old, new| old > new ? old : new } assert_equal HashWithIndifferentAccess, merged.class assert_equal 4, merged[:a] - assert_equal 3, merged['b'] + assert_equal 3, merged["b"] assert_equal 10, merged[:c] - other_indifferent = HashWithIndifferentAccess.new('a' => 9, :b => 2) + other_indifferent = HashWithIndifferentAccess.new("a" => 9, :b => 2) merged = hash.merge(other_indifferent) { |key, old, new| old + new } @@ -528,26 +527,26 @@ class HashExtTest < ActiveSupport::TestCase hash.reverse_merge! key: :new_value assert_equal :old_value, hash[:key] - hash = HashWithIndifferentAccess.new('some' => 'value', 'other' => 'value') - hash.reverse_merge!(:some => 'noclobber', :another => 'clobber') - assert_equal 'value', hash[:some] - assert_equal 'clobber', hash[:another] + hash = HashWithIndifferentAccess.new("some" => "value", "other" => "value") + hash.reverse_merge!(some: "noclobber", another: "clobber") + assert_equal "value", hash[:some] + assert_equal "clobber", hash[:another] end def test_indifferent_deleting - get_hash = proc{ { :a => 'foo' }.with_indifferent_access } + get_hash = proc { { a: "foo" }.with_indifferent_access } hash = get_hash.call - assert_equal hash.delete(:a), 'foo' + assert_equal hash.delete(:a), "foo" assert_equal hash.delete(:a), nil hash = get_hash.call - assert_equal hash.delete('a'), 'foo' - assert_equal hash.delete('a'), nil + assert_equal hash.delete("a"), "foo" + assert_equal hash.delete("a"), nil end def test_indifferent_select - hash = ActiveSupport::HashWithIndifferentAccess.new(@strings).select {|k,v| v == 1} + hash = ActiveSupport::HashWithIndifferentAccess.new(@strings).select { |k,v| v == 1 } - assert_equal({ 'a' => 1 }, hash) + assert_equal({ "a" => 1 }, hash) assert_instance_of ActiveSupport::HashWithIndifferentAccess, hash end @@ -557,23 +556,23 @@ class HashExtTest < ActiveSupport::TestCase end def test_indifferent_select_returns_a_hash_when_unchanged - hash = ActiveSupport::HashWithIndifferentAccess.new(@strings).select {|k,v| true} + hash = ActiveSupport::HashWithIndifferentAccess.new(@strings).select { |k,v| true } assert_instance_of ActiveSupport::HashWithIndifferentAccess, hash end def test_indifferent_select_bang indifferent_strings = ActiveSupport::HashWithIndifferentAccess.new(@strings) - indifferent_strings.select! {|k,v| v == 1} + indifferent_strings.select! { |k,v| v == 1 } - assert_equal({ 'a' => 1 }, indifferent_strings) + assert_equal({ "a" => 1 }, indifferent_strings) assert_instance_of ActiveSupport::HashWithIndifferentAccess, indifferent_strings end def test_indifferent_reject - hash = ActiveSupport::HashWithIndifferentAccess.new(@strings).reject {|k,v| v != 1} + hash = ActiveSupport::HashWithIndifferentAccess.new(@strings).reject { |k,v| v != 1 } - assert_equal({ 'a' => 1 }, hash) + assert_equal({ "a" => 1 }, hash) assert_instance_of ActiveSupport::HashWithIndifferentAccess, hash end @@ -584,9 +583,9 @@ class HashExtTest < ActiveSupport::TestCase def test_indifferent_reject_bang indifferent_strings = ActiveSupport::HashWithIndifferentAccess.new(@strings) - indifferent_strings.reject! {|k,v| v != 1} + indifferent_strings.reject! { |k,v| v != 1 } - assert_equal({ 'a' => 1 }, indifferent_strings) + assert_equal({ "a" => 1 }, indifferent_strings) assert_instance_of ActiveSupport::HashWithIndifferentAccess, indifferent_strings end @@ -596,10 +595,10 @@ class HashExtTest < ActiveSupport::TestCase # Should preserve the default value. mixed_with_default = @mixed.dup - mixed_with_default.default = '1234' + mixed_with_default.default = "1234" roundtrip = mixed_with_default.with_indifferent_access.to_hash assert_equal @strings, roundtrip - assert_equal '1234', roundtrip.default + assert_equal "1234", roundtrip.default # Ensure nested hashes are not HashWithIndiffereneAccess new_to_hash = @nested_mixed.with_indifferent_access.to_hash @@ -609,21 +608,21 @@ class HashExtTest < ActiveSupport::TestCase end def test_lookup_returns_the_same_object_that_is_stored_in_hash_indifferent_access - hash = HashWithIndifferentAccess.new {|h, k| h[k] = []} + hash = HashWithIndifferentAccess.new { |h, k| h[k] = [] } hash[:a] << 1 assert_equal [1], hash[:a] end def test_with_indifferent_access_has_no_side_effects_on_existing_hash - hash = {content: [{:foo => :bar, 'bar' => 'baz'}]} + hash = { content: [{ :foo => :bar, "bar" => "baz" }] } hash.with_indifferent_access assert_equal [:foo, "bar"], hash[:content].first.keys end def test_indifferent_hash_with_array_of_hashes - hash = { "urls" => { "url" => [ { "address" => "1" }, { "address" => "2" } ] }}.with_indifferent_access + hash = { "urls" => { "url" => [ { "address" => "1" }, { "address" => "2" } ] } }.with_indifferent_access assert_equal "1", hash[:urls][:url].first[:address] hash = hash.to_hash @@ -635,14 +634,14 @@ class HashExtTest < ActiveSupport::TestCase def test_should_preserve_array_subclass_when_value_is_array array = SubclassingArray.new array << { "address" => "1" } - hash = { "urls" => { "url" => array }}.with_indifferent_access + hash = { "urls" => { "url" => array } }.with_indifferent_access assert_equal SubclassingArray, hash[:urls][:url].class end def test_should_preserve_array_class_when_hash_value_is_frozen_array array = SubclassingArray.new array << { "address" => "1" } - hash = { "urls" => { "url" => array.freeze }}.with_indifferent_access + hash = { "urls" => { "url" => array.freeze } }.with_indifferent_access assert_equal SubclassingArray, hash[:urls][:url].class end @@ -650,9 +649,9 @@ class HashExtTest < ActiveSupport::TestCase h = HashWithIndifferentAccess.new h[:first] = 1 h = h.stringify_keys - assert_equal 1, h['first'] + assert_equal 1, h["first"] h = HashWithIndifferentAccess.new - h['first'] = 1 + h["first"] = 1 h = h.symbolize_keys assert_equal 1, h[:first] end @@ -661,40 +660,40 @@ class HashExtTest < ActiveSupport::TestCase h = HashWithIndifferentAccess.new h[:first] = 1 h = h.deep_stringify_keys - assert_equal 1, h['first'] + assert_equal 1, h["first"] h = HashWithIndifferentAccess.new - h['first'] = 1 + h["first"] = 1 h = h.deep_symbolize_keys assert_equal 1, h[:first] end def test_to_options_on_indifferent_preserves_hash h = HashWithIndifferentAccess.new - h['first'] = 1 + h["first"] = 1 h.to_options! - assert_equal 1, h['first'] + assert_equal 1, h["first"] end def test_to_options_on_indifferent_preserves_works_as_hash_with_dup - h = HashWithIndifferentAccess.new({ a: { b: 'b' } }) + h = HashWithIndifferentAccess.new(a: { b: "b" }) dup = h.dup - dup[:a][:c] = 'c' - assert_equal 'c', h[:a][:c] + dup[:a][:c] = "c" + assert_equal "c", h[:a][:c] end def test_indifferent_sub_hashes - h = {'user' => {'id' => 5}}.with_indifferent_access - ['user', :user].each {|user| [:id, 'id'].each {|id| assert_equal 5, h[user][id], "h[#{user.inspect}][#{id.inspect}] should be 5"}} + h = { "user" => { "id" => 5 } }.with_indifferent_access + ["user", :user].each { |user| [:id, "id"].each { |id| assert_equal 5, h[user][id], "h[#{user.inspect}][#{id.inspect}] should be 5" } } - h = {:user => {:id => 5}}.with_indifferent_access - ['user', :user].each {|user| [:id, 'id'].each {|id| assert_equal 5, h[user][id], "h[#{user.inspect}][#{id.inspect}] should be 5"}} + h = { user: { id: 5 } }.with_indifferent_access + ["user", :user].each { |user| [:id, "id"].each { |id| assert_equal 5, h[user][id], "h[#{user.inspect}][#{id.inspect}] should be 5" } } end def test_indifferent_duplication # Should preserve default value h = HashWithIndifferentAccess.new - h.default = '1234' + h.default = "1234" assert_equal h.default, h.dup.default # Should preserve class for subclasses @@ -704,52 +703,52 @@ class HashExtTest < ActiveSupport::TestCase def test_nested_dig_indifferent_access skip if RUBY_VERSION < "2.3.0" - data = {"this" => {"views" => 1234}}.with_indifferent_access + data = { "this" => { "views" => 1234 } }.with_indifferent_access assert_equal 1234, data.dig(:this, :views) end def test_assert_valid_keys assert_nothing_raised do - { :failure => "stuff", :funny => "business" }.assert_valid_keys([ :failure, :funny ]) - { :failure => "stuff", :funny => "business" }.assert_valid_keys(:failure, :funny) + { failure: "stuff", funny: "business" }.assert_valid_keys([ :failure, :funny ]) + { failure: "stuff", funny: "business" }.assert_valid_keys(:failure, :funny) end # not all valid keys are required to be present assert_nothing_raised do - { :failure => "stuff", :funny => "business" }.assert_valid_keys([ :failure, :funny, :sunny ]) - { :failure => "stuff", :funny => "business" }.assert_valid_keys(:failure, :funny, :sunny) + { failure: "stuff", funny: "business" }.assert_valid_keys([ :failure, :funny, :sunny ]) + { failure: "stuff", funny: "business" }.assert_valid_keys(:failure, :funny, :sunny) end exception = assert_raise ArgumentError do - { :failore => "stuff", :funny => "business" }.assert_valid_keys([ :failure, :funny ]) + { failore: "stuff", funny: "business" }.assert_valid_keys([ :failure, :funny ]) end assert_equal "Unknown key: :failore. Valid keys are: :failure, :funny", exception.message exception = assert_raise ArgumentError do - { :failore => "stuff", :funny => "business" }.assert_valid_keys(:failure, :funny) + { failore: "stuff", funny: "business" }.assert_valid_keys(:failure, :funny) end assert_equal "Unknown key: :failore. Valid keys are: :failure, :funny", exception.message exception = assert_raise ArgumentError do - { :failore => "stuff", :funny => "business" }.assert_valid_keys([ :failure ]) + { failore: "stuff", funny: "business" }.assert_valid_keys([ :failure ]) end assert_equal "Unknown key: :failore. Valid keys are: :failure", exception.message exception = assert_raise ArgumentError do - { :failore => "stuff", :funny => "business" }.assert_valid_keys(:failure) + { failore: "stuff", funny: "business" }.assert_valid_keys(:failure) end assert_equal "Unknown key: :failore. Valid keys are: :failure", exception.message end def test_assorted_keys_not_stringified - original = {Object.new => 2, 1 => 2, [] => true} + original = { Object.new => 2, 1 => 2, [] => true } indiff = original.with_indifferent_access - assert(!indiff.keys.any? {|k| k.kind_of? String}, "A key was converted to a string!") + assert(!indiff.keys.any? { |k| k.kind_of? String }, "A key was converted to a string!") end def test_deep_merge - hash_1 = { :a => "a", :b => "b", :c => { :c1 => "c1", :c2 => "c2", :c3 => { :d1 => "d1" } } } - hash_2 = { :a => 1, :c => { :c1 => 2, :c3 => { :d2 => "d2" } } } - expected = { :a => 1, :b => "b", :c => { :c1 => 2, :c2 => "c2", :c3 => { :d1 => "d1", :d2 => "d2" } } } + hash_1 = { a: "a", b: "b", c: { c1: "c1", c2: "c2", c3: { d1: "d1" } } } + hash_2 = { a: 1, c: { c1: 2, c3: { d2: "d2" } } } + expected = { a: 1, b: "b", c: { c1: 2, c2: "c2", c3: { d1: "d1", d2: "d2" } } } assert_equal expected, hash_1.deep_merge(hash_2) hash_1.deep_merge!(hash_2) @@ -757,9 +756,9 @@ class HashExtTest < ActiveSupport::TestCase end def test_deep_merge_with_block - hash_1 = { :a => "a", :b => "b", :c => { :c1 => "c1", :c2 => "c2", :c3 => { :d1 => "d1" } } } - hash_2 = { :a => 1, :c => { :c1 => 2, :c3 => { :d2 => "d2" } } } - expected = { :a => [:a, "a", 1], :b => "b", :c => { :c1 => [:c1, "c1", 2], :c2 => "c2", :c3 => { :d1 => "d1", :d2 => "d2" } } } + hash_1 = { a: "a", b: "b", c: { c1: "c1", c2: "c2", c3: { d1: "d1" } } } + hash_2 = { a: 1, c: { c1: 2, c3: { d2: "d2" } } } + expected = { a: [:a, "a", 1], b: "b", c: { c1: [:c1, "c1", 2], c2: "c2", c3: { d1: "d1", d2: "d2" } } } assert_equal(expected, hash_1.deep_merge(hash_2) { |k,o,n| [k, o, n] }) hash_1.deep_merge!(hash_2) { |k,o,n| [k, o, n] } @@ -768,8 +767,8 @@ class HashExtTest < ActiveSupport::TestCase def test_deep_merge_with_falsey_values hash_1 = { e: false } - hash_2 = { e: 'e' } - expected = { e: [:e, false, 'e'] } + hash_2 = { e: "e" } + expected = { e: [:e, false, "e"] } assert_equal(expected, hash_1.deep_merge(hash_2) { |k, o, n| [k, o, n] }) hash_1.deep_merge!(hash_2) { |k, o, n| [k, o, n] } @@ -777,9 +776,9 @@ class HashExtTest < ActiveSupport::TestCase end def test_deep_merge_on_indifferent_access - hash_1 = HashWithIndifferentAccess.new({ :a => "a", :b => "b", :c => { :c1 => "c1", :c2 => "c2", :c3 => { :d1 => "d1" } } }) - hash_2 = HashWithIndifferentAccess.new({ :a => 1, :c => { :c1 => 2, :c3 => { :d2 => "d2" } } }) - hash_3 = { :a => 1, :c => { :c1 => 2, :c3 => { :d2 => "d2" } } } + hash_1 = HashWithIndifferentAccess.new(a: "a", b: "b", c: { c1: "c1", c2: "c2", c3: { d1: "d1" } }) + hash_2 = HashWithIndifferentAccess.new(a: 1, c: { c1: 2, c3: { d2: "d2" } }) + hash_3 = { a: 1, c: { c1: 2, c3: { d2: "d2" } } } expected = { "a" => 1, "b" => "b", "c" => { "c1" => 2, "c2" => "c2", "c3" => { "d1" => "d1", "d2" => "d2" } } } assert_equal expected, hash_1.deep_merge(hash_2) assert_equal expected, hash_1.deep_merge(hash_3) @@ -791,9 +790,9 @@ class HashExtTest < ActiveSupport::TestCase def test_store_on_indifferent_access hash = HashWithIndifferentAccess.new hash.store(:test1, 1) - hash.store('test1', 11) + hash.store("test1", 11) hash[:test2] = 2 - hash['test2'] = 22 + hash["test2"] = 22 expected = { "test1" => 11, "test2" => 22 } assert_equal expected, hash end @@ -801,16 +800,16 @@ class HashExtTest < ActiveSupport::TestCase def test_constructor_on_indifferent_access hash = HashWithIndifferentAccess[:foo, 1] assert_equal 1, hash[:foo] - assert_equal 1, hash['foo'] + assert_equal 1, hash["foo"] hash[:foo] = 3 assert_equal 3, hash[:foo] - assert_equal 3, hash['foo'] + assert_equal 3, hash["foo"] end def test_reverse_merge - defaults = { :a => "x", :b => "y", :c => 10 }.freeze - options = { :a => 1, :b => 2 } - expected = { :a => 1, :b => 2, :c => 10 } + defaults = { a: "x", b: "y", c: 10 }.freeze + options = { a: 1, b: 2 } + expected = { a: 1, b: 2, c: 10 } # Should merge defaults into options, creating a new hash. assert_equal expected, options.reverse_merge(defaults) @@ -828,8 +827,8 @@ class HashExtTest < ActiveSupport::TestCase end def test_slice - original = { :a => 'x', :b => 'y', :c => 10 } - expected = { :a => 'x', :b => 'y' } + original = { a: "x", b: "y", c: 10 } + expected = { a: "x", b: "y" } # Should return a new hash with only the given keys. assert_equal expected, original.slice(:a, :b) @@ -837,15 +836,15 @@ class HashExtTest < ActiveSupport::TestCase end def test_slice_inplace - original = { :a => 'x', :b => 'y', :c => 10 } - expected = { :c => 10 } + original = { a: "x", b: "y", c: 10 } + expected = { c: 10 } # Should replace the hash with only the given keys. assert_equal expected, original.slice!(:a, :b) end def test_slice_with_an_array_key - original = { :a => 'x', :b => 'y', :c => 10, [:a, :b] => "an array key" } + original = { :a => "x", :b => "y", :c => 10, [:a, :b] => "an array key" } expected = { [:a, :b] => "an array key", :c => 10 } # Should return a new hash with only the given keys when given an array key. @@ -854,26 +853,26 @@ class HashExtTest < ActiveSupport::TestCase end def test_slice_inplace_with_an_array_key - original = { :a => 'x', :b => 'y', :c => 10, [:a, :b] => "an array key" } - expected = { :a => 'x', :b => 'y' } + original = { :a => "x", :b => "y", :c => 10, [:a, :b] => "an array key" } + expected = { a: "x", b: "y" } # Should replace the hash with only the given keys when given an array key. assert_equal expected, original.slice!([:a, :b], :c) end def test_slice_with_splatted_keys - original = { :a => 'x', :b => 'y', :c => 10, [:a, :b] => "an array key" } - expected = { :a => 'x', :b => "y" } + original = { :a => "x", :b => "y", :c => 10, [:a, :b] => "an array key" } + expected = { a: "x", b: "y" } # Should grab each of the splatted keys. assert_equal expected, original.slice(*[:a, :b]) end def test_indifferent_slice - original = { :a => 'x', :b => 'y', :c => 10 }.with_indifferent_access - expected = { :a => 'x', :b => 'y' }.with_indifferent_access + original = { a: "x", b: "y", c: 10 }.with_indifferent_access + expected = { a: "x", b: "y" }.with_indifferent_access - [['a', 'b'], [:a, :b]].each do |keys| + [["a", "b"], [:a, :b]].each do |keys| # Should return a new hash with only the given keys. assert_equal expected, original.slice(*keys), keys.inspect assert_not_equal expected, original @@ -881,10 +880,10 @@ class HashExtTest < ActiveSupport::TestCase end def test_indifferent_slice_inplace - original = { :a => 'x', :b => 'y', :c => 10 }.with_indifferent_access - expected = { :c => 10 }.with_indifferent_access + original = { a: "x", b: "y", c: 10 }.with_indifferent_access + expected = { c: 10 }.with_indifferent_access - [['a', 'b'], [:a, :b]].each do |keys| + [["a", "b"], [:a, :b]].each do |keys| # Should replace the hash with only the given keys. copy = original.dup assert_equal expected, copy.slice!(*keys) @@ -892,13 +891,13 @@ class HashExtTest < ActiveSupport::TestCase end def test_indifferent_slice_access_with_symbols - original = {'login' => 'bender', 'password' => 'shiny', 'stuff' => 'foo'} + original = { "login" => "bender", "password" => "shiny", "stuff" => "foo" } original = original.with_indifferent_access slice = original.slice(:login, :password) - assert_equal 'bender', slice[:login] - assert_equal 'bender', slice['login'] + assert_equal "bender", slice[:login] + assert_equal "bender", slice["login"] end def test_slice_bang_does_not_override_default @@ -920,17 +919,17 @@ class HashExtTest < ActiveSupport::TestCase end def test_extract - original = {:a => 1, :b => 2, :c => 3, :d => 4} - expected = {:a => 1, :b => 2} - remaining = {:c => 3, :d => 4} + original = { a: 1, b: 2, c: 3, d: 4 } + expected = { a: 1, b: 2 } + remaining = { c: 3, d: 4 } assert_equal expected, original.extract!(:a, :b, :x) assert_equal remaining, original end def test_extract_nils - original = {:a => nil, :b => nil} - expected = {:a => nil} + original = { a: nil, b: nil } + expected = { a: nil } extracted = original.extract!(:a, :x) assert_equal expected, extracted @@ -939,11 +938,11 @@ class HashExtTest < ActiveSupport::TestCase end def test_indifferent_extract - original = {:a => 1, 'b' => 2, :c => 3, 'd' => 4}.with_indifferent_access - expected = {:a => 1, :b => 2}.with_indifferent_access - remaining = {:c => 3, :d => 4}.with_indifferent_access + original = { :a => 1, "b" => 2, :c => 3, "d" => 4 }.with_indifferent_access + expected = { a: 1, b: 2 }.with_indifferent_access + remaining = { c: 3, d: 4 }.with_indifferent_access - [['a', 'b'], [:a, :b]].each do |keys| + [["a", "b"], [:a, :b]].each do |keys| copy = original.dup assert_equal expected, copy.extract!(*keys) assert_equal remaining, copy @@ -951,8 +950,8 @@ class HashExtTest < ActiveSupport::TestCase end def test_except - original = { :a => 'x', :b => 'y', :c => 10 } - expected = { :a => 'x', :b => 'y' } + original = { a: "x", b: "y", c: 10 } + expected = { a: "x", b: "y" } # Should return a new hash without the given keys. assert_equal expected, original.except(:c) @@ -964,8 +963,8 @@ class HashExtTest < ActiveSupport::TestCase end def test_except_with_more_than_one_argument - original = { :a => 'x', :b => 'y', :c => 10 } - expected = { :a => 'x' } + original = { a: "x", b: "y", c: 10 } + expected = { a: "x" } assert_equal expected, original.except(:b, :c) @@ -974,7 +973,7 @@ class HashExtTest < ActiveSupport::TestCase end def test_except_with_original_frozen - original = { :a => 'x', :b => 'y' } + original = { a: "x", b: "y" } original.freeze assert_nothing_raised { original.except(:a) } @@ -982,7 +981,7 @@ class HashExtTest < ActiveSupport::TestCase end def test_except_does_not_delete_values_in_original - original = { :a => 'x', :b => 'y' } + original = { a: "x", b: "y" } assert_not_called(original, :delete) do original.except(:a) end @@ -999,6 +998,10 @@ class HashExtTest < ActiveSupport::TestCase h = hash_with_only_nil_values.dup assert_equal({}, h.compact) assert_equal(hash_with_only_nil_values, h) + + h = @symbols.dup + assert_equal(@symbols, h.compact) + assert_equal(@symbols, h) end def test_compact! @@ -1012,11 +1015,15 @@ class HashExtTest < ActiveSupport::TestCase h = hash_with_only_nil_values.dup assert_equal({}, h.compact!) assert_equal({}, h) + + h = @symbols.dup + assert_equal(nil, h.compact!) + assert_equal(@symbols, h) end def test_new_with_to_hash_conversion hash = HashWithIndifferentAccess.new(HashByConversion.new(a: 1)) - assert hash.key?('a') + assert hash.key?("a") assert_equal 1, hash[:a] end @@ -1034,7 +1041,7 @@ class HashExtTest < ActiveSupport::TestCase assert_equal 3, new_hash[2] new_hash.default = 2 - assert_equal 2, new_hash[:non_existant] + assert_equal 2, new_hash[:non_existent] end def test_to_hash_with_raising_default_proc @@ -1073,10 +1080,10 @@ end class IWriteMyOwnXML def to_xml(options = {}) options[:indent] ||= 2 - xml = options[:builder] ||= Builder::XmlMarkup.new(:indent => options[:indent]) + xml = options[:builder] ||= Builder::XmlMarkup.new(indent: options[:indent]) xml.instruct! unless options[:skip_instruct] xml.level_one do - xml.tag!(:second_level, 'content') + xml.tag!(:second_level, "content") end end end @@ -1089,139 +1096,139 @@ class HashExtToParamTests < ActiveSupport::TestCase end def test_string_hash - assert_equal '', {}.to_param - assert_equal 'hello=world', { :hello => "world" }.to_param - assert_equal 'hello=10', { "hello" => 10 }.to_param - assert_equal 'hello=world&say_bye=true', {:hello => "world", "say_bye" => true}.to_param + assert_equal "", {}.to_param + assert_equal "hello=world", { hello: "world" }.to_param + assert_equal "hello=10", { "hello" => 10 }.to_param + assert_equal "hello=world&say_bye=true", { :hello => "world", "say_bye" => true }.to_param end def test_number_hash - assert_equal '10=20&30=40&50=60', {10 => 20, 30 => 40, 50 => 60}.to_param + assert_equal "10=20&30=40&50=60", { 10 => 20, 30 => 40, 50 => 60 }.to_param end def test_to_param_hash - assert_equal 'custom-1=param-1&custom2-1=param2-1', {ToParam.new('custom') => ToParam.new('param'), ToParam.new('custom2') => ToParam.new('param2')}.to_param + assert_equal "custom-1=param-1&custom2-1=param2-1", { ToParam.new("custom") => ToParam.new("param"), ToParam.new("custom2") => ToParam.new("param2") }.to_param end def test_to_param_hash_escapes_its_keys_and_values - assert_equal 'param+1=A+string+with+%2F+characters+%26+that+should+be+%3F+escaped', { 'param 1' => 'A string with / characters & that should be ? escaped' }.to_param + assert_equal "param+1=A+string+with+%2F+characters+%26+that+should+be+%3F+escaped", { "param 1" => "A string with / characters & that should be ? escaped" }.to_param end def test_to_param_orders_by_key_in_ascending_order - assert_equal 'a=2&b=1&c=0', Hash[*%w(b 1 c 0 a 2)].to_param + assert_equal "a=2&b=1&c=0", Hash[*%w(b 1 c 0 a 2)].to_param end end class HashToXmlTest < ActiveSupport::TestCase def setup - @xml_options = { :root => :person, :skip_instruct => true, :indent => 0 } + @xml_options = { root: :person, skip_instruct: true, indent: 0 } end def test_one_level - xml = { :name => "David", :street => "Paulina" }.to_xml(@xml_options) + xml = { name: "David", street: "Paulina" }.to_xml(@xml_options) assert_equal "<person>", xml.first(8) - assert xml.include?(%(<street>Paulina</street>)) - assert xml.include?(%(<name>David</name>)) + assert_includes xml, %(<street>Paulina</street>) + assert_includes xml, %(<name>David</name>) end def test_one_level_dasherize_false - xml = { :name => "David", :street_name => "Paulina" }.to_xml(@xml_options.merge(:dasherize => false)) + xml = { name: "David", street_name: "Paulina" }.to_xml(@xml_options.merge(dasherize: false)) assert_equal "<person>", xml.first(8) - assert xml.include?(%(<street_name>Paulina</street_name>)) - assert xml.include?(%(<name>David</name>)) + assert_includes xml, %(<street_name>Paulina</street_name>) + assert_includes xml, %(<name>David</name>) end def test_one_level_dasherize_true - xml = { :name => "David", :street_name => "Paulina" }.to_xml(@xml_options.merge(:dasherize => true)) + xml = { name: "David", street_name: "Paulina" }.to_xml(@xml_options.merge(dasherize: true)) assert_equal "<person>", xml.first(8) - assert xml.include?(%(<street-name>Paulina</street-name>)) - assert xml.include?(%(<name>David</name>)) + assert_includes xml, %(<street-name>Paulina</street-name>) + assert_includes xml, %(<name>David</name>) end def test_one_level_camelize_true - xml = { :name => "David", :street_name => "Paulina" }.to_xml(@xml_options.merge(:camelize => true)) + xml = { name: "David", street_name: "Paulina" }.to_xml(@xml_options.merge(camelize: true)) assert_equal "<Person>", xml.first(8) - assert xml.include?(%(<StreetName>Paulina</StreetName>)) - assert xml.include?(%(<Name>David</Name>)) + assert_includes xml, %(<StreetName>Paulina</StreetName>) + assert_includes xml, %(<Name>David</Name>) end def test_one_level_camelize_lower - xml = { :name => "David", :street_name => "Paulina" }.to_xml(@xml_options.merge(:camelize => :lower)) + xml = { name: "David", street_name: "Paulina" }.to_xml(@xml_options.merge(camelize: :lower)) assert_equal "<person>", xml.first(8) - assert xml.include?(%(<streetName>Paulina</streetName>)) - assert xml.include?(%(<name>David</name>)) + assert_includes xml, %(<streetName>Paulina</streetName>) + assert_includes xml, %(<name>David</name>) end def test_one_level_with_types - xml = { :name => "David", :street => "Paulina", :age => 26, :age_in_millis => 820497600000, :moved_on => Date.new(2005, 11, 15), :resident => :yes }.to_xml(@xml_options) + xml = { name: "David", street: "Paulina", age: 26, age_in_millis: 820497600000, moved_on: Date.new(2005, 11, 15), resident: :yes }.to_xml(@xml_options) assert_equal "<person>", xml.first(8) - assert xml.include?(%(<street>Paulina</street>)) - assert xml.include?(%(<name>David</name>)) - assert xml.include?(%(<age type="integer">26</age>)) - assert xml.include?(%(<age-in-millis type="integer">820497600000</age-in-millis>)) - assert xml.include?(%(<moved-on type="date">2005-11-15</moved-on>)) - assert xml.include?(%(<resident type="symbol">yes</resident>)) + assert_includes xml, %(<street>Paulina</street>) + assert_includes xml, %(<name>David</name>) + assert_includes xml, %(<age type="integer">26</age>) + assert_includes xml, %(<age-in-millis type="integer">820497600000</age-in-millis>) + assert_includes xml, %(<moved-on type="date">2005-11-15</moved-on>) + assert_includes xml, %(<resident type="symbol">yes</resident>) end def test_one_level_with_nils - xml = { :name => "David", :street => "Paulina", :age => nil }.to_xml(@xml_options) + xml = { name: "David", street: "Paulina", age: nil }.to_xml(@xml_options) assert_equal "<person>", xml.first(8) - assert xml.include?(%(<street>Paulina</street>)) - assert xml.include?(%(<name>David</name>)) - assert xml.include?(%(<age nil="true"/>)) + assert_includes xml, %(<street>Paulina</street>) + assert_includes xml, %(<name>David</name>) + assert_includes xml, %(<age nil="true"/>) end def test_one_level_with_skipping_types - xml = { :name => "David", :street => "Paulina", :age => nil }.to_xml(@xml_options.merge(:skip_types => true)) + xml = { name: "David", street: "Paulina", age: nil }.to_xml(@xml_options.merge(skip_types: true)) assert_equal "<person>", xml.first(8) - assert xml.include?(%(<street>Paulina</street>)) - assert xml.include?(%(<name>David</name>)) - assert xml.include?(%(<age nil="true"/>)) + assert_includes xml, %(<street>Paulina</street>) + assert_includes xml, %(<name>David</name>) + assert_includes xml, %(<age nil="true"/>) end def test_one_level_with_yielding - xml = { :name => "David", :street => "Paulina" }.to_xml(@xml_options) do |x| + xml = { name: "David", street: "Paulina" }.to_xml(@xml_options) do |x| x.creator("Rails") end assert_equal "<person>", xml.first(8) - assert xml.include?(%(<street>Paulina</street>)) - assert xml.include?(%(<name>David</name>)) - assert xml.include?(%(<creator>Rails</creator>)) + assert_includes xml, %(<street>Paulina</street>) + assert_includes xml, %(<name>David</name>) + assert_includes xml, %(<creator>Rails</creator>) end def test_two_levels - xml = { :name => "David", :address => { :street => "Paulina" } }.to_xml(@xml_options) + xml = { name: "David", address: { street: "Paulina" } }.to_xml(@xml_options) assert_equal "<person>", xml.first(8) - assert xml.include?(%(<address><street>Paulina</street></address>)) - assert xml.include?(%(<name>David</name>)) + assert_includes xml, %(<address><street>Paulina</street></address>) + assert_includes xml, %(<name>David</name>) end def test_two_levels_with_second_level_overriding_to_xml - xml = { :name => "David", :address => { :street => "Paulina" }, :child => IWriteMyOwnXML.new }.to_xml(@xml_options) + xml = { name: "David", address: { street: "Paulina" }, child: IWriteMyOwnXML.new }.to_xml(@xml_options) assert_equal "<person>", xml.first(8) - assert xml.include?(%(<address><street>Paulina</street></address>)) - assert xml.include?(%(<level_one><second_level>content</second_level></level_one>)) + assert_includes xml, %(<address><street>Paulina</street></address>) + assert_includes xml, %(<level_one><second_level>content</second_level></level_one>) end def test_two_levels_with_array - xml = { :name => "David", :addresses => [{ :street => "Paulina" }, { :street => "Evergreen" }] }.to_xml(@xml_options) + xml = { name: "David", addresses: [{ street: "Paulina" }, { street: "Evergreen" }] }.to_xml(@xml_options) assert_equal "<person>", xml.first(8) - assert xml.include?(%(<addresses type="array"><address>)) - assert xml.include?(%(<address><street>Paulina</street></address>)) - assert xml.include?(%(<address><street>Evergreen</street></address>)) - assert xml.include?(%(<name>David</name>)) + assert_includes xml, %(<addresses type="array"><address>) + assert_includes xml, %(<address><street>Paulina</street></address>) + assert_includes xml, %(<address><street>Evergreen</street></address>) + assert_includes xml, %(<name>David</name>) end def test_three_levels_with_array - xml = { :name => "David", :addresses => [{ :streets => [ { :name => "Paulina" }, { :name => "Paulina" } ] } ] }.to_xml(@xml_options) - assert xml.include?(%(<addresses type="array"><address><streets type="array"><street><name>)) + xml = { name: "David", addresses: [{ streets: [ { name: "Paulina" }, { name: "Paulina" } ] } ] }.to_xml(@xml_options) + assert_includes xml, %(<addresses type="array"><address><streets type="array"><street><name>) end def test_timezoned_attributes xml = { - :created_at => Time.utc(1999,2,2), - :local_created_at => Time.utc(1999,2,2).in_time_zone('Eastern Time (US & Canada)') + created_at: Time.utc(1999,2,2), + local_created_at: Time.utc(1999,2,2).in_time_zone("Eastern Time (US & Canada)") }.to_xml(@xml_options) assert_match %r{<created-at type=\"dateTime\">1999-02-02T00:00:00Z</created-at>}, xml assert_match %r{<local-created-at type=\"dateTime\">1999-02-01T19:00:00-05:00</local-created-at>}, xml @@ -1260,17 +1267,17 @@ class HashToXmlTest < ActiveSupport::TestCase EOT expected_topic_hash = { - :title => "The First Topic", - :author_name => "David", - :id => 1, - :approved => false, - :replies_count => 0, - :replies_close_in => 2592000000, - :written_on => Date.new(2003, 7, 16), - :viewed_at => Time.utc(2003, 7, 16, 9, 28), - :content => "Have a nice day", - :author_email_address => "david@loudthinking.com", - :parent_id => nil + title: "The First Topic", + author_name: "David", + id: 1, + approved: false, + replies_count: 0, + replies_close_in: 2592000000, + written_on: Date.new(2003, 7, 16), + viewed_at: Time.utc(2003, 7, 16, 9, 28), + content: "Have a nice day", + author_email_address: "david@loudthinking.com", + parent_id: nil }.stringify_keys assert_equal expected_topic_hash, Hash.from_xml(topics_xml)["topics"].first @@ -1295,18 +1302,18 @@ class HashToXmlTest < ActiveSupport::TestCase EOT expected_topic_hash = { - :title => "The First Topic", - :author_name => "David", - :id => 1, - :approved => true, - :replies_count => 0, - :replies_close_in => 2592000000, - :written_on => Date.new(2003, 7, 16), - :viewed_at => Time.utc(2003, 7, 16, 9, 28), - :author_email_address => "david@loudthinking.com", - :parent_id => nil, - :ad_revenue => BigDecimal("1.50"), - :optimum_viewing_angle => 135.0, + title: "The First Topic", + author_name: "David", + id: 1, + approved: true, + replies_count: 0, + replies_close_in: 2592000000, + written_on: Date.new(2003, 7, 16), + viewed_at: Time.utc(2003, 7, 16, 9, 28), + author_email_address: "david@loudthinking.com", + parent_id: nil, + ad_revenue: BigDecimal("1.50"), + optimum_viewing_angle: 135.0, }.stringify_keys assert_equal expected_topic_hash, Hash.from_xml(topic_xml)["topic"] @@ -1325,12 +1332,12 @@ class HashToXmlTest < ActiveSupport::TestCase EOT expected_topic_hash = { - :title => nil, - :id => nil, - :approved => nil, - :written_on => nil, - :viewed_at => nil, - :parent_id => nil + title: nil, + id: nil, + approved: nil, + written_on: nil, + viewed_at: nil, + parent_id: nil }.stringify_keys assert_equal expected_topic_hash, Hash.from_xml(topic_xml)["topic"] @@ -1369,17 +1376,17 @@ class HashToXmlTest < ActiveSupport::TestCase EOT expected_topic_hash = { - :title => "The First Topic", - :author_name => "David", - :id => 1, - :approved => false, - :replies_count => 0, - :replies_close_in => 2592000000, - :written_on => Date.new(2003, 7, 16), - :viewed_at => Time.utc(2003, 7, 16, 9, 28), - :content => "Have a nice day", - :author_email_address => "david@loudthinking.com", - :parent_id => nil + title: "The First Topic", + author_name: "David", + id: 1, + approved: false, + replies_count: 0, + replies_close_in: 2592000000, + written_on: Date.new(2003, 7, 16), + viewed_at: Time.utc(2003, 7, 16, 9, 28), + content: "Have a nice day", + author_email_address: "david@loudthinking.com", + parent_id: nil }.stringify_keys assert_equal expected_topic_hash, Hash.from_xml(topics_xml)["topics"].first @@ -1395,14 +1402,14 @@ class HashToXmlTest < ActiveSupport::TestCase EOT expected_topic_hash = { - :id => "175756086", - :owner => "55569174@N00", - :secret => "0279bf37a1", - :server => "76", - :title => "Colored Pencil PhotoBooth Fun", - :ispublic => "1", - :isfriend => "0", - :isfamily => "0", + id: "175756086", + owner: "55569174@N00", + secret: "0279bf37a1", + server: "76", + title: "Colored Pencil PhotoBooth Fun", + ispublic: "1", + isfriend: "0", + isfamily: "0", }.stringify_keys assert_equal expected_topic_hash, Hash.from_xml(topic_xml)["rsp"]["photos"]["photo"] @@ -1430,7 +1437,7 @@ class HashToXmlTest < ActiveSupport::TestCase <posts type="array"></posts> </blog> XML - expected_blog_hash = {"blog" => {"posts" => []}} + expected_blog_hash = { "blog" => { "posts" => [] } } assert_equal expected_blog_hash, Hash.from_xml(blog_xml) end @@ -1441,7 +1448,7 @@ class HashToXmlTest < ActiveSupport::TestCase </posts> </blog> XML - expected_blog_hash = {"blog" => {"posts" => []}} + expected_blog_hash = { "blog" => { "posts" => [] } } assert_equal expected_blog_hash, Hash.from_xml(blog_xml) end @@ -1453,7 +1460,7 @@ class HashToXmlTest < ActiveSupport::TestCase </posts> </blog> XML - expected_blog_hash = {"blog" => {"posts" => ["a post"]}} + expected_blog_hash = { "blog" => { "posts" => ["a post"] } } assert_equal expected_blog_hash, Hash.from_xml(blog_xml) end @@ -1466,7 +1473,7 @@ class HashToXmlTest < ActiveSupport::TestCase </posts> </blog> XML - expected_blog_hash = {"blog" => {"posts" => ["a post", "another post"]}} + expected_blog_hash = { "blog" => { "posts" => ["a post", "another post"] } } assert_equal expected_blog_hash, Hash.from_xml(blog_xml) end @@ -1478,12 +1485,12 @@ class HashToXmlTest < ActiveSupport::TestCase </blog> XML hash = Hash.from_xml(blog_xml) - assert hash.has_key?('blog') - assert hash['blog'].has_key?('logo') + assert hash.has_key?("blog") + assert hash["blog"].has_key?("logo") - file = hash['blog']['logo'] - assert_equal 'logo.png', file.original_filename - assert_equal 'image/png', file.content_type + file = hash["blog"]["logo"] + assert_equal "logo.png", file.original_filename + assert_equal "image/png", file.content_type end def test_file_from_xml_with_defaults @@ -1493,9 +1500,9 @@ class HashToXmlTest < ActiveSupport::TestCase </logo> </blog> XML - file = Hash.from_xml(blog_xml)['blog']['logo'] - assert_equal 'untitled', file.original_filename - assert_equal 'application/octet-stream', file.content_type + file = Hash.from_xml(blog_xml)["blog"]["logo"] + assert_equal "untitled", file.original_filename + assert_equal "application/octet-stream", file.content_type end def test_tag_with_attrs_and_whitespace @@ -1504,7 +1511,7 @@ class HashToXmlTest < ActiveSupport::TestCase </blog> XML hash = Hash.from_xml(xml) - assert_equal "bacon is the best", hash['blog']['name'] + assert_equal "bacon is the best", hash["blog"]["name"] end def test_empty_cdata_from_xml @@ -1527,13 +1534,13 @@ class HashToXmlTest < ActiveSupport::TestCase EOT expected_bacon_hash = { - :weight => 0.5, - :chunky => true, - :price => BigDecimal("12.50"), - :expires_at => Time.utc(2007,12,25,12,34,56), - :notes => "", - :illustration => "babe.png", - :caption => "That'll do, pig." + weight: 0.5, + chunky: true, + price: BigDecimal("12.50"), + expires_at: Time.utc(2007,12,25,12,34,56), + notes: "", + illustration: "babe.png", + caption: "That'll do, pig." }.stringify_keys assert_equal expected_bacon_hash, Hash.from_xml(bacon_xml)["bacon"] @@ -1549,8 +1556,8 @@ class HashToXmlTest < ActiveSupport::TestCase EOT expected_product_hash = { - :weight => 0.5, - :image => {'type' => 'ProductImage', 'filename' => 'image.gif' }, + weight: 0.5, + image: { "type" => "ProductImage", "filename" => "image.gif" }, }.stringify_keys assert_equal expected_product_hash, Hash.from_xml(product_xml)["product"] @@ -1573,17 +1580,17 @@ class HashToXmlTest < ActiveSupport::TestCase end def test_from_xml_array_one - expected = { 'numbers' => { 'type' => 'Array', 'value' => '1' }} + expected = { "numbers" => { "type" => "Array", "value" => "1" } } assert_equal expected, Hash.from_xml('<numbers type="Array"><value>1</value></numbers>') end def test_from_xml_array_many - expected = { 'numbers' => { 'type' => 'Array', 'value' => [ '1', '2' ] }} + expected = { "numbers" => { "type" => "Array", "value" => [ "1", "2" ] } } assert_equal expected, Hash.from_xml('<numbers type="Array"><value>1</value><value>2</value></numbers>') end def test_from_trusted_xml_allows_symbol_and_yaml_types - expected = { 'product' => { 'name' => :value }} + expected = { "product" => { "name" => :value } } assert_equal expected, Hash.from_trusted_xml('<product><name type="symbol">value</name></product>') assert_equal expected, Hash.from_trusted_xml('<product><name type="yaml">:value</name></product>') end @@ -1646,8 +1653,8 @@ class HashToXmlTest < ActiveSupport::TestCase # The XML builder seems to fail miserably when trying to tag something # with the same name as a Kernel method (throw, test, loop, select ...) def test_kernel_method_names_to_xml - hash = { :throw => { :ball => 'red' } } - expected = '<person><throw><ball>red</ball></throw></person>' + hash = { throw: { ball: "red" } } + expected = "<person><throw><ball>red</ball></throw></person>" assert_nothing_raised do assert_equal expected, hash.to_xml(@xml_options) @@ -1662,30 +1669,30 @@ class HashToXmlTest < ActiveSupport::TestCase def test_escaping_to_xml hash = { - :bare_string => 'First & Last Name', - :pre_escaped_string => 'First & Last Name' + bare_string: "First & Last Name", + pre_escaped_string: "First & Last Name" }.stringify_keys - expected_xml = '<person><bare-string>First & Last Name</bare-string><pre-escaped-string>First &amp; Last Name</pre-escaped-string></person>' + expected_xml = "<person><bare-string>First & Last Name</bare-string><pre-escaped-string>First &amp; Last Name</pre-escaped-string></person>" assert_equal expected_xml, hash.to_xml(@xml_options) end def test_unescaping_from_xml - xml_string = '<person><bare-string>First & Last Name</bare-string><pre-escaped-string>First &amp; Last Name</pre-escaped-string></person>' + xml_string = "<person><bare-string>First & Last Name</bare-string><pre-escaped-string>First &amp; Last Name</pre-escaped-string></person>" expected_hash = { - :bare_string => 'First & Last Name', - :pre_escaped_string => 'First & Last Name' + bare_string: "First & Last Name", + pre_escaped_string: "First & Last Name" }.stringify_keys - assert_equal expected_hash, Hash.from_xml(xml_string)['person'] + assert_equal expected_hash, Hash.from_xml(xml_string)["person"] end def test_roundtrip_to_xml_from_xml hash = { - :bare_string => 'First & Last Name', - :pre_escaped_string => 'First & Last Name' + bare_string: "First & Last Name", + pre_escaped_string: "First & Last Name" }.stringify_keys - assert_equal hash, Hash.from_xml(hash.to_xml(@xml_options))['person'] + assert_equal hash, Hash.from_xml(hash.to_xml(@xml_options))["person"] end def test_datetime_xml_type_with_utc_time @@ -1694,7 +1701,7 @@ class HashToXmlTest < ActiveSupport::TestCase <alert_at type="datetime">2008-02-10T15:30:45Z</alert_at> </alert> XML - alert_at = Hash.from_xml(alert_xml)['alert']['alert_at'] + alert_at = Hash.from_xml(alert_xml)["alert"]["alert_at"] assert alert_at.utc? assert_equal Time.utc(2008, 2, 10, 15, 30, 45), alert_at end @@ -1705,7 +1712,7 @@ class HashToXmlTest < ActiveSupport::TestCase <alert_at type="datetime">2008-02-10T10:30:45-05:00</alert_at> </alert> XML - alert_at = Hash.from_xml(alert_xml)['alert']['alert_at'] + alert_at = Hash.from_xml(alert_xml)["alert"]["alert_at"] assert alert_at.utc? assert_equal Time.utc(2008, 2, 10, 15, 30, 45), alert_at end @@ -1716,7 +1723,7 @@ class HashToXmlTest < ActiveSupport::TestCase <alert_at type="datetime">2050-02-10T15:30:45Z</alert_at> </alert> XML - alert_at = Hash.from_xml(alert_xml)['alert']['alert_at'] + alert_at = Hash.from_xml(alert_xml)["alert"]["alert_at"] assert alert_at.utc? assert_equal 2050, alert_at.year assert_equal 2, alert_at.month @@ -1727,20 +1734,20 @@ class HashToXmlTest < ActiveSupport::TestCase end def test_to_xml_dups_options - options = {:skip_instruct => true} + options = { skip_instruct: true } {}.to_xml(options) # :builder, etc, shouldn't be added to options - assert_equal({:skip_instruct => true}, options) + assert_equal({ skip_instruct: true }, options) end def test_expansion_count_is_limited expected = case ActiveSupport::XmlMini.backend.name - when 'ActiveSupport::XmlMini_REXML'; RuntimeError - when 'ActiveSupport::XmlMini_Nokogiri'; Nokogiri::XML::SyntaxError - when 'ActiveSupport::XmlMini_NokogiriSAX'; RuntimeError - when 'ActiveSupport::XmlMini_LibXML'; LibXML::XML::Error - when 'ActiveSupport::XmlMini_LibXMLSAX'; LibXML::XML::Error + when "ActiveSupport::XmlMini_REXML"; RuntimeError + when "ActiveSupport::XmlMini_Nokogiri"; Nokogiri::XML::SyntaxError + when "ActiveSupport::XmlMini_NokogiriSAX"; RuntimeError + when "ActiveSupport::XmlMini_LibXML"; LibXML::XML::Error + when "ActiveSupport::XmlMini_LibXMLSAX"; LibXML::XML::Error end assert_raise expected do diff --git a/activesupport/test/core_ext/integer_ext_test.rb b/activesupport/test/core_ext/integer_ext_test.rb index 41736fb672..137e8ce85f 100644 --- a/activesupport/test/core_ext/integer_ext_test.rb +++ b/activesupport/test/core_ext/integer_ext_test.rb @@ -1,5 +1,5 @@ -require 'abstract_unit' -require 'active_support/core_ext/integer' +require "abstract_unit" +require "active_support/core_ext/integer" class IntegerExtTest < ActiveSupport::TestCase PRIME = 22953686867719691230002707821868552601124472329079 @@ -19,12 +19,12 @@ class IntegerExtTest < ActiveSupport::TestCase def test_ordinalize # These tests are mostly just to ensure that the ordinalize method exists. # Its results are tested comprehensively in the inflector test cases. - assert_equal '1st', 1.ordinalize - assert_equal '8th', 8.ordinalize + assert_equal "1st", 1.ordinalize + assert_equal "8th", 8.ordinalize end def test_ordinal - assert_equal 'st', 1.ordinal - assert_equal 'th', 8.ordinal + assert_equal "st", 1.ordinal + assert_equal "th", 8.ordinal end end diff --git a/activesupport/test/core_ext/kernel/concern_test.rb b/activesupport/test/core_ext/kernel/concern_test.rb index 478a00d2d2..e7e4f99d7e 100644 --- a/activesupport/test/core_ext/kernel/concern_test.rb +++ b/activesupport/test/core_ext/kernel/concern_test.rb @@ -1,9 +1,9 @@ -require 'abstract_unit' -require 'active_support/core_ext/kernel/concern' +require "abstract_unit" +require "active_support/core_ext/kernel/concern" class KernelConcernTest < ActiveSupport::TestCase def test_may_be_defined_at_toplevel - mod = ::TOPLEVEL_BINDING.eval 'concern(:ToplevelConcern) { }' + mod = ::TOPLEVEL_BINDING.eval "concern(:ToplevelConcern) { }" assert_equal mod, ::ToplevelConcern assert_kind_of ActiveSupport::Concern, ::ToplevelConcern assert_not Object.ancestors.include?(::ToplevelConcern), mod.ancestors.inspect diff --git a/activesupport/test/core_ext/kernel_test.rb b/activesupport/test/core_ext/kernel_test.rb index 503e6595cb..db0008b735 100644 --- a/activesupport/test/core_ext/kernel_test.rb +++ b/activesupport/test/core_ext/kernel_test.rb @@ -1,5 +1,5 @@ -require 'abstract_unit' -require 'active_support/core_ext/kernel' +require "abstract_unit" +require "active_support/core_ext/kernel" class KernelTest < ActiveSupport::TestCase def test_silence_warnings diff --git a/activesupport/test/core_ext/load_error_test.rb b/activesupport/test/core_ext/load_error_test.rb index b2a75a2bcc..b50a35b2cb 100644 --- a/activesupport/test/core_ext/load_error_test.rb +++ b/activesupport/test/core_ext/load_error_test.rb @@ -1,6 +1,5 @@ -require 'abstract_unit' -require 'active_support/core_ext/load_error' - +require "abstract_unit" +require "active_support/core_ext/load_error" class TestMissingSourceFile < ActiveSupport::TestCase def test_it_is_deprecated @@ -15,12 +14,12 @@ class TestLoadError < ActiveSupport::TestCase assert_raise(LoadError) { require 'no_this_file_don\'t_exist' } end def test_with_load - assert_raise(LoadError) { load 'nor_does_this_one' } + assert_raise(LoadError) { load "nor_does_this_one" } end def test_path - begin load 'nor/this/one.rb' + begin load "nor/this/one.rb" rescue LoadError => e - assert_equal 'nor/this/one.rb', e.path + assert_equal "nor/this/one.rb", e.path end end end diff --git a/activesupport/test/core_ext/marshal_test.rb b/activesupport/test/core_ext/marshal_test.rb index 825df439a5..a899f98705 100644 --- a/activesupport/test/core_ext/marshal_test.rb +++ b/activesupport/test/core_ext/marshal_test.rb @@ -1,6 +1,6 @@ -require 'abstract_unit' -require 'active_support/core_ext/marshal' -require 'dependencies_test_helpers' +require "abstract_unit" +require "active_support/core_ext/marshal" +require "dependencies_test_helpers" class MarshalTest < ActiveSupport::TestCase include ActiveSupport::Testing::Isolation @@ -12,7 +12,7 @@ class MarshalTest < ActiveSupport::TestCase end test "that Marshal#load still works" do - sanity_data = ["test", [1, 2, 3], {a: [1, 2, 3]}, ActiveSupport::TestCase] + sanity_data = ["test", [1, 2, 3], { a: [1, 2, 3] }, ActiveSupport::TestCase] sanity_data.each do |obj| dumped = Marshal.dump(obj) assert_equal Marshal.method(:load).super_method.call(dumped), Marshal.load(dumped) @@ -29,7 +29,12 @@ class MarshalTest < ActiveSupport::TestCase ActiveSupport::Dependencies.clear with_autoloading_fixtures do - assert_kind_of EM, Marshal.load(dumped) + object = nil + assert_nothing_raised do + object = Marshal.load(dumped) + end + + assert_kind_of EM, object end end @@ -43,7 +48,12 @@ class MarshalTest < ActiveSupport::TestCase ActiveSupport::Dependencies.clear with_autoloading_fixtures do - assert_kind_of ClassFolder::ClassFolderSubclass, Marshal.load(dumped) + object = nil + assert_nothing_raised do + object = Marshal.load(dumped) + end + + assert_kind_of ClassFolder::ClassFolderSubclass, object end end @@ -64,6 +74,17 @@ class MarshalTest < ActiveSupport::TestCase end end + test "when one constant resolves to another" do + class Parent; C = Class.new; end + class Child < Parent; C = Class.new; end + + dump = Marshal.dump(Child::C.new) + + Child.send(:remove_const, :C) + + assert_raise(ArgumentError) { Marshal.load(dump) } + end + test "that a real missing class is causing an exception" do dumped = nil with_autoloading_fixtures do @@ -96,7 +117,7 @@ class MarshalTest < ActiveSupport::TestCase Marshal.load(dumped) end - assert_nothing_raised("EM failed to load while we expect only SomeClass to fail loading") do + assert_nothing_raised do EM.new end @@ -117,7 +138,12 @@ class MarshalTest < ActiveSupport::TestCase ActiveSupport::Dependencies.clear with_autoloading_fixtures do - assert_kind_of EM, Marshal.load(f) + object = nil + assert_nothing_raised do + object = Marshal.load(f) + end + + assert_kind_of EM, object end end end diff --git a/activesupport/test/core_ext/module/anonymous_test.rb b/activesupport/test/core_ext/module/anonymous_test.rb index cb556af772..f885444284 100644 --- a/activesupport/test/core_ext/module/anonymous_test.rb +++ b/activesupport/test/core_ext/module/anonymous_test.rb @@ -1,5 +1,5 @@ -require 'abstract_unit' -require 'active_support/core_ext/module/anonymous' +require "abstract_unit" +require "active_support/core_ext/module/anonymous" class AnonymousTest < ActiveSupport::TestCase test "an anonymous class or module are anonymous" do @@ -11,4 +11,4 @@ class AnonymousTest < ActiveSupport::TestCase assert !Kernel.anonymous? assert !Object.anonymous? end -end
\ No newline at end of file +end diff --git a/activesupport/test/core_ext/module/attr_internal_test.rb b/activesupport/test/core_ext/module/attr_internal_test.rb index 2aea14cf2b..8458e278ee 100644 --- a/activesupport/test/core_ext/module/attr_internal_test.rb +++ b/activesupport/test/core_ext/module/attr_internal_test.rb @@ -1,5 +1,5 @@ -require 'abstract_unit' -require 'active_support/core_ext/module/attr_internal' +require "abstract_unit" +require "active_support/core_ext/module/attr_internal" class AttrInternalTest < ActiveSupport::TestCase def setup @@ -10,44 +10,44 @@ class AttrInternalTest < ActiveSupport::TestCase def test_reader assert_nothing_raised { @target.attr_internal_reader :foo } - assert !@instance.instance_variable_defined?('@_foo') + assert !@instance.instance_variable_defined?("@_foo") assert_raise(NoMethodError) { @instance.foo = 1 } - @instance.instance_variable_set('@_foo', 1) + @instance.instance_variable_set("@_foo", 1) assert_nothing_raised { assert_equal 1, @instance.foo } end def test_writer assert_nothing_raised { @target.attr_internal_writer :foo } - assert !@instance.instance_variable_defined?('@_foo') + assert !@instance.instance_variable_defined?("@_foo") assert_nothing_raised { assert_equal 1, @instance.foo = 1 } - assert_equal 1, @instance.instance_variable_get('@_foo') + assert_equal 1, @instance.instance_variable_get("@_foo") assert_raise(NoMethodError) { @instance.foo } end def test_accessor assert_nothing_raised { @target.attr_internal :foo } - assert !@instance.instance_variable_defined?('@_foo') + assert !@instance.instance_variable_defined?("@_foo") assert_nothing_raised { assert_equal 1, @instance.foo = 1 } - assert_equal 1, @instance.instance_variable_get('@_foo') + assert_equal 1, @instance.instance_variable_get("@_foo") assert_nothing_raised { assert_equal 1, @instance.foo } end def test_naming_format - assert_equal '@_%s', Module.attr_internal_naming_format - assert_nothing_raised { Module.attr_internal_naming_format = '@abc%sdef' } + assert_equal "@_%s", Module.attr_internal_naming_format + assert_nothing_raised { Module.attr_internal_naming_format = "@abc%sdef" } @target.attr_internal :foo - assert !@instance.instance_variable_defined?('@_foo') - assert !@instance.instance_variable_defined?('@abcfoodef') + assert !@instance.instance_variable_defined?("@_foo") + assert !@instance.instance_variable_defined?("@abcfoodef") assert_nothing_raised { @instance.foo = 1 } - assert !@instance.instance_variable_defined?('@_foo') - assert @instance.instance_variable_defined?('@abcfoodef') + assert !@instance.instance_variable_defined?("@_foo") + assert @instance.instance_variable_defined?("@abcfoodef") ensure - Module.attr_internal_naming_format = '@_%s' + Module.attr_internal_naming_format = "@_%s" end end diff --git a/activesupport/test/core_ext/module/attribute_accessor_per_thread_test.rb b/activesupport/test/core_ext/module/attribute_accessor_per_thread_test.rb index 65fadc5c20..b816fa50e3 100644 --- a/activesupport/test/core_ext/module/attribute_accessor_per_thread_test.rb +++ b/activesupport/test/core_ext/module/attribute_accessor_per_thread_test.rb @@ -1,5 +1,5 @@ -require 'abstract_unit' -require 'active_support/core_ext/module/attribute_accessors_per_thread' +require "abstract_unit" +require "active_support/core_ext/module/attribute_accessors_per_thread" class ModuleAttributeAccessorPerThreadTest < ActiveSupport::TestCase def setup @@ -8,6 +8,12 @@ class ModuleAttributeAccessorPerThreadTest < ActiveSupport::TestCase thread_mattr_accessor :bar, instance_writer: false thread_mattr_reader :shaq, instance_reader: false thread_mattr_accessor :camp, instance_accessor: false + + def self.name; "MyClass" end + end + + @subclass = Class.new(@class) do + def self.name; "SubMyClass" end end @object = @class.new @@ -57,23 +63,23 @@ class ModuleAttributeAccessorPerThreadTest < ActiveSupport::TestCase def test_values_should_not_bleed_between_threads threads = [] threads << Thread.new do - @class.foo = 'things' + @class.foo = "things" sleep 1 - assert_equal 'things', @class.foo + assert_equal "things", @class.foo end threads << Thread.new do - @class.foo = 'other things' + @class.foo = "other things" sleep 1 - assert_equal 'other things', @class.foo + assert_equal "other things", @class.foo end - + threads << Thread.new do - @class.foo = 'really other things' + @class.foo = "really other things" sleep 1 - assert_equal 'really other things', @class.foo + assert_equal "really other things", @class.foo end - + threads.each { |t| t.join } end @@ -106,4 +112,20 @@ class ModuleAttributeAccessorPerThreadTest < ActiveSupport::TestCase end assert_equal "invalid attribute name: 2valid_part", exception.message end + + def test_should_return_same_value_by_class_or_instance_accessor + @class.foo = "fries" + + assert_equal @class.foo, @object.foo + end + + def test_should_not_affect_superclass_if_subclass_set_value + @class.foo = "super" + assert_equal @class.foo, "super" + assert_nil @subclass.foo + + @subclass.foo = "sub" + assert_equal @class.foo, "super" + assert_equal @subclass.foo, "sub" + end end diff --git a/activesupport/test/core_ext/module/attribute_accessor_test.rb b/activesupport/test/core_ext/module/attribute_accessor_test.rb index 0b0f3a2808..464a000d59 100644 --- a/activesupport/test/core_ext/module/attribute_accessor_test.rb +++ b/activesupport/test/core_ext/module/attribute_accessor_test.rb @@ -1,17 +1,17 @@ -require 'abstract_unit' -require 'active_support/core_ext/module/attribute_accessors' +require "abstract_unit" +require "active_support/core_ext/module/attribute_accessors" class ModuleAttributeAccessorTest < ActiveSupport::TestCase def setup m = @module = Module.new do mattr_accessor :foo - mattr_accessor :bar, :instance_writer => false - mattr_reader :shaq, :instance_reader => false - mattr_accessor :camp, :instance_accessor => false + mattr_accessor :bar, instance_writer: false + mattr_reader :shaq, instance_reader: false + mattr_accessor :camp, instance_accessor: false - cattr_accessor(:defa) { 'default_accessor_value' } - cattr_reader(:defr) { 'default_reader_value' } - cattr_writer(:defw) { 'default_writer_value' } + cattr_accessor(:defa) { "default_accessor_value" } + cattr_reader(:defr) { "default_reader_value" } + cattr_writer(:defw) { "default_writer_value" } cattr_accessor(:quux) { :quux } end @class = Class.new @@ -86,14 +86,14 @@ class ModuleAttributeAccessorTest < ActiveSupport::TestCase end def test_should_use_default_value_if_block_passed - assert_equal 'default_accessor_value', @module.defa - assert_equal 'default_reader_value', @module.defr - assert_equal 'default_writer_value', @module.class_variable_get('@@defw') + assert_equal "default_accessor_value", @module.defa + assert_equal "default_reader_value", @module.defr + assert_equal "default_writer_value", @module.class_variable_get("@@defw") end def test_should_not_invoke_default_value_block_multiple_times count = 0 - @module.cattr_accessor(:defcount){ count += 1 } + @module.cattr_accessor(:defcount) { count += 1 } assert_equal 1, count end end diff --git a/activesupport/test/core_ext/module/attribute_aliasing_test.rb b/activesupport/test/core_ext/module/attribute_aliasing_test.rb index 29c3053b47..d8c2dfd6b8 100644 --- a/activesupport/test/core_ext/module/attribute_aliasing_test.rb +++ b/activesupport/test/core_ext/module/attribute_aliasing_test.rb @@ -1,5 +1,5 @@ -require 'abstract_unit' -require 'active_support/core_ext/module/aliasing' +require "abstract_unit" +require "active_support/core_ext/module/aliasing" module AttributeAliasing class Content diff --git a/activesupport/test/core_ext/module/concerning_test.rb b/activesupport/test/core_ext/module/concerning_test.rb index 07d860b71c..098036828a 100644 --- a/activesupport/test/core_ext/module/concerning_test.rb +++ b/activesupport/test/core_ext/module/concerning_test.rb @@ -1,10 +1,10 @@ -require 'abstract_unit' -require 'active_support/core_ext/module/concerning' +require "abstract_unit" +require "active_support/core_ext/module/concerning" class ModuleConcerningTest < ActiveSupport::TestCase def test_concerning_declares_a_concern_and_includes_it_immediately - klass = Class.new { concerning(:Foo) { } } - assert klass.ancestors.include?(klass::Foo), klass.ancestors.inspect + klass = Class.new { concerning(:Foo) {} } + assert_includes klass.ancestors, klass::Foo, klass.ancestors.inspect end end @@ -21,13 +21,13 @@ class ModuleConcernTest < ActiveSupport::TestCase assert klass.const_defined?(:Baz, false) assert !ModuleConcernTest.const_defined?(:Baz) assert_kind_of ActiveSupport::Concern, klass::Baz - assert !klass.ancestors.include?(klass::Baz), klass.ancestors.inspect + assert_not_includes klass.ancestors, klass::Baz, klass.ancestors.inspect # Public method visibility by default - assert klass::Baz.public_instance_methods.map(&:to_s).include?('should_be_public') + assert_includes klass::Baz.public_instance_methods.map(&:to_s), "should_be_public" # Calls included hook - assert_equal 1, Class.new { include klass::Baz }.instance_variable_get('@foo') + assert_equal 1, Class.new { include klass::Baz }.instance_variable_get("@foo") end class Foo diff --git a/activesupport/test/core_ext/module/qualified_const_test.rb b/activesupport/test/core_ext/module/qualified_const_test.rb index a3146cabe1..418bc80ab9 100644 --- a/activesupport/test/core_ext/module/qualified_const_test.rb +++ b/activesupport/test/core_ext/module/qualified_const_test.rb @@ -1,5 +1,5 @@ -require 'abstract_unit' -require 'active_support/core_ext/module/qualified_const' +require "abstract_unit" +require "active_support/core_ext/module/qualified_const" module QualifiedConstTestMod X = false @@ -68,7 +68,7 @@ class QualifiedConstTest < ActiveSupport::TestCase assert_equal 1, QualifiedConstTestMod.qualified_const_get("N::X") assert_equal 2, QualifiedConstTestMod.qualified_const_get("M::C::X") - assert_raise(NameError) { QualifiedConstTestMod.qualified_const_get("M::C::Y")} + assert_raise(NameError) { QualifiedConstTestMod.qualified_const_get("M::C::Y") } end end @@ -89,8 +89,8 @@ class QualifiedConstTest < ActiveSupport::TestCase end ensure silence_warnings do - QualifiedConstTestMod.qualified_const_set('QualifiedConstTestMod::X', false) - QualifiedConstTestMod::M.qualified_const_set('X', 1) + QualifiedConstTestMod.qualified_const_set("QualifiedConstTestMod::X", false) + QualifiedConstTestMod::M.qualified_const_set("X", 1) end end end @@ -98,21 +98,21 @@ class QualifiedConstTest < ActiveSupport::TestCase test "reject absolute paths" do assert_deprecated do - assert_raise_with_message(NameError, "wrong constant name ::X") { Object.qualified_const_defined?("::X")} - assert_raise_with_message(NameError, "wrong constant name ::X") { Object.qualified_const_defined?("::X::Y")} + assert_raise_with_message(NameError, "wrong constant name ::X") { Object.qualified_const_defined?("::X") } + assert_raise_with_message(NameError, "wrong constant name ::X") { Object.qualified_const_defined?("::X::Y") } - assert_raise_with_message(NameError, "wrong constant name ::X") { Object.qualified_const_get("::X")} - assert_raise_with_message(NameError, "wrong constant name ::X") { Object.qualified_const_get("::X::Y")} + assert_raise_with_message(NameError, "wrong constant name ::X") { Object.qualified_const_get("::X") } + assert_raise_with_message(NameError, "wrong constant name ::X") { Object.qualified_const_get("::X::Y") } - assert_raise_with_message(NameError, "wrong constant name ::X") { Object.qualified_const_set("::X", nil)} - assert_raise_with_message(NameError, "wrong constant name ::X") { Object.qualified_const_set("::X::Y", nil)} + assert_raise_with_message(NameError, "wrong constant name ::X") { Object.qualified_const_set("::X", nil) } + assert_raise_with_message(NameError, "wrong constant name ::X") { Object.qualified_const_set("::X::Y", nil) } end end private - def assert_raise_with_message(expected_exception, expected_message, &block) - exception = assert_raise(expected_exception, &block) - assert_equal expected_message, exception.message - end + def assert_raise_with_message(expected_exception, expected_message, &block) + exception = assert_raise(expected_exception, &block) + assert_equal expected_message, exception.message + end end diff --git a/activesupport/test/core_ext/module/reachable_test.rb b/activesupport/test/core_ext/module/reachable_test.rb index 80eb31a5c4..487c7dee16 100644 --- a/activesupport/test/core_ext/module/reachable_test.rb +++ b/activesupport/test/core_ext/module/reachable_test.rb @@ -1,5 +1,5 @@ -require 'abstract_unit' -require 'active_support/core_ext/module/reachable' +require "abstract_unit" +require "active_support/core_ext/module/reachable" class AnonymousTest < ActiveSupport::TestCase test "an anonymous class or module is not reachable" do @@ -38,4 +38,4 @@ class AnonymousTest < ActiveSupport::TestCase assert !c.reachable? assert !m.reachable? end -end
\ No newline at end of file +end diff --git a/activesupport/test/core_ext/module/remove_method_test.rb b/activesupport/test/core_ext/module/remove_method_test.rb index 0d684dc70e..0c627f1e74 100644 --- a/activesupport/test/core_ext/module/remove_method_test.rb +++ b/activesupport/test/core_ext/module/remove_method_test.rb @@ -1,5 +1,5 @@ -require 'abstract_unit' -require 'active_support/core_ext/module/remove_method' +require "abstract_unit" +require "active_support/core_ext/module/remove_method" module RemoveMethodTests class A @@ -26,26 +26,25 @@ module RemoveMethodTests end class RemoveMethodTest < ActiveSupport::TestCase - def test_remove_method_from_an_object - RemoveMethodTests::A.class_eval{ - self.remove_possible_method(:do_something) + RemoveMethodTests::A.class_eval { + remove_possible_method(:do_something) } assert !RemoveMethodTests::A.new.respond_to?(:do_something) end def test_remove_singleton_method_from_an_object - RemoveMethodTests::A.class_eval{ - self.remove_possible_singleton_method(:do_something_else) + RemoveMethodTests::A.class_eval { + remove_possible_singleton_method(:do_something_else) } assert !RemoveMethodTests::A.respond_to?(:do_something_else) end def test_redefine_method_in_an_object - RemoveMethodTests::A.class_eval{ - self.redefine_method(:do_something) { return 100 } - self.redefine_method(:do_something_protected) { return 100 } - self.redefine_method(:do_something_private) { return 100 } + RemoveMethodTests::A.class_eval { + redefine_method(:do_something) { return 100 } + redefine_method(:do_something_protected) { return 100 } + redefine_method(:do_something_private) { return 100 } } assert_equal 100, RemoveMethodTests::A.new.do_something assert_equal 100, RemoveMethodTests::A.new.send(:do_something_protected) @@ -55,5 +54,4 @@ class RemoveMethodTest < ActiveSupport::TestCase assert RemoveMethodTests::A.protected_method_defined? :do_something_protected assert RemoveMethodTests::A.private_method_defined? :do_something_private end - end diff --git a/activesupport/test/core_ext/module_test.rb b/activesupport/test/core_ext/module_test.rb index 0ed66f8c37..36073b28b7 100644 --- a/activesupport/test/core_ext/module_test.rb +++ b/activesupport/test/core_ext/module_test.rb @@ -1,5 +1,5 @@ -require 'abstract_unit' -require 'active_support/core_ext/module' +require "abstract_unit" +require "active_support/core_ext/module" module One Constant1 = "Hello World" @@ -25,50 +25,56 @@ Somewhere = Struct.new(:street, :city) do end class Someone < Struct.new(:name, :place) - delegate :street, :city, :to_f, :to => :place - delegate :name=, :to => :place, :prefix => true - delegate :upcase, :to => "place.city" - delegate :table_name, :to => :class - delegate :table_name, :to => :class, :prefix => true + delegate :street, :city, :to_f, to: :place + delegate :name=, to: :place, prefix: true + delegate :upcase, to: "place.city" + delegate :table_name, to: :class + delegate :table_name, to: :class, prefix: true def self.table_name - 'some_table' + "some_table" end FAILED_DELEGATE_LINE = __LINE__ + 1 - delegate :foo, :to => :place + delegate :foo, to: :place FAILED_DELEGATE_LINE_2 = __LINE__ + 1 - delegate :bar, :to => :place, :allow_nil => true + delegate :bar, to: :place, allow_nil: true + + private + + def private_name + "Private" + end end Invoice = Struct.new(:client) do - delegate :street, :city, :name, :to => :client, :prefix => true - delegate :street, :city, :name, :to => :client, :prefix => :customer + delegate :street, :city, :name, to: :client, prefix: true + delegate :street, :city, :name, to: :client, prefix: :customer end Project = Struct.new(:description, :person) do - delegate :name, :to => :person, :allow_nil => true - delegate :to_f, :to => :description, :allow_nil => true + delegate :name, to: :person, allow_nil: true + delegate :to_f, to: :description, allow_nil: true end Developer = Struct.new(:client) do - delegate :name, :to => :client, :prefix => nil + delegate :name, to: :client, prefix: nil end Event = Struct.new(:case) do - delegate :foo, :to => :case + delegate :foo, to: :case end Tester = Struct.new(:client) do - delegate :name, :to => :client, :prefix => false + delegate :name, to: :client, prefix: false def foo; 1; end end Product = Struct.new(:name) do - delegate :name, :to => :manufacturer, :prefix => true - delegate :name, :to => :type, :prefix => true + delegate :name, to: :manufacturer, prefix: true + delegate :name, to: :type, prefix: true def manufacturer @manufacturer ||= begin @@ -83,6 +89,20 @@ Product = Struct.new(:name) do end end +DecoratedTester = Struct.new(:client) do + delegate_missing_to :client +end + +class DecoratedReserved + delegate_missing_to :case + + attr_reader :case + + def initialize(kase) + @case = kase + end +end + class Block def hello? true @@ -94,15 +114,15 @@ HasBlock = Struct.new(:block) do end class ParameterSet - delegate :[], :[]=, :to => :@params + delegate :[], :[]=, to: :@params def initialize - @params = {:foo => "bar"} + @params = { foo: "bar" } end end class Name - delegate :upcase, :to => :@full_name + delegate :upcase, to: :@full_name def initialize(first, last) @full_name = "#{first} #{last}" @@ -112,8 +132,8 @@ end class SideEffect attr_reader :ints - delegate :to_i, :to => :shift, :allow_nil => true - delegate :to_s, :to => :shift + delegate :to_i, to: :shift, allow_nil: true + delegate :to_s, to: :shift def initialize @ints = [1, 2, 3] @@ -160,8 +180,8 @@ class ModuleTest < ActiveSupport::TestCase end def test_delegation_to_class_method - assert_equal 'some_table', @david.table_name - assert_equal 'some_table', @david.class_table_name + assert_equal "some_table", @david.table_name + assert_equal "some_table", @david.class_table_name end def test_missing_delegation_target @@ -169,7 +189,22 @@ class ModuleTest < ActiveSupport::TestCase Name.send :delegate, :nowhere end assert_raise(ArgumentError) do - Name.send :delegate, :noplace, :tos => :hollywood + Name.send :delegate, :noplace, tos: :hollywood + end + end + + def test_delegation_target_when_prefix_is_true + assert_nothing_raised do + Name.send :delegate, :go, to: :you, prefix: true + end + assert_nothing_raised do + Name.send :delegate, :go, to: :_you, prefix: true + end + assert_raise(ArgumentError) do + Name.send :delegate, :go, to: :You, prefix: true + end + assert_raise(ArgumentError) do + Name.send :delegate, :go, to: :@you, prefix: true end end @@ -198,7 +233,7 @@ class ModuleTest < ActiveSupport::TestCase def initialize(client) @client = client end - delegate :name, :address, :to => :@client, :prefix => true + delegate :name, :address, to: :@client, prefix: true end end end @@ -226,7 +261,7 @@ class ModuleTest < ActiveSupport::TestCase def test_delegation_with_allow_nil_and_nil_value_and_prefix Project.class_eval do - delegate :name, :to => :person, :allow_nil => true, :prefix => true + delegate :name, to: :person, allow_nil: true, prefix: true end rails = Project.new("Rails") assert_nil rails.person_name @@ -255,7 +290,7 @@ class ModuleTest < ActiveSupport::TestCase assert_nothing_raised do Class.new(parent) do class << self - delegate :parent_method, :to => :superclass + delegate :parent_method, to: :superclass end end end @@ -277,7 +312,7 @@ class ModuleTest < ActiveSupport::TestCase rescue NoMethodError => e file_and_line = "#{__FILE__}:#{Someone::FAILED_DELEGATE_LINE}" # We can't simply check the first line of the backtrace, because JRuby reports the call to __send__ in the backtrace. - assert e.backtrace.any?{|a| a.include?(file_and_line)}, + assert e.backtrace.any? { |a| a.include?(file_and_line) }, "[#{e.backtrace.inspect}] did not include [#{file_and_line}]" end @@ -287,7 +322,7 @@ class ModuleTest < ActiveSupport::TestCase rescue NoMethodError => e file_and_line = "#{__FILE__}:#{Someone::FAILED_DELEGATE_LINE_2}" # We can't simply check the first line of the backtrace, because JRuby reports the call to __send__ in the backtrace. - assert e.backtrace.any?{|a| a.include?(file_and_line)}, + assert e.backtrace.any? { |a| a.include?(file_and_line) }, "[#{e.backtrace.inspect}] did not include [#{file_and_line}]" end @@ -297,12 +332,12 @@ class ModuleTest < ActiveSupport::TestCase assert_equal 1, se.to_i assert_equal [2, 3], se.ints - assert_equal '2', se.to_s + assert_equal "2", se.to_s assert_equal [3], se.ints end def test_delegation_doesnt_mask_nested_no_method_error_on_nil_receiver - product = Product.new('Widget') + product = Product.new("Widget") # Nested NoMethodError is a different name from the delegation assert_raise(NoMethodError) { product.manufacturer_name } @@ -316,6 +351,30 @@ class ModuleTest < ActiveSupport::TestCase assert has_block.hello? end + def test_delegate_to_missing_with_method + assert_equal "David", DecoratedTester.new(@david).name + end + + def test_delegate_to_missing_with_reserved_methods + assert_equal "David", DecoratedReserved.new(@david).name + end + + def test_delegate_to_missing_does_not_delegate_to_private_methods + e = assert_raises(NoMethodError) do + DecoratedReserved.new(@david).private_name + end + + assert_match(/undefined method `private_name' for/, e.message) + end + + def test_delegate_to_missing_does_not_delegate_to_fake_methods + e = assert_raises(NoMethodError) do + DecoratedReserved.new(@david).my_fake_method + end + + assert_match(/undefined method `my_fake_method' for/, e.message) + end + def test_parent assert_equal Yz::Zy, Yz::Zy::Cd.parent assert_equal Yz, Yz::Zy.parent @@ -328,7 +387,13 @@ class ModuleTest < ActiveSupport::TestCase end def test_local_constants - assert_equal %w(Constant1 Constant3), Ab.local_constants.sort.map(&:to_s) + ActiveSupport::Deprecation.silence do + assert_equal %w(Constant1 Constant3), Ab.local_constants.sort.map(&:to_s) + end + end + + def test_local_constants_is_deprecated + assert_deprecated { Ab.local_constants.sort.map(&:to_s) } end end @@ -343,11 +408,11 @@ end module BarMethods def bar_with_baz - bar_without_baz << '_with_baz' + bar_without_baz << "_with_baz" end def quux_with_baz! - quux_without_baz! << '_with_baz' + quux_without_baz! << "_with_baz" end def quux_with_baz? @@ -355,17 +420,17 @@ module BarMethods end def quux_with_baz=(v) - send(:quux_without_baz=, v) << '_with_baz' + send(:quux_without_baz=, v) << "_with_baz" end def duck_with_orange - duck_without_orange << '_with_orange' + duck_without_orange << "_with_orange" end end class MethodAliasingTest < ActiveSupport::TestCase def setup - Object.const_set :FooClassWithBarMethod, Class.new { def bar() 'bar' end } + Object.const_set :FooClassWithBarMethod, Class.new { def bar() "bar" end } @instance = FooClassWithBarMethod.new end @@ -396,7 +461,7 @@ class MethodAliasingTest < ActiveSupport::TestCase assert !@instance.respond_to?(method) end - assert_equal 'bar', @instance.bar + assert_equal "bar", @instance.bar FooClassWithBarMethod.class_eval { include BarMethodAliaser } @@ -404,15 +469,15 @@ class MethodAliasingTest < ActiveSupport::TestCase assert_respond_to @instance, method end - assert_equal 'bar_with_baz', @instance.bar - assert_equal 'bar', @instance.bar_without_baz + assert_equal "bar_with_baz", @instance.bar + assert_equal "bar", @instance.bar_without_baz end end def test_alias_method_chain_with_punctuation_method assert_deprecated(/alias_method_chain/) do FooClassWithBarMethod.class_eval do - def quux!; 'quux' end + def quux!; "quux" end end assert !@instance.respond_to?(:quux_with_baz!) @@ -422,17 +487,17 @@ class MethodAliasingTest < ActiveSupport::TestCase end assert_respond_to @instance, :quux_with_baz! - assert_equal 'quux_with_baz', @instance.quux! - assert_equal 'quux', @instance.quux_without_baz! + assert_equal "quux_with_baz", @instance.quux! + assert_equal "quux", @instance.quux_without_baz! end end def test_alias_method_chain_with_same_names_between_predicates_and_bang_methods assert_deprecated(/alias_method_chain/) do FooClassWithBarMethod.class_eval do - def quux!; 'quux!' end + def quux!; "quux!" end def quux?; true end - def quux=(v); 'quux=' end + def quux=(v); "quux=" end end assert !@instance.respond_to?(:quux_with_baz!) @@ -444,32 +509,31 @@ class MethodAliasingTest < ActiveSupport::TestCase assert_respond_to @instance, :quux_with_baz? assert_respond_to @instance, :quux_with_baz= - FooClassWithBarMethod.alias_method_chain :quux!, :baz - assert_equal 'quux!_with_baz', @instance.quux! - assert_equal 'quux!', @instance.quux_without_baz! + assert_equal "quux!_with_baz", @instance.quux! + assert_equal "quux!", @instance.quux_without_baz! FooClassWithBarMethod.alias_method_chain :quux?, :baz assert_equal false, @instance.quux? assert_equal true, @instance.quux_without_baz? FooClassWithBarMethod.alias_method_chain :quux=, :baz - assert_equal 'quux=_with_baz', @instance.send(:quux=, 1234) - assert_equal 'quux=', @instance.send(:quux_without_baz=, 1234) + assert_equal "quux=_with_baz", @instance.send(:quux=, 1234) + assert_equal "quux=", @instance.send(:quux_without_baz=, 1234) end end def test_alias_method_chain_with_feature_punctuation assert_deprecated(/alias_method_chain/) do FooClassWithBarMethod.class_eval do - def quux; 'quux' end - def quux?; 'quux?' end + def quux; "quux" end + def quux?; "quux?" end include BarMethodAliaser alias_method_chain :quux, :baz! end assert_nothing_raised do - assert_equal 'quux_with_baz', @instance.quux_with_baz! + assert_equal "quux_with_baz", @instance.quux_with_baz! end assert_raise(NameError) do @@ -492,15 +556,15 @@ class MethodAliasingTest < ActiveSupport::TestCase end assert_not_nil args - assert_equal 'quux', args[0] - assert_equal '?', args[1] + assert_equal "quux", args[0] + assert_equal "?", args[1] end end def test_alias_method_chain_preserves_private_method_status assert_deprecated(/alias_method_chain/) do FooClassWithBarMethod.class_eval do - def duck; 'duck' end + def duck; "duck" end include BarMethodAliaser private :duck alias_method_chain :duck, :orange @@ -510,7 +574,7 @@ class MethodAliasingTest < ActiveSupport::TestCase @instance.duck end - assert_equal 'duck_with_orange', @instance.instance_eval { duck } + assert_equal "duck_with_orange", @instance.instance_eval { duck } assert FooClassWithBarMethod.private_method_defined?(:duck) end end @@ -518,7 +582,7 @@ class MethodAliasingTest < ActiveSupport::TestCase def test_alias_method_chain_preserves_protected_method_status assert_deprecated(/alias_method_chain/) do FooClassWithBarMethod.class_eval do - def duck; 'duck' end + def duck; "duck" end include BarMethodAliaser protected :duck alias_method_chain :duck, :orange @@ -528,7 +592,7 @@ class MethodAliasingTest < ActiveSupport::TestCase @instance.duck end - assert_equal 'duck_with_orange', @instance.instance_eval { duck } + assert_equal "duck_with_orange", @instance.instance_eval { duck } assert FooClassWithBarMethod.protected_method_defined?(:duck) end end @@ -536,13 +600,13 @@ class MethodAliasingTest < ActiveSupport::TestCase def test_alias_method_chain_preserves_public_method_status assert_deprecated(/alias_method_chain/) do FooClassWithBarMethod.class_eval do - def duck; 'duck' end + def duck; "duck" end include BarMethodAliaser public :duck alias_method_chain :duck, :orange end - assert_equal 'duck_with_orange', @instance.duck + assert_equal "duck_with_orange", @instance.duck assert FooClassWithBarMethod.public_method_defined?(:duck) end end diff --git a/activesupport/test/core_ext/name_error_test.rb b/activesupport/test/core_ext/name_error_test.rb index 7525f80cf0..fdb9493d3c 100644 --- a/activesupport/test/core_ext/name_error_test.rb +++ b/activesupport/test/core_ext/name_error_test.rb @@ -1,5 +1,5 @@ -require 'abstract_unit' -require 'active_support/core_ext/name_error' +require "abstract_unit" +require "active_support/core_ext/name_error" class NameErrorTest < ActiveSupport::TestCase def test_name_error_should_set_missing_name diff --git a/activesupport/test/core_ext/numeric_ext_test.rb b/activesupport/test/core_ext/numeric_ext_test.rb index 5654aeb4f8..5e824747ed 100644 --- a/activesupport/test/core_ext/numeric_ext_test.rb +++ b/activesupport/test/core_ext/numeric_ext_test.rb @@ -1,7 +1,7 @@ -require 'abstract_unit' -require 'active_support/time' -require 'active_support/core_ext/numeric' -require 'active_support/core_ext/integer' +require "abstract_unit" +require "active_support/time" +require "active_support/core_ext/numeric" +require "active_support/core_ext/integer" class NumericExtTimeAndDateTimeTest < ActiveSupport::TestCase def setup @@ -23,41 +23,41 @@ class NumericExtTimeAndDateTimeTest < ActiveSupport::TestCase end def test_irregular_durations - assert_equal @now.advance(:days => 3000), 3000.days.since(@now) - assert_equal @now.advance(:months => 1), 1.month.since(@now) - assert_equal @now.advance(:months => -1), 1.month.until(@now) - assert_equal @now.advance(:years => 20), 20.years.since(@now) - assert_equal @dtnow.advance(:days => 3000), 3000.days.since(@dtnow) - assert_equal @dtnow.advance(:months => 1), 1.month.since(@dtnow) - assert_equal @dtnow.advance(:months => -1), 1.month.until(@dtnow) - assert_equal @dtnow.advance(:years => 20), 20.years.since(@dtnow) + assert_equal @now.advance(days: 3000), 3000.days.since(@now) + assert_equal @now.advance(months: 1), 1.month.since(@now) + assert_equal @now.advance(months: -1), 1.month.until(@now) + assert_equal @now.advance(years: 20), 20.years.since(@now) + assert_equal @dtnow.advance(days: 3000), 3000.days.since(@dtnow) + assert_equal @dtnow.advance(months: 1), 1.month.since(@dtnow) + assert_equal @dtnow.advance(months: -1), 1.month.until(@dtnow) + assert_equal @dtnow.advance(years: 20), 20.years.since(@dtnow) end def test_duration_addition - assert_equal @now.advance(:days => 1).advance(:months => 1), (1.day + 1.month).since(@now) - assert_equal @now.advance(:days => 7), (1.week + 5.seconds - 5.seconds).since(@now) - assert_equal @now.advance(:years => 2), (4.years - 2.years).since(@now) - assert_equal @dtnow.advance(:days => 1).advance(:months => 1), (1.day + 1.month).since(@dtnow) - assert_equal @dtnow.advance(:days => 7), (1.week + 5.seconds - 5.seconds).since(@dtnow) - assert_equal @dtnow.advance(:years => 2), (4.years - 2.years).since(@dtnow) + assert_equal @now.advance(days: 1).advance(months: 1), (1.day + 1.month).since(@now) + assert_equal @now.advance(days: 7), (1.week + 5.seconds - 5.seconds).since(@now) + assert_equal @now.advance(years: 2), (4.years - 2.years).since(@now) + assert_equal @dtnow.advance(days: 1).advance(months: 1), (1.day + 1.month).since(@dtnow) + assert_equal @dtnow.advance(days: 7), (1.week + 5.seconds - 5.seconds).since(@dtnow) + assert_equal @dtnow.advance(years: 2), (4.years - 2.years).since(@dtnow) end def test_time_plus_duration assert_equal @now + 8, @now + 8.seconds assert_equal @now + 22.9, @now + 22.9.seconds - assert_equal @now.advance(:days => 15), @now + 15.days - assert_equal @now.advance(:months => 1), @now + 1.month + assert_equal @now.advance(days: 15), @now + 15.days + assert_equal @now.advance(months: 1), @now + 1.month assert_equal @dtnow.since(8), @dtnow + 8.seconds assert_equal @dtnow.since(22.9), @dtnow + 22.9.seconds - assert_equal @dtnow.advance(:days => 15), @dtnow + 15.days - assert_equal @dtnow.advance(:months => 1), @dtnow + 1.month + assert_equal @dtnow.advance(days: 15), @dtnow + 15.days + assert_equal @dtnow.advance(months: 1), @dtnow + 1.month end def test_chaining_duration_operations - assert_equal @now.advance(:days => 2).advance(:months => -3), @now + 2.days - 3.months - assert_equal @now.advance(:days => 1).advance(:months => 2), @now + 1.day + 2.months - assert_equal @dtnow.advance(:days => 2).advance(:months => -3), @dtnow + 2.days - 3.months - assert_equal @dtnow.advance(:days => 1).advance(:months => 2), @dtnow + 1.day + 2.months + assert_equal @now.advance(days: 2).advance(months: -3), @now + 2.days - 3.months + assert_equal @now.advance(days: 1).advance(months: 2), @now + 1.day + 2.months + assert_equal @dtnow.advance(days: 2).advance(months: -3), @dtnow + 2.days - 3.months + assert_equal @dtnow.advance(days: 1).advance(months: 2), @dtnow + 1.day + 2.months end def test_duration_after_conversion_is_no_longer_accurate @@ -87,8 +87,8 @@ class NumericExtDateTest < ActiveSupport::TestCase end def test_chaining_duration_operations - assert_equal @today.advance(:days => 2).advance(:months => -3), @today + 2.days - 3.months - assert_equal @today.advance(:days => 1).advance(:months => 2), @today + 1.day + 2.months + assert_equal @today.advance(days: 2).advance(months: -3), @today + 2.days - 3.months + assert_equal @today.advance(days: 1).advance(months: 2), @today + 1.day + 2.months end def test_add_one_year_to_leap_day @@ -154,53 +154,52 @@ class NumericExtFormattingTest < ActiveSupport::TestCase def test_to_s__phone assert_equal("555-1234", 5551234.to_s(:phone)) assert_equal("800-555-1212", 8005551212.to_s(:phone)) - assert_equal("(800) 555-1212", 8005551212.to_s(:phone, :area_code => true)) - assert_equal("800 555 1212", 8005551212.to_s(:phone, :delimiter => " ")) - assert_equal("(800) 555-1212 x 123", 8005551212.to_s(:phone, :area_code => true, :extension => 123)) - assert_equal("800-555-1212", 8005551212.to_s(:phone, :extension => " ")) - assert_equal("555.1212", 5551212.to_s(:phone, :delimiter => '.')) - assert_equal("+1-800-555-1212", 8005551212.to_s(:phone, :country_code => 1)) - assert_equal("+18005551212", 8005551212.to_s(:phone, :country_code => 1, :delimiter => '')) + assert_equal("(800) 555-1212", 8005551212.to_s(:phone, area_code: true)) + assert_equal("800 555 1212", 8005551212.to_s(:phone, delimiter: " ")) + assert_equal("(800) 555-1212 x 123", 8005551212.to_s(:phone, area_code: true, extension: 123)) + assert_equal("800-555-1212", 8005551212.to_s(:phone, extension: " ")) + assert_equal("555.1212", 5551212.to_s(:phone, delimiter: ".")) + assert_equal("+1-800-555-1212", 8005551212.to_s(:phone, country_code: 1)) + assert_equal("+18005551212", 8005551212.to_s(:phone, country_code: 1, delimiter: "")) assert_equal("22-555-1212", 225551212.to_s(:phone)) - assert_equal("+45-22-555-1212", 225551212.to_s(:phone, :country_code => 45)) + assert_equal("+45-22-555-1212", 225551212.to_s(:phone, country_code: 45)) end def test_to_s__currency assert_equal("$1,234,567,890.50", 1234567890.50.to_s(:currency)) assert_equal("$1,234,567,890.51", 1234567890.506.to_s(:currency)) assert_equal("-$1,234,567,890.50", -1234567890.50.to_s(:currency)) - assert_equal("-$ 1,234,567,890.50", -1234567890.50.to_s(:currency, :format => "%u %n")) - assert_equal("($1,234,567,890.50)", -1234567890.50.to_s(:currency, :negative_format => "(%u%n)")) - assert_equal("$1,234,567,892", 1234567891.50.to_s(:currency, :precision => 0)) - assert_equal("$1,234,567,890.5", 1234567890.50.to_s(:currency, :precision => 1)) - assert_equal("£1234567890,50", 1234567890.50.to_s(:currency, :unit => "£", :separator => ",", :delimiter => "")) + assert_equal("-$ 1,234,567,890.50", -1234567890.50.to_s(:currency, format: "%u %n")) + assert_equal("($1,234,567,890.50)", -1234567890.50.to_s(:currency, negative_format: "(%u%n)")) + assert_equal("$1,234,567,892", 1234567891.50.to_s(:currency, precision: 0)) + assert_equal("$1,234,567,890.5", 1234567890.50.to_s(:currency, precision: 1)) + assert_equal("£1234567890,50", 1234567890.50.to_s(:currency, unit: "£", separator: ",", delimiter: "")) end - def test_to_s__rounded assert_equal("-111.235", -111.2346.to_s(:rounded)) assert_equal("111.235", 111.2346.to_s(:rounded)) - assert_equal("31.83", 31.825.to_s(:rounded, :precision => 2)) - assert_equal("111.23", 111.2346.to_s(:rounded, :precision => 2)) - assert_equal("111.00", 111.to_s(:rounded, :precision => 2)) - assert_equal("3268", (32.6751 * 100.00).to_s(:rounded, :precision => 0)) - assert_equal("112", 111.50.to_s(:rounded, :precision => 0)) - assert_equal("1234567892", 1234567891.50.to_s(:rounded, :precision => 0)) - assert_equal("0", 0.to_s(:rounded, :precision => 0)) - assert_equal("0.00100", 0.001.to_s(:rounded, :precision => 5)) - assert_equal("0.001", 0.00111.to_s(:rounded, :precision => 3)) - assert_equal("10.00", 9.995.to_s(:rounded, :precision => 2)) - assert_equal("11.00", 10.995.to_s(:rounded, :precision => 2)) - assert_equal("0.00", -0.001.to_s(:rounded, :precision => 2)) + assert_equal("31.83", 31.825.to_s(:rounded, precision: 2)) + assert_equal("111.23", 111.2346.to_s(:rounded, precision: 2)) + assert_equal("111.00", 111.to_s(:rounded, precision: 2)) + assert_equal("3268", (32.6751 * 100.00).to_s(:rounded, precision: 0)) + assert_equal("112", 111.50.to_s(:rounded, precision: 0)) + assert_equal("1234567892", 1234567891.50.to_s(:rounded, precision: 0)) + assert_equal("0", 0.to_s(:rounded, precision: 0)) + assert_equal("0.00100", 0.001.to_s(:rounded, precision: 5)) + assert_equal("0.001", 0.00111.to_s(:rounded, precision: 3)) + assert_equal("10.00", 9.995.to_s(:rounded, precision: 2)) + assert_equal("11.00", 10.995.to_s(:rounded, precision: 2)) + assert_equal("0.00", -0.001.to_s(:rounded, precision: 2)) end def test_to_s__percentage assert_equal("100.000%", 100.to_s(:percentage)) - assert_equal("100%", 100.to_s(:percentage, :precision => 0)) - assert_equal("302.06%", 302.0574.to_s(:percentage, :precision => 2)) - assert_equal("123.4%", 123.400.to_s(:percentage, :precision => 3, :strip_insignificant_zeros => true)) - assert_equal("1.000,000%", 1000.to_s(:percentage, :delimiter => '.', :separator => ',')) - assert_equal("1000.000 %", 1000.to_s(:percentage, :format => "%n %")) + assert_equal("100%", 100.to_s(:percentage, precision: 0)) + assert_equal("302.06%", 302.0574.to_s(:percentage, precision: 2)) + assert_equal("123.4%", 123.400.to_s(:percentage, precision: 3, strip_insignificant_zeros: true)) + assert_equal("1.000,000%", 1000.to_s(:percentage, delimiter: ".", separator: ",")) + assert_equal("1000.000 %", 1000.to_s(:percentage, format: "%n %")) end def test_to_s__delimited @@ -216,188 +215,180 @@ class NumericExtFormattingTest < ActiveSupport::TestCase end def test_to_s__delimited__with_options_hash - assert_equal '12 345 678', 12345678.to_s(:delimited, :delimiter => ' ') - assert_equal '12,345,678-05', 12345678.05.to_s(:delimited, :separator => '-') - assert_equal '12.345.678,05', 12345678.05.to_s(:delimited, :separator => ',', :delimiter => '.') - assert_equal '12.345.678,05', 12345678.05.to_s(:delimited, :delimiter => '.', :separator => ',') + assert_equal "12 345 678", 12345678.to_s(:delimited, delimiter: " ") + assert_equal "12,345,678-05", 12345678.05.to_s(:delimited, separator: "-") + assert_equal "12.345.678,05", 12345678.05.to_s(:delimited, separator: ",", delimiter: ".") + assert_equal "12.345.678,05", 12345678.05.to_s(:delimited, delimiter: ".", separator: ",") end - def test_to_s__rounded_with_custom_delimiter_and_separator - assert_equal '31,83', 31.825.to_s(:rounded, :precision => 2, :separator => ',') - assert_equal '1.231,83', 1231.825.to_s(:rounded, :precision => 2, :separator => ',', :delimiter => '.') + assert_equal "31,83", 31.825.to_s(:rounded, precision: 2, separator: ",") + assert_equal "1.231,83", 1231.825.to_s(:rounded, precision: 2, separator: ",", delimiter: ".") end def test_to_s__rounded__with_significant_digits - assert_equal "124000", 123987.to_s(:rounded, :precision => 3, :significant => true) - assert_equal "120000000", 123987876.to_s(:rounded, :precision => 2, :significant => true ) - assert_equal "9775", 9775.to_s(:rounded, :precision => 4, :significant => true ) - assert_equal "5.4", 5.3923.to_s(:rounded, :precision => 2, :significant => true ) - assert_equal "5", 5.3923.to_s(:rounded, :precision => 1, :significant => true ) - assert_equal "1", 1.232.to_s(:rounded, :precision => 1, :significant => true ) - assert_equal "7", 7.to_s(:rounded, :precision => 1, :significant => true ) - assert_equal "1", 1.to_s(:rounded, :precision => 1, :significant => true ) - assert_equal "53", 52.7923.to_s(:rounded, :precision => 2, :significant => true ) - assert_equal "9775.00", 9775.to_s(:rounded, :precision => 6, :significant => true ) - assert_equal "5.392900", 5.3929.to_s(:rounded, :precision => 7, :significant => true ) - assert_equal "0.0", 0.to_s(:rounded, :precision => 2, :significant => true ) - assert_equal "0", 0.to_s(:rounded, :precision => 1, :significant => true ) - assert_equal "0.0001", 0.0001.to_s(:rounded, :precision => 1, :significant => true ) - assert_equal "0.000100", 0.0001.to_s(:rounded, :precision => 3, :significant => true ) - assert_equal "0.0001", 0.0001111.to_s(:rounded, :precision => 1, :significant => true ) - assert_equal "10.0", 9.995.to_s(:rounded, :precision => 3, :significant => true) - assert_equal "9.99", 9.994.to_s(:rounded, :precision => 3, :significant => true) - assert_equal "11.0", 10.995.to_s(:rounded, :precision => 3, :significant => true) + assert_equal "124000", 123987.to_s(:rounded, precision: 3, significant: true) + assert_equal "120000000", 123987876.to_s(:rounded, precision: 2, significant: true ) + assert_equal "9775", 9775.to_s(:rounded, precision: 4, significant: true ) + assert_equal "5.4", 5.3923.to_s(:rounded, precision: 2, significant: true ) + assert_equal "5", 5.3923.to_s(:rounded, precision: 1, significant: true ) + assert_equal "1", 1.232.to_s(:rounded, precision: 1, significant: true ) + assert_equal "7", 7.to_s(:rounded, precision: 1, significant: true ) + assert_equal "1", 1.to_s(:rounded, precision: 1, significant: true ) + assert_equal "53", 52.7923.to_s(:rounded, precision: 2, significant: true ) + assert_equal "9775.00", 9775.to_s(:rounded, precision: 6, significant: true ) + assert_equal "5.392900", 5.3929.to_s(:rounded, precision: 7, significant: true ) + assert_equal "0.0", 0.to_s(:rounded, precision: 2, significant: true ) + assert_equal "0", 0.to_s(:rounded, precision: 1, significant: true ) + assert_equal "0.0001", 0.0001.to_s(:rounded, precision: 1, significant: true ) + assert_equal "0.000100", 0.0001.to_s(:rounded, precision: 3, significant: true ) + assert_equal "0.0001", 0.0001111.to_s(:rounded, precision: 1, significant: true ) + assert_equal "10.0", 9.995.to_s(:rounded, precision: 3, significant: true) + assert_equal "9.99", 9.994.to_s(:rounded, precision: 3, significant: true) + assert_equal "11.0", 10.995.to_s(:rounded, precision: 3, significant: true) end def test_to_s__rounded__with_strip_insignificant_zeros - assert_equal "9775.43", 9775.43.to_s(:rounded, :precision => 4, :strip_insignificant_zeros => true ) - assert_equal "9775.2", 9775.2.to_s(:rounded, :precision => 6, :significant => true, :strip_insignificant_zeros => true ) - assert_equal "0", 0.to_s(:rounded, :precision => 6, :significant => true, :strip_insignificant_zeros => true ) + assert_equal "9775.43", 9775.43.to_s(:rounded, precision: 4, strip_insignificant_zeros: true ) + assert_equal "9775.2", 9775.2.to_s(:rounded, precision: 6, significant: true, strip_insignificant_zeros: true ) + assert_equal "0", 0.to_s(:rounded, precision: 6, significant: true, strip_insignificant_zeros: true ) end def test_to_s__rounded__with_significant_true_and_zero_precision # Zero precision with significant is a mistake (would always return zero), # so we treat it as if significant was false (increases backwards compatibility for number_to_human_size) - assert_equal "124", 123.987.to_s(:rounded, :precision => 0, :significant => true) - assert_equal "12", 12.to_s(:rounded, :precision => 0, :significant => true ) + assert_equal "124", 123.987.to_s(:rounded, precision: 0, significant: true) + assert_equal "12", 12.to_s(:rounded, precision: 0, significant: true ) end def test_to_s__human_size - assert_equal '0 Bytes', 0.to_s(:human_size) - assert_equal '1 Byte', 1.to_s(:human_size) - assert_equal '3 Bytes', 3.14159265.to_s(:human_size) - assert_equal '123 Bytes', 123.0.to_s(:human_size) - assert_equal '123 Bytes', 123.to_s(:human_size) - assert_equal '1.21 KB', 1234.to_s(:human_size) - assert_equal '12.1 KB', 12345.to_s(:human_size) - assert_equal '1.18 MB', 1234567.to_s(:human_size) - assert_equal '1.15 GB', 1234567890.to_s(:human_size) - assert_equal '1.12 TB', 1234567890123.to_s(:human_size) - assert_equal '1.1 PB', 1234567890123456.to_s(:human_size) - assert_equal '1.07 EB', 1234567890123456789.to_s(:human_size) - assert_equal '1030 EB', exabytes(1026).to_s(:human_size) - assert_equal '444 KB', kilobytes(444).to_s(:human_size) - assert_equal '1020 MB', megabytes(1023).to_s(:human_size) - assert_equal '3 TB', terabytes(3).to_s(:human_size) - assert_equal '1.2 MB', 1234567.to_s(:human_size, :precision => 2) - assert_equal '3 Bytes', 3.14159265.to_s(:human_size, :precision => 4) - assert_equal '1 KB', kilobytes(1.0123).to_s(:human_size, :precision => 2) - assert_equal '1.01 KB', kilobytes(1.0100).to_s(:human_size, :precision => 4) - assert_equal '10 KB', kilobytes(10.000).to_s(:human_size, :precision => 4) - assert_equal '1 Byte', 1.1.to_s(:human_size) - assert_equal '10 Bytes', 10.to_s(:human_size) + assert_equal "0 Bytes", 0.to_s(:human_size) + assert_equal "1 Byte", 1.to_s(:human_size) + assert_equal "3 Bytes", 3.14159265.to_s(:human_size) + assert_equal "123 Bytes", 123.0.to_s(:human_size) + assert_equal "123 Bytes", 123.to_s(:human_size) + assert_equal "1.21 KB", 1234.to_s(:human_size) + assert_equal "12.1 KB", 12345.to_s(:human_size) + assert_equal "1.18 MB", 1234567.to_s(:human_size) + assert_equal "1.15 GB", 1234567890.to_s(:human_size) + assert_equal "1.12 TB", 1234567890123.to_s(:human_size) + assert_equal "1.1 PB", 1234567890123456.to_s(:human_size) + assert_equal "1.07 EB", 1234567890123456789.to_s(:human_size) + assert_equal "1030 EB", exabytes(1026).to_s(:human_size) + assert_equal "444 KB", kilobytes(444).to_s(:human_size) + assert_equal "1020 MB", megabytes(1023).to_s(:human_size) + assert_equal "3 TB", terabytes(3).to_s(:human_size) + assert_equal "1.2 MB", 1234567.to_s(:human_size, precision: 2) + assert_equal "3 Bytes", 3.14159265.to_s(:human_size, precision: 4) + assert_equal "1 KB", kilobytes(1.0123).to_s(:human_size, precision: 2) + assert_equal "1.01 KB", kilobytes(1.0100).to_s(:human_size, precision: 4) + assert_equal "10 KB", kilobytes(10.000).to_s(:human_size, precision: 4) + assert_equal "1 Byte", 1.1.to_s(:human_size) + assert_equal "10 Bytes", 10.to_s(:human_size) end def test_to_s__human_size_with_si_prefix assert_deprecated do - assert_equal '3 Bytes', 3.14159265.to_s(:human_size, :prefix => :si) - assert_equal '123 Bytes', 123.0.to_s(:human_size, :prefix => :si) - assert_equal '123 Bytes', 123.to_s(:human_size, :prefix => :si) - assert_equal '1.23 KB', 1234.to_s(:human_size, :prefix => :si) - assert_equal '12.3 KB', 12345.to_s(:human_size, :prefix => :si) - assert_equal '1.23 MB', 1234567.to_s(:human_size, :prefix => :si) - assert_equal '1.23 GB', 1234567890.to_s(:human_size, :prefix => :si) - assert_equal '1.23 TB', 1234567890123.to_s(:human_size, :prefix => :si) - assert_equal '1.23 PB', 1234567890123456.to_s(:human_size, :prefix => :si) - assert_equal '1.23 EB', 1234567890123456789.to_s(:human_size, :prefix => :si) + assert_equal "3 Bytes", 3.14159265.to_s(:human_size, prefix: :si) + assert_equal "123 Bytes", 123.0.to_s(:human_size, prefix: :si) + assert_equal "123 Bytes", 123.to_s(:human_size, prefix: :si) + assert_equal "1.23 KB", 1234.to_s(:human_size, prefix: :si) + assert_equal "12.3 KB", 12345.to_s(:human_size, prefix: :si) + assert_equal "1.23 MB", 1234567.to_s(:human_size, prefix: :si) + assert_equal "1.23 GB", 1234567890.to_s(:human_size, prefix: :si) + assert_equal "1.23 TB", 1234567890123.to_s(:human_size, prefix: :si) + assert_equal "1.23 PB", 1234567890123456.to_s(:human_size, prefix: :si) + assert_equal "1.23 EB", 1234567890123456789.to_s(:human_size, prefix: :si) end end def test_to_s__human_size_with_options_hash - assert_equal '1.2 MB', 1234567.to_s(:human_size, :precision => 2) - assert_equal '3 Bytes', 3.14159265.to_s(:human_size, :precision => 4) - assert_equal '1 KB', kilobytes(1.0123).to_s(:human_size, :precision => 2) - assert_equal '1.01 KB', kilobytes(1.0100).to_s(:human_size, :precision => 4) - assert_equal '10 KB', kilobytes(10.000).to_s(:human_size, :precision => 4) - assert_equal '1 TB', 1234567890123.to_s(:human_size, :precision => 1) - assert_equal '500 MB', 524288000.to_s(:human_size, :precision=>3) - assert_equal '10 MB', 9961472.to_s(:human_size, :precision=>0) - assert_equal '40 KB', 41010.to_s(:human_size, :precision => 1) - assert_equal '40 KB', 41100.to_s(:human_size, :precision => 2) - assert_equal '1.0 KB', kilobytes(1.0123).to_s(:human_size, :precision => 2, :strip_insignificant_zeros => false) - assert_equal '1.012 KB', kilobytes(1.0123).to_s(:human_size, :precision => 3, :significant => false) - assert_equal '1 KB', kilobytes(1.0123).to_s(:human_size, :precision => 0, :significant => true) #ignores significant it precision is 0 + assert_equal "1.2 MB", 1234567.to_s(:human_size, precision: 2) + assert_equal "3 Bytes", 3.14159265.to_s(:human_size, precision: 4) + assert_equal "1 KB", kilobytes(1.0123).to_s(:human_size, precision: 2) + assert_equal "1.01 KB", kilobytes(1.0100).to_s(:human_size, precision: 4) + assert_equal "10 KB", kilobytes(10.000).to_s(:human_size, precision: 4) + assert_equal "1 TB", 1234567890123.to_s(:human_size, precision: 1) + assert_equal "500 MB", 524288000.to_s(:human_size, precision: 3) + assert_equal "10 MB", 9961472.to_s(:human_size, precision: 0) + assert_equal "40 KB", 41010.to_s(:human_size, precision: 1) + assert_equal "40 KB", 41100.to_s(:human_size, precision: 2) + assert_equal "1.0 KB", kilobytes(1.0123).to_s(:human_size, precision: 2, strip_insignificant_zeros: false) + assert_equal "1.012 KB", kilobytes(1.0123).to_s(:human_size, precision: 3, significant: false) + assert_equal "1 KB", kilobytes(1.0123).to_s(:human_size, precision: 0, significant: true) #ignores significant it precision is 0 end def test_to_s__human_size_with_custom_delimiter_and_separator - assert_equal '1,01 KB', kilobytes(1.0123).to_s(:human_size, :precision => 3, :separator => ',') - assert_equal '1,01 KB', kilobytes(1.0100).to_s(:human_size, :precision => 4, :separator => ',') - assert_equal '1.000,1 TB', terabytes(1000.1).to_s(:human_size, :precision => 5, :delimiter => '.', :separator => ',') + assert_equal "1,01 KB", kilobytes(1.0123).to_s(:human_size, precision: 3, separator: ",") + assert_equal "1,01 KB", kilobytes(1.0100).to_s(:human_size, precision: 4, separator: ",") + assert_equal "1.000,1 TB", terabytes(1000.1).to_s(:human_size, precision: 5, delimiter: ".", separator: ",") end def test_number_to_human - assert_equal '-123', -123.to_s(:human) - assert_equal '-0.5', -0.5.to_s(:human) - assert_equal '0', 0.to_s(:human) - assert_equal '0.5', 0.5.to_s(:human) - assert_equal '123', 123.to_s(:human) - assert_equal '1.23 Thousand', 1234.to_s(:human) - assert_equal '12.3 Thousand', 12345.to_s(:human) - assert_equal '1.23 Million', 1234567.to_s(:human) - assert_equal '1.23 Billion', 1234567890.to_s(:human) - assert_equal '1.23 Trillion', 1234567890123.to_s(:human) - assert_equal '1.23 Quadrillion', 1234567890123456.to_s(:human) - assert_equal '1230 Quadrillion', 1234567890123456789.to_s(:human) - assert_equal '490 Thousand', 489939.to_s(:human, :precision => 2) - assert_equal '489.9 Thousand', 489939.to_s(:human, :precision => 4) - assert_equal '489 Thousand', 489000.to_s(:human, :precision => 4) - assert_equal '489.0 Thousand', 489000.to_s(:human, :precision => 4, :strip_insignificant_zeros => false) - assert_equal '1.2346 Million', 1234567.to_s(:human, :precision => 4, :significant => false) - assert_equal '1,2 Million', 1234567.to_s(:human, :precision => 1, :significant => false, :separator => ',') - assert_equal '1 Million', 1234567.to_s(:human, :precision => 0, :significant => true, :separator => ',') #significant forced to false + assert_equal "-123", -123.to_s(:human) + assert_equal "-0.5", -0.5.to_s(:human) + assert_equal "0", 0.to_s(:human) + assert_equal "0.5", 0.5.to_s(:human) + assert_equal "123", 123.to_s(:human) + assert_equal "1.23 Thousand", 1234.to_s(:human) + assert_equal "12.3 Thousand", 12345.to_s(:human) + assert_equal "1.23 Million", 1234567.to_s(:human) + assert_equal "1.23 Billion", 1234567890.to_s(:human) + assert_equal "1.23 Trillion", 1234567890123.to_s(:human) + assert_equal "1.23 Quadrillion", 1234567890123456.to_s(:human) + assert_equal "1230 Quadrillion", 1234567890123456789.to_s(:human) + assert_equal "490 Thousand", 489939.to_s(:human, precision: 2) + assert_equal "489.9 Thousand", 489939.to_s(:human, precision: 4) + assert_equal "489 Thousand", 489000.to_s(:human, precision: 4) + assert_equal "489.0 Thousand", 489000.to_s(:human, precision: 4, strip_insignificant_zeros: false) + assert_equal "1.2346 Million", 1234567.to_s(:human, precision: 4, significant: false) + assert_equal "1,2 Million", 1234567.to_s(:human, precision: 1, significant: false, separator: ",") + assert_equal "1 Million", 1234567.to_s(:human, precision: 0, significant: true, separator: ",") #significant forced to false end def test_number_to_human_with_custom_units #Only integers - volume = {:unit => "ml", :thousand => "lt", :million => "m3"} - assert_equal '123 lt', 123456.to_s(:human, :units => volume) - assert_equal '12 ml', 12.to_s(:human, :units => volume) - assert_equal '1.23 m3', 1234567.to_s(:human, :units => volume) + volume = { unit: "ml", thousand: "lt", million: "m3" } + assert_equal "123 lt", 123456.to_s(:human, units: volume) + assert_equal "12 ml", 12.to_s(:human, units: volume) + assert_equal "1.23 m3", 1234567.to_s(:human, units: volume) #Including fractionals - distance = {:mili => "mm", :centi => "cm", :deci => "dm", :unit => "m", :ten => "dam", :hundred => "hm", :thousand => "km"} - assert_equal '1.23 mm', 0.00123.to_s(:human, :units => distance) - assert_equal '1.23 cm', 0.0123.to_s(:human, :units => distance) - assert_equal '1.23 dm', 0.123.to_s(:human, :units => distance) - assert_equal '1.23 m', 1.23.to_s(:human, :units => distance) - assert_equal '1.23 dam', 12.3.to_s(:human, :units => distance) - assert_equal '1.23 hm', 123.to_s(:human, :units => distance) - assert_equal '1.23 km', 1230.to_s(:human, :units => distance) - assert_equal '1.23 km', 1230.to_s(:human, :units => distance) - assert_equal '1.23 km', 1230.to_s(:human, :units => distance) - assert_equal '12.3 km', 12300.to_s(:human, :units => distance) + distance = { mili: "mm", centi: "cm", deci: "dm", unit: "m", ten: "dam", hundred: "hm", thousand: "km" } + assert_equal "1.23 mm", 0.00123.to_s(:human, units: distance) + assert_equal "1.23 cm", 0.0123.to_s(:human, units: distance) + assert_equal "1.23 dm", 0.123.to_s(:human, units: distance) + assert_equal "1.23 m", 1.23.to_s(:human, units: distance) + assert_equal "1.23 dam", 12.3.to_s(:human, units: distance) + assert_equal "1.23 hm", 123.to_s(:human, units: distance) + assert_equal "1.23 km", 1230.to_s(:human, units: distance) + assert_equal "1.23 km", 1230.to_s(:human, units: distance) + assert_equal "1.23 km", 1230.to_s(:human, units: distance) + assert_equal "12.3 km", 12300.to_s(:human, units: distance) #The quantifiers don't need to be a continuous sequence - gangster = {:hundred => "hundred bucks", :million => "thousand quids"} - assert_equal '1 hundred bucks', 100.to_s(:human, :units => gangster) - assert_equal '25 hundred bucks', 2500.to_s(:human, :units => gangster) - assert_equal '25 thousand quids', 25000000.to_s(:human, :units => gangster) - assert_equal '12300 thousand quids', 12345000000.to_s(:human, :units => gangster) + gangster = { hundred: "hundred bucks", million: "thousand quids" } + assert_equal "1 hundred bucks", 100.to_s(:human, units: gangster) + assert_equal "25 hundred bucks", 2500.to_s(:human, units: gangster) + assert_equal "25 thousand quids", 25000000.to_s(:human, units: gangster) + assert_equal "12300 thousand quids", 12345000000.to_s(:human, units: gangster) #Spaces are stripped from the resulting string - assert_equal '4', 4.to_s(:human, :units => {:unit => "", :ten => 'tens '}) - assert_equal '4.5 tens', 45.to_s(:human, :units => {:unit => "", :ten => ' tens '}) + assert_equal "4", 4.to_s(:human, units: { unit: "", ten: "tens " }) + assert_equal "4.5 tens", 45.to_s(:human, units: { unit: "", ten: " tens " }) end def test_number_to_human_with_custom_format - assert_equal '123 times Thousand', 123456.to_s(:human, :format => "%n times %u") - volume = {:unit => "ml", :thousand => "lt", :million => "m3"} - assert_equal '123.lt', 123456.to_s(:human, :units => volume, :format => "%n.%u") + assert_equal "123 times Thousand", 123456.to_s(:human, format: "%n times %u") + volume = { unit: "ml", thousand: "lt", million: "m3" } + assert_equal "123.lt", 123456.to_s(:human, units: volume, format: "%n.%u") end def test_to_s__injected_on_proper_types - assert_equal Fixnum, 1230.class - assert_equal '1.23 Thousand', 1230.to_s(:human) - - assert_equal Float, Float(1230).class - assert_equal '1.23 Thousand', Float(1230).to_s(:human) - - assert_equal Bignum, (100**10).class - assert_equal '100000 Quadrillion', (100**10).to_s(:human) - - assert_equal BigDecimal, BigDecimal("1000010").class - assert_equal '1 Million', BigDecimal("1000010").to_s(:human) + assert_equal "1.23 Thousand", 1230.to_s(:human) + assert_equal "1.23 Thousand", Float(1230).to_s(:human) + assert_equal "100000 Quadrillion", (100**10).to_s(:human) + assert_equal "1 Million", BigDecimal("1000010").to_s(:human) end def test_to_formatted_s_is_deprecated @@ -407,23 +398,23 @@ class NumericExtFormattingTest < ActiveSupport::TestCase end def test_to_s_with_invalid_formatter - assert_equal '123', 123.to_s(:invalid) - assert_equal '2.5', 2.5.to_s(:invalid) - assert_equal '100000000000000000000', (100**10).to_s(:invalid) - assert_equal '1000010.0', BigDecimal("1000010").to_s(:invalid) + assert_equal "123", 123.to_s(:invalid) + assert_equal "2.5", 2.5.to_s(:invalid) + assert_equal "100000000000000000000", (100**10).to_s(:invalid) + assert_equal "1000010.0", BigDecimal("1000010").to_s(:invalid) end def test_default_to_s - assert_equal '123', 123.to_s - assert_equal '1111011', 123.to_s(2) + assert_equal "123", 123.to_s + assert_equal "1111011", 123.to_s(2) - assert_equal '2.5', 2.5.to_s + assert_equal "2.5", 2.5.to_s - assert_equal '100000000000000000000', (100**10).to_s - assert_equal '1010110101111000111010111100010110101100011000100000000000000000000', (100**10).to_s(2) + assert_equal "100000000000000000000", (100**10).to_s + assert_equal "1010110101111000111010111100010110101100011000100000000000000000000", (100**10).to_s(2) - assert_equal '1000010.0', BigDecimal("1000010").to_s - assert_equal '10000 10.0', BigDecimal("1000010").to_s('5F') + assert_equal "1000010.0", BigDecimal("1000010").to_s + assert_equal "10000 10.0", BigDecimal("1000010").to_s("5F") end def test_in_milliseconds diff --git a/activesupport/test/core_ext/object/acts_like_test.rb b/activesupport/test/core_ext/object/acts_like_test.rb index e68b1d23cb..631f4e63a8 100644 --- a/activesupport/test/core_ext/object/acts_like_test.rb +++ b/activesupport/test/core_ext/object/acts_like_test.rb @@ -1,5 +1,5 @@ -require 'abstract_unit' -require 'active_support/core_ext/object' +require "abstract_unit" +require "active_support/core_ext/object" class ObjectTests < ActiveSupport::TestCase class DuckTime diff --git a/activesupport/test/core_ext/object/blank_test.rb b/activesupport/test/core_ext/object/blank_test.rb index a142096993..ab0676524e 100644 --- a/activesupport/test/core_ext/object/blank_test.rb +++ b/activesupport/test/core_ext/object/blank_test.rb @@ -1,5 +1,5 @@ -require 'abstract_unit' -require 'active_support/core_ext/object/blank' +require "abstract_unit" +require "active_support/core_ext/object/blank" class BlankTest < ActiveSupport::TestCase class EmptyTrue @@ -14,8 +14,8 @@ class BlankTest < ActiveSupport::TestCase end end - BLANK = [ EmptyTrue.new, nil, false, '', ' ', " \n\t \r ", ' ', "\u00a0", [], {} ] - NOT = [ EmptyFalse.new, Object.new, true, 0, 1, 'a', [nil], { nil => 0 } ] + BLANK = [ EmptyTrue.new, nil, false, "", " ", " \n\t \r ", " ", "\u00a0", [], {} ] + NOT = [ EmptyFalse.new, Object.new, true, 0, 1, "a", [nil], { nil => 0 } ] def test_blank BLANK.each { |v| assert_equal true, v.blank?, "#{v.inspect} should be blank" } diff --git a/activesupport/test/core_ext/object/deep_dup_test.rb b/activesupport/test/core_ext/object/deep_dup_test.rb index 791b5e7172..e335ec1b40 100644 --- a/activesupport/test/core_ext/object/deep_dup_test.rb +++ b/activesupport/test/core_ext/object/deep_dup_test.rb @@ -1,8 +1,7 @@ -require 'abstract_unit' -require 'active_support/core_ext/object' +require "abstract_unit" +require "active_support/core_ext/object" class DeepDupTest < ActiveSupport::TestCase - def test_array_deep_dup array = [1, [2, 3]] dup = array.deep_dup @@ -12,15 +11,15 @@ class DeepDupTest < ActiveSupport::TestCase end def test_hash_deep_dup - hash = { :a => { :b => 'b' } } + hash = { a: { b: "b" } } dup = hash.deep_dup - dup[:a][:c] = 'c' + dup[:a][:c] = "c" assert_equal nil, hash[:a][:c] - assert_equal 'c', dup[:a][:c] + assert_equal "c", dup[:a][:c] end def test_array_deep_dup_with_hash_inside - array = [1, { :a => 2, :b => 3 } ] + array = [1, { a: 2, b: 3 } ] dup = array.deep_dup dup[1][:c] = 4 assert_equal nil, array[1][:c] @@ -28,16 +27,16 @@ class DeepDupTest < ActiveSupport::TestCase end def test_hash_deep_dup_with_array_inside - hash = { :a => [1, 2] } + hash = { a: [1, 2] } dup = hash.deep_dup - dup[:a][2] = 'c' + dup[:a][2] = "c" assert_equal nil, hash[:a][2] - assert_equal 'c', dup[:a][2] + assert_equal "c", dup[:a][2] end def test_deep_dup_initialize zero_hash = Hash.new 0 - hash = { :a => zero_hash } + hash = { a: zero_hash } dup = hash.deep_dup assert_equal 0, dup[:a][44] end @@ -51,9 +50,8 @@ class DeepDupTest < ActiveSupport::TestCase end def test_deep_dup_with_hash_class_key - hash = { Fixnum => 1 } + hash = { Integer => 1 } dup = hash.deep_dup assert_equal 1, dup.keys.length end - end diff --git a/activesupport/test/core_ext/object/duplicable_test.rb b/activesupport/test/core_ext/object/duplicable_test.rb index 042f5cfb34..2cbfefe235 100644 --- a/activesupport/test/core_ext/object/duplicable_test.rb +++ b/activesupport/test/core_ext/object/duplicable_test.rb @@ -1,12 +1,12 @@ -require 'abstract_unit' -require 'bigdecimal' -require 'active_support/core_ext/object/duplicable' -require 'active_support/core_ext/numeric/time' +require "abstract_unit" +require "bigdecimal" +require "active_support/core_ext/object/duplicable" +require "active_support/core_ext/numeric/time" class DuplicableTest < ActiveSupport::TestCase RAISE_DUP = [nil, false, true, :symbol, 1, 2.3, method(:puts)] - ALLOW_DUP = ['1', Object.new, /foo/, [], {}, Time.now, Class.new, Module.new] - ALLOW_DUP << BigDecimal.new('4.56') + ALLOW_DUP = ["1", Object.new, /foo/, [], {}, Time.now, Class.new, Module.new] + ALLOW_DUP << BigDecimal.new("4.56") def test_duplicable rubinius_skip "* Method#dup is allowed at the moment on Rubinius\n" \ diff --git a/activesupport/test/core_ext/object/inclusion_test.rb b/activesupport/test/core_ext/object/inclusion_test.rb index 32d512eca3..be211ec7dc 100644 --- a/activesupport/test/core_ext/object/inclusion_test.rb +++ b/activesupport/test/core_ext/object/inclusion_test.rb @@ -1,5 +1,5 @@ -require 'abstract_unit' -require 'active_support/core_ext/object/inclusion' +require "abstract_unit" +require "active_support/core_ext/object/inclusion" class InTest < ActiveSupport::TestCase def test_in_array @@ -46,11 +46,11 @@ class InTest < ActiveSupport::TestCase assert !A.in?(A) assert !A.in?(D) end - + def test_no_method_catching assert_raise(ArgumentError) { 1.in?(1) } end - + def test_presence_in assert_equal "stuff", "stuff".presence_in(%w( lots of stuff )) assert_nil "stuff".presence_in(%w( lots of crap )) diff --git a/activesupport/test/core_ext/object/instance_variables_test.rb b/activesupport/test/core_ext/object/instance_variables_test.rb index 9f4c5dc4f1..5bdb2fbc35 100644 --- a/activesupport/test/core_ext/object/instance_variables_test.rb +++ b/activesupport/test/core_ext/object/instance_variables_test.rb @@ -1,11 +1,11 @@ -require 'abstract_unit' -require 'active_support/core_ext/object' +require "abstract_unit" +require "active_support/core_ext/object" class ObjectInstanceVariableTest < ActiveSupport::TestCase def setup @source, @dest = Object.new, Object.new - @source.instance_variable_set(:@bar, 'bar') - @source.instance_variable_set(:@baz, 'baz') + @source.instance_variable_set(:@bar, "bar") + @source.instance_variable_set(:@baz, "baz") end def test_instance_variable_names @@ -13,19 +13,19 @@ class ObjectInstanceVariableTest < ActiveSupport::TestCase end def test_instance_values - assert_equal({'bar' => 'bar', 'baz' => 'baz'}, @source.instance_values) + assert_equal({ "bar" => "bar", "baz" => "baz" }, @source.instance_values) end def test_instance_exec_passes_arguments_to_block - assert_equal %w(hello goodbye), 'hello'.instance_exec('goodbye') { |v| [self, v] } + assert_equal %w(hello goodbye), "hello".instance_exec("goodbye") { |v| [self, v] } end def test_instance_exec_with_frozen_obj - assert_equal %w(olleh goodbye), 'hello'.freeze.instance_exec('goodbye') { |v| [reverse, v] } + assert_equal %w(olleh goodbye), "hello".freeze.instance_exec("goodbye") { |v| [reverse, v] } end def test_instance_exec_nested - assert_equal %w(goodbye olleh bar), 'hello'.instance_exec('goodbye') { |arg| - [arg] + instance_exec('bar') { |v| [reverse, v] } } + assert_equal %w(goodbye olleh bar), "hello".instance_exec("goodbye") { |arg| + [arg] + instance_exec("bar") { |v| [reverse, v] } } end end diff --git a/activesupport/test/core_ext/object/json_cherry_pick_test.rb b/activesupport/test/core_ext/object/json_cherry_pick_test.rb index 2f7ea3a497..dd4e90918e 100644 --- a/activesupport/test/core_ext/object/json_cherry_pick_test.rb +++ b/activesupport/test/core_ext/object/json_cherry_pick_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" # These test cases were added to test that cherry-picking the json extensions # works correctly, primarily for dependencies problems reported in #16131. They @@ -9,7 +9,7 @@ class JsonCherryPickTest < ActiveSupport::TestCase include ActiveSupport::Testing::Isolation def test_time_as_json - require_or_skip 'active_support/core_ext/object/json' + require_or_skip "active_support/core_ext/object/json" expected = Time.new(2004, 7, 25) actual = Time.parse(expected.as_json) @@ -18,7 +18,7 @@ class JsonCherryPickTest < ActiveSupport::TestCase end def test_date_as_json - require_or_skip 'active_support/core_ext/object/json' + require_or_skip "active_support/core_ext/object/json" expected = Date.new(2004, 7, 25) actual = Date.parse(expected.as_json) @@ -27,7 +27,7 @@ class JsonCherryPickTest < ActiveSupport::TestCase end def test_datetime_as_json - require_or_skip 'active_support/core_ext/object/json' + require_or_skip "active_support/core_ext/object/json" expected = DateTime.new(2004, 7, 25) actual = DateTime.parse(expected.as_json) diff --git a/activesupport/test/core_ext/object/json_gem_encoding_test.rb b/activesupport/test/core_ext/object/json_gem_encoding_test.rb index 02ab17fb64..f5016d0c2a 100644 --- a/activesupport/test/core_ext/object/json_gem_encoding_test.rb +++ b/activesupport/test/core_ext/object/json_gem_encoding_test.rb @@ -1,6 +1,6 @@ -require 'abstract_unit' -require 'json' -require 'json/encoding_test_cases' +require "abstract_unit" +require "json" +require "json/encoding_test_cases" # These test cases were added to test that we do not interfere with json gem's # output when the AS encoder is loaded, primarily for problems reported in @@ -10,10 +10,10 @@ require 'json/encoding_test_cases' # The AS::JSON encoder requires the BigDecimal core_ext, which, unfortunately, # changes the BigDecimal#to_s output, and consequently the JSON gem output. So -# we need to require this unfront to ensure we don't get a false failure, but +# we need to require this upfront to ensure we don't get a false failure, but # ideally we should just fix the BigDecimal core_ext to not change to_s without # arguments. -require 'active_support/core_ext/big_decimal' +require "active_support/core_ext/big_decimal" class JsonGemEncodingTest < ActiveSupport::TestCase include ActiveSupport::Testing::Isolation @@ -48,7 +48,7 @@ class JsonGemEncodingTest < ActiveSupport::TestCase exception = e end - require_or_skip 'active_support/core_ext/object/json' + require_or_skip "active_support/core_ext/object/json" if exception assert_raises_with_message JSON::GeneratorError, e.message do diff --git a/activesupport/test/core_ext/object/to_param_test.rb b/activesupport/test/core_ext/object/to_param_test.rb index 30a7557dc2..56246b24f3 100644 --- a/activesupport/test/core_ext/object/to_param_test.rb +++ b/activesupport/test/core_ext/object/to_param_test.rb @@ -1,5 +1,5 @@ -require 'abstract_unit' -require 'active_support/core_ext/object/to_param' +require "abstract_unit" +require "active_support/core_ext/object/to_param" class ToParamTest < ActiveSupport::TestCase class CustomString < String @@ -10,8 +10,8 @@ class ToParamTest < ActiveSupport::TestCase def test_object foo = Object.new - def foo.to_s; 'foo' end - assert_equal 'foo', foo.to_param + def foo.to_s; "foo" end + assert_equal "foo", foo.to_param end def test_nil @@ -25,13 +25,13 @@ class ToParamTest < ActiveSupport::TestCase def test_array # Empty Array - assert_equal '', [].to_param + assert_equal "", [].to_param array = [1, 2, 3, 4] assert_equal "1/2/3/4", array.to_param # Array of different objects - array = [1, '3', { a: 1, b: 2 }, nil, true, false, CustomString.new('object')] + array = [1, "3", { a: 1, b: 2 }, nil, true, false, CustomString.new("object")] assert_equal "1/3/a=1&b=2//true/false/custom-object", array.to_param end end diff --git a/activesupport/test/core_ext/object/to_query_test.rb b/activesupport/test/core_ext/object/to_query_test.rb index 09cab3ed35..298c8bf373 100644 --- a/activesupport/test/core_ext/object/to_query_test.rb +++ b/activesupport/test/core_ext/object/to_query_test.rb @@ -1,82 +1,82 @@ -require 'abstract_unit' -require 'active_support/ordered_hash' -require 'active_support/core_ext/object/to_query' -require 'active_support/core_ext/string/output_safety' +require "abstract_unit" +require "active_support/ordered_hash" +require "active_support/core_ext/object/to_query" +require "active_support/core_ext/string/output_safety" class ToQueryTest < ActiveSupport::TestCase def test_simple_conversion - assert_query_equal 'a=10', :a => 10 + assert_query_equal "a=10", a: 10 end def test_cgi_escaping - assert_query_equal 'a%3Ab=c+d', 'a:b' => 'c d' + assert_query_equal "a%3Ab=c+d", "a:b" => "c d" end def test_html_safe_parameter_key - assert_query_equal 'a%3Ab=c+d', 'a:b'.html_safe => 'c d' + assert_query_equal "a%3Ab=c+d", "a:b".html_safe => "c d" end def test_html_safe_parameter_value - assert_query_equal 'a=%5B10%5D', 'a' => '[10]'.html_safe + assert_query_equal "a=%5B10%5D", "a" => "[10]".html_safe end def test_nil_parameter_value empty = Object.new def empty.to_param; nil end - assert_query_equal 'a=', 'a' => empty + assert_query_equal "a=", "a" => empty end def test_nested_conversion - assert_query_equal 'person%5Blogin%5D=seckar&person%5Bname%5D=Nicholas', - :person => Hash[:login, 'seckar', :name, 'Nicholas'] + assert_query_equal "person%5Blogin%5D=seckar&person%5Bname%5D=Nicholas", + person: Hash[:login, "seckar", :name, "Nicholas"] end def test_multiple_nested - assert_query_equal 'account%5Bperson%5D%5Bid%5D=20&person%5Bid%5D=10', - Hash[:account, {:person => {:id => 20}}, :person, {:id => 10}] + assert_query_equal "account%5Bperson%5D%5Bid%5D=20&person%5Bid%5D=10", + Hash[:account, { person: { id: 20 } }, :person, { id: 10 }] end def test_array_values - assert_query_equal 'person%5Bid%5D%5B%5D=10&person%5Bid%5D%5B%5D=20', - :person => {:id => [10, 20]} + assert_query_equal "person%5Bid%5D%5B%5D=10&person%5Bid%5D%5B%5D=20", + person: { id: [10, 20] } end def test_array_values_are_not_sorted - assert_query_equal 'person%5Bid%5D%5B%5D=20&person%5Bid%5D%5B%5D=10', - :person => {:id => [20, 10]} + assert_query_equal "person%5Bid%5D%5B%5D=20&person%5Bid%5D%5B%5D=10", + person: { id: [20, 10] } end def test_empty_array - assert_equal "person%5B%5D=", [].to_query('person') + assert_equal "person%5B%5D=", [].to_query("person") end def test_nested_empty_hash - assert_equal '', + assert_equal "", {}.to_query - assert_query_equal 'a=1&b%5Bc%5D=3', - { a: 1, b: { c: 3, d: {} } } - assert_query_equal '', - { a: {b: {c: {}}} } - assert_query_equal 'b%5Bc%5D=false&b%5Be%5D=&b%5Bf%5D=&p=12', - { p: 12, b: { c: false, e: nil, f: '' } } - assert_query_equal 'b%5Bc%5D=3&b%5Bf%5D=', - { b: { c: 3, k: {}, f: '' } } - assert_query_equal 'b=3', - {a: [], b: 3} + assert_query_equal "a=1&b%5Bc%5D=3", + a: 1, b: { c: 3, d: {} } + assert_query_equal "", + a: { b: { c: {} } } + assert_query_equal "b%5Bc%5D=false&b%5Be%5D=&b%5Bf%5D=&p=12", + p: 12, b: { c: false, e: nil, f: "" } + assert_query_equal "b%5Bc%5D=3&b%5Bf%5D=", + b: { c: 3, k: {}, f: "" } + assert_query_equal "b=3", + a: [], b: 3 end def test_hash_with_namespace - hash = { name: 'Nakshay', nationality: 'Indian' } - assert_equal "user%5Bname%5D=Nakshay&user%5Bnationality%5D=Indian", hash.to_query('user') + hash = { name: "Nakshay", nationality: "Indian" } + assert_equal "user%5Bname%5D=Nakshay&user%5Bnationality%5D=Indian", hash.to_query("user") end def test_hash_sorted_lexicographically - hash = { type: 'human', name: 'Nakshay' } + hash = { type: "human", name: "Nakshay" } assert_equal "name=Nakshay&type=human", hash.to_query end private def assert_query_equal(expected, actual) - assert_equal expected.split('&'), actual.to_query.split('&') + assert_equal expected.split("&"), actual.to_query.split("&") end end diff --git a/activesupport/test/core_ext/object/try_test.rb b/activesupport/test/core_ext/object/try_test.rb index 25bf0207b8..5c8bf59952 100644 --- a/activesupport/test/core_ext/object/try_test.rb +++ b/activesupport/test/core_ext/object/try_test.rb @@ -1,5 +1,5 @@ -require 'abstract_unit' -require 'active_support/core_ext/object' +require "abstract_unit" +require "active_support/core_ext/object" class ObjectTryTest < ActiveSupport::TestCase def setup @@ -15,7 +15,7 @@ class ObjectTryTest < ActiveSupport::TestCase def test_nonexisting_method_with_arguments method = :undefined_method assert !@string.respond_to?(method) - assert_nil @string.try(method, 'llo', 'y') + assert_nil @string.try(method, "llo", "y") end def test_nonexisting_method_bang @@ -27,7 +27,7 @@ class ObjectTryTest < ActiveSupport::TestCase def test_nonexisting_method_with_arguments_bang method = :undefined_method assert !@string.respond_to?(method) - assert_raise(NoMethodError) { @string.try!(method, 'llo', 'y') } + assert_raise(NoMethodError) { @string.try!(method, "llo", "y") } end def test_valid_method @@ -35,11 +35,11 @@ class ObjectTryTest < ActiveSupport::TestCase end def test_argument_forwarding - assert_equal 'Hey', @string.try(:sub, 'llo', 'y') + assert_equal "Hey", @string.try(:sub, "llo", "y") end def test_block_forwarding - assert_equal 'Hey', @string.try(:sub, 'llo') { |match| 'y' } + assert_equal "Hey", @string.try(:sub, "llo") { |match| "y" } end def test_nil_to_type @@ -48,7 +48,7 @@ class ObjectTryTest < ActiveSupport::TestCase end def test_false_try - assert_equal 'false', false.try(:to_s) + assert_equal "false", false.try(:to_s) end def test_try_only_block @@ -78,7 +78,7 @@ class ObjectTryTest < ActiveSupport::TestCase private def private_method - 'private method' + "private method" end end @@ -90,7 +90,7 @@ class ObjectTryTest < ActiveSupport::TestCase private def private_method - 'private method' + "private method" end end @@ -99,22 +99,22 @@ class ObjectTryTest < ActiveSupport::TestCase class Decorator < SimpleDelegator def delegator_method - 'delegator method' + "delegator method" end def reverse - 'overridden reverse' + "overridden reverse" end private def private_delegator_method - 'private delegator method' + "private delegator method" end end def test_try_with_method_on_delegator - assert_equal 'delegator method', Decorator.new(@string).try(:delegator_method) + assert_equal "delegator method", Decorator.new(@string).try(:delegator_method) end def test_try_with_method_on_delegator_target @@ -122,7 +122,7 @@ class ObjectTryTest < ActiveSupport::TestCase end def test_try_with_overridden_method_on_delegator - assert_equal 'overridden reverse', Decorator.new(@string).reverse + assert_equal "overridden reverse", Decorator.new(@string).reverse end def test_try_with_private_method_on_delegator @@ -140,7 +140,7 @@ class ObjectTryTest < ActiveSupport::TestCase private def private_method - 'private method' + "private method" end end @@ -152,7 +152,7 @@ class ObjectTryTest < ActiveSupport::TestCase private def private_method - 'private method' + "private method" end end diff --git a/activesupport/test/core_ext/range_ext_test.rb b/activesupport/test/core_ext/range_ext_test.rb index f28cebda3d..fc0e72e09a 100644 --- a/activesupport/test/core_ext/range_ext_test.rb +++ b/activesupport/test/core_ext/range_ext_test.rb @@ -1,7 +1,7 @@ -require 'abstract_unit' -require 'active_support/time' -require 'active_support/core_ext/numeric' -require 'active_support/core_ext/range' +require "abstract_unit" +require "active_support/time" +require "active_support/core_ext/numeric" +require "active_support/core_ext/range" class RangeTest < ActiveSupport::TestCase def test_to_s_from_dates @@ -66,15 +66,15 @@ class RangeTest < ActiveSupport::TestCase end def test_exclusive_end_should_not_include_identical_with_inclusive_end - assert !(1...10).include?(1..10) + assert_not_includes (1...10), 1..10 end def test_should_not_include_overlapping_first - assert !(2..8).include?(1..3) + assert_not_includes (2..8), 1..3 end def test_should_not_include_overlapping_last - assert !(2..8).include?(5..9) + assert_not_includes (2..8), 5..9 end def test_should_include_identical_exclusive_with_floats @@ -99,21 +99,21 @@ class RangeTest < ActiveSupport::TestCase end def test_each_on_time_with_zone - twz = ActiveSupport::TimeWithZone.new(nil, ActiveSupport::TimeZone['Eastern Time (US & Canada)'] , Time.utc(2006,11,28,10,30)) + twz = ActiveSupport::TimeWithZone.new(nil, ActiveSupport::TimeZone["Eastern Time (US & Canada)"] , Time.utc(2006,11,28,10,30)) assert_raises TypeError do ((twz - 1.hour)..twz).each {} end end def test_step_on_time_with_zone - twz = ActiveSupport::TimeWithZone.new(nil, ActiveSupport::TimeZone['Eastern Time (US & Canada)'] , Time.utc(2006,11,28,10,30)) + twz = ActiveSupport::TimeWithZone.new(nil, ActiveSupport::TimeZone["Eastern Time (US & Canada)"] , Time.utc(2006,11,28,10,30)) assert_raises TypeError do ((twz - 1.hour)..twz).step(1) {} end end def test_include_on_time_with_zone - twz = ActiveSupport::TimeWithZone.new(nil, ActiveSupport::TimeZone['Eastern Time (US & Canada)'] , Time.utc(2006,11,28,10,30)) + twz = ActiveSupport::TimeWithZone.new(nil, ActiveSupport::TimeZone["Eastern Time (US & Canada)"] , Time.utc(2006,11,28,10,30)) assert_raises TypeError do ((twz - 1.hour)..twz).include?(twz) end diff --git a/activesupport/test/core_ext/regexp_ext_test.rb b/activesupport/test/core_ext/regexp_ext_test.rb index c2398d31bd..e569a9f234 100644 --- a/activesupport/test/core_ext/regexp_ext_test.rb +++ b/activesupport/test/core_ext/regexp_ext_test.rb @@ -1,5 +1,5 @@ -require 'abstract_unit' -require 'active_support/core_ext/regexp' +require "abstract_unit" +require "active_support/core_ext/regexp" class RegexpExtAccessTests < ActiveSupport::TestCase def test_multiline @@ -7,4 +7,28 @@ class RegexpExtAccessTests < ActiveSupport::TestCase assert_equal false, //.multiline? assert_equal false, /(?m:)/.multiline? end + + # Based on https://github.com/ruby/ruby/blob/trunk/test/ruby/test_regexp.rb. + def test_match_p + /back(...)/ =~ "backref" + # must match here, but not in a separate method, e.g., assert_send, + # to check if $~ is affected or not. + assert_equal false, //.match?(nil) + assert_equal true, //.match?("") + assert_equal true, /.../.match?(:abc) + assert_raise(TypeError) { /.../.match?(Object.new) } + assert_equal true, /b/.match?("abc") + assert_equal true, /b/.match?("abc", 1) + assert_equal true, /../.match?("abc", 1) + assert_equal true, /../.match?("abc", -2) + assert_equal false, /../.match?("abc", -4) + assert_equal false, /../.match?("abc", 4) + assert_equal true, /\z/.match?("") + assert_equal true, /\z/.match?("abc") + assert_equal true, /R.../.match?("Ruby") + assert_equal false, /R.../.match?("Ruby", 1) + assert_equal false, /P.../.match?("Ruby") + assert_equal "backref", $& + assert_equal "ref", $1 + end end diff --git a/activesupport/test/core_ext/secure_random_test.rb b/activesupport/test/core_ext/secure_random_test.rb index dfacb7fe9f..fc25f6ab41 100644 --- a/activesupport/test/core_ext/secure_random_test.rb +++ b/activesupport/test/core_ext/secure_random_test.rb @@ -1,5 +1,5 @@ -require 'abstract_unit' -require 'active_support/core_ext/securerandom' +require "abstract_unit" +require "active_support/core_ext/securerandom" class SecureRandomTest < ActiveSupport::TestCase def test_base58 diff --git a/activesupport/test/core_ext/string_ext_test.rb b/activesupport/test/core_ext/string_ext_test.rb index 2e69816364..4b40503d22 100644 --- a/activesupport/test/core_ext/string_ext_test.rb +++ b/activesupport/test/core_ext/string_ext_test.rb @@ -1,15 +1,16 @@ -require 'date' -require 'abstract_unit' -require 'inflector_test_cases' -require 'constantize_test_cases' - -require 'active_support/inflector' -require 'active_support/core_ext/string' -require 'active_support/time' -require 'active_support/core_ext/string/strip' -require 'active_support/core_ext/string/output_safety' -require 'active_support/core_ext/string/indent' -require 'time_zone_test_helpers' +require "date" +require "abstract_unit" +require "inflector_test_cases" +require "constantize_test_cases" + +require "active_support/inflector" +require "active_support/core_ext/string" +require "active_support/time" +require "active_support/core_ext/string/strip" +require "active_support/core_ext/string/output_safety" +require "active_support/core_ext/string/indent" +require "time_zone_test_helpers" +require "yaml" class StringInflectionsTest < ActiveSupport::TestCase include InflectorTestCases @@ -17,12 +18,12 @@ class StringInflectionsTest < ActiveSupport::TestCase include TimeZoneTestHelpers def test_strip_heredoc_on_an_empty_string - assert_equal '', ''.strip_heredoc + assert_equal "", "".strip_heredoc end def test_strip_heredoc_on_a_string_with_no_lines - assert_equal 'x', 'x'.strip_heredoc - assert_equal 'x', ' x'.strip_heredoc + assert_equal "x", "x".strip_heredoc + assert_equal "x", " x".strip_heredoc end def test_strip_heredoc_on_a_heredoc_with_no_margin @@ -59,7 +60,7 @@ class StringInflectionsTest < ActiveSupport::TestCase assert_equal("blargles", "blargle".pluralize(2)) end - test 'pluralize with count = 1 still returns new string' do + test "pluralize with count = 1 still returns new string" do name = "Kuldeep" assert_not_same name.pluralize(1), name end @@ -76,6 +77,18 @@ class StringInflectionsTest < ActiveSupport::TestCase end end + def test_upcase_first + assert_equal "What a Lovely Day", "what a Lovely Day".upcase_first + end + + def test_upcase_first_with_one_char + assert_equal "W", "w".upcase_first + end + + def test_upcase_first_with_empty_string + assert_equal "", "".upcase_first + end + def test_camelize CamelToUnderscore.each do |camel, underscore| assert_equal(camel, underscore.camelize) @@ -83,7 +96,7 @@ class StringInflectionsTest < ActiveSupport::TestCase end def test_camelize_lower - assert_equal('capital', 'Capital'.camelize(:lower)) + assert_equal("capital", "Capital".camelize(:lower)) end def test_dasherize @@ -151,41 +164,41 @@ class StringInflectionsTest < ActiveSupport::TestCase def test_string_parameterized_no_separator StringToParameterizeWithNoSeparator.each do |normal, slugged| - assert_equal(normal.parameterize(separator: ''), slugged) + assert_equal(normal.parameterize(separator: ""), slugged) end end def test_string_parameterized_no_separator_deprecated StringToParameterizeWithNoSeparator.each do |normal, slugged| assert_deprecated(/Passing the separator argument as a positional parameter is deprecated and will soon be removed. Use `separator: ''` instead./i) do - assert_equal(normal.parameterize(''), slugged) + assert_equal(normal.parameterize(""), slugged) end end end def test_string_parameterized_no_separator_preserve_case StringToParameterizePreserveCaseWithNoSeparator.each do |normal, slugged| - assert_equal(normal.parameterize(separator: '', preserve_case: true), slugged) + assert_equal(normal.parameterize(separator: "", preserve_case: true), slugged) end end def test_string_parameterized_underscore StringToParameterizeWithUnderscore.each do |normal, slugged| - assert_equal(normal.parameterize(separator: '_'), slugged) + assert_equal(normal.parameterize(separator: "_"), slugged) end end def test_string_parameterized_underscore_deprecated StringToParameterizeWithUnderscore.each do |normal, slugged| assert_deprecated(/Passing the separator argument as a positional parameter is deprecated and will soon be removed. Use `separator: '_'` instead./i) do - assert_equal(normal.parameterize('_'), slugged) + assert_equal(normal.parameterize("_"), slugged) end end end def test_string_parameterized_underscore_preserve_case StringToParameterizePreserceCaseWithUnderscore.each do |normal, slugged| - assert_equal(normal.parameterize(separator: '_', preserve_case: true), slugged) + assert_equal(normal.parameterize(separator: "_", preserve_case: true), slugged) end end @@ -202,23 +215,23 @@ class StringInflectionsTest < ActiveSupport::TestCase end def test_humanize_with_html_escape - assert_equal 'Hello', ERB::Util.html_escape("hello").humanize + assert_equal "Hello", ERB::Util.html_escape("hello").humanize end def test_ord - assert_equal 97, 'a'.ord - assert_equal 97, 'abc'.ord + assert_equal 97, "a".ord + assert_equal 97, "abc".ord end def test_starts_ends_with_alias s = "hello" - assert s.starts_with?('h') - assert s.starts_with?('hel') - assert !s.starts_with?('el') + assert s.starts_with?("h") + assert s.starts_with?("hel") + assert !s.starts_with?("el") - assert s.ends_with?('o') - assert s.ends_with?('lo') - assert !s.ends_with?('el') + assert s.ends_with?("o") + assert s.ends_with?("lo") + assert !s.ends_with?("el") end def test_string_squish @@ -250,16 +263,16 @@ class StringInflectionsTest < ActiveSupport::TestCase end def test_truncate_with_omission_and_separator - assert_equal "Hello[...]", "Hello World!".truncate(10, :omission => "[...]") - assert_equal "Hello[...]", "Hello Big World!".truncate(13, :omission => "[...]", :separator => ' ') - assert_equal "Hello Big[...]", "Hello Big World!".truncate(14, :omission => "[...]", :separator => ' ') - assert_equal "Hello Big[...]", "Hello Big World!".truncate(15, :omission => "[...]", :separator => ' ') + assert_equal "Hello[...]", "Hello World!".truncate(10, omission: "[...]") + assert_equal "Hello[...]", "Hello Big World!".truncate(13, omission: "[...]", separator: " ") + assert_equal "Hello Big[...]", "Hello Big World!".truncate(14, omission: "[...]", separator: " ") + assert_equal "Hello Big[...]", "Hello Big World!".truncate(15, omission: "[...]", separator: " ") end def test_truncate_with_omission_and_regexp_separator - assert_equal "Hello[...]", "Hello Big World!".truncate(13, :omission => "[...]", :separator => /\s/) - assert_equal "Hello Big[...]", "Hello Big World!".truncate(14, :omission => "[...]", :separator => /\s/) - assert_equal "Hello Big[...]", "Hello Big World!".truncate(15, :omission => "[...]", :separator => /\s/) + assert_equal "Hello[...]", "Hello Big World!".truncate(13, omission: "[...]", separator: /\s/) + assert_equal "Hello Big[...]", "Hello Big World!".truncate(14, omission: "[...]", separator: /\s/) + assert_equal "Hello Big[...]", "Hello Big World!".truncate(15, omission: "[...]", separator: /\s/) end def test_truncate_words @@ -268,19 +281,19 @@ class StringInflectionsTest < ActiveSupport::TestCase end def test_truncate_words_with_omission - assert_equal "Hello Big World!", "Hello Big World!".truncate_words(3, :omission => "[...]") - assert_equal "Hello Big[...]", "Hello Big World!".truncate_words(2, :omission => "[...]") + assert_equal "Hello Big World!", "Hello Big World!".truncate_words(3, omission: "[...]") + assert_equal "Hello Big[...]", "Hello Big World!".truncate_words(2, omission: "[...]") end def test_truncate_words_with_separator - assert_equal "Hello<br>Big<br>World!...", "Hello<br>Big<br>World!<br>".truncate_words(3, :separator => '<br>') - assert_equal "Hello<br>Big<br>World!", "Hello<br>Big<br>World!".truncate_words(3, :separator => '<br>') - assert_equal "Hello\n<br>Big...", "Hello\n<br>Big<br>Wide<br>World!".truncate_words(2, :separator => '<br>') + assert_equal "Hello<br>Big<br>World!...", "Hello<br>Big<br>World!<br>".truncate_words(3, separator: "<br>") + assert_equal "Hello<br>Big<br>World!", "Hello<br>Big<br>World!".truncate_words(3, separator: "<br>") + assert_equal "Hello\n<br>Big...", "Hello\n<br>Big<br>Wide<br>World!".truncate_words(2, separator: "<br>") end def test_truncate_words_with_separator_and_omission - assert_equal "Hello<br>Big<br>World![...]", "Hello<br>Big<br>World!<br>".truncate_words(3, :omission => "[...]", :separator => '<br>') - assert_equal "Hello<br>Big<br>World!", "Hello<br>Big<br>World!".truncate_words(3, :omission => "[...]", :separator => '<br>') + assert_equal "Hello<br>Big<br>World![...]", "Hello<br>Big<br>World!<br>".truncate_words(3, omission: "[...]", separator: "<br>") + assert_equal "Hello<br>Big<br>World!", "Hello<br>Big<br>World!".truncate_words(3, omission: "[...]", separator: "<br>") end def test_truncate_words_with_complex_string @@ -332,7 +345,7 @@ class StringInflectionsTest < ActiveSupport::TestCase end class StringAccessTest < ActiveSupport::TestCase - test "#at with Fixnum, returns a substring of one character at that position" do + test "#at with Integer, returns a substring of one character at that position" do assert_equal "h", "hello".at(0) end @@ -345,19 +358,19 @@ class StringAccessTest < ActiveSupport::TestCase assert_equal nil, "hello".at(/nonexisting/) end - test "#from with positive Fixnum, returns substring from the given position to the end" do + test "#from with positive Integer, returns substring from the given position to the end" do assert_equal "llo", "hello".from(2) end - test "#from with negative Fixnum, position is counted from the end" do + test "#from with negative Integer, position is counted from the end" do assert_equal "lo", "hello".from(-2) end - test "#to with positive Fixnum, substring from the beginning to the given position" do + test "#to with positive Integer, substring from the beginning to the given position" do assert_equal "hel", "hello".to(2) end - test "#to with negative Fixnum, position is counted from the end" do + test "#to with negative Integer, position is counted from the end" do assert_equal "hell", "hello".to(-2) end @@ -368,17 +381,17 @@ class StringAccessTest < ActiveSupport::TestCase test "#first returns the first character" do assert_equal "h", "hello".first - assert_equal 'x', 'x'.first + assert_equal "x", "x".first end - test "#first with Fixnum, returns a substring from the beginning to position" do + test "#first with Integer, returns a substring from the beginning to position" do assert_equal "he", "hello".first(2) assert_equal "", "hello".first(0) assert_equal "hello", "hello".first(10) - assert_equal 'x', 'x'.first(4) + assert_equal "x", "x".first(4) end - test "#first with Fixnum >= string length still returns a new string" do + test "#first with Integer >= string length still returns a new string" do string = "hello" different_string = string.first(5) assert_not_same different_string, string @@ -386,17 +399,17 @@ class StringAccessTest < ActiveSupport::TestCase test "#last returns the last character" do assert_equal "o", "hello".last - assert_equal 'x', 'x'.last + assert_equal "x", "x".last end - test "#last with Fixnum, returns a substring from the end to position" do + test "#last with Integer, returns a substring from the end to position" do assert_equal "llo", "hello".last(3) assert_equal "hello", "hello".last(10) assert_equal "", "hello".last(0) - assert_equal 'x', 'x'.last(4) + assert_equal "x", "x".last(4) end - test "#last with Fixnum >= string length still returns a new string" do + test "#last with Integer >= string length still returns a new string" do string = "hello" different_string = string.last(5) assert_not_same different_string, string @@ -444,16 +457,24 @@ class StringConversionsTest < ActiveSupport::TestCase assert_equal Time.local(2011, 2, 27, 17, 50), "2011-02-27 13:50 -0100".to_time assert_equal Time.utc(2011, 2, 27, 23, 50), "2011-02-27 22:50 -0100".to_time(:utc) assert_equal Time.local(2005, 2, 27, 22, 50), "2005-02-27 14:50 -0500".to_time + assert_nil "010".to_time assert_nil "".to_time end end def test_string_to_time_utc_offset with_env_tz "US/Eastern" do - assert_equal 0, "2005-02-27 23:50".to_time(:utc).utc_offset - assert_equal(-18000, "2005-02-27 23:50".to_time.utc_offset) - assert_equal 0, "2005-02-27 22:50 -0100".to_time(:utc).utc_offset - assert_equal(-18000, "2005-02-27 22:50 -0100".to_time.utc_offset) + if ActiveSupport.to_time_preserves_timezone + assert_equal 0, "2005-02-27 23:50".to_time(:utc).utc_offset + assert_equal(-18000, "2005-02-27 23:50".to_time.utc_offset) + assert_equal 0, "2005-02-27 22:50 -0100".to_time(:utc).utc_offset + assert_equal(-3600, "2005-02-27 22:50 -0100".to_time.utc_offset) + else + assert_equal 0, "2005-02-27 23:50".to_time(:utc).utc_offset + assert_equal(-18000, "2005-02-27 23:50".to_time.utc_offset) + assert_equal 0, "2005-02-27 22:50 -0100".to_time(:utc).utc_offset + assert_equal(-18000, "2005-02-27 22:50 -0100".to_time.utc_offset) + end end end @@ -612,14 +633,14 @@ end class StringBehaviourTest < ActiveSupport::TestCase def test_acts_like_string - assert 'Bambi'.acts_like_string? + assert "Bambi".acts_like_string? end end class CoreExtStringMultibyteTest < ActiveSupport::TestCase - UTF8_STRING = 'こにちわ' - ASCII_STRING = 'ohayo'.encode('US-ASCII') - EUC_JP_STRING = 'さよなら'.encode('EUC-JP') + UTF8_STRING = "こにちわ" + ASCII_STRING = "ohayo".encode("US-ASCII") + EUC_JP_STRING = "さよなら".encode("EUC-JP") INVALID_UTF8_STRING = "\270\236\010\210\245" def test_core_ext_adds_mb_chars @@ -661,7 +682,7 @@ class OutputSafetyTest < ActiveSupport::TestCase assert_equal @string, @string.html_safe end - test "A fixnum is safe by default" do + test "An integer is safe by default" do assert 5.html_safe? end @@ -792,15 +813,15 @@ class OutputSafetyTest < ActiveSupport::TestCase assert_equal ["<p>", "<b>", "<h1>"], @other_string end - test "Concatting a fixnum to safe always yields safe" do + test "Concatting an integer to safe always yields safe" do string = @string.html_safe string = string.concat(13) assert_equal "hello".concat(13), string assert string.html_safe? end - test 'emits normal string yaml' do - assert_equal 'foo'.to_yaml, 'foo'.html_safe.to_yaml(:foo => 1) + test "emits normal string yaml" do + assert_equal "foo".to_yaml, "foo".html_safe.to_yaml(foo: 1) end test "call to_param returns a normal string" do @@ -811,7 +832,7 @@ class OutputSafetyTest < ActiveSupport::TestCase test "ERB::Util.html_escape should escape unsafe characters" do string = '<>&"\'' - expected = '<>&"'' + expected = "<>&"'" assert_equal expected, ERB::Util.html_escape(string) end @@ -827,7 +848,7 @@ class OutputSafetyTest < ActiveSupport::TestCase end test "ERB::Util.html_escape_once only escapes once" do - string = '1 < 2 & 3' + string = "1 < 2 & 3" escaped_string = "1 < 2 & 3" assert_equal escaped_string, ERB::Util.html_escape_once(string) @@ -842,15 +863,15 @@ class OutputSafetyTest < ActiveSupport::TestCase end class StringExcludeTest < ActiveSupport::TestCase - test 'inverse of #include' do - assert_equal false, 'foo'.exclude?('o') - assert_equal true, 'foo'.exclude?('p') + test "inverse of #include" do + assert_equal false, "foo".exclude?("o") + assert_equal true, "foo".exclude?("p") end end class StringIndentTest < ActiveSupport::TestCase - test 'does not indent strings that only contain newlines (edge cases)' do - ['', "\n", "\n" * 7].each do |str| + test "does not indent strings that only contain newlines (edge cases)" do + ["", "\n", "\n" * 7].each do |str| assert_nil str.indent!(8) assert_equal str, str.indent(8) assert_equal str, str.indent(1, "\t") @@ -872,8 +893,8 @@ class StringIndentTest < ActiveSupport::TestCase # Nothing is said about existing indentation that mixes spaces and tabs, so # there is nothing to test. - test 'uses the indent char if passed' do - assert_equal <<EXPECTED, <<ACTUAL.indent(4, '.') + test "uses the indent char if passed" do + assert_equal <<EXPECTED, <<ACTUAL.indent(4, ".") .... def some_method(x, y) .... some_code .... end @@ -883,7 +904,7 @@ EXPECTED end ACTUAL - assert_equal <<EXPECTED, <<ACTUAL.indent(2, ' ') + assert_equal <<EXPECTED, <<ACTUAL.indent(2, " ") def some_method(x, y) some_code end @@ -898,7 +919,7 @@ ACTUAL assert_equal " foo\n\n bar", "foo\n\nbar".indent(1) end - test 'indents blank lines if told so' do + test "indents blank lines if told so" do assert_equal " foo\n \n bar", "foo\n\nbar".indent(1, nil, true) end end diff --git a/activesupport/test/core_ext/time_ext_test.rb b/activesupport/test/core_ext/time_ext_test.rb index e45df63fd5..a6c9a7d5a8 100644 --- a/activesupport/test/core_ext/time_ext_test.rb +++ b/activesupport/test/core_ext/time_ext_test.rb @@ -1,7 +1,7 @@ -require 'abstract_unit' -require 'active_support/time' -require 'core_ext/date_and_time_behavior' -require 'time_zone_test_helpers' +require "abstract_unit" +require "active_support/time" +require "core_ext/date_and_time_behavior" +require "time_zone_test_helpers" class TimeExtCalculationsTest < ActiveSupport::TestCase def date_time_init(year,month,day,hour,minute,second,usec=0) @@ -20,42 +20,42 @@ class TimeExtCalculationsTest < ActiveSupport::TestCase end def test_seconds_since_midnight_at_daylight_savings_time_start - with_env_tz 'US/Eastern' do + with_env_tz "US/Eastern" do # dt: US: 2005 April 3rd 2:00am ST => April 3rd 3:00am DT - assert_equal 2*3600-1, Time.local(2005,4,3,1,59,59).seconds_since_midnight, 'just before DST start' - assert_equal 2*3600+1, Time.local(2005,4,3,3, 0, 1).seconds_since_midnight, 'just after DST start' + assert_equal 2*3600-1, Time.local(2005,4,3,1,59,59).seconds_since_midnight, "just before DST start" + assert_equal 2*3600+1, Time.local(2005,4,3,3, 0, 1).seconds_since_midnight, "just after DST start" end - with_env_tz 'NZ' do + with_env_tz "NZ" do # dt: New Zealand: 2006 October 1st 2:00am ST => October 1st 3:00am DT - assert_equal 2*3600-1, Time.local(2006,10,1,1,59,59).seconds_since_midnight, 'just before DST start' - assert_equal 2*3600+1, Time.local(2006,10,1,3, 0, 1).seconds_since_midnight, 'just after DST start' + assert_equal 2*3600-1, Time.local(2006,10,1,1,59,59).seconds_since_midnight, "just before DST start" + assert_equal 2*3600+1, Time.local(2006,10,1,3, 0, 1).seconds_since_midnight, "just after DST start" end end def test_seconds_since_midnight_at_daylight_savings_time_end - with_env_tz 'US/Eastern' do + with_env_tz "US/Eastern" do # st: US: 2005 October 30th 2:00am DT => October 30th 1:00am ST # avoid setting a time between 1:00 and 2:00 since that requires specifying whether DST is active - assert_equal 1*3600-1, Time.local(2005,10,30,0,59,59).seconds_since_midnight, 'just before DST end' - assert_equal 3*3600+1, Time.local(2005,10,30,2, 0, 1).seconds_since_midnight, 'just after DST end' + assert_equal 1*3600-1, Time.local(2005,10,30,0,59,59).seconds_since_midnight, "just before DST end" + assert_equal 3*3600+1, Time.local(2005,10,30,2, 0, 1).seconds_since_midnight, "just after DST end" # now set a time between 1:00 and 2:00 by specifying whether DST is active # uses: Time.local( sec, min, hour, day, month, year, wday, yday, isdst, tz ) - assert_equal 1*3600+30*60, Time.local(0,30,1,30,10,2005,0,0,true,ENV['TZ']).seconds_since_midnight, 'before DST end' - assert_equal 2*3600+30*60, Time.local(0,30,1,30,10,2005,0,0,false,ENV['TZ']).seconds_since_midnight, 'after DST end' + assert_equal 1*3600+30*60, Time.local(0,30,1,30,10,2005,0,0,true,ENV["TZ"]).seconds_since_midnight, "before DST end" + assert_equal 2*3600+30*60, Time.local(0,30,1,30,10,2005,0,0,false,ENV["TZ"]).seconds_since_midnight, "after DST end" end - with_env_tz 'NZ' do + with_env_tz "NZ" do # st: New Zealand: 2006 March 19th 3:00am DT => March 19th 2:00am ST # avoid setting a time between 2:00 and 3:00 since that requires specifying whether DST is active - assert_equal 2*3600-1, Time.local(2006,3,19,1,59,59).seconds_since_midnight, 'just before DST end' - assert_equal 4*3600+1, Time.local(2006,3,19,3, 0, 1).seconds_since_midnight, 'just after DST end' + assert_equal 2*3600-1, Time.local(2006,3,19,1,59,59).seconds_since_midnight, "just before DST end" + assert_equal 4*3600+1, Time.local(2006,3,19,3, 0, 1).seconds_since_midnight, "just after DST end" # now set a time between 2:00 and 3:00 by specifying whether DST is active # uses: Time.local( sec, min, hour, day, month, year, wday, yday, isdst, tz ) - assert_equal 2*3600+30*60, Time.local(0,30,2,19,3,2006,0,0,true, ENV['TZ']).seconds_since_midnight, 'before DST end' - assert_equal 3*3600+30*60, Time.local(0,30,2,19,3,2006,0,0,false,ENV['TZ']).seconds_since_midnight, 'after DST end' + assert_equal 2*3600+30*60, Time.local(0,30,2,19,3,2006,0,0,true, ENV["TZ"]).seconds_since_midnight, "before DST end" + assert_equal 3*3600+30*60, Time.local(0,30,2,19,3,2006,0,0,false,ENV["TZ"]).seconds_since_midnight, "after DST end" end end @@ -68,66 +68,80 @@ class TimeExtCalculationsTest < ActiveSupport::TestCase end def test_seconds_until_end_of_day_at_daylight_savings_time_start - with_env_tz 'US/Eastern' do + with_env_tz "US/Eastern" do # dt: US: 2005 April 3rd 2:00am ST => April 3rd 3:00am DT - assert_equal 21*3600, Time.local(2005,4,3,1,59,59).seconds_until_end_of_day, 'just before DST start' - assert_equal 21*3600-2, Time.local(2005,4,3,3,0,1).seconds_until_end_of_day, 'just after DST start' + assert_equal 21*3600, Time.local(2005,4,3,1,59,59).seconds_until_end_of_day, "just before DST start" + assert_equal 21*3600-2, Time.local(2005,4,3,3,0,1).seconds_until_end_of_day, "just after DST start" end - with_env_tz 'NZ' do + with_env_tz "NZ" do # dt: New Zealand: 2006 October 1st 2:00am ST => October 1st 3:00am DT - assert_equal 21*3600, Time.local(2006,10,1,1,59,59).seconds_until_end_of_day, 'just before DST start' - assert_equal 21*3600-2, Time.local(2006,10,1,3,0,1).seconds_until_end_of_day, 'just after DST start' + assert_equal 21*3600, Time.local(2006,10,1,1,59,59).seconds_until_end_of_day, "just before DST start" + assert_equal 21*3600-2, Time.local(2006,10,1,3,0,1).seconds_until_end_of_day, "just after DST start" end end def test_seconds_until_end_of_day_at_daylight_savings_time_end - with_env_tz 'US/Eastern' do + with_env_tz "US/Eastern" do # st: US: 2005 October 30th 2:00am DT => October 30th 1:00am ST # avoid setting a time between 1:00 and 2:00 since that requires specifying whether DST is active - assert_equal 24*3600, Time.local(2005,10,30,0,59,59).seconds_until_end_of_day, 'just before DST end' - assert_equal 22*3600-2, Time.local(2005,10,30,2,0,1).seconds_until_end_of_day, 'just after DST end' + assert_equal 24*3600, Time.local(2005,10,30,0,59,59).seconds_until_end_of_day, "just before DST end" + assert_equal 22*3600-2, Time.local(2005,10,30,2,0,1).seconds_until_end_of_day, "just after DST end" # now set a time between 1:00 and 2:00 by specifying whether DST is active # uses: Time.local( sec, min, hour, day, month, year, wday, yday, isdst, tz ) - assert_equal 24*3600-30*60-1, Time.local(0,30,1,30,10,2005,0,0,true,ENV['TZ']).seconds_until_end_of_day, 'before DST end' - assert_equal 23*3600-30*60-1, Time.local(0,30,1,30,10,2005,0,0,false,ENV['TZ']).seconds_until_end_of_day, 'after DST end' + assert_equal 24*3600-30*60-1, Time.local(0,30,1,30,10,2005,0,0,true,ENV["TZ"]).seconds_until_end_of_day, "before DST end" + assert_equal 23*3600-30*60-1, Time.local(0,30,1,30,10,2005,0,0,false,ENV["TZ"]).seconds_until_end_of_day, "after DST end" end - with_env_tz 'NZ' do + with_env_tz "NZ" do # st: New Zealand: 2006 March 19th 3:00am DT => March 19th 2:00am ST # avoid setting a time between 2:00 and 3:00 since that requires specifying whether DST is active - assert_equal 23*3600, Time.local(2006,3,19,1,59,59).seconds_until_end_of_day, 'just before DST end' - assert_equal 21*3600-2, Time.local(2006,3,19,3,0,1).seconds_until_end_of_day, 'just after DST end' + assert_equal 23*3600, Time.local(2006,3,19,1,59,59).seconds_until_end_of_day, "just before DST end" + assert_equal 21*3600-2, Time.local(2006,3,19,3,0,1).seconds_until_end_of_day, "just after DST end" # now set a time between 2:00 and 3:00 by specifying whether DST is active # uses: Time.local( sec, min, hour, day, month, year, wday, yday, isdst, tz ) - assert_equal 23*3600-30*60-1, Time.local(0,30,2,19,3,2006,0,0,true, ENV['TZ']).seconds_until_end_of_day, 'before DST end' - assert_equal 22*3600-30*60-1, Time.local(0,30,2,19,3,2006,0,0,false,ENV['TZ']).seconds_until_end_of_day, 'after DST end' + assert_equal 23*3600-30*60-1, Time.local(0,30,2,19,3,2006,0,0,true, ENV["TZ"]).seconds_until_end_of_day, "before DST end" + assert_equal 22*3600-30*60-1, Time.local(0,30,2,19,3,2006,0,0,false,ENV["TZ"]).seconds_until_end_of_day, "after DST end" end end + def test_sec_fraction + time = Time.utc(2016, 4, 23, 0, 0, Rational(1,10000000000)) + assert_equal Rational(1,10000000000), time.sec_fraction + + time = Time.utc(2016, 4, 23, 0, 0, 0.0000000001) + assert_equal 0.0000000001.to_r, time.sec_fraction + + time = Time.utc(2016, 4, 23, 0, 0, 0, Rational(1,10000)) + assert_equal Rational(1,10000000000), time.sec_fraction + + time = Time.utc(2016, 4, 23, 0, 0, 0, 0.0001) + assert_equal 0.0001.to_r / 1000000, time.sec_fraction + end + def test_beginning_of_day assert_equal Time.local(2005,2,4,0,0,0), Time.local(2005,2,4,10,10,10).beginning_of_day - with_env_tz 'US/Eastern' do - assert_equal Time.local(2006,4,2,0,0,0), Time.local(2006,4,2,10,10,10).beginning_of_day, 'start DST' - assert_equal Time.local(2006,10,29,0,0,0), Time.local(2006,10,29,10,10,10).beginning_of_day, 'ends DST' + with_env_tz "US/Eastern" do + assert_equal Time.local(2006,4,2,0,0,0), Time.local(2006,4,2,10,10,10).beginning_of_day, "start DST" + assert_equal Time.local(2006,10,29,0,0,0), Time.local(2006,10,29,10,10,10).beginning_of_day, "ends DST" end - with_env_tz 'NZ' do - assert_equal Time.local(2006,3,19,0,0,0), Time.local(2006,3,19,10,10,10).beginning_of_day, 'ends DST' - assert_equal Time.local(2006,10,1,0,0,0), Time.local(2006,10,1,10,10,10).beginning_of_day, 'start DST' + with_env_tz "NZ" do + assert_equal Time.local(2006,3,19,0,0,0), Time.local(2006,3,19,10,10,10).beginning_of_day, "ends DST" + assert_equal Time.local(2006,10,1,0,0,0), Time.local(2006,10,1,10,10,10).beginning_of_day, "start DST" end end def test_middle_of_day assert_equal Time.local(2005,2,4,12,0,0), Time.local(2005,2,4,10,10,10).middle_of_day - with_env_tz 'US/Eastern' do - assert_equal Time.local(2006,4,2,12,0,0), Time.local(2006,4,2,10,10,10).middle_of_day, 'start DST' - assert_equal Time.local(2006,10,29,12,0,0), Time.local(2006,10,29,10,10,10).middle_of_day, 'ends DST' + with_env_tz "US/Eastern" do + assert_equal Time.local(2006,4,2,12,0,0), Time.local(2006,4,2,10,10,10).middle_of_day, "start DST" + assert_equal Time.local(2006,10,29,12,0,0), Time.local(2006,10,29,10,10,10).middle_of_day, "ends DST" end - with_env_tz 'NZ' do - assert_equal Time.local(2006,3,19,12,0,0), Time.local(2006,3,19,10,10,10).middle_of_day, 'ends DST' - assert_equal Time.local(2006,10,1,12,0,0), Time.local(2006,10,1,10,10,10).middle_of_day, 'start DST' + with_env_tz "NZ" do + assert_equal Time.local(2006,3,19,12,0,0), Time.local(2006,3,19,10,10,10).middle_of_day, "ends DST" + assert_equal Time.local(2006,10,1,12,0,0), Time.local(2006,10,1,10,10,10).middle_of_day, "start DST" end end @@ -141,16 +155,16 @@ class TimeExtCalculationsTest < ActiveSupport::TestCase def test_end_of_day assert_equal Time.local(2007,8,12,23,59,59,Rational(999999999, 1000)), Time.local(2007,8,12,10,10,10).end_of_day - with_env_tz 'US/Eastern' do - assert_equal Time.local(2007,4,2,23,59,59,Rational(999999999, 1000)), Time.local(2007,4,2,10,10,10).end_of_day, 'start DST' - assert_equal Time.local(2007,10,29,23,59,59,Rational(999999999, 1000)), Time.local(2007,10,29,10,10,10).end_of_day, 'ends DST' + with_env_tz "US/Eastern" do + assert_equal Time.local(2007,4,2,23,59,59,Rational(999999999, 1000)), Time.local(2007,4,2,10,10,10).end_of_day, "start DST" + assert_equal Time.local(2007,10,29,23,59,59,Rational(999999999, 1000)), Time.local(2007,10,29,10,10,10).end_of_day, "ends DST" end - with_env_tz 'NZ' do - assert_equal Time.local(2006,3,19,23,59,59,Rational(999999999, 1000)), Time.local(2006,3,19,10,10,10).end_of_day, 'ends DST' - assert_equal Time.local(2006,10,1,23,59,59,Rational(999999999, 1000)), Time.local(2006,10,1,10,10,10).end_of_day, 'start DST' + with_env_tz "NZ" do + assert_equal Time.local(2006,3,19,23,59,59,Rational(999999999, 1000)), Time.local(2006,3,19,10,10,10).end_of_day, "ends DST" + assert_equal Time.local(2006,10,1,23,59,59,Rational(999999999, 1000)), Time.local(2006,10,1,10,10,10).end_of_day, "start DST" end - with_env_tz 'Asia/Yekaterinburg' do - assert_equal Time.local(2015, 2, 8, 23, 59, 59, Rational(999999999, 1000)), Time.new(2015, 2, 8, 8, 0, 0, '+05:00').end_of_day + with_env_tz "Asia/Yekaterinburg" do + assert_equal Time.local(2015, 2, 8, 23, 59, 59, Rational(999999999, 1000)), Time.new(2015, 2, 8, 8, 0, 0, "+05:00").end_of_day end end @@ -174,74 +188,74 @@ class TimeExtCalculationsTest < ActiveSupport::TestCase end def test_daylight_savings_time_crossings_backward_start - with_env_tz 'US/Eastern' do + with_env_tz "US/Eastern" do # dt: US: 2005 April 3rd 4:18am - assert_equal Time.local(2005,4,2,3,18,0), Time.local(2005,4,3,4,18,0).ago(24.hours), 'dt-24.hours=>st' - assert_equal Time.local(2005,4,2,3,18,0), Time.local(2005,4,3,4,18,0).ago(86400), 'dt-86400=>st' - assert_equal Time.local(2005,4,2,3,18,0), Time.local(2005,4,3,4,18,0).ago(86400.seconds), 'dt-86400.seconds=>st' + assert_equal Time.local(2005,4,2,3,18,0), Time.local(2005,4,3,4,18,0).ago(24.hours), "dt-24.hours=>st" + assert_equal Time.local(2005,4,2,3,18,0), Time.local(2005,4,3,4,18,0).ago(86400), "dt-86400=>st" + assert_equal Time.local(2005,4,2,3,18,0), Time.local(2005,4,3,4,18,0).ago(86400.seconds), "dt-86400.seconds=>st" - assert_equal Time.local(2005,4,1,4,18,0), Time.local(2005,4,2,4,18,0).ago(24.hours), 'st-24.hours=>st' - assert_equal Time.local(2005,4,1,4,18,0), Time.local(2005,4,2,4,18,0).ago(86400), 'st-86400=>st' - assert_equal Time.local(2005,4,1,4,18,0), Time.local(2005,4,2,4,18,0).ago(86400.seconds), 'st-86400.seconds=>st' + assert_equal Time.local(2005,4,1,4,18,0), Time.local(2005,4,2,4,18,0).ago(24.hours), "st-24.hours=>st" + assert_equal Time.local(2005,4,1,4,18,0), Time.local(2005,4,2,4,18,0).ago(86400), "st-86400=>st" + assert_equal Time.local(2005,4,1,4,18,0), Time.local(2005,4,2,4,18,0).ago(86400.seconds), "st-86400.seconds=>st" end - with_env_tz 'NZ' do + with_env_tz "NZ" do # dt: New Zealand: 2006 October 1st 4:18am - assert_equal Time.local(2006,9,30,3,18,0), Time.local(2006,10,1,4,18,0).ago(24.hours), 'dt-24.hours=>st' - assert_equal Time.local(2006,9,30,3,18,0), Time.local(2006,10,1,4,18,0).ago(86400), 'dt-86400=>st' - assert_equal Time.local(2006,9,30,3,18,0), Time.local(2006,10,1,4,18,0).ago(86400.seconds), 'dt-86400.seconds=>st' + assert_equal Time.local(2006,9,30,3,18,0), Time.local(2006,10,1,4,18,0).ago(24.hours), "dt-24.hours=>st" + assert_equal Time.local(2006,9,30,3,18,0), Time.local(2006,10,1,4,18,0).ago(86400), "dt-86400=>st" + assert_equal Time.local(2006,9,30,3,18,0), Time.local(2006,10,1,4,18,0).ago(86400.seconds), "dt-86400.seconds=>st" - assert_equal Time.local(2006,9,29,4,18,0), Time.local(2006,9,30,4,18,0).ago(24.hours), 'st-24.hours=>st' - assert_equal Time.local(2006,9,29,4,18,0), Time.local(2006,9,30,4,18,0).ago(86400), 'st-86400=>st' - assert_equal Time.local(2006,9,29,4,18,0), Time.local(2006,9,30,4,18,0).ago(86400.seconds), 'st-86400.seconds=>st' + assert_equal Time.local(2006,9,29,4,18,0), Time.local(2006,9,30,4,18,0).ago(24.hours), "st-24.hours=>st" + assert_equal Time.local(2006,9,29,4,18,0), Time.local(2006,9,30,4,18,0).ago(86400), "st-86400=>st" + assert_equal Time.local(2006,9,29,4,18,0), Time.local(2006,9,30,4,18,0).ago(86400.seconds), "st-86400.seconds=>st" end end def test_daylight_savings_time_crossings_backward_end - with_env_tz 'US/Eastern' do + with_env_tz "US/Eastern" do # st: US: 2005 October 30th 4:03am - assert_equal Time.local(2005,10,29,5,3), Time.local(2005,10,30,4,3,0).ago(24.hours), 'st-24.hours=>dt' - assert_equal Time.local(2005,10,29,5,3), Time.local(2005,10,30,4,3,0).ago(86400), 'st-86400=>dt' - assert_equal Time.local(2005,10,29,5,3), Time.local(2005,10,30,4,3,0).ago(86400.seconds), 'st-86400.seconds=>dt' + assert_equal Time.local(2005,10,29,5,3), Time.local(2005,10,30,4,3,0).ago(24.hours), "st-24.hours=>dt" + assert_equal Time.local(2005,10,29,5,3), Time.local(2005,10,30,4,3,0).ago(86400), "st-86400=>dt" + assert_equal Time.local(2005,10,29,5,3), Time.local(2005,10,30,4,3,0).ago(86400.seconds), "st-86400.seconds=>dt" - assert_equal Time.local(2005,10,28,4,3), Time.local(2005,10,29,4,3,0).ago(24.hours), 'dt-24.hours=>dt' - assert_equal Time.local(2005,10,28,4,3), Time.local(2005,10,29,4,3,0).ago(86400), 'dt-86400=>dt' - assert_equal Time.local(2005,10,28,4,3), Time.local(2005,10,29,4,3,0).ago(86400.seconds), 'dt-86400.seconds=>dt' + assert_equal Time.local(2005,10,28,4,3), Time.local(2005,10,29,4,3,0).ago(24.hours), "dt-24.hours=>dt" + assert_equal Time.local(2005,10,28,4,3), Time.local(2005,10,29,4,3,0).ago(86400), "dt-86400=>dt" + assert_equal Time.local(2005,10,28,4,3), Time.local(2005,10,29,4,3,0).ago(86400.seconds), "dt-86400.seconds=>dt" end - with_env_tz 'NZ' do + with_env_tz "NZ" do # st: New Zealand: 2006 March 19th 4:03am - assert_equal Time.local(2006,3,18,5,3), Time.local(2006,3,19,4,3,0).ago(24.hours), 'st-24.hours=>dt' - assert_equal Time.local(2006,3,18,5,3), Time.local(2006,3,19,4,3,0).ago(86400), 'st-86400=>dt' - assert_equal Time.local(2006,3,18,5,3), Time.local(2006,3,19,4,3,0).ago(86400.seconds), 'st-86400.seconds=>dt' + assert_equal Time.local(2006,3,18,5,3), Time.local(2006,3,19,4,3,0).ago(24.hours), "st-24.hours=>dt" + assert_equal Time.local(2006,3,18,5,3), Time.local(2006,3,19,4,3,0).ago(86400), "st-86400=>dt" + assert_equal Time.local(2006,3,18,5,3), Time.local(2006,3,19,4,3,0).ago(86400.seconds), "st-86400.seconds=>dt" - assert_equal Time.local(2006,3,17,4,3), Time.local(2006,3,18,4,3,0).ago(24.hours), 'dt-24.hours=>dt' - assert_equal Time.local(2006,3,17,4,3), Time.local(2006,3,18,4,3,0).ago(86400), 'dt-86400=>dt' - assert_equal Time.local(2006,3,17,4,3), Time.local(2006,3,18,4,3,0).ago(86400.seconds), 'dt-86400.seconds=>dt' + assert_equal Time.local(2006,3,17,4,3), Time.local(2006,3,18,4,3,0).ago(24.hours), "dt-24.hours=>dt" + assert_equal Time.local(2006,3,17,4,3), Time.local(2006,3,18,4,3,0).ago(86400), "dt-86400=>dt" + assert_equal Time.local(2006,3,17,4,3), Time.local(2006,3,18,4,3,0).ago(86400.seconds), "dt-86400.seconds=>dt" end end def test_daylight_savings_time_crossings_backward_start_1day - with_env_tz 'US/Eastern' do + with_env_tz "US/Eastern" do # dt: US: 2005 April 3rd 4:18am - assert_equal Time.local(2005,4,2,4,18,0), Time.local(2005,4,3,4,18,0).ago(1.day), 'dt-1.day=>st' - assert_equal Time.local(2005,4,1,4,18,0), Time.local(2005,4,2,4,18,0).ago(1.day), 'st-1.day=>st' + assert_equal Time.local(2005,4,2,4,18,0), Time.local(2005,4,3,4,18,0).ago(1.day), "dt-1.day=>st" + assert_equal Time.local(2005,4,1,4,18,0), Time.local(2005,4,2,4,18,0).ago(1.day), "st-1.day=>st" end - with_env_tz 'NZ' do + with_env_tz "NZ" do # dt: New Zealand: 2006 October 1st 4:18am - assert_equal Time.local(2006,9,30,4,18,0), Time.local(2006,10,1,4,18,0).ago(1.day), 'dt-1.day=>st' - assert_equal Time.local(2006,9,29,4,18,0), Time.local(2006,9,30,4,18,0).ago(1.day), 'st-1.day=>st' + assert_equal Time.local(2006,9,30,4,18,0), Time.local(2006,10,1,4,18,0).ago(1.day), "dt-1.day=>st" + assert_equal Time.local(2006,9,29,4,18,0), Time.local(2006,9,30,4,18,0).ago(1.day), "st-1.day=>st" end end def test_daylight_savings_time_crossings_backward_end_1day - with_env_tz 'US/Eastern' do + with_env_tz "US/Eastern" do # st: US: 2005 October 30th 4:03am - assert_equal Time.local(2005,10,29,4,3), Time.local(2005,10,30,4,3,0).ago(1.day), 'st-1.day=>dt' - assert_equal Time.local(2005,10,28,4,3), Time.local(2005,10,29,4,3,0).ago(1.day), 'dt-1.day=>dt' + assert_equal Time.local(2005,10,29,4,3), Time.local(2005,10,30,4,3,0).ago(1.day), "st-1.day=>dt" + assert_equal Time.local(2005,10,28,4,3), Time.local(2005,10,29,4,3,0).ago(1.day), "dt-1.day=>dt" end - with_env_tz 'NZ' do + with_env_tz "NZ" do # st: New Zealand: 2006 March 19th 4:03am - assert_equal Time.local(2006,3,18,4,3), Time.local(2006,3,19,4,3,0).ago(1.day), 'st-1.day=>dt' - assert_equal Time.local(2006,3,17,4,3), Time.local(2006,3,18,4,3,0).ago(1.day), 'dt-1.day=>dt' + assert_equal Time.local(2006,3,18,4,3), Time.local(2006,3,19,4,3,0).ago(1.day), "st-1.day=>dt" + assert_equal Time.local(2006,3,17,4,3), Time.local(2006,3,18,4,3,0).ago(1.day), "dt-1.day=>dt" end end @@ -255,250 +269,250 @@ class TimeExtCalculationsTest < ActiveSupport::TestCase end def test_daylight_savings_time_crossings_forward_start - with_env_tz 'US/Eastern' do + with_env_tz "US/Eastern" do # st: US: 2005 April 2nd 7:27pm - assert_equal Time.local(2005,4,3,20,27,0), Time.local(2005,4,2,19,27,0).since(24.hours), 'st+24.hours=>dt' - assert_equal Time.local(2005,4,3,20,27,0), Time.local(2005,4,2,19,27,0).since(86400), 'st+86400=>dt' - assert_equal Time.local(2005,4,3,20,27,0), Time.local(2005,4,2,19,27,0).since(86400.seconds), 'st+86400.seconds=>dt' + assert_equal Time.local(2005,4,3,20,27,0), Time.local(2005,4,2,19,27,0).since(24.hours), "st+24.hours=>dt" + assert_equal Time.local(2005,4,3,20,27,0), Time.local(2005,4,2,19,27,0).since(86400), "st+86400=>dt" + assert_equal Time.local(2005,4,3,20,27,0), Time.local(2005,4,2,19,27,0).since(86400.seconds), "st+86400.seconds=>dt" - assert_equal Time.local(2005,4,4,19,27,0), Time.local(2005,4,3,19,27,0).since(24.hours), 'dt+24.hours=>dt' - assert_equal Time.local(2005,4,4,19,27,0), Time.local(2005,4,3,19,27,0).since(86400), 'dt+86400=>dt' - assert_equal Time.local(2005,4,4,19,27,0), Time.local(2005,4,3,19,27,0).since(86400.seconds), 'dt+86400.seconds=>dt' + assert_equal Time.local(2005,4,4,19,27,0), Time.local(2005,4,3,19,27,0).since(24.hours), "dt+24.hours=>dt" + assert_equal Time.local(2005,4,4,19,27,0), Time.local(2005,4,3,19,27,0).since(86400), "dt+86400=>dt" + assert_equal Time.local(2005,4,4,19,27,0), Time.local(2005,4,3,19,27,0).since(86400.seconds), "dt+86400.seconds=>dt" end - with_env_tz 'NZ' do + with_env_tz "NZ" do # st: New Zealand: 2006 September 30th 7:27pm - assert_equal Time.local(2006,10,1,20,27,0), Time.local(2006,9,30,19,27,0).since(24.hours), 'st+24.hours=>dt' - assert_equal Time.local(2006,10,1,20,27,0), Time.local(2006,9,30,19,27,0).since(86400), 'st+86400=>dt' - assert_equal Time.local(2006,10,1,20,27,0), Time.local(2006,9,30,19,27,0).since(86400.seconds), 'st+86400.seconds=>dt' + assert_equal Time.local(2006,10,1,20,27,0), Time.local(2006,9,30,19,27,0).since(24.hours), "st+24.hours=>dt" + assert_equal Time.local(2006,10,1,20,27,0), Time.local(2006,9,30,19,27,0).since(86400), "st+86400=>dt" + assert_equal Time.local(2006,10,1,20,27,0), Time.local(2006,9,30,19,27,0).since(86400.seconds), "st+86400.seconds=>dt" - assert_equal Time.local(2006,10,2,19,27,0), Time.local(2006,10,1,19,27,0).since(24.hours), 'dt+24.hours=>dt' - assert_equal Time.local(2006,10,2,19,27,0), Time.local(2006,10,1,19,27,0).since(86400), 'dt+86400=>dt' - assert_equal Time.local(2006,10,2,19,27,0), Time.local(2006,10,1,19,27,0).since(86400.seconds), 'dt+86400.seconds=>dt' + assert_equal Time.local(2006,10,2,19,27,0), Time.local(2006,10,1,19,27,0).since(24.hours), "dt+24.hours=>dt" + assert_equal Time.local(2006,10,2,19,27,0), Time.local(2006,10,1,19,27,0).since(86400), "dt+86400=>dt" + assert_equal Time.local(2006,10,2,19,27,0), Time.local(2006,10,1,19,27,0).since(86400.seconds), "dt+86400.seconds=>dt" end end def test_daylight_savings_time_crossings_forward_start_1day - with_env_tz 'US/Eastern' do + with_env_tz "US/Eastern" do # st: US: 2005 April 2nd 7:27pm - assert_equal Time.local(2005,4,3,19,27,0), Time.local(2005,4,2,19,27,0).since(1.day), 'st+1.day=>dt' - assert_equal Time.local(2005,4,4,19,27,0), Time.local(2005,4,3,19,27,0).since(1.day), 'dt+1.day=>dt' + assert_equal Time.local(2005,4,3,19,27,0), Time.local(2005,4,2,19,27,0).since(1.day), "st+1.day=>dt" + assert_equal Time.local(2005,4,4,19,27,0), Time.local(2005,4,3,19,27,0).since(1.day), "dt+1.day=>dt" end - with_env_tz 'NZ' do + with_env_tz "NZ" do # st: New Zealand: 2006 September 30th 7:27pm - assert_equal Time.local(2006,10,1,19,27,0), Time.local(2006,9,30,19,27,0).since(1.day), 'st+1.day=>dt' - assert_equal Time.local(2006,10,2,19,27,0), Time.local(2006,10,1,19,27,0).since(1.day), 'dt+1.day=>dt' + assert_equal Time.local(2006,10,1,19,27,0), Time.local(2006,9,30,19,27,0).since(1.day), "st+1.day=>dt" + assert_equal Time.local(2006,10,2,19,27,0), Time.local(2006,10,1,19,27,0).since(1.day), "dt+1.day=>dt" end end def test_daylight_savings_time_crossings_forward_start_tomorrow - with_env_tz 'US/Eastern' do + with_env_tz "US/Eastern" do # st: US: 2005 April 2nd 7:27pm - assert_equal Time.local(2005,4,3,19,27,0), Time.local(2005,4,2,19,27,0).tomorrow, 'st+1.day=>dt' - assert_equal Time.local(2005,4,4,19,27,0), Time.local(2005,4,3,19,27,0).tomorrow, 'dt+1.day=>dt' + assert_equal Time.local(2005,4,3,19,27,0), Time.local(2005,4,2,19,27,0).tomorrow, "st+1.day=>dt" + assert_equal Time.local(2005,4,4,19,27,0), Time.local(2005,4,3,19,27,0).tomorrow, "dt+1.day=>dt" end - with_env_tz 'NZ' do + with_env_tz "NZ" do # st: New Zealand: 2006 September 30th 7:27pm - assert_equal Time.local(2006,10,1,19,27,0), Time.local(2006,9,30,19,27,0).tomorrow, 'st+1.day=>dt' - assert_equal Time.local(2006,10,2,19,27,0), Time.local(2006,10,1,19,27,0).tomorrow, 'dt+1.day=>dt' + assert_equal Time.local(2006,10,1,19,27,0), Time.local(2006,9,30,19,27,0).tomorrow, "st+1.day=>dt" + assert_equal Time.local(2006,10,2,19,27,0), Time.local(2006,10,1,19,27,0).tomorrow, "dt+1.day=>dt" end end def test_daylight_savings_time_crossings_backward_start_yesterday - with_env_tz 'US/Eastern' do + with_env_tz "US/Eastern" do # st: US: 2005 April 2nd 7:27pm - assert_equal Time.local(2005,4,2,19,27,0), Time.local(2005,4,3,19,27,0).yesterday, 'dt-1.day=>st' - assert_equal Time.local(2005,4,3,19,27,0), Time.local(2005,4,4,19,27,0).yesterday, 'dt-1.day=>dt' + assert_equal Time.local(2005,4,2,19,27,0), Time.local(2005,4,3,19,27,0).yesterday, "dt-1.day=>st" + assert_equal Time.local(2005,4,3,19,27,0), Time.local(2005,4,4,19,27,0).yesterday, "dt-1.day=>dt" end - with_env_tz 'NZ' do + with_env_tz "NZ" do # st: New Zealand: 2006 September 30th 7:27pm - assert_equal Time.local(2006,9,30,19,27,0), Time.local(2006,10,1,19,27,0).yesterday, 'dt-1.day=>st' - assert_equal Time.local(2006,10,1,19,27,0), Time.local(2006,10,2,19,27,0).yesterday, 'dt-1.day=>dt' + assert_equal Time.local(2006,9,30,19,27,0), Time.local(2006,10,1,19,27,0).yesterday, "dt-1.day=>st" + assert_equal Time.local(2006,10,1,19,27,0), Time.local(2006,10,2,19,27,0).yesterday, "dt-1.day=>dt" end end def test_daylight_savings_time_crossings_forward_end - with_env_tz 'US/Eastern' do + with_env_tz "US/Eastern" do # dt: US: 2005 October 30th 12:45am - assert_equal Time.local(2005,10,30,23,45,0), Time.local(2005,10,30,0,45,0).since(24.hours), 'dt+24.hours=>st' - assert_equal Time.local(2005,10,30,23,45,0), Time.local(2005,10,30,0,45,0).since(86400), 'dt+86400=>st' - assert_equal Time.local(2005,10,30,23,45,0), Time.local(2005,10,30,0,45,0).since(86400.seconds), 'dt+86400.seconds=>st' + assert_equal Time.local(2005,10,30,23,45,0), Time.local(2005,10,30,0,45,0).since(24.hours), "dt+24.hours=>st" + assert_equal Time.local(2005,10,30,23,45,0), Time.local(2005,10,30,0,45,0).since(86400), "dt+86400=>st" + assert_equal Time.local(2005,10,30,23,45,0), Time.local(2005,10,30,0,45,0).since(86400.seconds), "dt+86400.seconds=>st" - assert_equal Time.local(2005,11, 1,0,45,0), Time.local(2005,10,31,0,45,0).since(24.hours), 'st+24.hours=>st' - assert_equal Time.local(2005,11, 1,0,45,0), Time.local(2005,10,31,0,45,0).since(86400), 'st+86400=>st' - assert_equal Time.local(2005,11, 1,0,45,0), Time.local(2005,10,31,0,45,0).since(86400.seconds), 'st+86400.seconds=>st' + assert_equal Time.local(2005,11, 1,0,45,0), Time.local(2005,10,31,0,45,0).since(24.hours), "st+24.hours=>st" + assert_equal Time.local(2005,11, 1,0,45,0), Time.local(2005,10,31,0,45,0).since(86400), "st+86400=>st" + assert_equal Time.local(2005,11, 1,0,45,0), Time.local(2005,10,31,0,45,0).since(86400.seconds), "st+86400.seconds=>st" end - with_env_tz 'NZ' do + with_env_tz "NZ" do # dt: New Zealand: 2006 March 19th 1:45am - assert_equal Time.local(2006,3,20,0,45,0), Time.local(2006,3,19,1,45,0).since(24.hours), 'dt+24.hours=>st' - assert_equal Time.local(2006,3,20,0,45,0), Time.local(2006,3,19,1,45,0).since(86400), 'dt+86400=>st' - assert_equal Time.local(2006,3,20,0,45,0), Time.local(2006,3,19,1,45,0).since(86400.seconds), 'dt+86400.seconds=>st' + assert_equal Time.local(2006,3,20,0,45,0), Time.local(2006,3,19,1,45,0).since(24.hours), "dt+24.hours=>st" + assert_equal Time.local(2006,3,20,0,45,0), Time.local(2006,3,19,1,45,0).since(86400), "dt+86400=>st" + assert_equal Time.local(2006,3,20,0,45,0), Time.local(2006,3,19,1,45,0).since(86400.seconds), "dt+86400.seconds=>st" - assert_equal Time.local(2006,3,21,1,45,0), Time.local(2006,3,20,1,45,0).since(24.hours), 'st+24.hours=>st' - assert_equal Time.local(2006,3,21,1,45,0), Time.local(2006,3,20,1,45,0).since(86400), 'st+86400=>st' - assert_equal Time.local(2006,3,21,1,45,0), Time.local(2006,3,20,1,45,0).since(86400.seconds), 'st+86400.seconds=>st' + assert_equal Time.local(2006,3,21,1,45,0), Time.local(2006,3,20,1,45,0).since(24.hours), "st+24.hours=>st" + assert_equal Time.local(2006,3,21,1,45,0), Time.local(2006,3,20,1,45,0).since(86400), "st+86400=>st" + assert_equal Time.local(2006,3,21,1,45,0), Time.local(2006,3,20,1,45,0).since(86400.seconds), "st+86400.seconds=>st" end end def test_daylight_savings_time_crossings_forward_end_1day - with_env_tz 'US/Eastern' do + with_env_tz "US/Eastern" do # dt: US: 2005 October 30th 12:45am - assert_equal Time.local(2005,10,31,0,45,0), Time.local(2005,10,30,0,45,0).since(1.day), 'dt+1.day=>st' - assert_equal Time.local(2005,11, 1,0,45,0), Time.local(2005,10,31,0,45,0).since(1.day), 'st+1.day=>st' + assert_equal Time.local(2005,10,31,0,45,0), Time.local(2005,10,30,0,45,0).since(1.day), "dt+1.day=>st" + assert_equal Time.local(2005,11, 1,0,45,0), Time.local(2005,10,31,0,45,0).since(1.day), "st+1.day=>st" end - with_env_tz 'NZ' do + with_env_tz "NZ" do # dt: New Zealand: 2006 March 19th 1:45am - assert_equal Time.local(2006,3,20,1,45,0), Time.local(2006,3,19,1,45,0).since(1.day), 'dt+1.day=>st' - assert_equal Time.local(2006,3,21,1,45,0), Time.local(2006,3,20,1,45,0).since(1.day), 'st+1.day=>st' + assert_equal Time.local(2006,3,20,1,45,0), Time.local(2006,3,19,1,45,0).since(1.day), "dt+1.day=>st" + assert_equal Time.local(2006,3,21,1,45,0), Time.local(2006,3,20,1,45,0).since(1.day), "st+1.day=>st" end end def test_daylight_savings_time_crossings_forward_end_tomorrow - with_env_tz 'US/Eastern' do + with_env_tz "US/Eastern" do # dt: US: 2005 October 30th 12:45am - assert_equal Time.local(2005,10,31,0,45,0), Time.local(2005,10,30,0,45,0).tomorrow, 'dt+1.day=>st' - assert_equal Time.local(2005,11, 1,0,45,0), Time.local(2005,10,31,0,45,0).tomorrow, 'st+1.day=>st' + assert_equal Time.local(2005,10,31,0,45,0), Time.local(2005,10,30,0,45,0).tomorrow, "dt+1.day=>st" + assert_equal Time.local(2005,11, 1,0,45,0), Time.local(2005,10,31,0,45,0).tomorrow, "st+1.day=>st" end - with_env_tz 'NZ' do + with_env_tz "NZ" do # dt: New Zealand: 2006 March 19th 1:45am - assert_equal Time.local(2006,3,20,1,45,0), Time.local(2006,3,19,1,45,0).tomorrow, 'dt+1.day=>st' - assert_equal Time.local(2006,3,21,1,45,0), Time.local(2006,3,20,1,45,0).tomorrow, 'st+1.day=>st' + assert_equal Time.local(2006,3,20,1,45,0), Time.local(2006,3,19,1,45,0).tomorrow, "dt+1.day=>st" + assert_equal Time.local(2006,3,21,1,45,0), Time.local(2006,3,20,1,45,0).tomorrow, "st+1.day=>st" end end def test_daylight_savings_time_crossings_backward_end_yesterday - with_env_tz 'US/Eastern' do + with_env_tz "US/Eastern" do # dt: US: 2005 October 30th 12:45am - assert_equal Time.local(2005,10,30,0,45,0), Time.local(2005,10,31,0,45,0).yesterday, 'st-1.day=>dt' - assert_equal Time.local(2005,10, 31,0,45,0), Time.local(2005,11,1,0,45,0).yesterday, 'st-1.day=>st' + assert_equal Time.local(2005,10,30,0,45,0), Time.local(2005,10,31,0,45,0).yesterday, "st-1.day=>dt" + assert_equal Time.local(2005,10, 31,0,45,0), Time.local(2005,11,1,0,45,0).yesterday, "st-1.day=>st" end - with_env_tz 'NZ' do + with_env_tz "NZ" do # dt: New Zealand: 2006 March 19th 1:45am - assert_equal Time.local(2006,3,19,1,45,0), Time.local(2006,3,20,1,45,0).yesterday, 'st-1.day=>dt' - assert_equal Time.local(2006,3,20,1,45,0), Time.local(2006,3,21,1,45,0).yesterday, 'st-1.day=>st' + assert_equal Time.local(2006,3,19,1,45,0), Time.local(2006,3,20,1,45,0).yesterday, "st-1.day=>dt" + assert_equal Time.local(2006,3,20,1,45,0), Time.local(2006,3,21,1,45,0).yesterday, "st-1.day=>st" end end def test_change - assert_equal Time.local(2006,2,22,15,15,10), Time.local(2005,2,22,15,15,10).change(:year => 2006) - assert_equal Time.local(2005,6,22,15,15,10), Time.local(2005,2,22,15,15,10).change(:month => 6) - assert_equal Time.local(2012,9,22,15,15,10), Time.local(2005,2,22,15,15,10).change(:year => 2012, :month => 9) - assert_equal Time.local(2005,2,22,16), Time.local(2005,2,22,15,15,10).change(:hour => 16) - assert_equal Time.local(2005,2,22,16,45), Time.local(2005,2,22,15,15,10).change(:hour => 16, :min => 45) - assert_equal Time.local(2005,2,22,15,45), Time.local(2005,2,22,15,15,10).change(:min => 45) - - assert_equal Time.local(2005,1,2, 5, 0, 0, 0), Time.local(2005,1,2,11,22,33,44).change(:hour => 5) - assert_equal Time.local(2005,1,2,11, 6, 0, 0), Time.local(2005,1,2,11,22,33,44).change(:min => 6) - assert_equal Time.local(2005,1,2,11,22, 7, 0), Time.local(2005,1,2,11,22,33,44).change(:sec => 7) - assert_equal Time.local(2005,1,2,11,22,33, 8), Time.local(2005,1,2,11,22,33,44).change(:usec => 8) - assert_equal Time.local(2005,1,2,11,22,33, 8), Time.local(2005,1,2,11,22,33,2).change(:nsec => 8000) - assert_raise(ArgumentError) { Time.local(2005,1,2,11,22,33, 8).change(:usec => 1, :nsec => 1) } - assert_nothing_raised(ArgumentError) { Time.new(2015, 5, 9, 10, 00, 00, '+03:00').change(nsec: 999999999) } + assert_equal Time.local(2006,2,22,15,15,10), Time.local(2005,2,22,15,15,10).change(year: 2006) + assert_equal Time.local(2005,6,22,15,15,10), Time.local(2005,2,22,15,15,10).change(month: 6) + assert_equal Time.local(2012,9,22,15,15,10), Time.local(2005,2,22,15,15,10).change(year: 2012, month: 9) + assert_equal Time.local(2005,2,22,16), Time.local(2005,2,22,15,15,10).change(hour: 16) + assert_equal Time.local(2005,2,22,16,45), Time.local(2005,2,22,15,15,10).change(hour: 16, min: 45) + assert_equal Time.local(2005,2,22,15,45), Time.local(2005,2,22,15,15,10).change(min: 45) + + assert_equal Time.local(2005,1,2, 5, 0, 0, 0), Time.local(2005,1,2,11,22,33,44).change(hour: 5) + assert_equal Time.local(2005,1,2,11, 6, 0, 0), Time.local(2005,1,2,11,22,33,44).change(min: 6) + assert_equal Time.local(2005,1,2,11,22, 7, 0), Time.local(2005,1,2,11,22,33,44).change(sec: 7) + assert_equal Time.local(2005,1,2,11,22,33, 8), Time.local(2005,1,2,11,22,33,44).change(usec: 8) + assert_equal Time.local(2005,1,2,11,22,33, 8), Time.local(2005,1,2,11,22,33,2).change(nsec: 8000) + assert_raise(ArgumentError) { Time.local(2005,1,2,11,22,33, 8).change(usec: 1, nsec: 1) } + assert_nothing_raised { Time.new(2015, 5, 9, 10, 00, 00, "+03:00").change(nsec: 999999999) } end def test_utc_change - assert_equal Time.utc(2006,2,22,15,15,10), Time.utc(2005,2,22,15,15,10).change(:year => 2006) - assert_equal Time.utc(2005,6,22,15,15,10), Time.utc(2005,2,22,15,15,10).change(:month => 6) - assert_equal Time.utc(2012,9,22,15,15,10), Time.utc(2005,2,22,15,15,10).change(:year => 2012, :month => 9) - assert_equal Time.utc(2005,2,22,16), Time.utc(2005,2,22,15,15,10).change(:hour => 16) - assert_equal Time.utc(2005,2,22,16,45), Time.utc(2005,2,22,15,15,10).change(:hour => 16, :min => 45) - assert_equal Time.utc(2005,2,22,15,45), Time.utc(2005,2,22,15,15,10).change(:min => 45) - assert_equal Time.utc(2005,1,2,11,22,33,8), Time.utc(2005,1,2,11,22,33,2).change(:nsec => 8000) + assert_equal Time.utc(2006,2,22,15,15,10), Time.utc(2005,2,22,15,15,10).change(year: 2006) + assert_equal Time.utc(2005,6,22,15,15,10), Time.utc(2005,2,22,15,15,10).change(month: 6) + assert_equal Time.utc(2012,9,22,15,15,10), Time.utc(2005,2,22,15,15,10).change(year: 2012, month: 9) + assert_equal Time.utc(2005,2,22,16), Time.utc(2005,2,22,15,15,10).change(hour: 16) + assert_equal Time.utc(2005,2,22,16,45), Time.utc(2005,2,22,15,15,10).change(hour: 16, min: 45) + assert_equal Time.utc(2005,2,22,15,45), Time.utc(2005,2,22,15,15,10).change(min: 45) + assert_equal Time.utc(2005,1,2,11,22,33,8), Time.utc(2005,1,2,11,22,33,2).change(nsec: 8000) end def test_offset_change - assert_equal Time.new(2006,2,22,15,15,10,"-08:00"), Time.new(2005,2,22,15,15,10,"-08:00").change(:year => 2006) - assert_equal Time.new(2005,6,22,15,15,10,"-08:00"), Time.new(2005,2,22,15,15,10,"-08:00").change(:month => 6) - assert_equal Time.new(2012,9,22,15,15,10,"-08:00"), Time.new(2005,2,22,15,15,10,"-08:00").change(:year => 2012, :month => 9) - assert_equal Time.new(2005,2,22,16,0,0,"-08:00"), Time.new(2005,2,22,15,15,10,"-08:00").change(:hour => 16) - assert_equal Time.new(2005,2,22,16,45,0,"-08:00"), Time.new(2005,2,22,15,15,10,"-08:00").change(:hour => 16, :min => 45) - assert_equal Time.new(2005,2,22,15,45,0,"-08:00"), Time.new(2005,2,22,15,15,10,"-08:00").change(:min => 45) - assert_equal Time.new(2005,2,22,15,15,10,"-08:00"), Time.new(2005,2,22,15,15,0,"-08:00").change(:sec => 10) - assert_equal 10, Time.new(2005,2,22,15,15,0,"-08:00").change(:usec => 10).usec - assert_equal 10, Time.new(2005,2,22,15,15,0,"-08:00").change(:nsec => 10).nsec - assert_raise(ArgumentError) { Time.new(2005, 2, 22, 15, 15, 45, "-08:00").change(:usec => 1000000) } - assert_raise(ArgumentError) { Time.new(2005, 2, 22, 15, 15, 45, "-08:00").change(:nsec => 1000000000) } + assert_equal Time.new(2006,2,22,15,15,10,"-08:00"), Time.new(2005,2,22,15,15,10,"-08:00").change(year: 2006) + assert_equal Time.new(2005,6,22,15,15,10,"-08:00"), Time.new(2005,2,22,15,15,10,"-08:00").change(month: 6) + assert_equal Time.new(2012,9,22,15,15,10,"-08:00"), Time.new(2005,2,22,15,15,10,"-08:00").change(year: 2012, month: 9) + assert_equal Time.new(2005,2,22,16,0,0,"-08:00"), Time.new(2005,2,22,15,15,10,"-08:00").change(hour: 16) + assert_equal Time.new(2005,2,22,16,45,0,"-08:00"), Time.new(2005,2,22,15,15,10,"-08:00").change(hour: 16, min: 45) + assert_equal Time.new(2005,2,22,15,45,0,"-08:00"), Time.new(2005,2,22,15,15,10,"-08:00").change(min: 45) + assert_equal Time.new(2005,2,22,15,15,10,"-08:00"), Time.new(2005,2,22,15,15,0,"-08:00").change(sec: 10) + assert_equal 10, Time.new(2005,2,22,15,15,0,"-08:00").change(usec: 10).usec + assert_equal 10, Time.new(2005,2,22,15,15,0,"-08:00").change(nsec: 10).nsec + assert_raise(ArgumentError) { Time.new(2005, 2, 22, 15, 15, 45, "-08:00").change(usec: 1000000) } + assert_raise(ArgumentError) { Time.new(2005, 2, 22, 15, 15, 45, "-08:00").change(nsec: 1000000000) } end def test_advance - assert_equal Time.local(2006,2,28,15,15,10), Time.local(2005,2,28,15,15,10).advance(:years => 1) - assert_equal Time.local(2005,6,28,15,15,10), Time.local(2005,2,28,15,15,10).advance(:months => 4) - assert_equal Time.local(2005,3,21,15,15,10), Time.local(2005,2,28,15,15,10).advance(:weeks => 3) - assert_equal Time.local(2005,3,25,3,15,10), Time.local(2005,2,28,15,15,10).advance(:weeks => 3.5) - assert_in_delta Time.local(2005,3,26,12,51,10), Time.local(2005,2,28,15,15,10).advance(:weeks => 3.7), 1 - assert_equal Time.local(2005,3,5,15,15,10), Time.local(2005,2,28,15,15,10).advance(:days => 5) - assert_equal Time.local(2005,3,6,3,15,10), Time.local(2005,2,28,15,15,10).advance(:days => 5.5) - assert_in_delta Time.local(2005,3,6,8,3,10), Time.local(2005,2,28,15,15,10).advance(:days => 5.7), 1 - assert_equal Time.local(2012,9,28,15,15,10), Time.local(2005,2,28,15,15,10).advance(:years => 7, :months => 7) - assert_equal Time.local(2013,10,3,15,15,10), Time.local(2005,2,28,15,15,10).advance(:years => 7, :months => 19, :days => 5) - assert_equal Time.local(2013,10,17,15,15,10), Time.local(2005,2,28,15,15,10).advance(:years => 7, :months => 19, :weeks => 2, :days => 5) - assert_equal Time.local(2001,12,27,15,15,10), Time.local(2005,2,28,15,15,10).advance(:years => -3, :months => -2, :days => -1) - assert_equal Time.local(2005,2,28,15,15,10), Time.local(2004,2,29,15,15,10).advance(:years => 1) #leap day plus one year - assert_equal Time.local(2005,2,28,20,15,10), Time.local(2005,2,28,15,15,10).advance(:hours => 5) - assert_equal Time.local(2005,2,28,15,22,10), Time.local(2005,2,28,15,15,10).advance(:minutes => 7) - assert_equal Time.local(2005,2,28,15,15,19), Time.local(2005,2,28,15,15,10).advance(:seconds => 9) - assert_equal Time.local(2005,2,28,20,22,19), Time.local(2005,2,28,15,15,10).advance(:hours => 5, :minutes => 7, :seconds => 9) - assert_equal Time.local(2005,2,28,10,8,1), Time.local(2005,2,28,15,15,10).advance(:hours => -5, :minutes => -7, :seconds => -9) - assert_equal Time.local(2013,10,17,20,22,19), Time.local(2005,2,28,15,15,10).advance(:years => 7, :months => 19, :weeks => 2, :days => 5, :hours => 5, :minutes => 7, :seconds => 9) + assert_equal Time.local(2006,2,28,15,15,10), Time.local(2005,2,28,15,15,10).advance(years: 1) + assert_equal Time.local(2005,6,28,15,15,10), Time.local(2005,2,28,15,15,10).advance(months: 4) + assert_equal Time.local(2005,3,21,15,15,10), Time.local(2005,2,28,15,15,10).advance(weeks: 3) + assert_equal Time.local(2005,3,25,3,15,10), Time.local(2005,2,28,15,15,10).advance(weeks: 3.5) + assert_in_delta Time.local(2005,3,26,12,51,10), Time.local(2005,2,28,15,15,10).advance(weeks: 3.7), 1 + assert_equal Time.local(2005,3,5,15,15,10), Time.local(2005,2,28,15,15,10).advance(days: 5) + assert_equal Time.local(2005,3,6,3,15,10), Time.local(2005,2,28,15,15,10).advance(days: 5.5) + assert_in_delta Time.local(2005,3,6,8,3,10), Time.local(2005,2,28,15,15,10).advance(days: 5.7), 1 + assert_equal Time.local(2012,9,28,15,15,10), Time.local(2005,2,28,15,15,10).advance(years: 7, months: 7) + assert_equal Time.local(2013,10,3,15,15,10), Time.local(2005,2,28,15,15,10).advance(years: 7, months: 19, days: 5) + assert_equal Time.local(2013,10,17,15,15,10), Time.local(2005,2,28,15,15,10).advance(years: 7, months: 19, weeks: 2, days: 5) + assert_equal Time.local(2001,12,27,15,15,10), Time.local(2005,2,28,15,15,10).advance(years: -3, months: -2, days: -1) + assert_equal Time.local(2005,2,28,15,15,10), Time.local(2004,2,29,15,15,10).advance(years: 1) #leap day plus one year + assert_equal Time.local(2005,2,28,20,15,10), Time.local(2005,2,28,15,15,10).advance(hours: 5) + assert_equal Time.local(2005,2,28,15,22,10), Time.local(2005,2,28,15,15,10).advance(minutes: 7) + assert_equal Time.local(2005,2,28,15,15,19), Time.local(2005,2,28,15,15,10).advance(seconds: 9) + assert_equal Time.local(2005,2,28,20,22,19), Time.local(2005,2,28,15,15,10).advance(hours: 5, minutes: 7, seconds: 9) + assert_equal Time.local(2005,2,28,10,8,1), Time.local(2005,2,28,15,15,10).advance(hours: -5, minutes: -7, seconds: -9) + assert_equal Time.local(2013,10,17,20,22,19), Time.local(2005,2,28,15,15,10).advance(years: 7, months: 19, weeks: 2, days: 5, hours: 5, minutes: 7, seconds: 9) end def test_utc_advance - assert_equal Time.utc(2006,2,22,15,15,10), Time.utc(2005,2,22,15,15,10).advance(:years => 1) - assert_equal Time.utc(2005,6,22,15,15,10), Time.utc(2005,2,22,15,15,10).advance(:months => 4) - assert_equal Time.utc(2005,3,21,15,15,10), Time.utc(2005,2,28,15,15,10).advance(:weeks => 3) - assert_equal Time.utc(2005,3,25,3,15,10), Time.utc(2005,2,28,15,15,10).advance(:weeks => 3.5) - assert_in_delta Time.utc(2005,3,26,12,51,10), Time.utc(2005,2,28,15,15,10).advance(:weeks => 3.7), 1 - assert_equal Time.utc(2005,3,5,15,15,10), Time.utc(2005,2,28,15,15,10).advance(:days => 5) - assert_equal Time.utc(2005,3,6,3,15,10), Time.utc(2005,2,28,15,15,10).advance(:days => 5.5) - assert_in_delta Time.utc(2005,3,6,8,3,10), Time.utc(2005,2,28,15,15,10).advance(:days => 5.7), 1 - assert_equal Time.utc(2012,9,22,15,15,10), Time.utc(2005,2,22,15,15,10).advance(:years => 7, :months => 7) - assert_equal Time.utc(2013,10,3,15,15,10), Time.utc(2005,2,22,15,15,10).advance(:years => 7, :months => 19, :days => 11) - assert_equal Time.utc(2013,10,17,15,15,10), Time.utc(2005,2,28,15,15,10).advance(:years => 7, :months => 19, :weeks => 2, :days => 5) - assert_equal Time.utc(2001,12,27,15,15,10), Time.utc(2005,2,28,15,15,10).advance(:years => -3, :months => -2, :days => -1) - assert_equal Time.utc(2005,2,28,15,15,10), Time.utc(2004,2,29,15,15,10).advance(:years => 1) #leap day plus one year - assert_equal Time.utc(2005,2,28,20,15,10), Time.utc(2005,2,28,15,15,10).advance(:hours => 5) - assert_equal Time.utc(2005,2,28,15,22,10), Time.utc(2005,2,28,15,15,10).advance(:minutes => 7) - assert_equal Time.utc(2005,2,28,15,15,19), Time.utc(2005,2,28,15,15,10).advance(:seconds => 9) - assert_equal Time.utc(2005,2,28,20,22,19), Time.utc(2005,2,28,15,15,10).advance(:hours => 5, :minutes => 7, :seconds => 9) - assert_equal Time.utc(2005,2,28,10,8,1), Time.utc(2005,2,28,15,15,10).advance(:hours => -5, :minutes => -7, :seconds => -9) - assert_equal Time.utc(2013,10,17,20,22,19), Time.utc(2005,2,28,15,15,10).advance(:years => 7, :months => 19, :weeks => 2, :days => 5, :hours => 5, :minutes => 7, :seconds => 9) + assert_equal Time.utc(2006,2,22,15,15,10), Time.utc(2005,2,22,15,15,10).advance(years: 1) + assert_equal Time.utc(2005,6,22,15,15,10), Time.utc(2005,2,22,15,15,10).advance(months: 4) + assert_equal Time.utc(2005,3,21,15,15,10), Time.utc(2005,2,28,15,15,10).advance(weeks: 3) + assert_equal Time.utc(2005,3,25,3,15,10), Time.utc(2005,2,28,15,15,10).advance(weeks: 3.5) + assert_in_delta Time.utc(2005,3,26,12,51,10), Time.utc(2005,2,28,15,15,10).advance(weeks: 3.7), 1 + assert_equal Time.utc(2005,3,5,15,15,10), Time.utc(2005,2,28,15,15,10).advance(days: 5) + assert_equal Time.utc(2005,3,6,3,15,10), Time.utc(2005,2,28,15,15,10).advance(days: 5.5) + assert_in_delta Time.utc(2005,3,6,8,3,10), Time.utc(2005,2,28,15,15,10).advance(days: 5.7), 1 + assert_equal Time.utc(2012,9,22,15,15,10), Time.utc(2005,2,22,15,15,10).advance(years: 7, months: 7) + assert_equal Time.utc(2013,10,3,15,15,10), Time.utc(2005,2,22,15,15,10).advance(years: 7, months: 19, days: 11) + assert_equal Time.utc(2013,10,17,15,15,10), Time.utc(2005,2,28,15,15,10).advance(years: 7, months: 19, weeks: 2, days: 5) + assert_equal Time.utc(2001,12,27,15,15,10), Time.utc(2005,2,28,15,15,10).advance(years: -3, months: -2, days: -1) + assert_equal Time.utc(2005,2,28,15,15,10), Time.utc(2004,2,29,15,15,10).advance(years: 1) #leap day plus one year + assert_equal Time.utc(2005,2,28,20,15,10), Time.utc(2005,2,28,15,15,10).advance(hours: 5) + assert_equal Time.utc(2005,2,28,15,22,10), Time.utc(2005,2,28,15,15,10).advance(minutes: 7) + assert_equal Time.utc(2005,2,28,15,15,19), Time.utc(2005,2,28,15,15,10).advance(seconds: 9) + assert_equal Time.utc(2005,2,28,20,22,19), Time.utc(2005,2,28,15,15,10).advance(hours: 5, minutes: 7, seconds: 9) + assert_equal Time.utc(2005,2,28,10,8,1), Time.utc(2005,2,28,15,15,10).advance(hours: -5, minutes: -7, seconds: -9) + assert_equal Time.utc(2013,10,17,20,22,19), Time.utc(2005,2,28,15,15,10).advance(years: 7, months: 19, weeks: 2, days: 5, hours: 5, minutes: 7, seconds: 9) end def test_offset_advance - assert_equal Time.new(2006,2,22,15,15,10,'-08:00'), Time.new(2005,2,22,15,15,10,'-08:00').advance(:years => 1) - assert_equal Time.new(2005,6,22,15,15,10,'-08:00'), Time.new(2005,2,22,15,15,10,'-08:00').advance(:months => 4) - assert_equal Time.new(2005,3,21,15,15,10,'-08:00'), Time.new(2005,2,28,15,15,10,'-08:00').advance(:weeks => 3) - assert_equal Time.new(2005,3,25,3,15,10,'-08:00'), Time.new(2005,2,28,15,15,10,'-08:00').advance(:weeks => 3.5) - assert_in_delta Time.new(2005,3,26,12,51,10,'-08:00'), Time.new(2005,2,28,15,15,10,'-08:00').advance(:weeks => 3.7), 1 - assert_equal Time.new(2005,3,5,15,15,10,'-08:00'), Time.new(2005,2,28,15,15,10,'-08:00').advance(:days => 5) - assert_equal Time.new(2005,3,6,3,15,10,'-08:00'), Time.new(2005,2,28,15,15,10,'-08:00').advance(:days => 5.5) - assert_in_delta Time.new(2005,3,6,8,3,10,'-08:00'), Time.new(2005,2,28,15,15,10,'-08:00').advance(:days => 5.7), 1 - assert_equal Time.new(2012,9,22,15,15,10,'-08:00'), Time.new(2005,2,22,15,15,10,'-08:00').advance(:years => 7, :months => 7) - assert_equal Time.new(2013,10,3,15,15,10,'-08:00'), Time.new(2005,2,22,15,15,10,'-08:00').advance(:years => 7, :months => 19, :days => 11) - assert_equal Time.new(2013,10,17,15,15,10,'-08:00'), Time.new(2005,2,28,15,15,10,'-08:00').advance(:years => 7, :months => 19, :weeks => 2, :days => 5) - assert_equal Time.new(2001,12,27,15,15,10,'-08:00'), Time.new(2005,2,28,15,15,10,'-08:00').advance(:years => -3, :months => -2, :days => -1) - assert_equal Time.new(2005,2,28,15,15,10,'-08:00'), Time.new(2004,2,29,15,15,10,'-08:00').advance(:years => 1) #leap day plus one year - assert_equal Time.new(2005,2,28,20,15,10,'-08:00'), Time.new(2005,2,28,15,15,10,'-08:00').advance(:hours => 5) - assert_equal Time.new(2005,2,28,15,22,10,'-08:00'), Time.new(2005,2,28,15,15,10,'-08:00').advance(:minutes => 7) - assert_equal Time.new(2005,2,28,15,15,19,'-08:00'), Time.new(2005,2,28,15,15,10,'-08:00').advance(:seconds => 9) - assert_equal Time.new(2005,2,28,20,22,19,'-08:00'), Time.new(2005,2,28,15,15,10,'-08:00').advance(:hours => 5, :minutes => 7, :seconds => 9) - assert_equal Time.new(2005,2,28,10,8,1,'-08:00'), Time.new(2005,2,28,15,15,10,'-08:00').advance(:hours => -5, :minutes => -7, :seconds => -9) - assert_equal Time.new(2013,10,17,20,22,19,'-08:00'), Time.new(2005,2,28,15,15,10,'-08:00').advance(:years => 7, :months => 19, :weeks => 2, :days => 5, :hours => 5, :minutes => 7, :seconds => 9) + assert_equal Time.new(2006,2,22,15,15,10,"-08:00"), Time.new(2005,2,22,15,15,10,"-08:00").advance(years: 1) + assert_equal Time.new(2005,6,22,15,15,10,"-08:00"), Time.new(2005,2,22,15,15,10,"-08:00").advance(months: 4) + assert_equal Time.new(2005,3,21,15,15,10,"-08:00"), Time.new(2005,2,28,15,15,10,"-08:00").advance(weeks: 3) + assert_equal Time.new(2005,3,25,3,15,10,"-08:00"), Time.new(2005,2,28,15,15,10,"-08:00").advance(weeks: 3.5) + assert_in_delta Time.new(2005,3,26,12,51,10,"-08:00"), Time.new(2005,2,28,15,15,10,"-08:00").advance(weeks: 3.7), 1 + assert_equal Time.new(2005,3,5,15,15,10,"-08:00"), Time.new(2005,2,28,15,15,10,"-08:00").advance(days: 5) + assert_equal Time.new(2005,3,6,3,15,10,"-08:00"), Time.new(2005,2,28,15,15,10,"-08:00").advance(days: 5.5) + assert_in_delta Time.new(2005,3,6,8,3,10,"-08:00"), Time.new(2005,2,28,15,15,10,"-08:00").advance(days: 5.7), 1 + assert_equal Time.new(2012,9,22,15,15,10,"-08:00"), Time.new(2005,2,22,15,15,10,"-08:00").advance(years: 7, months: 7) + assert_equal Time.new(2013,10,3,15,15,10,"-08:00"), Time.new(2005,2,22,15,15,10,"-08:00").advance(years: 7, months: 19, days: 11) + assert_equal Time.new(2013,10,17,15,15,10,"-08:00"), Time.new(2005,2,28,15,15,10,"-08:00").advance(years: 7, months: 19, weeks: 2, days: 5) + assert_equal Time.new(2001,12,27,15,15,10,"-08:00"), Time.new(2005,2,28,15,15,10,"-08:00").advance(years: -3, months: -2, days: -1) + assert_equal Time.new(2005,2,28,15,15,10,"-08:00"), Time.new(2004,2,29,15,15,10,"-08:00").advance(years: 1) #leap day plus one year + assert_equal Time.new(2005,2,28,20,15,10,"-08:00"), Time.new(2005,2,28,15,15,10,"-08:00").advance(hours: 5) + assert_equal Time.new(2005,2,28,15,22,10,"-08:00"), Time.new(2005,2,28,15,15,10,"-08:00").advance(minutes: 7) + assert_equal Time.new(2005,2,28,15,15,19,"-08:00"), Time.new(2005,2,28,15,15,10,"-08:00").advance(seconds: 9) + assert_equal Time.new(2005,2,28,20,22,19,"-08:00"), Time.new(2005,2,28,15,15,10,"-08:00").advance(hours: 5, minutes: 7, seconds: 9) + assert_equal Time.new(2005,2,28,10,8,1,"-08:00"), Time.new(2005,2,28,15,15,10,"-08:00").advance(hours: -5, minutes: -7, seconds: -9) + assert_equal Time.new(2013,10,17,20,22,19,"-08:00"), Time.new(2005,2,28,15,15,10,"-08:00").advance(years: 7, months: 19, weeks: 2, days: 5, hours: 5, minutes: 7, seconds: 9) end def test_advance_with_nsec t = Time.at(0, Rational(108635108, 1000)) - assert_equal t, t.advance(:months => 0) + assert_equal t, t.advance(months: 0) end def test_advance_gregorian_proleptic - assert_equal Time.local(1582,10,14,15,15,10), Time.local(1582,10,15,15,15,10).advance(:days => -1) - assert_equal Time.local(1582,10,15,15,15,10), Time.local(1582,10,14,15,15,10).advance(:days => 1) - assert_equal Time.local(1582,10,5,15,15,10), Time.local(1582,10,4,15,15,10).advance(:days => 1) - assert_equal Time.local(1582,10,4,15,15,10), Time.local(1582,10,5,15,15,10).advance(:days => -1) + assert_equal Time.local(1582,10,14,15,15,10), Time.local(1582,10,15,15,15,10).advance(days: -1) + assert_equal Time.local(1582,10,15,15,15,10), Time.local(1582,10,14,15,15,10).advance(days: 1) + assert_equal Time.local(1582,10,5,15,15,10), Time.local(1582,10,4,15,15,10).advance(days: 1) + assert_equal Time.local(1582,10,4,15,15,10), Time.local(1582,10,5,15,15,10).advance(days: -1) end def test_last_week - with_env_tz 'US/Eastern' do + with_env_tz "US/Eastern" do assert_equal Time.local(2005,2,21), Time.local(2005,3,1,15,15,10).last_week assert_equal Time.local(2005,2,22), Time.local(2005,3,1,15,15,10).last_week(:tuesday) assert_equal Time.local(2005,2,25), Time.local(2005,3,1,15,15,10).last_week(:friday) @@ -508,20 +522,20 @@ class TimeExtCalculationsTest < ActiveSupport::TestCase end def test_next_week_near_daylight_start - with_env_tz 'US/Eastern' do - assert_equal Time.local(2006,4,3), Time.local(2006,4,2,23,1,0).next_week, 'just crossed standard => daylight' + with_env_tz "US/Eastern" do + assert_equal Time.local(2006,4,3), Time.local(2006,4,2,23,1,0).next_week, "just crossed standard => daylight" end - with_env_tz 'NZ' do - assert_equal Time.local(2006,10,2), Time.local(2006,10,1,23,1,0).next_week, 'just crossed standard => daylight' + with_env_tz "NZ" do + assert_equal Time.local(2006,10,2), Time.local(2006,10,1,23,1,0).next_week, "just crossed standard => daylight" end end def test_next_week_near_daylight_end - with_env_tz 'US/Eastern' do - assert_equal Time.local(2006,10,30), Time.local(2006,10,29,23,1,0).next_week, 'just crossed daylight => standard' + with_env_tz "US/Eastern" do + assert_equal Time.local(2006,10,30), Time.local(2006,10,29,23,1,0).next_week, "just crossed daylight => standard" end - with_env_tz 'NZ' do - assert_equal Time.local(2006,3,20), Time.local(2006,3,19,23,1,0).next_week, 'just crossed daylight => standard' + with_env_tz "NZ" do + assert_equal Time.local(2006,3,20), Time.local(2006,3,19,23,1,0).next_week, "just crossed daylight => standard" end end @@ -550,8 +564,8 @@ class TimeExtCalculationsTest < ActiveSupport::TestCase end def test_custom_date_format - Time::DATE_FORMATS[:custom] = '%Y%m%d%H%M%S' - assert_equal '20050221143000', Time.local(2005, 2, 21, 14, 30, 0).to_s(:custom) + Time::DATE_FORMATS[:custom] = "%Y%m%d%H%M%S" + assert_equal "20050221143000", Time.local(2005, 2, 21, 14, 30, 0).to_s(:custom) Time::DATE_FORMATS.delete(:custom) end @@ -561,17 +575,17 @@ class TimeExtCalculationsTest < ActiveSupport::TestCase def test_to_datetime assert_equal Time.utc(2005, 2, 21, 17, 44, 30).to_datetime, DateTime.civil(2005, 2, 21, 17, 44, 30, 0) - with_env_tz 'US/Eastern' do + with_env_tz "US/Eastern" do assert_equal Time.local(2005, 2, 21, 17, 44, 30).to_datetime, DateTime.civil(2005, 2, 21, 17, 44, 30, Rational(Time.local(2005, 2, 21, 17, 44, 30).utc_offset, 86400)) end - with_env_tz 'NZ' do + with_env_tz "NZ" do assert_equal Time.local(2005, 2, 21, 17, 44, 30).to_datetime, DateTime.civil(2005, 2, 21, 17, 44, 30, Rational(Time.local(2005, 2, 21, 17, 44, 30).utc_offset, 86400)) end assert_equal ::Date::ITALY, Time.utc(2005, 2, 21, 17, 44, 30).to_datetime.start # use Ruby's default start value end def test_to_time - with_env_tz 'US/Eastern' do + with_env_tz "US/Eastern" do assert_equal Time, Time.local(2005, 2, 21, 17, 44, 30).to_time.class assert_equal Time.local(2005, 2, 21, 17, 44, 30), Time.local(2005, 2, 21, 17, 44, 30).to_time assert_equal Time.local(2005, 2, 21, 17, 44, 30).utc_offset, Time.local(2005, 2, 21, 17, 44, 30).to_time.utc_offset @@ -663,7 +677,7 @@ class TimeExtCalculationsTest < ActiveSupport::TestCase end def test_past_with_time_current_as_time_local - with_env_tz 'US/Eastern' do + with_env_tz "US/Eastern" do Time.stub(:current, Time.local(2005,2,10,15,30,45)) do assert_equal true, Time.local(2005,2,10,15,30,44).past? assert_equal false, Time.local(2005,2,10,15,30,45).past? @@ -676,8 +690,8 @@ class TimeExtCalculationsTest < ActiveSupport::TestCase end def test_past_with_time_current_as_time_with_zone - with_env_tz 'US/Eastern' do - twz = Time.utc(2005,2,10,15,30,45).in_time_zone('Central Time (US & Canada)') + with_env_tz "US/Eastern" do + twz = Time.utc(2005,2,10,15,30,45).in_time_zone("Central Time (US & Canada)") Time.stub(:current, twz) do assert_equal true, Time.local(2005,2,10,10,30,44).past? assert_equal false, Time.local(2005,2,10,10,30,45).past? @@ -690,7 +704,7 @@ class TimeExtCalculationsTest < ActiveSupport::TestCase end def test_future_with_time_current_as_time_local - with_env_tz 'US/Eastern' do + with_env_tz "US/Eastern" do Time.stub(:current, Time.local(2005,2,10,15,30,45)) do assert_equal false, Time.local(2005,2,10,15,30,44).future? assert_equal false, Time.local(2005,2,10,15,30,45).future? @@ -703,8 +717,8 @@ class TimeExtCalculationsTest < ActiveSupport::TestCase end def test_future_with_time_current_as_time_with_zone - with_env_tz 'US/Eastern' do - twz = Time.utc(2005,2,10,15,30,45).in_time_zone('Central Time (US & Canada)') + with_env_tz "US/Eastern" do + twz = Time.utc(2005,2,10,15,30,45).in_time_zone("Central Time (US & Canada)") Time.stub(:current, twz) do assert_equal false, Time.local(2005,2,10,10,30,44).future? assert_equal false, Time.local(2005,2,10,10,30,45).future? @@ -721,17 +735,17 @@ class TimeExtCalculationsTest < ActiveSupport::TestCase end def test_formatted_offset_with_utc - assert_equal '+00:00', Time.utc(2000).formatted_offset - assert_equal '+0000', Time.utc(2000).formatted_offset(false) - assert_equal 'UTC', Time.utc(2000).formatted_offset(true, 'UTC') + assert_equal "+00:00", Time.utc(2000).formatted_offset + assert_equal "+0000", Time.utc(2000).formatted_offset(false) + assert_equal "UTC", Time.utc(2000).formatted_offset(true, "UTC") end def test_formatted_offset_with_local - with_env_tz 'US/Eastern' do - assert_equal '-05:00', Time.local(2000).formatted_offset - assert_equal '-0500', Time.local(2000).formatted_offset(false) - assert_equal '-04:00', Time.local(2000, 7).formatted_offset - assert_equal '-0400', Time.local(2000, 7).formatted_offset(false) + with_env_tz "US/Eastern" do + assert_equal "-05:00", Time.local(2000).formatted_offset + assert_equal "-0500", Time.local(2000).formatted_offset(false) + assert_equal "-04:00", Time.local(2000, 7).formatted_offset + assert_equal "-0400", Time.local(2000, 7).formatted_offset(false) end end @@ -748,16 +762,16 @@ class TimeExtCalculationsTest < ActiveSupport::TestCase end def test_compare_with_time_with_zone - assert_equal 1, Time.utc(2000) <=> ActiveSupport::TimeWithZone.new( Time.utc(1999, 12, 31, 23, 59, 59), ActiveSupport::TimeZone['UTC'] ) - assert_equal 0, Time.utc(2000) <=> ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 1, 0, 0, 0), ActiveSupport::TimeZone['UTC'] ) - assert_equal(-1, Time.utc(2000) <=> ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 1, 0, 0, 1), ActiveSupport::TimeZone['UTC'] )) + assert_equal 1, Time.utc(2000) <=> ActiveSupport::TimeWithZone.new( Time.utc(1999, 12, 31, 23, 59, 59), ActiveSupport::TimeZone["UTC"] ) + assert_equal 0, Time.utc(2000) <=> ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 1, 0, 0, 0), ActiveSupport::TimeZone["UTC"] ) + assert_equal(-1, Time.utc(2000) <=> ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 1, 0, 0, 1), ActiveSupport::TimeZone["UTC"] )) end def test_compare_with_string assert_equal 1, Time.utc(2000) <=> Time.utc(1999, 12, 31, 23, 59, 59, 999).to_s assert_equal 0, Time.utc(2000) <=> Time.utc(2000, 1, 1, 0, 0, 0).to_s assert_equal( -1, Time.utc(2000) <=> Time.utc(2000, 1, 1, 0, 0, 1, 0).to_s) - assert_equal nil, Time.utc(2000) <=> 'Invalid as Time' + assert_equal nil, Time.utc(2000) <=> "Invalid as Time" end def test_at_with_datetime @@ -772,42 +786,42 @@ class TimeExtCalculationsTest < ActiveSupport::TestCase end def test_at_with_datetime_returns_local_time - with_env_tz 'US/Eastern' do - dt = DateTime.civil(2000, 1, 1, 0, 0, 0, '+0') + with_env_tz "US/Eastern" do + dt = DateTime.civil(2000, 1, 1, 0, 0, 0, "+0") assert_equal Time.local(1999, 12, 31, 19, 0, 0), Time.at(dt) - assert_equal 'EST', Time.at(dt).zone + assert_equal "EST", Time.at(dt).zone assert_equal(-18000, Time.at(dt).utc_offset) # Daylight savings - dt = DateTime.civil(2000, 7, 1, 1, 0, 0, '+1') + dt = DateTime.civil(2000, 7, 1, 1, 0, 0, "+1") assert_equal Time.local(2000, 6, 30, 20, 0, 0), Time.at(dt) - assert_equal 'EDT', Time.at(dt).zone + assert_equal "EDT", Time.at(dt).zone assert_equal(-14400, Time.at(dt).utc_offset) end end def test_at_with_time_with_zone - assert_equal Time.utc(2000, 1, 1, 0, 0, 0), Time.at(ActiveSupport::TimeWithZone.new(Time.utc(2000, 1, 1, 0, 0, 0), ActiveSupport::TimeZone['UTC'])) + assert_equal Time.utc(2000, 1, 1, 0, 0, 0), Time.at(ActiveSupport::TimeWithZone.new(Time.utc(2000, 1, 1, 0, 0, 0), ActiveSupport::TimeZone["UTC"])) # Only test this if the underlying Time.at raises a TypeError begin Time.at_without_coercion(Time.now, 0) rescue TypeError - assert_raise(TypeError) { assert_equal(Time.utc(2000, 1, 1, 0, 0, 0), Time.at(ActiveSupport::TimeWithZone.new(Time.utc(2000, 1, 1, 0, 0, 0), ActiveSupport::TimeZone['UTC']), 0)) } + assert_raise(TypeError) { assert_equal(Time.utc(2000, 1, 1, 0, 0, 0), Time.at(ActiveSupport::TimeWithZone.new(Time.utc(2000, 1, 1, 0, 0, 0), ActiveSupport::TimeZone["UTC"]), 0)) } end end def test_at_with_time_with_zone_returns_local_time - with_env_tz 'US/Eastern' do - twz = ActiveSupport::TimeWithZone.new(Time.utc(2000, 1, 1, 0, 0, 0), ActiveSupport::TimeZone['London']) + with_env_tz "US/Eastern" do + twz = ActiveSupport::TimeWithZone.new(Time.utc(2000, 1, 1, 0, 0, 0), ActiveSupport::TimeZone["London"]) assert_equal Time.local(1999, 12, 31, 19, 0, 0), Time.at(twz) - assert_equal 'EST', Time.at(twz).zone + assert_equal "EST", Time.at(twz).zone assert_equal(-18000, Time.at(twz).utc_offset) # Daylight savings - twz = ActiveSupport::TimeWithZone.new(Time.utc(2000, 7, 1, 0, 0, 0), ActiveSupport::TimeZone['London']) + twz = ActiveSupport::TimeWithZone.new(Time.utc(2000, 7, 1, 0, 0, 0), ActiveSupport::TimeZone["London"]) assert_equal Time.local(2000, 6, 30, 20, 0, 0), Time.at(twz) - assert_equal 'EDT', Time.at(twz).zone + assert_equal "EDT", Time.at(twz).zone assert_equal(-14400, Time.at(twz).utc_offset) end end @@ -817,33 +831,33 @@ class TimeExtCalculationsTest < ActiveSupport::TestCase end def test_at_with_utc_time - with_env_tz 'US/Eastern' do + with_env_tz "US/Eastern" do assert_equal Time.utc(2000), Time.at(Time.utc(2000)) - assert_equal 'UTC', Time.at(Time.utc(2000)).zone + assert_equal "UTC", Time.at(Time.utc(2000)).zone assert_equal(0, Time.at(Time.utc(2000)).utc_offset) end end def test_at_with_local_time - with_env_tz 'US/Eastern' do + with_env_tz "US/Eastern" do assert_equal Time.local(2000), Time.at(Time.local(2000)) - assert_equal 'EST', Time.at(Time.local(2000)).zone + assert_equal "EST", Time.at(Time.local(2000)).zone assert_equal(-18000, Time.at(Time.local(2000)).utc_offset) assert_equal Time.local(2000, 7, 1), Time.at(Time.local(2000, 7, 1)) - assert_equal 'EDT', Time.at(Time.local(2000, 7, 1)).zone + assert_equal "EDT", Time.at(Time.local(2000, 7, 1)).zone assert_equal(-14400, Time.at(Time.local(2000, 7, 1)).utc_offset) end end def test_eql? - assert_equal true, Time.utc(2000).eql?( ActiveSupport::TimeWithZone.new(Time.utc(2000), ActiveSupport::TimeZone['UTC']) ) + assert_equal true, Time.utc(2000).eql?( ActiveSupport::TimeWithZone.new(Time.utc(2000), ActiveSupport::TimeZone["UTC"]) ) assert_equal true, Time.utc(2000).eql?( ActiveSupport::TimeWithZone.new(Time.utc(2000), ActiveSupport::TimeZone["Hawaii"]) ) - assert_equal false,Time.utc(2000, 1, 1, 0, 0, 1).eql?( ActiveSupport::TimeWithZone.new(Time.utc(2000), ActiveSupport::TimeZone['UTC']) ) + assert_equal false,Time.utc(2000, 1, 1, 0, 0, 1).eql?( ActiveSupport::TimeWithZone.new(Time.utc(2000), ActiveSupport::TimeZone["UTC"]) ) end def test_minus_with_time_with_zone - assert_equal 86_400.0, Time.utc(2000, 1, 2) - ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 1), ActiveSupport::TimeZone['UTC'] ) + assert_equal 86_400.0, Time.utc(2000, 1, 2) - ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 1), ActiveSupport::TimeZone["UTC"] ) end def test_minus_with_datetime @@ -851,7 +865,7 @@ class TimeExtCalculationsTest < ActiveSupport::TestCase end def test_time_created_with_local_constructor_cannot_represent_times_during_hour_skipped_by_dst - with_env_tz 'US/Eastern' do + with_env_tz "US/Eastern" do # On Apr 2 2006 at 2:00AM in US, clocks were moved forward to 3:00AM. # Therefore, 2AM EST doesn't exist for this date; Time.local fails over to 3:00AM EDT assert_equal Time.local(2006, 4, 2, 3), Time.local(2006, 4, 2, 2) @@ -861,11 +875,11 @@ class TimeExtCalculationsTest < ActiveSupport::TestCase def test_case_equality assert Time === Time.utc(2000) - assert Time === ActiveSupport::TimeWithZone.new(Time.utc(2000), ActiveSupport::TimeZone['UTC']) + assert Time === ActiveSupport::TimeWithZone.new(Time.utc(2000), ActiveSupport::TimeZone["UTC"]) assert Time === Class.new(Time).utc(2000) assert_equal false, Time === DateTime.civil(2000) assert_equal false, Class.new(Time) === Time.utc(2000) - assert_equal false, Class.new(Time) === ActiveSupport::TimeWithZone.new(Time.utc(2000), ActiveSupport::TimeZone['UTC']) + assert_equal false, Class.new(Time) === ActiveSupport::TimeWithZone.new(Time.utc(2000), ActiveSupport::TimeZone["UTC"]) end def test_all_day @@ -928,7 +942,7 @@ class TimeExtMarshalingTest < ActiveSupport::TestCase end def test_marshalling_preserves_fractional_seconds - t = Time.parse('00:00:00.500') + t = Time.parse("00:00:00.500") unmarshaled = Marshal.load(Marshal.dump(t)) assert_equal t.to_f, unmarshaled.to_f assert_equal t, unmarshaled diff --git a/activesupport/test/core_ext/time_with_zone_test.rb b/activesupport/test/core_ext/time_with_zone_test.rb index 7acada011d..e35aa6e154 100644 --- a/activesupport/test/core_ext/time_with_zone_test.rb +++ b/activesupport/test/core_ext/time_with_zone_test.rb @@ -1,20 +1,23 @@ -require 'abstract_unit' -require 'active_support/time' -require 'time_zone_test_helpers' -require 'active_support/core_ext/string/strip' -require 'yaml' +require "abstract_unit" +require "active_support/time" +require "time_zone_test_helpers" +require "active_support/core_ext/string/strip" +require "yaml" class TimeWithZoneTest < ActiveSupport::TestCase include TimeZoneTestHelpers def setup @utc = Time.utc(2000, 1, 1, 0) - @time_zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)'] + @time_zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"] @twz = ActiveSupport::TimeWithZone.new(@utc, @time_zone) + @dt_twz = ActiveSupport::TimeWithZone.new(@utc.to_datetime, @time_zone) end def test_utc assert_equal @utc, @twz.utc + assert_instance_of Time, @twz.utc + assert_instance_of Time, @dt_twz.utc end def test_time @@ -26,52 +29,54 @@ class TimeWithZoneTest < ActiveSupport::TestCase end def test_in_time_zone - Time.use_zone 'Alaska' do - assert_equal ActiveSupport::TimeWithZone.new(@utc, ActiveSupport::TimeZone['Alaska']), @twz.in_time_zone + Time.use_zone "Alaska" do + assert_equal ActiveSupport::TimeWithZone.new(@utc, ActiveSupport::TimeZone["Alaska"]), @twz.in_time_zone end end def test_in_time_zone_with_argument - assert_equal ActiveSupport::TimeWithZone.new(@utc, ActiveSupport::TimeZone['Alaska']), @twz.in_time_zone('Alaska') + assert_equal ActiveSupport::TimeWithZone.new(@utc, ActiveSupport::TimeZone["Alaska"]), @twz.in_time_zone("Alaska") end def test_in_time_zone_with_new_zone_equal_to_old_zone_does_not_create_new_object - assert_equal @twz.object_id, @twz.in_time_zone(ActiveSupport::TimeZone['Eastern Time (US & Canada)']).object_id + assert_equal @twz.object_id, @twz.in_time_zone(ActiveSupport::TimeZone["Eastern Time (US & Canada)"]).object_id end def test_in_time_zone_with_bad_argument - assert_raise(ArgumentError) { @twz.in_time_zone('No such timezone exists') } + assert_raise(ArgumentError) { @twz.in_time_zone("No such timezone exists") } assert_raise(ArgumentError) { @twz.in_time_zone(-15.hours) } assert_raise(ArgumentError) { @twz.in_time_zone(Object.new) } end def test_localtime assert_equal @twz.localtime, @twz.utc.getlocal + assert_instance_of Time, @twz.localtime + assert_instance_of Time, @dt_twz.localtime end def test_utc? assert_equal false, @twz.utc? - assert_equal true, ActiveSupport::TimeWithZone.new(Time.utc(2000), ActiveSupport::TimeZone['UTC']).utc? - assert_equal true, ActiveSupport::TimeWithZone.new(Time.utc(2000), ActiveSupport::TimeZone['Etc/UTC']).utc? - assert_equal true, ActiveSupport::TimeWithZone.new(Time.utc(2000), ActiveSupport::TimeZone['Universal']).utc? - assert_equal true, ActiveSupport::TimeWithZone.new(Time.utc(2000), ActiveSupport::TimeZone['UCT']).utc? - assert_equal true, ActiveSupport::TimeWithZone.new(Time.utc(2000), ActiveSupport::TimeZone['Etc/UCT']).utc? - assert_equal true, ActiveSupport::TimeWithZone.new(Time.utc(2000), ActiveSupport::TimeZone['Etc/Universal']).utc? + assert_equal true, ActiveSupport::TimeWithZone.new(Time.utc(2000), ActiveSupport::TimeZone["UTC"]).utc? + assert_equal true, ActiveSupport::TimeWithZone.new(Time.utc(2000), ActiveSupport::TimeZone["Etc/UTC"]).utc? + assert_equal true, ActiveSupport::TimeWithZone.new(Time.utc(2000), ActiveSupport::TimeZone["Universal"]).utc? + assert_equal true, ActiveSupport::TimeWithZone.new(Time.utc(2000), ActiveSupport::TimeZone["UCT"]).utc? + assert_equal true, ActiveSupport::TimeWithZone.new(Time.utc(2000), ActiveSupport::TimeZone["Etc/UCT"]).utc? + assert_equal true, ActiveSupport::TimeWithZone.new(Time.utc(2000), ActiveSupport::TimeZone["Etc/Universal"]).utc? - assert_equal false, ActiveSupport::TimeWithZone.new(Time.utc(2000), ActiveSupport::TimeZone['Africa/Abidjan']).utc? - assert_equal false, ActiveSupport::TimeWithZone.new(Time.utc(2000), ActiveSupport::TimeZone['Africa/Banjul']).utc? - assert_equal false, ActiveSupport::TimeWithZone.new(Time.utc(2000), ActiveSupport::TimeZone['Africa/Freetown']).utc? - assert_equal false, ActiveSupport::TimeWithZone.new(Time.utc(2000), ActiveSupport::TimeZone['GMT']).utc? - assert_equal false, ActiveSupport::TimeWithZone.new(Time.utc(2000), ActiveSupport::TimeZone['GMT0']).utc? - assert_equal false, ActiveSupport::TimeWithZone.new(Time.utc(2000), ActiveSupport::TimeZone['Greenwich']).utc? - assert_equal false, ActiveSupport::TimeWithZone.new(Time.utc(2000), ActiveSupport::TimeZone['Iceland']).utc? - assert_equal false, ActiveSupport::TimeWithZone.new(Time.utc(2000), ActiveSupport::TimeZone['Africa/Monrovia']).utc? + assert_equal false, ActiveSupport::TimeWithZone.new(Time.utc(2000), ActiveSupport::TimeZone["Africa/Abidjan"]).utc? + assert_equal false, ActiveSupport::TimeWithZone.new(Time.utc(2000), ActiveSupport::TimeZone["Africa/Banjul"]).utc? + assert_equal false, ActiveSupport::TimeWithZone.new(Time.utc(2000), ActiveSupport::TimeZone["Africa/Freetown"]).utc? + assert_equal false, ActiveSupport::TimeWithZone.new(Time.utc(2000), ActiveSupport::TimeZone["GMT"]).utc? + assert_equal false, ActiveSupport::TimeWithZone.new(Time.utc(2000), ActiveSupport::TimeZone["GMT0"]).utc? + assert_equal false, ActiveSupport::TimeWithZone.new(Time.utc(2000), ActiveSupport::TimeZone["Greenwich"]).utc? + assert_equal false, ActiveSupport::TimeWithZone.new(Time.utc(2000), ActiveSupport::TimeZone["Iceland"]).utc? + assert_equal false, ActiveSupport::TimeWithZone.new(Time.utc(2000), ActiveSupport::TimeZone["Africa/Monrovia"]).utc? end def test_formatted_offset - assert_equal '-05:00', @twz.formatted_offset - assert_equal '-04:00', ActiveSupport::TimeWithZone.new(Time.utc(2000, 6), @time_zone).formatted_offset #dst + assert_equal "-05:00", @twz.formatted_offset + assert_equal "-04:00", ActiveSupport::TimeWithZone.new(Time.utc(2000, 6), @time_zone).formatted_offset #dst end def test_dst? @@ -80,8 +85,8 @@ class TimeWithZoneTest < ActiveSupport::TestCase end def test_zone - assert_equal 'EST', @twz.zone - assert_equal 'EDT', ActiveSupport::TimeWithZone.new(Time.utc(2000, 6), @time_zone).zone #dst + assert_equal "EST", @twz.zone + assert_equal "EDT", ActiveSupport::TimeWithZone.new(Time.utc(2000, 6), @time_zone).zone #dst end def test_nsec @@ -93,28 +98,28 @@ class TimeWithZoneTest < ActiveSupport::TestCase end def test_strftime - assert_equal '1999-12-31 19:00:00 EST -0500', @twz.strftime('%Y-%m-%d %H:%M:%S %Z %z') + assert_equal "1999-12-31 19:00:00 EST -0500", @twz.strftime("%Y-%m-%d %H:%M:%S %Z %z") end def test_strftime_with_escaping - assert_equal '%Z %z', @twz.strftime('%%Z %%z') - assert_equal '%EST %-0500', @twz.strftime('%%%Z %%%z') + assert_equal "%Z %z", @twz.strftime("%%Z %%z") + assert_equal "%EST %-0500", @twz.strftime("%%%Z %%%z") end def test_inspect - assert_equal 'Fri, 31 Dec 1999 19:00:00 EST -05:00', @twz.inspect + assert_equal "Fri, 31 Dec 1999 19:00:00 EST -05:00", @twz.inspect end def test_to_s - assert_equal '1999-12-31 19:00:00 -0500', @twz.to_s + assert_equal "1999-12-31 19:00:00 -0500", @twz.to_s end def test_to_formatted_s - assert_equal '1999-12-31 19:00:00 -0500', @twz.to_formatted_s + assert_equal "1999-12-31 19:00:00 -0500", @twz.to_formatted_s end def test_to_s_db - assert_equal '2000-01-01 00:00:00', @twz.to_s(:db) + assert_equal "2000-01-01 00:00:00", @twz.to_s(:db) end def test_xmlschema @@ -161,7 +166,7 @@ class TimeWithZoneTest < ActiveSupport::TestCase time: 1999-12-31 19:00:00.000000000 Z EOF - assert_equal(yaml, { 'twz' => @twz }.to_yaml) + assert_equal(yaml, { "twz" => @twz }.to_yaml) end def test_yaml_load @@ -186,11 +191,11 @@ class TimeWithZoneTest < ActiveSupport::TestCase time: 1999-12-31 19:00:00.000000000 Z EOF - assert_equal({ 'twz' => @twz }, YAML.load(yaml)) + assert_equal({ "twz" => @twz }, YAML.load(yaml)) end def test_httpdate - assert_equal 'Sat, 01 Jan 2000 00:00:00 GMT', @twz.httpdate + assert_equal "Sat, 01 Jan 2000 00:00:00 GMT", @twz.httpdate end def test_rfc2822 @@ -210,9 +215,9 @@ class TimeWithZoneTest < ActiveSupport::TestCase end def test_compare_with_time_with_zone - assert_equal 1, @twz <=> ActiveSupport::TimeWithZone.new( Time.utc(1999, 12, 31, 23, 59, 59), ActiveSupport::TimeZone['UTC'] ) - assert_equal 0, @twz <=> ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 1, 0, 0, 0), ActiveSupport::TimeZone['UTC'] ) - assert_equal(-1, @twz <=> ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 1, 0, 0, 1), ActiveSupport::TimeZone['UTC'] )) + assert_equal 1, @twz <=> ActiveSupport::TimeWithZone.new( Time.utc(1999, 12, 31, 23, 59, 59), ActiveSupport::TimeZone["UTC"] ) + assert_equal 0, @twz <=> ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 1, 0, 0, 0), ActiveSupport::TimeZone["UTC"] ) + assert_equal(-1, @twz <=> ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 1, 0, 0, 1), ActiveSupport::TimeZone["UTC"] )) end def test_between? @@ -230,7 +235,7 @@ class TimeWithZoneTest < ActiveSupport::TestCase end def test_past_with_time_current_as_time_local - with_env_tz 'US/Eastern' do + with_env_tz "US/Eastern" do Time.stub(:current, Time.local(2005,2,10,15,30,45)) do assert_equal true, ActiveSupport::TimeWithZone.new( nil, @time_zone, Time.local(2005,2,10,15,30,44)).past? assert_equal false, ActiveSupport::TimeWithZone.new( nil, @time_zone, Time.local(2005,2,10,15,30,45)).past? @@ -249,7 +254,7 @@ class TimeWithZoneTest < ActiveSupport::TestCase end def test_future_with_time_current_as_time_local - with_env_tz 'US/Eastern' do + with_env_tz "US/Eastern" do Time.stub(:current, Time.local(2005,2,10,15,30,45)) do assert_equal false, ActiveSupport::TimeWithZone.new( nil, @time_zone, Time.local(2005,2,10,15,30,44)).future? assert_equal false, ActiveSupport::TimeWithZone.new( nil, @time_zone, Time.local(2005,2,10,15,30,45)).future? @@ -317,38 +322,38 @@ class TimeWithZoneTest < ActiveSupport::TestCase end def test_minus_with_time - assert_equal 86_400.0, ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 2), ActiveSupport::TimeZone['UTC'] ) - Time.utc(2000, 1, 1) - assert_equal 86_400.0, ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 2), ActiveSupport::TimeZone['Hawaii'] ) - Time.utc(2000, 1, 1) + assert_equal 86_400.0, ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 2), ActiveSupport::TimeZone["UTC"] ) - Time.utc(2000, 1, 1) + assert_equal 86_400.0, ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 2), ActiveSupport::TimeZone["Hawaii"] ) - Time.utc(2000, 1, 1) end def test_minus_with_time_precision - assert_equal 86_399.999999998, ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 2, 23, 59, 59, Rational(999999999, 1000)), ActiveSupport::TimeZone['UTC'] ) - Time.utc(2000, 1, 2, 0, 0, 0, Rational(1, 1000)) - assert_equal 86_399.999999998, ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 2, 23, 59, 59, Rational(999999999, 1000)), ActiveSupport::TimeZone['Hawaii'] ) - Time.utc(2000, 1, 2, 0, 0, 0, Rational(1, 1000)) + assert_equal 86_399.999999998, ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 2, 23, 59, 59, Rational(999999999, 1000)), ActiveSupport::TimeZone["UTC"] ) - Time.utc(2000, 1, 2, 0, 0, 0, Rational(1, 1000)) + assert_equal 86_399.999999998, ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 2, 23, 59, 59, Rational(999999999, 1000)), ActiveSupport::TimeZone["Hawaii"] ) - Time.utc(2000, 1, 2, 0, 0, 0, Rational(1, 1000)) end def test_minus_with_time_with_zone - twz1 = ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 1), ActiveSupport::TimeZone['UTC'] ) - twz2 = ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 2), ActiveSupport::TimeZone['UTC'] ) + twz1 = ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 1), ActiveSupport::TimeZone["UTC"] ) + twz2 = ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 2), ActiveSupport::TimeZone["UTC"] ) assert_equal 86_400.0, twz2 - twz1 end def test_minus_with_time_with_zone_precision - twz1 = ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 1, 0, 0, 0, Rational(1, 1000)), ActiveSupport::TimeZone['UTC'] ) - twz2 = ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 1, 23, 59, 59, Rational(999999999, 1000)), ActiveSupport::TimeZone['UTC'] ) + twz1 = ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 1, 0, 0, 0, Rational(1, 1000)), ActiveSupport::TimeZone["UTC"] ) + twz2 = ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 1, 23, 59, 59, Rational(999999999, 1000)), ActiveSupport::TimeZone["UTC"] ) assert_equal 86_399.999999998, twz2 - twz1 end def test_minus_with_datetime - assert_equal 86_400.0, ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 2), ActiveSupport::TimeZone['UTC'] ) - DateTime.civil(2000, 1, 1) + assert_equal 86_400.0, ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 2), ActiveSupport::TimeZone["UTC"] ) - DateTime.civil(2000, 1, 1) end def test_minus_with_datetime_precision - assert_equal 86_399.999999999, ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 1, 23, 59, 59, Rational(999999999, 1000)), ActiveSupport::TimeZone['UTC'] ) - DateTime.civil(2000, 1, 1) + assert_equal 86_399.999999999, ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 1, 23, 59, 59, Rational(999999999, 1000)), ActiveSupport::TimeZone["UTC"] ) - DateTime.civil(2000, 1, 1) end def test_minus_with_wrapped_datetime - assert_equal 86_400.0, ActiveSupport::TimeWithZone.new( DateTime.civil(2000, 1, 2), ActiveSupport::TimeZone['UTC'] ) - Time.utc(2000, 1, 1) - assert_equal 86_400.0, ActiveSupport::TimeWithZone.new( DateTime.civil(2000, 1, 2), ActiveSupport::TimeZone['UTC'] ) - DateTime.civil(2000, 1, 1) + assert_equal 86_400.0, ActiveSupport::TimeWithZone.new( DateTime.civil(2000, 1, 2), ActiveSupport::TimeZone["UTC"] ) - Time.utc(2000, 1, 1) + assert_equal 86_400.0, ActiveSupport::TimeWithZone.new( DateTime.civil(2000, 1, 2), ActiveSupport::TimeZone["UTC"] ) - DateTime.civil(2000, 1, 1) end def test_plus_and_minus_enforce_spring_dst_rules @@ -356,15 +361,15 @@ class TimeWithZoneTest < ActiveSupport::TestCase twz = ActiveSupport::TimeWithZone.new(utc, @time_zone) assert_equal Time.utc(2006,4,2,1,59,59), twz.time assert_equal false, twz.dst? - assert_equal 'EST', twz.zone + assert_equal "EST", twz.zone twz = twz + 1 assert_equal Time.utc(2006,4,2,3), twz.time # adding 1 sec springs forward to 3:00AM EDT assert_equal true, twz.dst? - assert_equal 'EDT', twz.zone + assert_equal "EDT", twz.zone twz = twz - 1 # subtracting 1 second takes goes back to 1:59:59AM EST assert_equal Time.utc(2006,4,2,1,59,59), twz.time assert_equal false, twz.dst? - assert_equal 'EST', twz.zone + assert_equal "EST", twz.zone end def test_plus_and_minus_enforce_fall_dst_rules @@ -372,29 +377,29 @@ class TimeWithZoneTest < ActiveSupport::TestCase twz = ActiveSupport::TimeWithZone.new(utc, @time_zone) assert_equal Time.utc(2006,10,29,1,59,59), twz.time assert_equal true, twz.dst? - assert_equal 'EDT', twz.zone + assert_equal "EDT", twz.zone twz = twz + 1 assert_equal Time.utc(2006,10,29,1), twz.time # adding 1 sec falls back from 1:59:59 EDT to 1:00AM EST assert_equal false, twz.dst? - assert_equal 'EST', twz.zone + assert_equal "EST", twz.zone twz = twz - 1 assert_equal Time.utc(2006,10,29,1,59,59), twz.time # subtracting 1 sec goes back to 1:59:59AM EDT assert_equal true, twz.dst? - assert_equal 'EDT', twz.zone + assert_equal "EDT", twz.zone end def test_to_a - assert_equal [45, 30, 5, 1, 2, 2000, 2, 32, false, "HST"], ActiveSupport::TimeWithZone.new( Time.utc(2000, 2, 1, 15, 30, 45), ActiveSupport::TimeZone['Hawaii'] ).to_a + assert_equal [45, 30, 5, 1, 2, 2000, 2, 32, false, "HST"], ActiveSupport::TimeWithZone.new( Time.utc(2000, 2, 1, 15, 30, 45), ActiveSupport::TimeZone["Hawaii"] ).to_a end def test_to_f - result = ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 1), ActiveSupport::TimeZone['Hawaii'] ).to_f + result = ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 1), ActiveSupport::TimeZone["Hawaii"] ).to_f assert_equal 946684800.0, result assert_kind_of Float, result end def test_to_i - result = ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 1), ActiveSupport::TimeZone['Hawaii'] ).to_i + result = ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 1), ActiveSupport::TimeZone["Hawaii"] ).to_i assert_equal 946684800, result assert_kind_of Integer, result end @@ -406,18 +411,18 @@ class TimeWithZoneTest < ActiveSupport::TestCase end def test_to_r - result = ActiveSupport::TimeWithZone.new(Time.utc(2000, 1, 1), ActiveSupport::TimeZone['Hawaii']).to_r + result = ActiveSupport::TimeWithZone.new(Time.utc(2000, 1, 1), ActiveSupport::TimeZone["Hawaii"]).to_r assert_equal Rational(946684800, 1), result assert_kind_of Rational, result end def test_time_at - time = ActiveSupport::TimeWithZone.new(Time.utc(2000, 1, 1), ActiveSupport::TimeZone['Hawaii']) + time = ActiveSupport::TimeWithZone.new(Time.utc(2000, 1, 1), ActiveSupport::TimeZone["Hawaii"]) assert_equal time, Time.at(time) end def test_to_time - with_env_tz 'US/Eastern' do + with_env_tz "US/Eastern" do assert_equal Time, @twz.to_time.class assert_equal Time.local(1999, 12, 31, 19), @twz.to_time assert_equal Time.local(1999, 12, 31, 19).utc_offset, @twz.to_time.utc_offset @@ -426,13 +431,13 @@ class TimeWithZoneTest < ActiveSupport::TestCase def test_to_date # 1 sec before midnight Jan 1 EST - assert_equal Date.new(1999, 12, 31), ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 1, 4, 59, 59), ActiveSupport::TimeZone['Eastern Time (US & Canada)'] ).to_date + assert_equal Date.new(1999, 12, 31), ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 1, 4, 59, 59), ActiveSupport::TimeZone["Eastern Time (US & Canada)"] ).to_date # midnight Jan 1 EST - assert_equal Date.new(2000, 1, 1), ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 1, 5, 0, 0), ActiveSupport::TimeZone['Eastern Time (US & Canada)'] ).to_date + assert_equal Date.new(2000, 1, 1), ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 1, 5, 0, 0), ActiveSupport::TimeZone["Eastern Time (US & Canada)"] ).to_date # 1 sec before midnight Jan 2 EST - assert_equal Date.new(2000, 1, 1), ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 2, 4, 59, 59), ActiveSupport::TimeZone['Eastern Time (US & Canada)'] ).to_date + assert_equal Date.new(2000, 1, 1), ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 2, 4, 59, 59), ActiveSupport::TimeZone["Eastern Time (US & Canada)"] ).to_date # midnight Jan 2 EST - assert_equal Date.new(2000, 1, 2), ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 2, 5, 0, 0), ActiveSupport::TimeZone['Eastern Time (US & Canada)'] ).to_date + assert_equal Date.new(2000, 1, 2), ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 2, 5, 0, 0), ActiveSupport::TimeZone["Eastern Time (US & Canada)"] ).to_date end def test_to_datetime @@ -457,7 +462,7 @@ class TimeWithZoneTest < ActiveSupport::TestCase end def test_class_name - assert_equal 'Time', ActiveSupport::TimeWithZone.name + assert_equal "Time", ActiveSupport::TimeWithZone.name end def test_method_missing_with_time_return_value @@ -470,19 +475,19 @@ class TimeWithZoneTest < ActiveSupport::TestCase mtime = Marshal.load(marshal_str) assert_equal Time.utc(2000, 1, 1, 0), mtime.utc assert mtime.utc.utc? - assert_equal ActiveSupport::TimeZone['Eastern Time (US & Canada)'], mtime.time_zone + assert_equal ActiveSupport::TimeZone["Eastern Time (US & Canada)"], mtime.time_zone assert_equal Time.utc(1999, 12, 31, 19), mtime.time assert mtime.time.utc? assert_equal @twz.inspect, mtime.inspect end def test_marshal_dump_and_load_with_tzinfo_identifier - twz = ActiveSupport::TimeWithZone.new(@utc, TZInfo::Timezone.get('America/New_York')) + twz = ActiveSupport::TimeWithZone.new(@utc, TZInfo::Timezone.get("America/New_York")) marshal_str = Marshal.dump(twz) mtime = Marshal.load(marshal_str) assert_equal Time.utc(2000, 1, 1, 0), mtime.utc assert mtime.utc.utc? - assert_equal 'America/New_York', mtime.time_zone.name + assert_equal "America/New_York", mtime.time_zone.name assert_equal Time.utc(1999, 12, 31, 19), mtime.time assert mtime.time.utc? assert_equal @twz.inspect, mtime.inspect @@ -503,8 +508,8 @@ class TimeWithZoneTest < ActiveSupport::TestCase def test_method_missing_with_non_time_return_value time = @twz.time - def time.foo; 'bar'; end - assert_equal 'bar', @twz.foo + def time.foo; "bar"; end + assert_equal "bar", @twz.foo end def test_date_part_value_methods @@ -538,9 +543,9 @@ class TimeWithZoneTest < ActiveSupport::TestCase end def test_utc_to_local_conversion_saves_period_in_instance_variable - assert_nil @twz.instance_variable_get('@period') + assert_nil @twz.instance_variable_get("@period") @twz.time - assert_kind_of TZInfo::TimezonePeriod, @twz.instance_variable_get('@period') + assert_kind_of TZInfo::TimezonePeriod, @twz.instance_variable_get("@period") end def test_instance_created_with_local_time_returns_correct_utc_time @@ -552,14 +557,14 @@ class TimeWithZoneTest < ActiveSupport::TestCase twz = ActiveSupport::TimeWithZone.new(nil, @time_zone, Time.utc(2006,4,2,2)) # first second of DST assert_equal Time.utc(2006,4,2,3), twz.time # springs forward to 3AM assert_equal true, twz.dst? - assert_equal 'EDT', twz.zone + assert_equal "EDT", twz.zone end def test_instance_created_with_local_time_enforces_fall_dst_rules twz = ActiveSupport::TimeWithZone.new(nil, @time_zone, Time.utc(2006,10,29,1)) # 1AM can be either DST or non-DST; we'll pick DST assert_equal Time.utc(2006,10,29,1), twz.time assert_equal true, twz.dst? - assert_equal 'EDT', twz.zone + assert_equal "EDT", twz.zone end def test_ruby_19_weekday_name_query_methods @@ -579,33 +584,33 @@ class TimeWithZoneTest < ActiveSupport::TestCase def test_change assert_equal "Fri, 31 Dec 1999 19:00:00 EST -05:00", @twz.inspect - assert_equal "Mon, 31 Dec 2001 19:00:00 EST -05:00", @twz.change(:year => 2001).inspect - assert_equal "Wed, 31 Mar 1999 19:00:00 EST -05:00", @twz.change(:month => 3).inspect - assert_equal "Wed, 03 Mar 1999 19:00:00 EST -05:00", @twz.change(:month => 2).inspect - assert_equal "Wed, 15 Dec 1999 19:00:00 EST -05:00", @twz.change(:day => 15).inspect - assert_equal "Fri, 31 Dec 1999 06:00:00 EST -05:00", @twz.change(:hour => 6).inspect - assert_equal "Fri, 31 Dec 1999 19:15:00 EST -05:00", @twz.change(:min => 15).inspect - assert_equal "Fri, 31 Dec 1999 19:00:30 EST -05:00", @twz.change(:sec => 30).inspect + assert_equal "Mon, 31 Dec 2001 19:00:00 EST -05:00", @twz.change(year: 2001).inspect + assert_equal "Wed, 31 Mar 1999 19:00:00 EST -05:00", @twz.change(month: 3).inspect + assert_equal "Wed, 03 Mar 1999 19:00:00 EST -05:00", @twz.change(month: 2).inspect + assert_equal "Wed, 15 Dec 1999 19:00:00 EST -05:00", @twz.change(day: 15).inspect + assert_equal "Fri, 31 Dec 1999 06:00:00 EST -05:00", @twz.change(hour: 6).inspect + assert_equal "Fri, 31 Dec 1999 19:15:00 EST -05:00", @twz.change(min: 15).inspect + assert_equal "Fri, 31 Dec 1999 19:00:30 EST -05:00", @twz.change(sec: 30).inspect end def test_change_at_dst_boundary - twz = ActiveSupport::TimeWithZone.new(Time.at(1319936400).getutc, ActiveSupport::TimeZone['Madrid']) - assert_equal twz, twz.change(:min => 0) + twz = ActiveSupport::TimeWithZone.new(Time.at(1319936400).getutc, ActiveSupport::TimeZone["Madrid"]) + assert_equal twz, twz.change(min: 0) end def test_round_at_dst_boundary - twz = ActiveSupport::TimeWithZone.new(Time.at(1319936400).getutc, ActiveSupport::TimeZone['Madrid']) + twz = ActiveSupport::TimeWithZone.new(Time.at(1319936400).getutc, ActiveSupport::TimeZone["Madrid"]) assert_equal twz, twz.round end def test_advance assert_equal "Fri, 31 Dec 1999 19:00:00 EST -05:00", @twz.inspect - assert_equal "Mon, 31 Dec 2001 19:00:00 EST -05:00", @twz.advance(:years => 2).inspect - assert_equal "Fri, 31 Mar 2000 19:00:00 EST -05:00", @twz.advance(:months => 3).inspect - assert_equal "Tue, 04 Jan 2000 19:00:00 EST -05:00", @twz.advance(:days => 4).inspect - assert_equal "Sat, 01 Jan 2000 01:00:00 EST -05:00", @twz.advance(:hours => 6).inspect - assert_equal "Fri, 31 Dec 1999 19:15:00 EST -05:00", @twz.advance(:minutes => 15).inspect - assert_equal "Fri, 31 Dec 1999 19:00:30 EST -05:00", @twz.advance(:seconds => 30).inspect + assert_equal "Mon, 31 Dec 2001 19:00:00 EST -05:00", @twz.advance(years: 2).inspect + assert_equal "Fri, 31 Mar 2000 19:00:00 EST -05:00", @twz.advance(months: 3).inspect + assert_equal "Tue, 04 Jan 2000 19:00:00 EST -05:00", @twz.advance(days: 4).inspect + assert_equal "Sat, 01 Jan 2000 01:00:00 EST -05:00", @twz.advance(hours: 6).inspect + assert_equal "Fri, 31 Dec 1999 19:15:00 EST -05:00", @twz.advance(minutes: 15).inspect + assert_equal "Fri, 31 Dec 1999 19:00:30 EST -05:00", @twz.advance(seconds: 30).inspect end def test_beginning_of_year @@ -670,6 +675,10 @@ class TimeWithZoneTest < ActiveSupport::TestCase assert_equal "Fri, 31 Dec 1999 19:00:01 EST -05:00", @twz.since(1).inspect end + def test_in + assert_equal "Fri, 31 Dec 1999 19:00:01 EST -05:00", @twz.in(1).inspect + end + def test_ago assert_equal "Fri, 31 Dec 1999 18:59:59 EST -05:00", @twz.ago(1).inspect end @@ -680,53 +689,61 @@ class TimeWithZoneTest < ActiveSupport::TestCase def test_advance_1_year_from_leap_day twz = ActiveSupport::TimeWithZone.new(nil, @time_zone, Time.utc(2004,2,29)) - assert_equal "Mon, 28 Feb 2005 00:00:00 EST -05:00", twz.advance(:years => 1).inspect + assert_equal "Mon, 28 Feb 2005 00:00:00 EST -05:00", twz.advance(years: 1).inspect assert_equal "Mon, 28 Feb 2005 00:00:00 EST -05:00", twz.years_since(1).inspect assert_equal "Mon, 28 Feb 2005 00:00:00 EST -05:00", twz.since(1.year).inspect + assert_equal "Mon, 28 Feb 2005 00:00:00 EST -05:00", twz.in(1.year).inspect assert_equal "Mon, 28 Feb 2005 00:00:00 EST -05:00", (twz + 1.year).inspect end def test_advance_1_month_from_last_day_of_january twz = ActiveSupport::TimeWithZone.new(nil, @time_zone, Time.utc(2005,1,31)) - assert_equal "Mon, 28 Feb 2005 00:00:00 EST -05:00", twz.advance(:months => 1).inspect + assert_equal "Mon, 28 Feb 2005 00:00:00 EST -05:00", twz.advance(months: 1).inspect assert_equal "Mon, 28 Feb 2005 00:00:00 EST -05:00", twz.months_since(1).inspect assert_equal "Mon, 28 Feb 2005 00:00:00 EST -05:00", twz.since(1.month).inspect + assert_equal "Mon, 28 Feb 2005 00:00:00 EST -05:00", twz.in(1.month).inspect assert_equal "Mon, 28 Feb 2005 00:00:00 EST -05:00", (twz + 1.month).inspect end def test_advance_1_month_from_last_day_of_january_during_leap_year twz = ActiveSupport::TimeWithZone.new(nil, @time_zone, Time.utc(2000,1,31)) - assert_equal "Tue, 29 Feb 2000 00:00:00 EST -05:00", twz.advance(:months => 1).inspect + assert_equal "Tue, 29 Feb 2000 00:00:00 EST -05:00", twz.advance(months: 1).inspect assert_equal "Tue, 29 Feb 2000 00:00:00 EST -05:00", twz.months_since(1).inspect assert_equal "Tue, 29 Feb 2000 00:00:00 EST -05:00", twz.since(1.month).inspect + assert_equal "Tue, 29 Feb 2000 00:00:00 EST -05:00", twz.in(1.month).inspect assert_equal "Tue, 29 Feb 2000 00:00:00 EST -05:00", (twz + 1.month).inspect end def test_advance_1_month_into_spring_dst_gap twz = ActiveSupport::TimeWithZone.new(nil, @time_zone, Time.utc(2006,3,2,2)) - assert_equal "Sun, 02 Apr 2006 03:00:00 EDT -04:00", twz.advance(:months => 1).inspect + assert_equal "Sun, 02 Apr 2006 03:00:00 EDT -04:00", twz.advance(months: 1).inspect assert_equal "Sun, 02 Apr 2006 03:00:00 EDT -04:00", twz.months_since(1).inspect assert_equal "Sun, 02 Apr 2006 03:00:00 EDT -04:00", twz.since(1.month).inspect + assert_equal "Sun, 02 Apr 2006 03:00:00 EDT -04:00", twz.in(1.month).inspect assert_equal "Sun, 02 Apr 2006 03:00:00 EDT -04:00", (twz + 1.month).inspect end def test_advance_1_second_into_spring_dst_gap twz = ActiveSupport::TimeWithZone.new(nil, @time_zone, Time.utc(2006,4,2,1,59,59)) - assert_equal "Sun, 02 Apr 2006 03:00:00 EDT -04:00", twz.advance(:seconds => 1).inspect + assert_equal "Sun, 02 Apr 2006 03:00:00 EDT -04:00", twz.advance(seconds: 1).inspect assert_equal "Sun, 02 Apr 2006 03:00:00 EDT -04:00", (twz + 1).inspect + assert_equal "Sun, 02 Apr 2006 03:00:00 EDT -04:00", (twz + 1.second).inspect assert_equal "Sun, 02 Apr 2006 03:00:00 EDT -04:00", twz.since(1).inspect assert_equal "Sun, 02 Apr 2006 03:00:00 EDT -04:00", twz.since(1.second).inspect - assert_equal "Sun, 02 Apr 2006 03:00:00 EDT -04:00", (twz + 1.second).inspect + assert_equal "Sun, 02 Apr 2006 03:00:00 EDT -04:00", twz.in(1).inspect + assert_equal "Sun, 02 Apr 2006 03:00:00 EDT -04:00", twz.in(1.second).inspect end def test_advance_1_day_across_spring_dst_transition twz = ActiveSupport::TimeWithZone.new(nil, @time_zone, Time.utc(2006,4,1,10,30)) # In 2006, spring DST transition occurred Apr 2 at 2AM; this day was only 23 hours long # When we advance 1 day, we want to end up at the same time on the next day - assert_equal "Sun, 02 Apr 2006 10:30:00 EDT -04:00", twz.advance(:days => 1).inspect + assert_equal "Sun, 02 Apr 2006 10:30:00 EDT -04:00", twz.advance(days: 1).inspect assert_equal "Sun, 02 Apr 2006 10:30:00 EDT -04:00", twz.since(1.days).inspect + assert_equal "Sun, 02 Apr 2006 10:30:00 EDT -04:00", twz.in(1.days).inspect assert_equal "Sun, 02 Apr 2006 10:30:00 EDT -04:00", (twz + 1.days).inspect assert_equal "Sun, 02 Apr 2006 10:30:01 EDT -04:00", twz.since(1.days + 1.second).inspect + assert_equal "Sun, 02 Apr 2006 10:30:01 EDT -04:00", twz.in(1.days + 1.second).inspect assert_equal "Sun, 02 Apr 2006 10:30:01 EDT -04:00", (twz + 1.days + 1.second).inspect end @@ -734,7 +751,7 @@ class TimeWithZoneTest < ActiveSupport::TestCase twz = ActiveSupport::TimeWithZone.new(nil, @time_zone, Time.utc(2006,4,2,10,30)) # In 2006, spring DST transition occurred Apr 2 at 2AM; this day was only 23 hours long # When we advance back 1 day, we want to end up at the same time on the previous day - assert_equal "Sat, 01 Apr 2006 10:30:00 EST -05:00", twz.advance(:days => -1).inspect + assert_equal "Sat, 01 Apr 2006 10:30:00 EST -05:00", twz.advance(days: -1).inspect assert_equal "Sat, 01 Apr 2006 10:30:00 EST -05:00", twz.ago(1.days).inspect assert_equal "Sat, 01 Apr 2006 10:30:00 EST -05:00", (twz - 1.days).inspect assert_equal "Sat, 01 Apr 2006 10:30:01 EST -05:00", twz.ago(1.days - 1.second).inspect @@ -748,13 +765,17 @@ class TimeWithZoneTest < ActiveSupport::TestCase assert_equal "Sun, 02 Apr 2006 11:30:00 EDT -04:00", (twz + 86400.seconds).inspect assert_equal "Sun, 02 Apr 2006 11:30:00 EDT -04:00", twz.since(86400).inspect assert_equal "Sun, 02 Apr 2006 11:30:00 EDT -04:00", twz.since(86400.seconds).inspect - assert_equal "Sun, 02 Apr 2006 11:30:00 EDT -04:00", twz.advance(:seconds => 86400).inspect + assert_equal "Sun, 02 Apr 2006 11:30:00 EDT -04:00", twz.in(86400).inspect + assert_equal "Sun, 02 Apr 2006 11:30:00 EDT -04:00", twz.in(86400.seconds).inspect + assert_equal "Sun, 02 Apr 2006 11:30:00 EDT -04:00", twz.advance(seconds: 86400).inspect assert_equal "Sun, 02 Apr 2006 11:30:00 EDT -04:00", (twz + 1440.minutes).inspect assert_equal "Sun, 02 Apr 2006 11:30:00 EDT -04:00", twz.since(1440.minutes).inspect - assert_equal "Sun, 02 Apr 2006 11:30:00 EDT -04:00", twz.advance(:minutes => 1440).inspect + assert_equal "Sun, 02 Apr 2006 11:30:00 EDT -04:00", twz.in(1440.minutes).inspect + assert_equal "Sun, 02 Apr 2006 11:30:00 EDT -04:00", twz.advance(minutes: 1440).inspect assert_equal "Sun, 02 Apr 2006 11:30:00 EDT -04:00", (twz + 24.hours).inspect assert_equal "Sun, 02 Apr 2006 11:30:00 EDT -04:00", twz.since(24.hours).inspect - assert_equal "Sun, 02 Apr 2006 11:30:00 EDT -04:00", twz.advance(:hours => 24).inspect + assert_equal "Sun, 02 Apr 2006 11:30:00 EDT -04:00", twz.in(24.hours).inspect + assert_equal "Sun, 02 Apr 2006 11:30:00 EDT -04:00", twz.advance(hours: 24).inspect end def test_advance_1_day_expressed_as_number_of_seconds_minutes_or_hours_across_spring_dst_transition_backwards @@ -765,23 +786,25 @@ class TimeWithZoneTest < ActiveSupport::TestCase assert_equal "Sat, 01 Apr 2006 10:30:00 EST -05:00", (twz - 86400.seconds).inspect assert_equal "Sat, 01 Apr 2006 10:30:00 EST -05:00", twz.ago(86400).inspect assert_equal "Sat, 01 Apr 2006 10:30:00 EST -05:00", twz.ago(86400.seconds).inspect - assert_equal "Sat, 01 Apr 2006 10:30:00 EST -05:00", twz.advance(:seconds => -86400).inspect + assert_equal "Sat, 01 Apr 2006 10:30:00 EST -05:00", twz.advance(seconds: -86400).inspect assert_equal "Sat, 01 Apr 2006 10:30:00 EST -05:00", (twz - 1440.minutes).inspect assert_equal "Sat, 01 Apr 2006 10:30:00 EST -05:00", twz.ago(1440.minutes).inspect - assert_equal "Sat, 01 Apr 2006 10:30:00 EST -05:00", twz.advance(:minutes => -1440).inspect + assert_equal "Sat, 01 Apr 2006 10:30:00 EST -05:00", twz.advance(minutes: -1440).inspect assert_equal "Sat, 01 Apr 2006 10:30:00 EST -05:00", (twz - 24.hours).inspect assert_equal "Sat, 01 Apr 2006 10:30:00 EST -05:00", twz.ago(24.hours).inspect - assert_equal "Sat, 01 Apr 2006 10:30:00 EST -05:00", twz.advance(:hours => -24).inspect + assert_equal "Sat, 01 Apr 2006 10:30:00 EST -05:00", twz.advance(hours: -24).inspect end def test_advance_1_day_across_fall_dst_transition twz = ActiveSupport::TimeWithZone.new(nil, @time_zone, Time.utc(2006,10,28,10,30)) # In 2006, fall DST transition occurred Oct 29 at 2AM; this day was 25 hours long # When we advance 1 day, we want to end up at the same time on the next day - assert_equal "Sun, 29 Oct 2006 10:30:00 EST -05:00", twz.advance(:days => 1).inspect + assert_equal "Sun, 29 Oct 2006 10:30:00 EST -05:00", twz.advance(days: 1).inspect assert_equal "Sun, 29 Oct 2006 10:30:00 EST -05:00", twz.since(1.days).inspect + assert_equal "Sun, 29 Oct 2006 10:30:00 EST -05:00", twz.in(1.days).inspect assert_equal "Sun, 29 Oct 2006 10:30:00 EST -05:00", (twz + 1.days).inspect assert_equal "Sun, 29 Oct 2006 10:30:01 EST -05:00", twz.since(1.days + 1.second).inspect + assert_equal "Sun, 29 Oct 2006 10:30:01 EST -05:00", twz.in(1.days + 1.second).inspect assert_equal "Sun, 29 Oct 2006 10:30:01 EST -05:00", (twz + 1.days + 1.second).inspect end @@ -789,7 +812,7 @@ class TimeWithZoneTest < ActiveSupport::TestCase twz = ActiveSupport::TimeWithZone.new(nil, @time_zone, Time.utc(2006,10,29,10,30)) # In 2006, fall DST transition occurred Oct 29 at 2AM; this day was 25 hours long # When we advance backwards 1 day, we want to end up at the same time on the previous day - assert_equal "Sat, 28 Oct 2006 10:30:00 EDT -04:00", twz.advance(:days => -1).inspect + assert_equal "Sat, 28 Oct 2006 10:30:00 EDT -04:00", twz.advance(days: -1).inspect assert_equal "Sat, 28 Oct 2006 10:30:00 EDT -04:00", twz.ago(1.days).inspect assert_equal "Sat, 28 Oct 2006 10:30:00 EDT -04:00", (twz - 1.days).inspect assert_equal "Sat, 28 Oct 2006 10:30:01 EDT -04:00", twz.ago(1.days - 1.second).inspect @@ -803,13 +826,17 @@ class TimeWithZoneTest < ActiveSupport::TestCase assert_equal "Sun, 29 Oct 2006 09:30:00 EST -05:00", (twz + 86400.seconds).inspect assert_equal "Sun, 29 Oct 2006 09:30:00 EST -05:00", twz.since(86400).inspect assert_equal "Sun, 29 Oct 2006 09:30:00 EST -05:00", twz.since(86400.seconds).inspect - assert_equal "Sun, 29 Oct 2006 09:30:00 EST -05:00", twz.advance(:seconds => 86400).inspect + assert_equal "Sun, 29 Oct 2006 09:30:00 EST -05:00", twz.in(86400).inspect + assert_equal "Sun, 29 Oct 2006 09:30:00 EST -05:00", twz.in(86400.seconds).inspect + assert_equal "Sun, 29 Oct 2006 09:30:00 EST -05:00", twz.advance(seconds: 86400).inspect assert_equal "Sun, 29 Oct 2006 09:30:00 EST -05:00", (twz + 1440.minutes).inspect assert_equal "Sun, 29 Oct 2006 09:30:00 EST -05:00", twz.since(1440.minutes).inspect - assert_equal "Sun, 29 Oct 2006 09:30:00 EST -05:00", twz.advance(:minutes => 1440).inspect + assert_equal "Sun, 29 Oct 2006 09:30:00 EST -05:00", twz.in(1440.minutes).inspect + assert_equal "Sun, 29 Oct 2006 09:30:00 EST -05:00", twz.advance(minutes: 1440).inspect assert_equal "Sun, 29 Oct 2006 09:30:00 EST -05:00", (twz + 24.hours).inspect assert_equal "Sun, 29 Oct 2006 09:30:00 EST -05:00", twz.since(24.hours).inspect - assert_equal "Sun, 29 Oct 2006 09:30:00 EST -05:00", twz.advance(:hours => 24).inspect + assert_equal "Sun, 29 Oct 2006 09:30:00 EST -05:00", twz.in(24.hours).inspect + assert_equal "Sun, 29 Oct 2006 09:30:00 EST -05:00", twz.advance(hours: 24).inspect end def test_advance_1_day_expressed_as_number_of_seconds_minutes_or_hours_across_fall_dst_transition_backwards @@ -820,26 +847,61 @@ class TimeWithZoneTest < ActiveSupport::TestCase assert_equal "Sat, 28 Oct 2006 10:30:00 EDT -04:00", (twz - 86400.seconds).inspect assert_equal "Sat, 28 Oct 2006 10:30:00 EDT -04:00", twz.ago(86400).inspect assert_equal "Sat, 28 Oct 2006 10:30:00 EDT -04:00", twz.ago(86400.seconds).inspect - assert_equal "Sat, 28 Oct 2006 10:30:00 EDT -04:00", twz.advance(:seconds => -86400).inspect + assert_equal "Sat, 28 Oct 2006 10:30:00 EDT -04:00", twz.advance(seconds: -86400).inspect assert_equal "Sat, 28 Oct 2006 10:30:00 EDT -04:00", (twz - 1440.minutes).inspect assert_equal "Sat, 28 Oct 2006 10:30:00 EDT -04:00", twz.ago(1440.minutes).inspect - assert_equal "Sat, 28 Oct 2006 10:30:00 EDT -04:00", twz.advance(:minutes => -1440).inspect + assert_equal "Sat, 28 Oct 2006 10:30:00 EDT -04:00", twz.advance(minutes: -1440).inspect assert_equal "Sat, 28 Oct 2006 10:30:00 EDT -04:00", (twz - 24.hours).inspect assert_equal "Sat, 28 Oct 2006 10:30:00 EDT -04:00", twz.ago(24.hours).inspect - assert_equal "Sat, 28 Oct 2006 10:30:00 EDT -04:00", twz.advance(:hours => -24).inspect + assert_equal "Sat, 28 Oct 2006 10:30:00 EDT -04:00", twz.advance(hours: -24).inspect + end + + def test_advance_1_week_across_spring_dst_transition + twz = ActiveSupport::TimeWithZone.new(nil, @time_zone, Time.utc(2006,4,1,10,30)) + assert_equal "Sat, 08 Apr 2006 10:30:00 EDT -04:00", twz.advance(weeks: 1).inspect + assert_equal "Sat, 08 Apr 2006 10:30:00 EDT -04:00", twz.weeks_since(1).inspect + assert_equal "Sat, 08 Apr 2006 10:30:00 EDT -04:00", twz.since(1.week).inspect + assert_equal "Sat, 08 Apr 2006 10:30:00 EDT -04:00", twz.in(1.week).inspect + assert_equal "Sat, 08 Apr 2006 10:30:00 EDT -04:00", (twz + 1.week).inspect + end + + def test_advance_1_week_across_spring_dst_transition_backwards + twz = ActiveSupport::TimeWithZone.new(nil, @time_zone, Time.utc(2006,4,8,10,30)) + assert_equal "Sat, 01 Apr 2006 10:30:00 EST -05:00", twz.advance(weeks: -1).inspect + assert_equal "Sat, 01 Apr 2006 10:30:00 EST -05:00", twz.weeks_ago(1).inspect + assert_equal "Sat, 01 Apr 2006 10:30:00 EST -05:00", twz.ago(1.week).inspect + assert_equal "Sat, 01 Apr 2006 10:30:00 EST -05:00", (twz - 1.week).inspect + end + + def test_advance_1_week_across_fall_dst_transition + twz = ActiveSupport::TimeWithZone.new(nil, @time_zone, Time.utc(2006,10,28,10,30)) + assert_equal "Sat, 04 Nov 2006 10:30:00 EST -05:00", twz.advance(weeks: 1).inspect + assert_equal "Sat, 04 Nov 2006 10:30:00 EST -05:00", twz.weeks_since(1).inspect + assert_equal "Sat, 04 Nov 2006 10:30:00 EST -05:00", twz.since(1.week).inspect + assert_equal "Sat, 04 Nov 2006 10:30:00 EST -05:00", twz.in(1.week).inspect + assert_equal "Sat, 04 Nov 2006 10:30:00 EST -05:00", (twz + 1.week).inspect + end + + def test_advance_1_week_across_fall_dst_transition_backwards + twz = ActiveSupport::TimeWithZone.new(nil, @time_zone, Time.utc(2006,11,4,10,30)) + assert_equal "Sat, 28 Oct 2006 10:30:00 EDT -04:00", twz.advance(weeks: -1).inspect + assert_equal "Sat, 28 Oct 2006 10:30:00 EDT -04:00", twz.weeks_ago(1).inspect + assert_equal "Sat, 28 Oct 2006 10:30:00 EDT -04:00", twz.ago(1.week).inspect + assert_equal "Sat, 28 Oct 2006 10:30:00 EDT -04:00", (twz - 1.week).inspect end def test_advance_1_month_across_spring_dst_transition twz = ActiveSupport::TimeWithZone.new(nil, @time_zone, Time.utc(2006,4,1,10,30)) - assert_equal "Mon, 01 May 2006 10:30:00 EDT -04:00", twz.advance(:months => 1).inspect + assert_equal "Mon, 01 May 2006 10:30:00 EDT -04:00", twz.advance(months: 1).inspect assert_equal "Mon, 01 May 2006 10:30:00 EDT -04:00", twz.months_since(1).inspect assert_equal "Mon, 01 May 2006 10:30:00 EDT -04:00", twz.since(1.month).inspect + assert_equal "Mon, 01 May 2006 10:30:00 EDT -04:00", twz.in(1.month).inspect assert_equal "Mon, 01 May 2006 10:30:00 EDT -04:00", (twz + 1.month).inspect end def test_advance_1_month_across_spring_dst_transition_backwards twz = ActiveSupport::TimeWithZone.new(nil, @time_zone, Time.utc(2006,5,1,10,30)) - assert_equal "Sat, 01 Apr 2006 10:30:00 EST -05:00", twz.advance(:months => -1).inspect + assert_equal "Sat, 01 Apr 2006 10:30:00 EST -05:00", twz.advance(months: -1).inspect assert_equal "Sat, 01 Apr 2006 10:30:00 EST -05:00", twz.months_ago(1).inspect assert_equal "Sat, 01 Apr 2006 10:30:00 EST -05:00", twz.ago(1.month).inspect assert_equal "Sat, 01 Apr 2006 10:30:00 EST -05:00", (twz - 1.month).inspect @@ -847,15 +909,16 @@ class TimeWithZoneTest < ActiveSupport::TestCase def test_advance_1_month_across_fall_dst_transition twz = ActiveSupport::TimeWithZone.new(nil, @time_zone, Time.utc(2006,10,28,10,30)) - assert_equal "Tue, 28 Nov 2006 10:30:00 EST -05:00", twz.advance(:months => 1).inspect + assert_equal "Tue, 28 Nov 2006 10:30:00 EST -05:00", twz.advance(months: 1).inspect assert_equal "Tue, 28 Nov 2006 10:30:00 EST -05:00", twz.months_since(1).inspect assert_equal "Tue, 28 Nov 2006 10:30:00 EST -05:00", twz.since(1.month).inspect + assert_equal "Tue, 28 Nov 2006 10:30:00 EST -05:00", twz.in(1.month).inspect assert_equal "Tue, 28 Nov 2006 10:30:00 EST -05:00", (twz + 1.month).inspect end def test_advance_1_month_across_fall_dst_transition_backwards twz = ActiveSupport::TimeWithZone.new(nil, @time_zone, Time.utc(2006,11,28,10,30)) - assert_equal "Sat, 28 Oct 2006 10:30:00 EDT -04:00", twz.advance(:months => -1).inspect + assert_equal "Sat, 28 Oct 2006 10:30:00 EDT -04:00", twz.advance(months: -1).inspect assert_equal "Sat, 28 Oct 2006 10:30:00 EDT -04:00", twz.months_ago(1).inspect assert_equal "Sat, 28 Oct 2006 10:30:00 EDT -04:00", twz.ago(1.month).inspect assert_equal "Sat, 28 Oct 2006 10:30:00 EDT -04:00", (twz - 1.month).inspect @@ -863,20 +926,24 @@ class TimeWithZoneTest < ActiveSupport::TestCase def test_advance_1_year twz = ActiveSupport::TimeWithZone.new(nil, @time_zone, Time.utc(2008,2,15,10,30)) - assert_equal "Sun, 15 Feb 2009 10:30:00 EST -05:00", twz.advance(:years => 1).inspect + assert_equal "Sun, 15 Feb 2009 10:30:00 EST -05:00", twz.advance(years: 1).inspect assert_equal "Sun, 15 Feb 2009 10:30:00 EST -05:00", twz.years_since(1).inspect + assert_equal "Sun, 15 Feb 2009 10:30:00 EST -05:00", twz.since(1.year).inspect + assert_equal "Sun, 15 Feb 2009 10:30:00 EST -05:00", twz.in(1.year).inspect assert_equal "Sun, 15 Feb 2009 10:30:00 EST -05:00", (twz + 1.year).inspect - assert_equal "Thu, 15 Feb 2007 10:30:00 EST -05:00", twz.advance(:years => -1).inspect + assert_equal "Thu, 15 Feb 2007 10:30:00 EST -05:00", twz.advance(years: -1).inspect assert_equal "Thu, 15 Feb 2007 10:30:00 EST -05:00", twz.years_ago(1).inspect assert_equal "Thu, 15 Feb 2007 10:30:00 EST -05:00", (twz - 1.year).inspect end def test_advance_1_year_during_dst twz = ActiveSupport::TimeWithZone.new(nil, @time_zone, Time.utc(2008,7,15,10,30)) - assert_equal "Wed, 15 Jul 2009 10:30:00 EDT -04:00", twz.advance(:years => 1).inspect + assert_equal "Wed, 15 Jul 2009 10:30:00 EDT -04:00", twz.advance(years: 1).inspect assert_equal "Wed, 15 Jul 2009 10:30:00 EDT -04:00", twz.years_since(1).inspect + assert_equal "Wed, 15 Jul 2009 10:30:00 EDT -04:00", twz.since(1.year).inspect + assert_equal "Wed, 15 Jul 2009 10:30:00 EDT -04:00", twz.in(1.year).inspect assert_equal "Wed, 15 Jul 2009 10:30:00 EDT -04:00", (twz + 1.year).inspect - assert_equal "Sun, 15 Jul 2007 10:30:00 EDT -04:00", twz.advance(:years => -1).inspect + assert_equal "Sun, 15 Jul 2007 10:30:00 EDT -04:00", twz.advance(years: -1).inspect assert_equal "Sun, 15 Jul 2007 10:30:00 EDT -04:00", twz.years_ago(1).inspect assert_equal "Sun, 15 Jul 2007 10:30:00 EDT -04:00", (twz - 1.year).inspect end @@ -904,13 +971,13 @@ class TimeWithZoneMethodsForTimeAndDateTimeTest < ActiveSupport::TestCase end def test_in_time_zone - Time.use_zone 'Alaska' do - assert_equal 'Fri, 31 Dec 1999 15:00:00 AKST -09:00', @t.in_time_zone.inspect - assert_equal 'Fri, 31 Dec 1999 15:00:00 AKST -09:00', @dt.in_time_zone.inspect + Time.use_zone "Alaska" do + assert_equal "Fri, 31 Dec 1999 15:00:00 AKST -09:00", @t.in_time_zone.inspect + assert_equal "Fri, 31 Dec 1999 15:00:00 AKST -09:00", @dt.in_time_zone.inspect end - Time.use_zone 'Hawaii' do - assert_equal 'Fri, 31 Dec 1999 14:00:00 HST -10:00', @t.in_time_zone.inspect - assert_equal 'Fri, 31 Dec 1999 14:00:00 HST -10:00', @dt.in_time_zone.inspect + Time.use_zone "Hawaii" do + assert_equal "Fri, 31 Dec 1999 14:00:00 HST -10:00", @t.in_time_zone.inspect + assert_equal "Fri, 31 Dec 1999 14:00:00 HST -10:00", @dt.in_time_zone.inspect end Time.use_zone nil do assert_equal @t, @t.in_time_zone @@ -920,20 +987,20 @@ class TimeWithZoneMethodsForTimeAndDateTimeTest < ActiveSupport::TestCase def test_nil_time_zone Time.use_zone nil do - assert !@t.in_time_zone.respond_to?(:period), 'no period method' - assert !@dt.in_time_zone.respond_to?(:period), 'no period method' + assert !@t.in_time_zone.respond_to?(:period), "no period method" + assert !@dt.in_time_zone.respond_to?(:period), "no period method" end end def test_in_time_zone_with_argument - Time.use_zone 'Eastern Time (US & Canada)' do # Time.zone will not affect #in_time_zone(zone) - assert_equal 'Fri, 31 Dec 1999 15:00:00 AKST -09:00', @t.in_time_zone('Alaska').inspect - assert_equal 'Fri, 31 Dec 1999 15:00:00 AKST -09:00', @dt.in_time_zone('Alaska').inspect - assert_equal 'Fri, 31 Dec 1999 14:00:00 HST -10:00', @t.in_time_zone('Hawaii').inspect - assert_equal 'Fri, 31 Dec 1999 14:00:00 HST -10:00', @dt.in_time_zone('Hawaii').inspect - assert_equal 'Sat, 01 Jan 2000 00:00:00 UTC +00:00', @t.in_time_zone('UTC').inspect - assert_equal 'Sat, 01 Jan 2000 00:00:00 UTC +00:00', @dt.in_time_zone('UTC').inspect - assert_equal 'Fri, 31 Dec 1999 15:00:00 AKST -09:00', @t.in_time_zone(-9.hours).inspect + Time.use_zone "Eastern Time (US & Canada)" do # Time.zone will not affect #in_time_zone(zone) + assert_equal "Fri, 31 Dec 1999 15:00:00 AKST -09:00", @t.in_time_zone("Alaska").inspect + assert_equal "Fri, 31 Dec 1999 15:00:00 AKST -09:00", @dt.in_time_zone("Alaska").inspect + assert_equal "Fri, 31 Dec 1999 14:00:00 HST -10:00", @t.in_time_zone("Hawaii").inspect + assert_equal "Fri, 31 Dec 1999 14:00:00 HST -10:00", @dt.in_time_zone("Hawaii").inspect + assert_equal "Sat, 01 Jan 2000 00:00:00 UTC +00:00", @t.in_time_zone("UTC").inspect + assert_equal "Sat, 01 Jan 2000 00:00:00 UTC +00:00", @dt.in_time_zone("UTC").inspect + assert_equal "Fri, 31 Dec 1999 15:00:00 AKST -09:00", @t.in_time_zone(-9.hours).inspect end end @@ -947,119 +1014,119 @@ class TimeWithZoneMethodsForTimeAndDateTimeTest < ActiveSupport::TestCase end def test_in_time_zone_with_time_local_instance - with_env_tz 'US/Eastern' do + with_env_tz "US/Eastern" do time = Time.local(1999, 12, 31, 19) # == Time.utc(2000) - assert_equal 'Fri, 31 Dec 1999 15:00:00 AKST -09:00', time.in_time_zone('Alaska').inspect + assert_equal "Fri, 31 Dec 1999 15:00:00 AKST -09:00", time.in_time_zone("Alaska").inspect end end def test_localtime - Time.zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)'] + Time.zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"] assert_equal @dt.in_time_zone.localtime, @dt.in_time_zone.utc.to_time.getlocal end def test_use_zone - Time.zone = 'Alaska' - Time.use_zone 'Hawaii' do - assert_equal ActiveSupport::TimeZone['Hawaii'], Time.zone + Time.zone = "Alaska" + Time.use_zone "Hawaii" do + assert_equal ActiveSupport::TimeZone["Hawaii"], Time.zone end - assert_equal ActiveSupport::TimeZone['Alaska'], Time.zone + assert_equal ActiveSupport::TimeZone["Alaska"], Time.zone end def test_use_zone_with_exception_raised - Time.zone = 'Alaska' + Time.zone = "Alaska" assert_raise RuntimeError do - Time.use_zone('Hawaii') { raise RuntimeError } + Time.use_zone("Hawaii") { raise RuntimeError } end - assert_equal ActiveSupport::TimeZone['Alaska'], Time.zone + assert_equal ActiveSupport::TimeZone["Alaska"], Time.zone end def test_use_zone_raises_on_invalid_timezone - Time.zone = 'Alaska' + Time.zone = "Alaska" assert_raise ArgumentError do - Time.use_zone("No such timezone exists") { } + Time.use_zone("No such timezone exists") {} end - assert_equal ActiveSupport::TimeZone['Alaska'], Time.zone + assert_equal ActiveSupport::TimeZone["Alaska"], Time.zone end def test_time_zone_getter_and_setter - Time.zone = ActiveSupport::TimeZone['Alaska'] - assert_equal ActiveSupport::TimeZone['Alaska'], Time.zone - Time.zone = 'Alaska' - assert_equal ActiveSupport::TimeZone['Alaska'], Time.zone + Time.zone = ActiveSupport::TimeZone["Alaska"] + assert_equal ActiveSupport::TimeZone["Alaska"], Time.zone + Time.zone = "Alaska" + assert_equal ActiveSupport::TimeZone["Alaska"], Time.zone Time.zone = -9.hours - assert_equal ActiveSupport::TimeZone['Alaska'], Time.zone + assert_equal ActiveSupport::TimeZone["Alaska"], Time.zone Time.zone = nil assert_equal nil, Time.zone end def test_time_zone_getter_and_setter_with_zone_default_set old_zone_default = Time.zone_default - Time.zone_default = ActiveSupport::TimeZone['Alaska'] - assert_equal ActiveSupport::TimeZone['Alaska'], Time.zone - Time.zone = ActiveSupport::TimeZone['Hawaii'] - assert_equal ActiveSupport::TimeZone['Hawaii'], Time.zone + Time.zone_default = ActiveSupport::TimeZone["Alaska"] + assert_equal ActiveSupport::TimeZone["Alaska"], Time.zone + Time.zone = ActiveSupport::TimeZone["Hawaii"] + assert_equal ActiveSupport::TimeZone["Hawaii"], Time.zone Time.zone = nil - assert_equal ActiveSupport::TimeZone['Alaska'], Time.zone + assert_equal ActiveSupport::TimeZone["Alaska"], Time.zone ensure Time.zone_default = old_zone_default end def test_time_zone_setter_is_thread_safe - Time.use_zone 'Paris' do - t1 = Thread.new { Time.zone = 'Alaska' }.join - t2 = Thread.new { Time.zone = 'Hawaii' }.join + Time.use_zone "Paris" do + t1 = Thread.new { Time.zone = "Alaska" }.join + t2 = Thread.new { Time.zone = "Hawaii" }.join assert t1.stop?, "Thread 1 did not finish running" assert t2.stop?, "Thread 2 did not finish running" - assert_equal ActiveSupport::TimeZone['Paris'], Time.zone - assert_equal ActiveSupport::TimeZone['Alaska'], t1[:time_zone] - assert_equal ActiveSupport::TimeZone['Hawaii'], t2[:time_zone] + assert_equal ActiveSupport::TimeZone["Paris"], Time.zone + assert_equal ActiveSupport::TimeZone["Alaska"], t1[:time_zone] + assert_equal ActiveSupport::TimeZone["Hawaii"], t2[:time_zone] end end def test_time_zone_setter_with_tzinfo_timezone_object_wraps_in_rails_time_zone - tzinfo = TZInfo::Timezone.get('America/New_York') + tzinfo = TZInfo::Timezone.get("America/New_York") Time.zone = tzinfo assert_kind_of ActiveSupport::TimeZone, Time.zone assert_equal tzinfo, Time.zone.tzinfo - assert_equal 'America/New_York', Time.zone.name + assert_equal "America/New_York", Time.zone.name assert_equal(-18_000, Time.zone.utc_offset) end def test_time_zone_setter_with_tzinfo_timezone_identifier_does_lookup_and_wraps_in_rails_time_zone - Time.zone = 'America/New_York' + Time.zone = "America/New_York" assert_kind_of ActiveSupport::TimeZone, Time.zone - assert_equal 'America/New_York', Time.zone.tzinfo.name - assert_equal 'America/New_York', Time.zone.name + assert_equal "America/New_York", Time.zone.tzinfo.name + assert_equal "America/New_York", Time.zone.name assert_equal(-18_000, Time.zone.utc_offset) end def test_time_zone_setter_with_invalid_zone - assert_raise(ArgumentError){ Time.zone = "No such timezone exists" } - assert_raise(ArgumentError){ Time.zone = -15.hours } - assert_raise(ArgumentError){ Time.zone = Object.new } + assert_raise(ArgumentError) { Time.zone = "No such timezone exists" } + assert_raise(ArgumentError) { Time.zone = -15.hours } + assert_raise(ArgumentError) { Time.zone = Object.new } end def test_find_zone_without_bang_returns_nil_if_time_zone_can_not_be_found - assert_nil Time.find_zone('No such timezone exists') + assert_nil Time.find_zone("No such timezone exists") assert_nil Time.find_zone(-15.hours) assert_nil Time.find_zone(Object.new) end def test_find_zone_with_bang_raises_if_time_zone_can_not_be_found - assert_raise(ArgumentError) { Time.find_zone!('No such timezone exists') } + assert_raise(ArgumentError) { Time.find_zone!("No such timezone exists") } assert_raise(ArgumentError) { Time.find_zone!(-15.hours) } assert_raise(ArgumentError) { Time.find_zone!(Object.new) } end def test_time_zone_setter_with_find_zone_without_bang - assert_nil Time.zone = Time.find_zone('No such timezone exists') + assert_nil Time.zone = Time.find_zone("No such timezone exists") assert_nil Time.zone = Time.find_zone(-15.hours) assert_nil Time.zone = Time.find_zone(Object.new) end def test_current_returns_time_now_when_zone_not_set - with_env_tz 'US/Eastern' do + with_env_tz "US/Eastern" do Time.stub(:now, Time.local(2000)) do assert_equal false, Time.current.is_a?(ActiveSupport::TimeWithZone) assert_equal Time.local(2000), Time.current @@ -1068,22 +1135,22 @@ class TimeWithZoneMethodsForTimeAndDateTimeTest < ActiveSupport::TestCase end def test_current_returns_time_zone_now_when_zone_set - Time.zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)'] - with_env_tz 'US/Eastern' do + Time.zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"] + with_env_tz "US/Eastern" do Time.stub(:now, Time.local(2000)) do assert_equal true, Time.current.is_a?(ActiveSupport::TimeWithZone) - assert_equal 'Eastern Time (US & Canada)', Time.current.time_zone.name + assert_equal "Eastern Time (US & Canada)", Time.current.time_zone.name assert_equal Time.utc(2000), Time.current.time end end end def test_time_in_time_zone_doesnt_affect_receiver - with_env_tz 'Europe/London' do + with_env_tz "Europe/London" do time = Time.local(2000, 7, 1) - time_with_zone = time.in_time_zone('Eastern Time (US & Canada)') + time_with_zone = time.in_time_zone("Eastern Time (US & Canada)") assert_equal Time.utc(2000, 6, 30, 23, 0, 0), time_with_zone - assert_not time.utc?, 'time expected to be local, but is UTC' + assert_not time.utc?, "time expected to be local, but is UTC" end end end @@ -1096,11 +1163,11 @@ class TimeWithZoneMethodsForDate < ActiveSupport::TestCase end def test_in_time_zone - with_tz_default 'Alaska' do - assert_equal 'Sat, 01 Jan 2000 00:00:00 AKST -09:00', @d.in_time_zone.inspect + with_tz_default "Alaska" do + assert_equal "Sat, 01 Jan 2000 00:00:00 AKST -09:00", @d.in_time_zone.inspect end - with_tz_default 'Hawaii' do - assert_equal 'Sat, 01 Jan 2000 00:00:00 HST -10:00', @d.in_time_zone.inspect + with_tz_default "Hawaii" do + assert_equal "Sat, 01 Jan 2000 00:00:00 HST -10:00", @d.in_time_zone.inspect end with_tz_default nil do assert_equal @d.to_time, @d.in_time_zone @@ -1109,16 +1176,16 @@ class TimeWithZoneMethodsForDate < ActiveSupport::TestCase def test_nil_time_zone with_tz_default nil do - assert !@d.in_time_zone.respond_to?(:period), 'no period method' + assert !@d.in_time_zone.respond_to?(:period), "no period method" end end def test_in_time_zone_with_argument - with_tz_default 'Eastern Time (US & Canada)' do # Time.zone will not affect #in_time_zone(zone) - assert_equal 'Sat, 01 Jan 2000 00:00:00 AKST -09:00', @d.in_time_zone('Alaska').inspect - assert_equal 'Sat, 01 Jan 2000 00:00:00 HST -10:00', @d.in_time_zone('Hawaii').inspect - assert_equal 'Sat, 01 Jan 2000 00:00:00 UTC +00:00', @d.in_time_zone('UTC').inspect - assert_equal 'Sat, 01 Jan 2000 00:00:00 AKST -09:00', @d.in_time_zone(-9.hours).inspect + with_tz_default "Eastern Time (US & Canada)" do # Time.zone will not affect #in_time_zone(zone) + assert_equal "Sat, 01 Jan 2000 00:00:00 AKST -09:00", @d.in_time_zone("Alaska").inspect + assert_equal "Sat, 01 Jan 2000 00:00:00 HST -10:00", @d.in_time_zone("Hawaii").inspect + assert_equal "Sat, 01 Jan 2000 00:00:00 UTC +00:00", @d.in_time_zone("UTC").inspect + assert_equal "Sat, 01 Jan 2000 00:00:00 AKST -09:00", @d.in_time_zone(-9.hours).inspect end end @@ -1139,15 +1206,15 @@ class TimeWithZoneMethodsForString < ActiveSupport::TestCase end def test_in_time_zone - with_tz_default 'Alaska' do - assert_equal 'Sat, 01 Jan 2000 00:00:00 AKST -09:00', @s.in_time_zone.inspect - assert_equal 'Fri, 31 Dec 1999 15:00:00 AKST -09:00', @u.in_time_zone.inspect - assert_equal 'Fri, 31 Dec 1999 15:00:00 AKST -09:00', @z.in_time_zone.inspect + with_tz_default "Alaska" do + assert_equal "Sat, 01 Jan 2000 00:00:00 AKST -09:00", @s.in_time_zone.inspect + assert_equal "Fri, 31 Dec 1999 15:00:00 AKST -09:00", @u.in_time_zone.inspect + assert_equal "Fri, 31 Dec 1999 15:00:00 AKST -09:00", @z.in_time_zone.inspect end - with_tz_default 'Hawaii' do - assert_equal 'Sat, 01 Jan 2000 00:00:00 HST -10:00', @s.in_time_zone.inspect - assert_equal 'Fri, 31 Dec 1999 14:00:00 HST -10:00', @u.in_time_zone.inspect - assert_equal 'Fri, 31 Dec 1999 14:00:00 HST -10:00', @z.in_time_zone.inspect + with_tz_default "Hawaii" do + assert_equal "Sat, 01 Jan 2000 00:00:00 HST -10:00", @s.in_time_zone.inspect + assert_equal "Fri, 31 Dec 1999 14:00:00 HST -10:00", @u.in_time_zone.inspect + assert_equal "Fri, 31 Dec 1999 14:00:00 HST -10:00", @z.in_time_zone.inspect end with_tz_default nil do assert_equal @s.to_time, @s.in_time_zone @@ -1158,26 +1225,26 @@ class TimeWithZoneMethodsForString < ActiveSupport::TestCase def test_nil_time_zone with_tz_default nil do - assert !@s.in_time_zone.respond_to?(:period), 'no period method' - assert !@u.in_time_zone.respond_to?(:period), 'no period method' - assert !@z.in_time_zone.respond_to?(:period), 'no period method' + assert !@s.in_time_zone.respond_to?(:period), "no period method" + assert !@u.in_time_zone.respond_to?(:period), "no period method" + assert !@z.in_time_zone.respond_to?(:period), "no period method" end end def test_in_time_zone_with_argument - with_tz_default 'Eastern Time (US & Canada)' do # Time.zone will not affect #in_time_zone(zone) - assert_equal 'Sat, 01 Jan 2000 00:00:00 AKST -09:00', @s.in_time_zone('Alaska').inspect - assert_equal 'Fri, 31 Dec 1999 15:00:00 AKST -09:00', @u.in_time_zone('Alaska').inspect - assert_equal 'Fri, 31 Dec 1999 15:00:00 AKST -09:00', @z.in_time_zone('Alaska').inspect - assert_equal 'Sat, 01 Jan 2000 00:00:00 HST -10:00', @s.in_time_zone('Hawaii').inspect - assert_equal 'Fri, 31 Dec 1999 14:00:00 HST -10:00', @u.in_time_zone('Hawaii').inspect - assert_equal 'Fri, 31 Dec 1999 14:00:00 HST -10:00', @z.in_time_zone('Hawaii').inspect - assert_equal 'Sat, 01 Jan 2000 00:00:00 UTC +00:00', @s.in_time_zone('UTC').inspect - assert_equal 'Sat, 01 Jan 2000 00:00:00 UTC +00:00', @u.in_time_zone('UTC').inspect - assert_equal 'Sat, 01 Jan 2000 00:00:00 UTC +00:00', @z.in_time_zone('UTC').inspect - assert_equal 'Sat, 01 Jan 2000 00:00:00 AKST -09:00', @s.in_time_zone(-9.hours).inspect - assert_equal 'Fri, 31 Dec 1999 15:00:00 AKST -09:00', @u.in_time_zone(-9.hours).inspect - assert_equal 'Fri, 31 Dec 1999 15:00:00 AKST -09:00', @z.in_time_zone(-9.hours).inspect + with_tz_default "Eastern Time (US & Canada)" do # Time.zone will not affect #in_time_zone(zone) + assert_equal "Sat, 01 Jan 2000 00:00:00 AKST -09:00", @s.in_time_zone("Alaska").inspect + assert_equal "Fri, 31 Dec 1999 15:00:00 AKST -09:00", @u.in_time_zone("Alaska").inspect + assert_equal "Fri, 31 Dec 1999 15:00:00 AKST -09:00", @z.in_time_zone("Alaska").inspect + assert_equal "Sat, 01 Jan 2000 00:00:00 HST -10:00", @s.in_time_zone("Hawaii").inspect + assert_equal "Fri, 31 Dec 1999 14:00:00 HST -10:00", @u.in_time_zone("Hawaii").inspect + assert_equal "Fri, 31 Dec 1999 14:00:00 HST -10:00", @z.in_time_zone("Hawaii").inspect + assert_equal "Sat, 01 Jan 2000 00:00:00 UTC +00:00", @s.in_time_zone("UTC").inspect + assert_equal "Sat, 01 Jan 2000 00:00:00 UTC +00:00", @u.in_time_zone("UTC").inspect + assert_equal "Sat, 01 Jan 2000 00:00:00 UTC +00:00", @z.in_time_zone("UTC").inspect + assert_equal "Sat, 01 Jan 2000 00:00:00 AKST -09:00", @s.in_time_zone(-9.hours).inspect + assert_equal "Fri, 31 Dec 1999 15:00:00 AKST -09:00", @u.in_time_zone(-9.hours).inspect + assert_equal "Fri, 31 Dec 1999 15:00:00 AKST -09:00", @z.in_time_zone(-9.hours).inspect end end diff --git a/activesupport/test/core_ext/uri_ext_test.rb b/activesupport/test/core_ext/uri_ext_test.rb index 1694fe7e72..0f13ca9c0e 100644 --- a/activesupport/test/core_ext/uri_ext_test.rb +++ b/activesupport/test/core_ext/uri_ext_test.rb @@ -1,6 +1,6 @@ -require 'abstract_unit' -require 'uri' -require 'active_support/core_ext/uri' +require "abstract_unit" +require "uri" +require "active_support/core_ext/uri" class URIExtTest < ActiveSupport::TestCase def test_uri_decode_handle_multibyte diff --git a/activesupport/test/dependencies/conflict.rb b/activesupport/test/dependencies/conflict.rb index e888b7b54c..7eff49bbfa 100644 --- a/activesupport/test/dependencies/conflict.rb +++ b/activesupport/test/dependencies/conflict.rb @@ -1 +1 @@ -Conflict = 1
\ No newline at end of file +Conflict = 1 diff --git a/activesupport/test/dependencies/cross_site_depender.rb b/activesupport/test/dependencies/cross_site_depender.rb index a31015fc5e..fbc3b64f56 100644 --- a/activesupport/test/dependencies/cross_site_depender.rb +++ b/activesupport/test/dependencies/cross_site_depender.rb @@ -1,3 +1,3 @@ class CrossSiteDepender CrossSiteDependency -end
\ No newline at end of file +end diff --git a/activesupport/test/dependencies/mutual_one.rb b/activesupport/test/dependencies/mutual_one.rb index 576eb31711..05f08f82d3 100644 --- a/activesupport/test/dependencies/mutual_one.rb +++ b/activesupport/test/dependencies/mutual_one.rb @@ -1,4 +1,4 @@ $mutual_dependencies_count += 1 -require_dependency 'mutual_two' -require_dependency 'mutual_two.rb' -require_dependency 'mutual_two' +require_dependency "mutual_two" +require_dependency "mutual_two.rb" +require_dependency "mutual_two" diff --git a/activesupport/test/dependencies/mutual_two.rb b/activesupport/test/dependencies/mutual_two.rb index fdbc2dcd84..1d87d334af 100644 --- a/activesupport/test/dependencies/mutual_two.rb +++ b/activesupport/test/dependencies/mutual_two.rb @@ -1,4 +1,4 @@ $mutual_dependencies_count += 1 -require_dependency 'mutual_one.rb' -require_dependency 'mutual_one' -require_dependency 'mutual_one.rb' +require_dependency "mutual_one.rb" +require_dependency "mutual_one" +require_dependency "mutual_one.rb" diff --git a/activesupport/test/dependencies/raises_exception.rb b/activesupport/test/dependencies/raises_exception.rb index dd745ac20e..0a56680fe3 100644 --- a/activesupport/test/dependencies/raises_exception.rb +++ b/activesupport/test/dependencies/raises_exception.rb @@ -1,3 +1,3 @@ $raises_exception_load_count += 1 -raise Exception, 'Loading me failed, so do not add to loaded or history.' +raise Exception, "Loading me failed, so do not add to loaded or history." $raises_exception_load_count += 1 diff --git a/activesupport/test/dependencies/raises_exception_without_blame_file.rb b/activesupport/test/dependencies/raises_exception_without_blame_file.rb index 4b2da6ff30..7c3856b1e6 100644 --- a/activesupport/test/dependencies/raises_exception_without_blame_file.rb +++ b/activesupport/test/dependencies/raises_exception_without_blame_file.rb @@ -1,4 +1,4 @@ -exception = Exception.new('I am not blamable!') +exception = Exception.new("I am not blamable!") class << exception undef_method(:blame_file!) end diff --git a/activesupport/test/dependencies/requires_nonexistent0.rb b/activesupport/test/dependencies/requires_nonexistent0.rb index 7e24b3916c..7f8a0d8419 100644 --- a/activesupport/test/dependencies/requires_nonexistent0.rb +++ b/activesupport/test/dependencies/requires_nonexistent0.rb @@ -1 +1 @@ -require 'RMagickDontExistDude' +require "RMagickDontExistDude" diff --git a/activesupport/test/dependencies/requires_nonexistent1.rb b/activesupport/test/dependencies/requires_nonexistent1.rb index 41e6668164..0055177d67 100644 --- a/activesupport/test/dependencies/requires_nonexistent1.rb +++ b/activesupport/test/dependencies/requires_nonexistent1.rb @@ -1 +1 @@ -require_dependency 'requires_nonexistent0' +require_dependency "requires_nonexistent0" diff --git a/activesupport/test/dependencies/service_one.rb b/activesupport/test/dependencies/service_one.rb index f43bfea235..afc3042269 100644 --- a/activesupport/test/dependencies/service_one.rb +++ b/activesupport/test/dependencies/service_one.rb @@ -2,4 +2,4 @@ $loaded_service_one ||= 0 $loaded_service_one += 1 class ServiceOne -end
\ No newline at end of file +end diff --git a/activesupport/test/dependencies/service_two.rb b/activesupport/test/dependencies/service_two.rb index 5205a78bb8..aabfc3c553 100644 --- a/activesupport/test/dependencies/service_two.rb +++ b/activesupport/test/dependencies/service_two.rb @@ -1,2 +1,2 @@ class ServiceTwo -end
\ No newline at end of file +end diff --git a/activesupport/test/dependencies_test.rb b/activesupport/test/dependencies_test.rb index 757e600646..54068f5a08 100644 --- a/activesupport/test/dependencies_test.rb +++ b/activesupport/test/dependencies_test.rb @@ -1,7 +1,7 @@ -require 'abstract_unit' -require 'pp' -require 'active_support/dependencies' -require 'dependencies_test_helpers' +require "abstract_unit" +require "pp" +require "active_support/dependencies" +require "dependencies_test_helpers" module ModuleWithMissing mattr_accessor :missing_count @@ -29,18 +29,18 @@ class DependenciesTest < ActiveSupport::TestCase def test_depend_on_path expected = assert_raises(LoadError) do - Kernel.require 'omgwtfbbq' + Kernel.require "omgwtfbbq" end e = assert_raises(LoadError) do - ActiveSupport::Dependencies.depend_on 'omgwtfbbq' + ActiveSupport::Dependencies.depend_on "omgwtfbbq" end assert_equal expected.path, e.path end def test_require_dependency_accepts_an_object_which_implements_to_path o = Object.new - def o.to_path; 'dependencies/service_one'; end + def o.to_path; "dependencies/service_one"; end assert_nothing_raised { require_dependency o } @@ -51,8 +51,8 @@ class DependenciesTest < ActiveSupport::TestCase def test_tracking_loaded_files with_loading do - require_dependency 'dependencies/service_one' - require_dependency 'dependencies/service_two' + require_dependency "dependencies/service_one" + require_dependency "dependencies/service_two" assert_equal 2, ActiveSupport::Dependencies.loaded.size end ensure @@ -61,8 +61,8 @@ class DependenciesTest < ActiveSupport::TestCase def test_tracking_identical_loaded_files with_loading do - require_dependency 'dependencies/service_one' - require_dependency 'dependencies/service_one' + require_dependency "dependencies/service_one" + require_dependency "dependencies/service_one" assert_equal 1, ActiveSupport::Dependencies.loaded.size end ensure @@ -75,32 +75,33 @@ class DependenciesTest < ActiveSupport::TestCase def test_dependency_which_raises_exception_isnt_added_to_loaded_set with_loading do - filename = 'dependencies/raises_exception' + filename = "dependencies/raises_exception" + expanded = File.expand_path(filename) $raises_exception_load_count = 0 5.times do |count| - e = assert_raise Exception, 'should have loaded dependencies/raises_exception which raises an exception' do + e = assert_raise Exception, "should have loaded dependencies/raises_exception which raises an exception" do require_dependency filename end - assert_equal 'Loading me failed, so do not add to loaded or history.', e.message + assert_equal "Loading me failed, so do not add to loaded or history.", e.message assert_equal count + 1, $raises_exception_load_count - assert_not ActiveSupport::Dependencies.loaded.include?(filename) - assert_not ActiveSupport::Dependencies.history.include?(filename) + assert_not ActiveSupport::Dependencies.loaded.include?(expanded) + assert_not ActiveSupport::Dependencies.history.include?(expanded) end end end def test_dependency_which_raises_doesnt_blindly_call_blame_file! with_loading do - filename = 'dependencies/raises_exception_without_blame_file' + filename = "dependencies/raises_exception_without_blame_file" assert_raises(Exception) { require_dependency filename } end end def test_warnings_should_be_enabled_on_first_load - with_loading 'dependencies' do + with_loading "dependencies" do old_warnings, ActiveSupport::Dependencies.warnings_on_first_load = ActiveSupport::Dependencies.warnings_on_first_load, true filename = "check_warnings" expanded = File.expand_path("#{File.dirname(__FILE__)}/dependencies/#{filename}") @@ -111,41 +112,41 @@ class DependenciesTest < ActiveSupport::TestCase silence_warnings { require_dependency filename } assert_equal 1, $check_warnings_load_count - assert_equal true, $checked_verbose, 'On first load warnings should be enabled.' + assert_equal true, $checked_verbose, "On first load warnings should be enabled." - assert ActiveSupport::Dependencies.loaded.include?(expanded) + assert_includes ActiveSupport::Dependencies.loaded, expanded ActiveSupport::Dependencies.clear assert_not ActiveSupport::Dependencies.loaded.include?(expanded) - assert ActiveSupport::Dependencies.history.include?(expanded) + assert_includes ActiveSupport::Dependencies.history, expanded silence_warnings { require_dependency filename } assert_equal 2, $check_warnings_load_count - assert_equal nil, $checked_verbose, 'After first load warnings should be left alone.' + assert_equal nil, $checked_verbose, "After first load warnings should be left alone." - assert ActiveSupport::Dependencies.loaded.include?(expanded) + assert_includes ActiveSupport::Dependencies.loaded, expanded ActiveSupport::Dependencies.clear assert_not ActiveSupport::Dependencies.loaded.include?(expanded) - assert ActiveSupport::Dependencies.history.include?(expanded) + assert_includes ActiveSupport::Dependencies.history, expanded enable_warnings { require_dependency filename } assert_equal 3, $check_warnings_load_count - assert_equal true, $checked_verbose, 'After first load warnings should be left alone.' + assert_equal true, $checked_verbose, "After first load warnings should be left alone." - assert ActiveSupport::Dependencies.loaded.include?(expanded) + assert_includes ActiveSupport::Dependencies.loaded, expanded ActiveSupport::Dependencies.warnings_on_first_load = old_warnings end end def test_mutual_dependencies_dont_infinite_loop - with_loading 'dependencies' do + with_loading "dependencies" do $mutual_dependencies_count = 0 - assert_nothing_raised { require_dependency 'mutual_one' } + assert_nothing_raised { require_dependency "mutual_one" } assert_equal 2, $mutual_dependencies_count ActiveSupport::Dependencies.clear $mutual_dependencies_count = 0 - assert_nothing_raised { require_dependency 'mutual_two' } + assert_nothing_raised { require_dependency "mutual_two" } assert_equal 2, $mutual_dependencies_count end end @@ -166,7 +167,7 @@ class DependenciesTest < ActiveSupport::TestCase def test_require_dependency_does_not_assume_any_particular_constant_is_defined with_autoloading_fixtures do - require_dependency 'typo' + require_dependency "typo" assert_equal 1, TypO end end @@ -174,7 +175,7 @@ class DependenciesTest < ActiveSupport::TestCase # Regression, see https://github.com/rails/rails/issues/16468. def test_require_dependency_interaction_with_autoloading with_autoloading_fixtures do - require_dependency 'typo' + require_dependency "typo" assert_equal 1, TypO e = assert_raise(LoadError) { Typo } @@ -252,7 +253,7 @@ class DependenciesTest < ActiveSupport::TestCase with_autoloading_fixtures do assert_kind_of Class, ClassFolder::ClassFolderSubclass assert_kind_of Class, ClassFolder - assert_equal 'indeed', ClassFolder::ClassFolderSubclass::ConstantInClassFolder + assert_equal "indeed", ClassFolder::ClassFolderSubclass::ConstantInClassFolder end ensure remove_constants(:ClassFolder) @@ -268,6 +269,28 @@ class DependenciesTest < ActiveSupport::TestCase remove_constants(:ModuleFolder) end + def test_raising_discards_autoloaded_constants + with_autoloading_fixtures do + assert_raises(Exception, "arbitray exception message") { RaisesArbitraryException } + assert_not defined?(A) + assert_not defined?(RaisesArbitraryException) + end + ensure + remove_constants(:A, :RaisesArbitraryException) + end + + def test_throwing_discards_autoloaded_constants + with_autoloading_fixtures do + catch :t do + Throws + end + assert_not defined?(A) + assert_not defined?(Throws) + end + ensure + remove_constants(:A, :Throws) + end + def test_doesnt_break_normal_require path = File.expand_path("../autoloading_fixtures/load_path", __FILE__) original_path = $:.dup @@ -313,7 +336,7 @@ class DependenciesTest < ActiveSupport::TestCase $:.push(path) with_loading do - assert_equal true, require('loaded_constant') + assert_equal true, require("loaded_constant") end ensure remove_constants(:LoadedConstant) @@ -327,7 +350,7 @@ class DependenciesTest < ActiveSupport::TestCase with_loading do Object.module_eval "module LoadedConstant; end" - assert_equal true, require('loaded_constant') + assert_equal true, require("loaded_constant") end ensure remove_constants(:LoadedConstant) @@ -340,8 +363,8 @@ class DependenciesTest < ActiveSupport::TestCase $:.push(path) with_loading do - require 'loaded_constant' - assert_equal false, require('loaded_constant') + require "loaded_constant" + assert_equal false, require("loaded_constant") end ensure remove_constants(:LoadedConstant) @@ -350,7 +373,7 @@ class DependenciesTest < ActiveSupport::TestCase def test_require_raises_load_error_when_file_not_found with_loading do - assert_raise(LoadError) { require 'this_file_dont_exist_dude' } + assert_raise(LoadError) { require "this_file_dont_exist_dude" } end end @@ -360,8 +383,8 @@ class DependenciesTest < ActiveSupport::TestCase $:.push(path) with_loading do - assert_equal true, load('loaded_constant.rb') - assert_equal true, load('loaded_constant.rb') + assert_equal true, load("loaded_constant.rb") + assert_equal true, load("loaded_constant.rb") end ensure remove_constants(:LoadedConstant) @@ -370,7 +393,7 @@ class DependenciesTest < ActiveSupport::TestCase def test_load_raises_load_error_when_file_not_found with_loading do - assert_raise(LoadError) { load 'this_file_dont_exist_dude.rb' } + assert_raise(LoadError) { load "this_file_dont_exist_dude.rb" } end end @@ -406,38 +429,38 @@ class DependenciesTest < ActiveSupport::TestCase end def test_loadable_constants_for_path_should_handle_empty_autoloads - assert_equal [], ActiveSupport::Dependencies.loadable_constants_for_path('hello') + assert_equal [], ActiveSupport::Dependencies.loadable_constants_for_path("hello") end def test_loadable_constants_for_path_should_handle_relative_paths - fake_root = 'dependencies' - relative_root = File.dirname(__FILE__) + '/dependencies' - ['', '/'].each do |suffix| + fake_root = "dependencies" + relative_root = File.dirname(__FILE__) + "/dependencies" + ["", "/"].each do |suffix| with_loading fake_root + suffix do - assert_equal ["A::B"], ActiveSupport::Dependencies.loadable_constants_for_path(relative_root + '/a/b') + assert_equal ["A::B"], ActiveSupport::Dependencies.loadable_constants_for_path(relative_root + "/a/b") end end end def test_loadable_constants_for_path_should_provide_all_results - fake_root = '/usr/apps/backpack' - with_loading fake_root, fake_root + '/lib' do + fake_root = "/usr/apps/backpack" + with_loading fake_root, fake_root + "/lib" do root = ActiveSupport::Dependencies.autoload_paths.first - assert_equal ["Lib::A::B", "A::B"], ActiveSupport::Dependencies.loadable_constants_for_path(root + '/lib/a/b') + assert_equal ["Lib::A::B", "A::B"], ActiveSupport::Dependencies.loadable_constants_for_path(root + "/lib/a/b") end end def test_loadable_constants_for_path_should_uniq_results - fake_root = '/usr/apps/backpack/lib' - with_loading fake_root, fake_root + '/' do + fake_root = "/usr/apps/backpack/lib" + with_loading fake_root, fake_root + "/" do root = ActiveSupport::Dependencies.autoload_paths.first - assert_equal ["A::B"], ActiveSupport::Dependencies.loadable_constants_for_path(root + '/a/b') + assert_equal ["A::B"], ActiveSupport::Dependencies.loadable_constants_for_path(root + "/a/b") end end def test_loadable_constants_with_load_path_without_trailing_slash - path = File.dirname(__FILE__) + '/autoloading_fixtures/class_folder/inline_class.rb' - with_loading 'autoloading_fixtures/class/' do + path = File.dirname(__FILE__) + "/autoloading_fixtures/class_folder/inline_class.rb" + with_loading "autoloading_fixtures/class/" do assert_equal [], ActiveSupport::Dependencies.loadable_constants_for_path(path) end end @@ -501,29 +524,29 @@ class DependenciesTest < ActiveSupport::TestCase end def test_file_search - with_loading 'dependencies' do + with_loading "dependencies" do root = ActiveSupport::Dependencies.autoload_paths.first - assert_equal nil, ActiveSupport::Dependencies.search_for_file('service_three') - assert_equal nil, ActiveSupport::Dependencies.search_for_file('service_three.rb') - assert_equal root + '/service_one.rb', ActiveSupport::Dependencies.search_for_file('service_one') - assert_equal root + '/service_one.rb', ActiveSupport::Dependencies.search_for_file('service_one.rb') + assert_equal nil, ActiveSupport::Dependencies.search_for_file("service_three") + assert_equal nil, ActiveSupport::Dependencies.search_for_file("service_three.rb") + assert_equal root + "/service_one.rb", ActiveSupport::Dependencies.search_for_file("service_one") + assert_equal root + "/service_one.rb", ActiveSupport::Dependencies.search_for_file("service_one.rb") end end def test_file_search_uses_first_in_load_path - with_loading 'dependencies', 'autoloading_fixtures' do + with_loading "dependencies", "autoloading_fixtures" do deps, autoload = ActiveSupport::Dependencies.autoload_paths assert_match %r/dependencies/, deps assert_match %r/autoloading_fixtures/, autoload - assert_equal deps + '/conflict.rb', ActiveSupport::Dependencies.search_for_file('conflict') + assert_equal deps + "/conflict.rb", ActiveSupport::Dependencies.search_for_file("conflict") end - with_loading 'autoloading_fixtures', 'dependencies' do + with_loading "autoloading_fixtures", "dependencies" do autoload, deps = ActiveSupport::Dependencies.autoload_paths assert_match %r/dependencies/, deps assert_match %r/autoloading_fixtures/, autoload - assert_equal autoload + '/conflict.rb', ActiveSupport::Dependencies.search_for_file('conflict') + assert_equal autoload + "/conflict.rb", ActiveSupport::Dependencies.search_for_file("conflict") end end @@ -561,11 +584,11 @@ class DependenciesTest < ActiveSupport::TestCase def test_const_missing_in_anonymous_modules_raises_if_the_constant_belongs_to_Object with_autoloading_fixtures do - require_dependency 'em' + require_dependency "em" mod = Module.new e = assert_raise(NameError) { mod::EM } - assert_equal 'EM cannot be autoloaded from an anonymous class or module', e.message + assert_equal "EM cannot be autoloaded from an anonymous class or module", e.message assert_equal :EM, e.name end ensure @@ -573,7 +596,7 @@ class DependenciesTest < ActiveSupport::TestCase end def test_removal_from_tree_should_be_detected - with_loading 'dependencies' do + with_loading "dependencies" do c = ServiceOne ActiveSupport::Dependencies.clear assert_not defined?(ServiceOne) @@ -587,7 +610,7 @@ class DependenciesTest < ActiveSupport::TestCase end def test_references_should_work - with_loading 'dependencies' do + with_loading "dependencies" do c = ActiveSupport::Dependencies.reference("ServiceOne") service_one_first = ServiceOne assert_equal service_one_first, c.get("ServiceOne") @@ -602,7 +625,7 @@ class DependenciesTest < ActiveSupport::TestCase end def test_constantize_shortcut_for_cached_constant_lookups - with_loading 'dependencies' do + with_loading "dependencies" do assert_equal ServiceOne, ActiveSupport::Dependencies.constantize("ServiceOne") end ensure @@ -610,7 +633,7 @@ class DependenciesTest < ActiveSupport::TestCase end def test_nested_load_error_isnt_rescued - with_loading 'dependencies' do + with_loading "dependencies" do assert_raise(LoadError) do RequiresNonexistent1 end @@ -636,7 +659,7 @@ class DependenciesTest < ActiveSupport::TestCase def test_autoload_once_pathnames_do_not_add_to_autoloaded_constants with_autoloading_fixtures do - pathnames = ActiveSupport::Dependencies.autoload_paths.collect{|p| Pathname.new(p)} + pathnames = ActiveSupport::Dependencies.autoload_paths.collect { |p| Pathname.new(p) } ActiveSupport::Dependencies.autoload_paths = pathnames ActiveSupport::Dependencies.autoload_once_paths = pathnames @@ -654,7 +677,7 @@ class DependenciesTest < ActiveSupport::TestCase def test_application_should_special_case_application_controller with_autoloading_fixtures do - require_dependency 'application' + require_dependency "application" assert_equal 10, ApplicationController assert ActiveSupport::Dependencies.autoloaded?(:ApplicationController) end @@ -664,14 +687,14 @@ class DependenciesTest < ActiveSupport::TestCase def test_preexisting_constants_are_not_marked_as_autoloaded with_autoloading_fixtures do - require_dependency 'em' + require_dependency "em" assert ActiveSupport::Dependencies.autoloaded?(:EM) ActiveSupport::Dependencies.clear end Object.const_set :EM, Class.new with_autoloading_fixtures do - require_dependency 'em' + require_dependency "em" assert ! ActiveSupport::Dependencies.autoloaded?(:EM), "EM shouldn't be marked autoloaded!" ActiveSupport::Dependencies.clear end @@ -733,15 +756,15 @@ class DependenciesTest < ActiveSupport::TestCase end def test_new_contants_in_without_constants - assert_equal [], (ActiveSupport::Dependencies.new_constants_in(Object) { }) - assert ActiveSupport::Dependencies.constant_watch_stack.all? {|k,v| v.empty? } + assert_equal [], (ActiveSupport::Dependencies.new_constants_in(Object) {}) + assert ActiveSupport::Dependencies.constant_watch_stack.all? { |k,v| v.empty? } end def test_new_constants_in_with_a_single_constant assert_equal ["Hello"], ActiveSupport::Dependencies.new_constants_in(Object) { Object.const_set :Hello, 10 }.map(&:to_s) - assert ActiveSupport::Dependencies.constant_watch_stack.all? {|k,v| v.empty? } + assert ActiveSupport::Dependencies.constant_watch_stack.all? { |k,v| v.empty? } ensure remove_constants(:Hello) end @@ -758,7 +781,7 @@ class DependenciesTest < ActiveSupport::TestCase end assert_equal ["OuterAfter", "OuterBefore"], outer.sort.map(&:to_s) - assert ActiveSupport::Dependencies.constant_watch_stack.all? {|k,v| v.empty? } + assert ActiveSupport::Dependencies.constant_watch_stack.all? { |k,v| v.empty? } ensure remove_constants(:OuterBefore, :Inner, :OuterAfter) end @@ -777,7 +800,7 @@ class DependenciesTest < ActiveSupport::TestCase M.const_set :OuterAfter, 30 end assert_equal ["M::OuterAfter", "M::OuterBefore"], outer.sort - assert ActiveSupport::Dependencies.constant_watch_stack.all? {|k,v| v.empty? } + assert ActiveSupport::Dependencies.constant_watch_stack.all? { |k,v| v.empty? } ensure remove_constants(:M) end @@ -795,7 +818,7 @@ class DependenciesTest < ActiveSupport::TestCase M.const_set :OuterAfter, 30 end assert_equal ["M::OuterAfter", "M::OuterBefore"], outer.sort - assert ActiveSupport::Dependencies.constant_watch_stack.all? {|k,v| v.empty? } + assert ActiveSupport::Dependencies.constant_watch_stack.all? { |k,v| v.empty? } ensure remove_constants(:M) end @@ -818,7 +841,7 @@ class DependenciesTest < ActiveSupport::TestCase assert_not defined?(MultipleConstantFile) assert_not defined?(SiblingConstant) - require_dependency 'multiple_constant_file' + require_dependency "multiple_constant_file" assert defined?(MultipleConstantFile) assert defined?(SiblingConstant) assert ActiveSupport::Dependencies.autoloaded?(:MultipleConstantFile) @@ -858,7 +881,7 @@ class DependenciesTest < ActiveSupport::TestCase assert_not defined?(ClassFolder::NestedClass) assert_not defined?(ClassFolder::SiblingClass) - require_dependency 'class_folder/nested_class' + require_dependency "class_folder/nested_class" assert defined?(ClassFolder::NestedClass) assert defined?(ClassFolder::SiblingClass) @@ -936,7 +959,7 @@ class DependenciesTest < ActiveSupport::TestCase e = assert_raise NameError do ::RaisesNameError::FooBarBaz.object_id end - assert_equal 'uninitialized constant RaisesNameError::FooBarBaz', e.message + assert_equal "uninitialized constant RaisesNameError::FooBarBaz", e.message assert !defined?(::RaisesNameError), "::RaisesNameError is defined but it should have failed!" end @@ -951,8 +974,8 @@ class DependenciesTest < ActiveSupport::TestCase end def test_remove_constant_handles_double_colon_at_start - Object.const_set 'DeleteMe', Module.new - DeleteMe.const_set 'OrMe', Module.new + Object.const_set "DeleteMe", Module.new + DeleteMe.const_set "OrMe", Module.new ActiveSupport::Dependencies.remove_constant "::DeleteMe::OrMe" assert_not defined?(DeleteMe::OrMe) assert defined?(DeleteMe) @@ -963,9 +986,9 @@ class DependenciesTest < ActiveSupport::TestCase end def test_remove_constant_does_not_trigger_loading_autoloads - constant = 'ShouldNotBeAutoloaded' + constant = "ShouldNotBeAutoloaded" Object.class_eval do - autoload constant, File.expand_path('../autoloading_fixtures/should_not_be_required', __FILE__) + autoload constant, File.expand_path("../autoloading_fixtures/should_not_be_required", __FILE__) end assert_nil ActiveSupport::Dependencies.remove_constant(constant), "Kernel#autoload has been triggered by remove_constant" @@ -978,8 +1001,8 @@ class DependenciesTest < ActiveSupport::TestCase with_autoloading_fixtures do _ = ::A # assignment to silence parse-time warning "possibly useless use of :: in void context" _ = ::A::B # assignment to silence parse-time warning "possibly useless use of :: in void context" - ActiveSupport::Dependencies.remove_constant('A') - ActiveSupport::Dependencies.remove_constant('A::B') + ActiveSupport::Dependencies.remove_constant("A") + ActiveSupport::Dependencies.remove_constant("A::B") assert_not defined?(A) end ensure @@ -1013,10 +1036,9 @@ class DependenciesTest < ActiveSupport::TestCase remove_constants(:A) end - def test_autoload_once_paths_should_behave_when_recursively_loading old_path = ActiveSupport::Dependencies.autoload_once_paths - with_loading 'dependencies', 'autoloading_fixtures' do + with_loading "dependencies", "autoloading_fixtures" do ActiveSupport::Dependencies.autoload_once_paths = [ActiveSupport::Dependencies.autoload_paths.last] assert_not defined?(CrossSiteDependency) assert_nothing_raised { CrossSiteDepender.nil? } @@ -1037,21 +1059,13 @@ class DependenciesTest < ActiveSupport::TestCase end def test_load_and_require_stay_private - assert Object.private_methods.include?(:load) - assert Object.private_methods.include?(:require) + assert_includes Object.private_methods, :load + assert_includes Object.private_methods, :require ActiveSupport::Dependencies.unhook! - assert Object.private_methods.include?(:load) - assert Object.private_methods.include?(:require) - ensure - ActiveSupport::Dependencies.hook! - end - - def test_unhook - ActiveSupport::Dependencies.unhook! - assert !Module.new.respond_to?(:const_missing_without_dependencies) - assert !Module.new.respond_to?(:load_without_new_constant_marking) + assert_includes Object.private_methods, :load + assert_includes Object.private_methods, :require ensure ActiveSupport::Dependencies.hook! end diff --git a/activesupport/test/dependencies_test_helpers.rb b/activesupport/test/dependencies_test_helpers.rb index e4d5197112..9bc63ed89e 100644 --- a/activesupport/test/dependencies_test_helpers.rb +++ b/activesupport/test/dependencies_test_helpers.rb @@ -17,7 +17,7 @@ module DependenciesTestHelpers end def with_autoloading_fixtures(&block) - with_loading 'autoloading_fixtures', &block + with_loading "autoloading_fixtures", &block end def remove_constants(*constants) @@ -25,4 +25,4 @@ module DependenciesTestHelpers Object.send(:remove_const, constant) if Object.const_defined?(constant) end end -end
\ No newline at end of file +end diff --git a/activesupport/test/deprecation/method_wrappers_test.rb b/activesupport/test/deprecation/method_wrappers_test.rb index 9a4ca2b217..85d057bb02 100644 --- a/activesupport/test/deprecation/method_wrappers_test.rb +++ b/activesupport/test/deprecation/method_wrappers_test.rb @@ -1,5 +1,5 @@ -require 'abstract_unit' -require 'active_support/deprecation' +require "abstract_unit" +require "active_support/deprecation" class MethodWrappersTest < ActiveSupport::TestCase def setup @@ -11,7 +11,7 @@ class MethodWrappersTest < ActiveSupport::TestCase def test_deprecate_methods_warning_default warning = /old_method is deprecated and will be removed from Rails \d.\d \(use new_method instead\)/ - ActiveSupport::Deprecation.deprecate_methods(@klass, :old_method => :new_method) + ActiveSupport::Deprecation.deprecate_methods(@klass, old_method: :new_method) assert_deprecated(warning) { assert_equal "abc", @klass.new.old_method } end @@ -19,7 +19,7 @@ class MethodWrappersTest < ActiveSupport::TestCase def test_deprecate_methods_warning_with_optional_deprecator warning = /old_method is deprecated and will be removed from MyGem next-release \(use new_method instead\)/ deprecator = ActiveSupport::Deprecation.new("next-release", "MyGem") - ActiveSupport::Deprecation.deprecate_methods(@klass, :old_method => :new_method, :deprecator => deprecator) + ActiveSupport::Deprecation.deprecate_methods(@klass, old_method: :new_method, deprecator: deprecator) assert_deprecated(warning, deprecator) { assert_equal "abc", @klass.new.old_method } end @@ -27,7 +27,7 @@ class MethodWrappersTest < ActiveSupport::TestCase def test_deprecate_methods_warning_when_deprecated_with_custom_deprecator warning = /old_method is deprecated and will be removed from MyGem next-release \(use new_method instead\)/ deprecator = ActiveSupport::Deprecation.new("next-release", "MyGem") - deprecator.deprecate_methods(@klass, :old_method => :new_method) + deprecator.deprecate_methods(@klass, old_method: :new_method) assert_deprecated(warning, deprecator) { assert_equal "abc", @klass.new.old_method } end diff --git a/activesupport/test/deprecation/proxy_wrappers_test.rb b/activesupport/test/deprecation/proxy_wrappers_test.rb index e4f0f0f7c2..67afd75c44 100644 --- a/activesupport/test/deprecation/proxy_wrappers_test.rb +++ b/activesupport/test/deprecation/proxy_wrappers_test.rb @@ -1,5 +1,5 @@ -require 'abstract_unit' -require 'active_support/deprecation' +require "abstract_unit" +require "active_support/deprecation" class ProxyWrappersTest < ActiveSupport::TestCase Waffles = false diff --git a/activesupport/test/deprecation_test.rb b/activesupport/test/deprecation_test.rb index 45c88b79cb..e2a3331cfa 100644 --- a/activesupport/test/deprecation_test.rb +++ b/activesupport/test/deprecation_test.rb @@ -1,16 +1,16 @@ -require 'abstract_unit' -require 'active_support/testing/stream' +require "abstract_unit" +require "active_support/testing/stream" class Deprecatee def initialize @request = ActiveSupport::Deprecation::DeprecatedInstanceVariableProxy.new(self, :request) - @_request = 'there we go' + @_request = "there we go" end def request; @_request end def old_request; @request end def partially(foo = nil) - ActiveSupport::Deprecation.warn('calling with foo=nil is out') if foo.nil? + ActiveSupport::Deprecation.warn("calling with foo=nil is out") if foo.nil? end def not() 2 end @@ -24,7 +24,7 @@ class Deprecatee def c; end def d; end def e; end - deprecate :a, :b, :c => :e, :d => "you now need to do something extra for this one" + deprecate :a, :b, c: :e, d: "you now need to do something extra for this one" def f=(v); end deprecate :f= @@ -32,10 +32,9 @@ class Deprecatee module B C = 1 end - A = ActiveSupport::Deprecation::DeprecatedConstantProxy.new('Deprecatee::A', 'Deprecatee::B::C') + A = ActiveSupport::Deprecation::DeprecatedConstantProxy.new("Deprecatee::A", "Deprecatee::B::C") end - class DeprecationTest < ActiveSupport::TestCase include ActiveSupport::Testing::Stream @@ -79,7 +78,7 @@ class DeprecationTest < ActiveSupport::TestCase end def test_deprecate_object - deprecated_object = ActiveSupport::Deprecation::DeprecatedObjectProxy.new(Object.new, ':bomb:') + deprecated_object = ActiveSupport::Deprecation::DeprecatedObjectProxy.new(Object.new, ":bomb:") assert_deprecated(/:bomb:/) { deprecated_object.to_s } end @@ -104,7 +103,7 @@ class DeprecationTest < ActiveSupport::TestCase def test_raise_behaviour ActiveSupport::Deprecation.behavior = :raise - message = 'Revise this deprecated stuff now!' + message = "Revise this deprecated stuff now!" callstack = caller_locations e = assert_raise ActiveSupport::DeprecationException do @@ -119,7 +118,7 @@ class DeprecationTest < ActiveSupport::TestCase behavior = ActiveSupport::Deprecation.behavior.first content = capture(:stderr) { - assert_nil behavior.call('Some error!', ['call stack!']) + assert_nil behavior.call("Some error!", ["call stack!"]) } assert_match(/Some error!/, content) assert_match(/call stack!/, content) @@ -129,7 +128,7 @@ class DeprecationTest < ActiveSupport::TestCase ActiveSupport::Deprecation.behavior = :stderr content = capture(:stderr) { - ActiveSupport::Deprecation.warn('Instance error!', ['instance call stack!']) + ActiveSupport::Deprecation.warn("Instance error!", ["instance call stack!"]) } assert_match(/Instance error!/, content) @@ -141,16 +140,16 @@ class DeprecationTest < ActiveSupport::TestCase behavior = ActiveSupport::Deprecation.behavior.first stderr_output = capture(:stderr) { - assert_nil behavior.call('Some error!', ['call stack!']) + assert_nil behavior.call("Some error!", ["call stack!"]) } - assert stderr_output.blank? + assert stderr_output.empty? end def test_deprecated_instance_variable_proxy assert_not_deprecated { @dtc.request.size } - assert_deprecated('@request.size') { assert_equal @dtc.request.size, @dtc.old_request.size } - assert_deprecated('@request.to_s') { assert_equal @dtc.request.to_s, @dtc.old_request.to_s } + assert_deprecated("@request.size") { assert_equal @dtc.request.size, @dtc.old_request.size } + assert_deprecated("@request.to_s") { assert_equal @dtc.request.to_s, @dtc.old_request.to_s } end def test_deprecated_instance_variable_proxy_shouldnt_warn_on_inspect @@ -159,7 +158,7 @@ class DeprecationTest < ActiveSupport::TestCase def test_deprecated_constant_proxy assert_not_deprecated { Deprecatee::B::C } - assert_deprecated('Deprecatee::A') { assert_equal Deprecatee::B::C, Deprecatee::A } + assert_deprecated("Deprecatee::A") { assert_equal Deprecatee::B::C, Deprecatee::A } assert_not_deprecated { assert_equal Deprecatee::B::C.class, Deprecatee::A.class } end @@ -178,12 +177,12 @@ class DeprecationTest < ActiveSupport::TestCase end def test_assert_deprecated_matches_any_warning - assert_deprecated 'abc' do - ActiveSupport::Deprecation.warn 'abc' - ActiveSupport::Deprecation.warn 'def' + assert_deprecated "abc" do + ActiveSupport::Deprecation.warn "abc" + ActiveSupport::Deprecation.warn "def" end rescue Minitest::Assertion - flunk 'assert_deprecated should match any warning in block, not just the last one' + flunk "assert_deprecated should match any warning in block, not just the last one" end def test_assert_not_deprecated_returns_result_of_block @@ -191,17 +190,17 @@ class DeprecationTest < ActiveSupport::TestCase end def test_assert_deprecated_returns_result_of_block - result = assert_deprecated('abc') do - ActiveSupport::Deprecation.warn 'abc' + result = assert_deprecated("abc") do + ActiveSupport::Deprecation.warn "abc" 123 end assert_equal 123, result end def test_assert_deprecated_warn_work_with_default_behavior - ActiveSupport::Deprecation.instance_variable_set('@behavior', nil) - assert_deprecated('abc') do - ActiveSupport::Deprecation.warn 'abc' + ActiveSupport::Deprecation.instance_variable_set("@behavior", nil) + assert_deprecated("abc") do + ActiveSupport::Deprecation.warn "abc" end end @@ -280,7 +279,7 @@ class DeprecationTest < ActiveSupport::TestCase def test_deprecated_constant_with_deprecator_given deprecator = deprecator_with_messages klass = Class.new - klass.const_set(:OLD, ActiveSupport::Deprecation::DeprecatedConstantProxy.new('klass::OLD', 'Object', deprecator) ) + klass.const_set(:OLD, ActiveSupport::Deprecation::DeprecatedConstantProxy.new("klass::OLD", "Object", deprecator) ) assert_difference("deprecator.messages.size") do klass::OLD.to_s end @@ -341,7 +340,7 @@ class DeprecationTest < ActiveSupport::TestCase end def test_default_deprecation_horizon_should_always_bigger_than_current_rails_version - assert ActiveSupport::Deprecation.new.deprecation_horizon > ActiveSupport::VERSION::STRING + assert_operator ActiveSupport::Deprecation.new.deprecation_horizon, :>, ActiveSupport::VERSION::STRING end def test_default_gem_name @@ -353,7 +352,7 @@ class DeprecationTest < ActiveSupport::TestCase end def test_custom_gem_name - deprecator = ActiveSupport::Deprecation.new('2.0', 'Custom') + deprecator = ActiveSupport::Deprecation.new("2.0", "Custom") deprecator.send(:deprecated_method_warning, :deprecated_method, "You are calling deprecated method").tap do |message| assert_match(/is deprecated and will be removed from Custom/, message) @@ -364,11 +363,10 @@ class DeprecationTest < ActiveSupport::TestCase def deprecator_with_messages klass = Class.new(ActiveSupport::Deprecation) deprecator = klass.new - deprecator.behavior = Proc.new{|message, callstack| deprecator.messages << message} + deprecator.behavior = Proc.new { |message, callstack| deprecator.messages << message } def deprecator.messages @messages ||= [] end deprecator end - end diff --git a/activesupport/test/descendants_tracker_test_cases.rb b/activesupport/test/descendants_tracker_test_cases.rb index 69e046998e..09c5ce1f07 100644 --- a/activesupport/test/descendants_tracker_test_cases.rb +++ b/activesupport/test/descendants_tracker_test_cases.rb @@ -1,4 +1,4 @@ -require 'set' +require "set" module DescendantsTrackerTestCases class Parent @@ -42,24 +42,24 @@ module DescendantsTrackerTestCases protected - def assert_equal_sets(expected, actual) - assert_equal Set.new(expected), Set.new(actual) - end - - def mark_as_autoloaded(*klasses) - # If ActiveSupport::Dependencies is not loaded, forget about autoloading. - # This allows using AS::DescendantsTracker without AS::Dependencies. - if defined? ActiveSupport::Dependencies - old_autoloaded = ActiveSupport::Dependencies.autoloaded_constants.dup - ActiveSupport::Dependencies.autoloaded_constants = klasses.map(&:name) + def assert_equal_sets(expected, actual) + assert_equal Set.new(expected), Set.new(actual) end - old_descendants = ActiveSupport::DescendantsTracker.class_eval("@@direct_descendants").dup - old_descendants.each { |k, v| old_descendants[k] = v.dup } + def mark_as_autoloaded(*klasses) + # If ActiveSupport::Dependencies is not loaded, forget about autoloading. + # This allows using AS::DescendantsTracker without AS::Dependencies. + if defined? ActiveSupport::Dependencies + old_autoloaded = ActiveSupport::Dependencies.autoloaded_constants.dup + ActiveSupport::Dependencies.autoloaded_constants = klasses.map(&:name) + end + + old_descendants = ActiveSupport::DescendantsTracker.class_eval("@@direct_descendants").dup + old_descendants.each { |k, v| old_descendants[k] = v.dup } - yield - ensure - ActiveSupport::Dependencies.autoloaded_constants = old_autoloaded if defined? ActiveSupport::Dependencies - ActiveSupport::DescendantsTracker.class_eval("@@direct_descendants").replace(old_descendants) - end + yield + ensure + ActiveSupport::Dependencies.autoloaded_constants = old_autoloaded if defined? ActiveSupport::Dependencies + ActiveSupport::DescendantsTracker.class_eval("@@direct_descendants").replace(old_descendants) + end end diff --git a/activesupport/test/descendants_tracker_with_autoloading_test.rb b/activesupport/test/descendants_tracker_with_autoloading_test.rb index a2ae066a21..e202667a8a 100644 --- a/activesupport/test/descendants_tracker_with_autoloading_test.rb +++ b/activesupport/test/descendants_tracker_with_autoloading_test.rb @@ -1,7 +1,7 @@ -require 'abstract_unit' -require 'active_support/descendants_tracker' -require 'active_support/dependencies' -require 'descendants_tracker_test_cases' +require "abstract_unit" +require "active_support/descendants_tracker" +require "active_support/dependencies" +require "descendants_tracker_test_cases" class DescendantsTrackerWithAutoloadingTest < ActiveSupport::TestCase include DescendantsTrackerTestCases diff --git a/activesupport/test/descendants_tracker_without_autoloading_test.rb b/activesupport/test/descendants_tracker_without_autoloading_test.rb index 00b449af51..72adc30ace 100644 --- a/activesupport/test/descendants_tracker_without_autoloading_test.rb +++ b/activesupport/test/descendants_tracker_without_autoloading_test.rb @@ -1,6 +1,6 @@ -require 'abstract_unit' -require 'active_support/descendants_tracker' -require 'descendants_tracker_test_cases' +require "abstract_unit" +require "active_support/descendants_tracker" +require "descendants_tracker_test_cases" class DescendantsTrackerWithoutAutoloadingTest < ActiveSupport::TestCase include DescendantsTrackerTestCases diff --git a/activesupport/test/evented_file_update_checker_test.rb b/activesupport/test/evented_file_update_checker_test.rb index bc3f77bd54..77d8dcb0f8 100644 --- a/activesupport/test/evented_file_update_checker_test.rb +++ b/activesupport/test/evented_file_update_checker_test.rb @@ -1,17 +1,17 @@ -require 'abstract_unit' -require 'pathname' -require 'file_update_checker_shared_tests' +require "abstract_unit" +require "pathname" +require "file_update_checker_shared_tests" class EventedFileUpdateCheckerTest < ActiveSupport::TestCase include FileUpdateCheckerSharedTests def setup - skip if ENV['LISTEN'] == '0' + skip if ENV["LISTEN"] == "0" super end def new_checker(files = [], dirs = {}, &block) - ActiveSupport::EventedFileUpdateChecker.new(files, dirs, &block).tap do + ActiveSupport::EventedFileUpdateChecker.new(files, dirs, &block).tap do |c| wait end end @@ -34,6 +34,50 @@ class EventedFileUpdateCheckerTest < ActiveSupport::TestCase super wait end + + test "notifies forked processes" do + jruby_skip "Forking not available on JRuby" + + FileUtils.touch(tmpfiles) + + checker = new_checker(tmpfiles) {} + assert !checker.updated? + + # Pipes used for flow controll across fork. + boot_reader, boot_writer = IO.pipe + touch_reader, touch_writer = IO.pipe + + pid = fork do + assert checker.updated? + + # Clear previous check value. + checker.execute + assert !checker.updated? + + # Fork is booted, ready for file to be touched + # notify parent process. + boot_writer.write("booted") + + # Wait for parent process to signal that file + # has been touched. + IO.select([touch_reader]) + + assert checker.updated? + end + + assert pid + + # Wait for fork to be booted before touching files. + IO.select([boot_reader]) + touch(tmpfiles) + + # Notify fork that files have been touched. + touch_writer.write("touched") + + assert checker.updated? + + Process.wait(pid) + end end class EventedFileUpdateCheckerPathHelperTest < ActiveSupport::TestCase @@ -45,33 +89,33 @@ class EventedFileUpdateCheckerPathHelperTest < ActiveSupport::TestCase @ph = ActiveSupport::EventedFileUpdateChecker::PathHelper.new end - test '#xpath returns the expanded path as a Pathname object' do + test "#xpath returns the expanded path as a Pathname object" do assert_equal pn(__FILE__).expand_path, @ph.xpath(__FILE__) end - test '#normalize_extension returns a bare extension as is' do - assert_equal 'rb', @ph.normalize_extension('rb') + test "#normalize_extension returns a bare extension as is" do + assert_equal "rb", @ph.normalize_extension("rb") end - test '#normalize_extension removes a leading dot' do - assert_equal 'rb', @ph.normalize_extension('.rb') + test "#normalize_extension removes a leading dot" do + assert_equal "rb", @ph.normalize_extension(".rb") end - test '#normalize_extension supports symbols' do - assert_equal 'rb', @ph.normalize_extension(:rb) + test "#normalize_extension supports symbols" do + assert_equal "rb", @ph.normalize_extension(:rb) end - test '#longest_common_subpath finds the longest common subpath, if there is one' do + test "#longest_common_subpath finds the longest common subpath, if there is one" do paths = %w( /foo/bar /foo/baz /foo/bar/baz/woo/zoo ).map { |path| pn(path) } - assert_equal pn('/foo'), @ph.longest_common_subpath(paths) + assert_equal pn("/foo"), @ph.longest_common_subpath(paths) end - test '#longest_common_subpath returns the root directory as an edge case' do + test "#longest_common_subpath returns the root directory as an edge case" do paths = %w( /foo/bar /foo/baz @@ -79,30 +123,30 @@ class EventedFileUpdateCheckerPathHelperTest < ActiveSupport::TestCase /wadus ).map { |path| pn(path) } - assert_equal pn('/'), @ph.longest_common_subpath(paths) + assert_equal pn("/"), @ph.longest_common_subpath(paths) end - test '#longest_common_subpath returns nil for an empty collection' do + test "#longest_common_subpath returns nil for an empty collection" do assert_nil @ph.longest_common_subpath([]) end - test '#existing_parent returns the most specific existing ascendant' do + test "#existing_parent returns the most specific existing ascendant" do wd = Pathname.getwd assert_equal wd, @ph.existing_parent(wd) - assert_equal wd, @ph.existing_parent(wd.join('non-existing/directory')) - assert_equal pn('/'), @ph.existing_parent(pn('/non-existing/directory')) + assert_equal wd, @ph.existing_parent(wd.join("non-existing/directory")) + assert_equal pn("/"), @ph.existing_parent(pn("/non-existing/directory")) end - test '#filter_out_descendants returns the same collection if there are no descendants (empty)' do + test "#filter_out_descendants returns the same collection if there are no descendants (empty)" do assert_equal [], @ph.filter_out_descendants([]) end - test '#filter_out_descendants returns the same collection if there are no descendants (one)' do - assert_equal ['/foo'], @ph.filter_out_descendants(['/foo']) + test "#filter_out_descendants returns the same collection if there are no descendants (one)" do + assert_equal ["/foo"], @ph.filter_out_descendants(["/foo"]) end - test '#filter_out_descendants returns the same collection if there are no descendants (several)' do + test "#filter_out_descendants returns the same collection if there are no descendants (several)" do paths = %w( /Rails.root/app/controllers /Rails.root/app/models @@ -112,7 +156,7 @@ class EventedFileUpdateCheckerPathHelperTest < ActiveSupport::TestCase assert_equal paths, @ph.filter_out_descendants(paths) end - test '#filter_out_descendants filters out descendants preserving order' do + test "#filter_out_descendants filters out descendants preserving order" do paths = %w( /Rails.root/app/controllers /Rails.root/app/controllers/concerns @@ -124,7 +168,7 @@ class EventedFileUpdateCheckerPathHelperTest < ActiveSupport::TestCase assert_equal paths.values_at(0, 2, 4), @ph.filter_out_descendants(paths) end - test '#filter_out_descendants works on path units' do + test "#filter_out_descendants works on path units" do paths = %w( /foo/bar /foo/barrrr @@ -133,7 +177,7 @@ class EventedFileUpdateCheckerPathHelperTest < ActiveSupport::TestCase assert_equal paths, @ph.filter_out_descendants(paths) end - test '#filter_out_descendants deals correctly with the root directory' do + test "#filter_out_descendants deals correctly with the root directory" do paths = %w( / /foo @@ -143,7 +187,7 @@ class EventedFileUpdateCheckerPathHelperTest < ActiveSupport::TestCase assert_equal paths.values_at(0), @ph.filter_out_descendants(paths) end - test '#filter_out_descendants preserves duplicates' do + test "#filter_out_descendants preserves duplicates" do paths = %w( /foo /foo/bar diff --git a/activesupport/test/executor_test.rb b/activesupport/test/executor_test.rb new file mode 100644 index 0000000000..03ec6020c3 --- /dev/null +++ b/activesupport/test/executor_test.rb @@ -0,0 +1,240 @@ +require "abstract_unit" + +class ExecutorTest < ActiveSupport::TestCase + class DummyError < RuntimeError + end + + def test_wrap_invokes_callbacks + called = [] + executor.to_run { called << :run } + executor.to_complete { called << :complete } + + executor.wrap do + called << :body + end + + assert_equal [:run, :body, :complete], called + end + + def test_callbacks_share_state + result = false + executor.to_run { @foo = true } + executor.to_complete { result = @foo } + + executor.wrap {} + + assert result + end + + def test_separated_calls_invoke_callbacks + called = [] + executor.to_run { called << :run } + executor.to_complete { called << :complete } + + state = executor.run! + called << :body + state.complete! + + assert_equal [:run, :body, :complete], called + end + + def test_exceptions_unwind + called = [] + executor.to_run { called << :run_1 } + executor.to_run { raise DummyError } + executor.to_run { called << :run_2 } + executor.to_complete { called << :complete } + + assert_raises(DummyError) do + executor.wrap { called << :body } + end + + assert_equal [:run_1, :complete], called + end + + def test_avoids_double_wrapping + called = [] + executor.to_run { called << :run } + executor.to_complete { called << :complete } + + executor.wrap do + called << :early + executor.wrap do + called << :body + end + called << :late + end + + assert_equal [:run, :early, :body, :late, :complete], called + end + + def test_hooks_carry_state + supplied_state = :none + + hook = Class.new do + define_method(:run) do + :some_state + end + + define_method(:complete) do |state| + supplied_state = state + end + end.new + + executor.register_hook(hook) + + executor.wrap {} + + assert_equal :some_state, supplied_state + end + + def test_nil_state_is_sufficient + supplied_state = :none + + hook = Class.new do + define_method(:run) do + nil + end + + define_method(:complete) do |state| + supplied_state = state + end + end.new + + executor.register_hook(hook) + + executor.wrap {} + + assert_equal nil, supplied_state + end + + def test_exception_skips_uninvoked_hook + supplied_state = :none + + hook = Class.new do + define_method(:run) do + :some_state + end + + define_method(:complete) do |state| + supplied_state = state + end + end.new + + executor.to_run do + raise DummyError + end + executor.register_hook(hook) + + assert_raises(DummyError) do + executor.wrap {} + end + + assert_equal :none, supplied_state + end + + def test_exception_unwinds_invoked_hook + supplied_state = :none + + hook = Class.new do + define_method(:run) do + :some_state + end + + define_method(:complete) do |state| + supplied_state = state + end + end.new + + executor.register_hook(hook) + executor.to_run do + raise DummyError + end + + assert_raises(DummyError) do + executor.wrap {} + end + + assert_equal :some_state, supplied_state + end + + def test_hook_insertion_order + invoked = [] + supplied_state = [] + + hook_class = Class.new do + attr_accessor :letter + + define_method(:initialize) do |letter| + self.letter = letter + end + + define_method(:run) do + invoked << :"run_#{letter}" + :"state_#{letter}" + end + + define_method(:complete) do |state| + invoked << :"complete_#{letter}" + supplied_state << state + end + end + + executor.register_hook(hook_class.new(:a)) + executor.register_hook(hook_class.new(:b)) + executor.register_hook(hook_class.new(:c), outer: true) + executor.register_hook(hook_class.new(:d)) + + executor.wrap {} + + assert_equal [:run_c, :run_a, :run_b, :run_d, :complete_a, :complete_b, :complete_d, :complete_c], invoked + assert_equal [:state_a, :state_b, :state_d, :state_c], supplied_state + end + + def test_class_serial_is_unaffected + skip if !defined?(RubyVM) + + hook = Class.new do + define_method(:run) do + nil + end + + define_method(:complete) do |state| + nil + end + end.new + + executor.register_hook(hook) + + before = RubyVM.stat(:class_serial) + executor.wrap {} + executor.wrap {} + executor.wrap {} + after = RubyVM.stat(:class_serial) + + assert_equal before, after + end + + def test_separate_classes_can_wrap + other_executor = Class.new(ActiveSupport::Executor) + + called = [] + executor.to_run { called << :run } + executor.to_complete { called << :complete } + other_executor.to_run { called << :other_run } + other_executor.to_complete { called << :other_complete } + + executor.wrap do + other_executor.wrap do + called << :body + end + end + + assert_equal [:run, :other_run, :body, :other_complete, :complete], called + end + + private + def executor + @executor ||= Class.new(ActiveSupport::Executor) + end +end diff --git a/activesupport/test/file_update_checker_shared_tests.rb b/activesupport/test/file_update_checker_shared_tests.rb index 9c07e38fe5..48cd387196 100644 --- a/activesupport/test/file_update_checker_shared_tests.rb +++ b/activesupport/test/file_update_checker_shared_tests.rb @@ -1,27 +1,29 @@ -require 'fileutils' +require "fileutils" module FileUpdateCheckerSharedTests extend ActiveSupport::Testing::Declarative include FileUtils def tmpdir - @tmpdir ||= Dir.mktmpdir(nil, __dir__) + @tmpdir end def tmpfile(name) - "#{tmpdir}/#{name}" + File.join(tmpdir, name) end def tmpfiles @tmpfiles ||= %w(foo.rb bar.rb baz.rb).map { |f| tmpfile(f) } end - def teardown - FileUtils.rm_rf(@tmpdir) if defined? @tmpdir + def run(*args) + capture_exceptions do + Dir.mktmpdir(nil, __dir__) { |dir| @tmpdir = dir; super } + end end - test 'should not execute the block if no paths are given' do - silence_warnings { require 'listen' } + test "should not execute the block if no paths are given" do + silence_warnings { require "listen" } i = 0 checker = new_checker { i += 1 } @@ -30,7 +32,7 @@ module FileUpdateCheckerSharedTests assert_equal 0, i end - test 'should not execute the block if no files change' do + test "should not execute the block if no files change" do i = 0 FileUtils.touch(tmpfiles) @@ -41,18 +43,19 @@ module FileUpdateCheckerSharedTests assert_equal 0, i end - test 'should execute the block once when files are created' do + test "should execute the block once when files are created" do i = 0 checker = new_checker(tmpfiles) { i += 1 } touch(tmpfiles) + wait assert checker.execute_if_updated assert_equal 1, i end - test 'should execute the block once when files are modified' do + test "should execute the block once when files are modified" do i = 0 FileUtils.touch(tmpfiles) @@ -60,12 +63,13 @@ module FileUpdateCheckerSharedTests checker = new_checker(tmpfiles) { i += 1 } touch(tmpfiles) + wait assert checker.execute_if_updated assert_equal 1, i end - test 'should execute the block once when files are deleted' do + test "should execute the block once when files are deleted" do i = 0 FileUtils.touch(tmpfiles) @@ -73,25 +77,25 @@ module FileUpdateCheckerSharedTests checker = new_checker(tmpfiles) { i += 1 } rm_f(tmpfiles) + wait assert checker.execute_if_updated assert_equal 1, i end - - test 'updated should become true when watched files are created' do + test "updated should become true when watched files are created" do i = 0 checker = new_checker(tmpfiles) { i += 1 } assert !checker.updated? touch(tmpfiles) + wait assert checker.updated? end - - test 'updated should become true when watched files are modified' do + test "updated should become true when watched files are modified" do i = 0 FileUtils.touch(tmpfiles) @@ -100,11 +104,12 @@ module FileUpdateCheckerSharedTests assert !checker.updated? touch(tmpfiles) + wait assert checker.updated? end - test 'updated should become true when watched files are deleted' do + test "updated should become true when watched files are deleted" do i = 0 FileUtils.touch(tmpfiles) @@ -113,11 +118,12 @@ module FileUpdateCheckerSharedTests assert !checker.updated? rm_f(tmpfiles) + wait assert checker.updated? end - test 'should be robust to handle files with wrong modified time' do + test "should be robust to handle files with wrong modified time" do i = 0 FileUtils.touch(tmpfiles) @@ -129,112 +135,140 @@ module FileUpdateCheckerSharedTests checker = new_checker(tmpfiles) { i += 1 } touch(tmpfiles[1..-1]) + wait + + assert checker.execute_if_updated + assert_equal 1, i + end + + test "should return max_time for files with mtime = Time.at(0)" do + i = 0 + + FileUtils.touch(tmpfiles) + + time = Time.at(0) # wrong mtime from the future + File.utime(time, time, tmpfiles[0]) + + checker = new_checker(tmpfiles) { i += 1 } + + touch(tmpfiles[1..-1]) + wait assert checker.execute_if_updated assert_equal 1, i end - test 'should cache updated result until execute' do + test "should cache updated result until execute" do i = 0 checker = new_checker(tmpfiles) { i += 1 } assert !checker.updated? touch(tmpfiles) + wait assert checker.updated? checker.execute assert !checker.updated? end - test 'should execute the block if files change in a watched directory one extension' do + test "should execute the block if files change in a watched directory one extension" do i = 0 checker = new_checker([], tmpdir => :rb) { i += 1 } - touch(tmpfile('foo.rb')) + touch(tmpfile("foo.rb")) + wait assert checker.execute_if_updated assert_equal 1, i end - test 'should execute the block if files change in a watched directory several extensions' do + test "should execute the block if files change in a watched directory several extensions" do i = 0 checker = new_checker([], tmpdir => [:rb, :txt]) { i += 1 } - touch(tmpfile('foo.rb')) + touch(tmpfile("foo.rb")) + wait assert checker.execute_if_updated assert_equal 1, i - touch(tmpfile('foo.txt')) + touch(tmpfile("foo.txt")) + wait assert checker.execute_if_updated assert_equal 2, i end - test 'should not execute the block if the file extension is not watched' do + test "should not execute the block if the file extension is not watched" do i = 0 checker = new_checker([], tmpdir => :txt) { i += 1 } - touch(tmpfile('foo.rb')) + touch(tmpfile("foo.rb")) + wait assert !checker.execute_if_updated assert_equal 0, i end - test 'does not assume files exist on instantiation' do + test "does not assume files exist on instantiation" do i = 0 - non_existing = tmpfile('non_existing.rb') + non_existing = tmpfile("non_existing.rb") checker = new_checker([non_existing]) { i += 1 } touch(non_existing) + wait assert checker.execute_if_updated assert_equal 1, i end - test 'detects files in new subdirectories' do + test "detects files in new subdirectories" do i = 0 checker = new_checker([], tmpdir => :rb) { i += 1 } - subdir = tmpfile('subdir') + subdir = tmpfile("subdir") mkdir(subdir) wait assert !checker.execute_if_updated assert_equal 0, i - touch("#{subdir}/nested.rb") + touch(File.join(subdir, "nested.rb")) + wait assert checker.execute_if_updated assert_equal 1, i end - test 'looked up extensions are inherited in subdirectories not listening to them' do + test "looked up extensions are inherited in subdirectories not listening to them" do i = 0 - subdir = tmpfile('subdir') + subdir = tmpfile("subdir") mkdir(subdir) checker = new_checker([], tmpdir => :rb, subdir => :txt) { i += 1 } - touch(tmpfile('new.txt')) + touch(tmpfile("new.txt")) + wait assert !checker.execute_if_updated assert_equal 0, i # subdir does not look for Ruby files, but its parent tmpdir does. - touch("#{subdir}/nested.rb") + touch(File.join(subdir, "nested.rb")) + wait assert checker.execute_if_updated assert_equal 1, i - touch("#{subdir}/nested.txt") + touch(File.join(subdir, "nested.txt")) + wait assert checker.execute_if_updated assert_equal 2, i diff --git a/activesupport/test/file_update_checker_test.rb b/activesupport/test/file_update_checker_test.rb index 752f7836cd..55b0b46644 100644 --- a/activesupport/test/file_update_checker_test.rb +++ b/activesupport/test/file_update_checker_test.rb @@ -1,5 +1,5 @@ -require 'abstract_unit' -require 'file_update_checker_shared_tests' +require "abstract_unit" +require "file_update_checker_shared_tests" class FileUpdateCheckerTest < ActiveSupport::TestCase include FileUpdateCheckerSharedTests diff --git a/activesupport/test/fixtures/autoload/another_class.rb b/activesupport/test/fixtures/autoload/another_class.rb index a240b3de41..ab6e075ab4 100644 --- a/activesupport/test/fixtures/autoload/another_class.rb +++ b/activesupport/test/fixtures/autoload/another_class.rb @@ -1,2 +1,2 @@ class Fixtures::AnotherClass -end
\ No newline at end of file +end diff --git a/activesupport/test/fixtures/autoload/some_class.rb b/activesupport/test/fixtures/autoload/some_class.rb index 13b3c73ef5..30d41eb0bf 100644 --- a/activesupport/test/fixtures/autoload/some_class.rb +++ b/activesupport/test/fixtures/autoload/some_class.rb @@ -1,2 +1,2 @@ class Fixtures::Autoload::SomeClass -end
\ No newline at end of file +end diff --git a/activesupport/test/gzip_test.rb b/activesupport/test/gzip_test.rb index 0e3cf3b429..d88408b55c 100644 --- a/activesupport/test/gzip_test.rb +++ b/activesupport/test/gzip_test.rb @@ -1,5 +1,5 @@ -require 'abstract_unit' -require 'active_support/core_ext/object/blank' +require "abstract_unit" +require "active_support/core_ext/object/blank" class GzipTest < ActiveSupport::TestCase def test_compress_should_decompress_to_the_same_value @@ -13,9 +13,9 @@ class GzipTest < ActiveSupport::TestCase end def test_compress_should_return_a_binary_string - compressed = ActiveSupport::Gzip.compress('') + compressed = ActiveSupport::Gzip.compress("") - assert_equal Encoding.find('binary'), compressed.encoding + assert_equal Encoding.find("binary"), compressed.encoding assert !compressed.blank?, "a compressed blank string should not be blank" end diff --git a/activesupport/test/i18n_test.rb b/activesupport/test/i18n_test.rb index 3faa15e7fd..7d88d2dc6b 100644 --- a/activesupport/test/i18n_test.rb +++ b/activesupport/test/i18n_test.rb @@ -1,6 +1,6 @@ -require 'abstract_unit' -require 'active_support/time' -require 'active_support/core_ext/array/conversions' +require "abstract_unit" +require "active_support/time" +require "active_support/core_ext/array/conversions" class I18nTest < ActiveSupport::TestCase def setup @@ -18,15 +18,15 @@ class I18nTest < ActiveSupport::TestCase end def test_date_localization_with_default_format - assert_equal @date.strftime("%Y-%m-%d"), I18n.localize(@date, :format => :default) + assert_equal @date.strftime("%Y-%m-%d"), I18n.localize(@date, format: :default) end def test_date_localization_with_short_format - assert_equal @date.strftime("%b %d"), I18n.localize(@date, :format => :short) + assert_equal @date.strftime("%b %d"), I18n.localize(@date, format: :short) end def test_date_localization_with_long_format - assert_equal @date.strftime("%B %d, %Y"), I18n.localize(@date, :format => :long) + assert_equal @date.strftime("%B %d, %Y"), I18n.localize(@date, format: :long) end def test_time_localization_should_use_default_format @@ -34,15 +34,15 @@ class I18nTest < ActiveSupport::TestCase end def test_time_localization_with_default_format - assert_equal @time.strftime("%a, %d %b %Y %H:%M:%S %z"), I18n.localize(@time, :format => :default) + assert_equal @time.strftime("%a, %d %b %Y %H:%M:%S %z"), I18n.localize(@time, format: :default) end def test_time_localization_with_short_format - assert_equal @time.strftime("%d %b %H:%M"), I18n.localize(@time, :format => :short) + assert_equal @time.strftime("%d %b %H:%M"), I18n.localize(@time, format: :short) end def test_time_localization_with_long_format - assert_equal @time.strftime("%B %d, %Y %H:%M"), I18n.localize(@time, :format => :long) + assert_equal @time.strftime("%B %d, %Y %H:%M"), I18n.localize(@time, format: :long) end def test_day_names @@ -66,39 +66,39 @@ class I18nTest < ActiveSupport::TestCase end def test_time_am - assert_equal 'am', I18n.translate(:'time.am') + assert_equal "am", I18n.translate(:'time.am') end def test_time_pm - assert_equal 'pm', I18n.translate(:'time.pm') + assert_equal "pm", I18n.translate(:'time.pm') end def test_words_connector - assert_equal ', ', I18n.translate(:'support.array.words_connector') + assert_equal ", ", I18n.translate(:'support.array.words_connector') end def test_two_words_connector - assert_equal ' and ', I18n.translate(:'support.array.two_words_connector') + assert_equal " and ", I18n.translate(:'support.array.two_words_connector') end def test_last_word_connector - assert_equal ', and ', I18n.translate(:'support.array.last_word_connector') + assert_equal ", and ", I18n.translate(:'support.array.last_word_connector') end def test_to_sentence default_two_words_connector = I18n.translate(:'support.array.two_words_connector') default_last_word_connector = I18n.translate(:'support.array.last_word_connector') - assert_equal 'a, b, and c', %w[a b c].to_sentence - I18n.backend.store_translations 'en', :support => { :array => { :two_words_connector => ' & ' } } - assert_equal 'a & b', %w[a b].to_sentence - I18n.backend.store_translations 'en', :support => { :array => { :last_word_connector => ' and ' } } - assert_equal 'a, b and c', %w[a b c].to_sentence + assert_equal "a, b, and c", %w[a b c].to_sentence + I18n.backend.store_translations "en", support: { array: { two_words_connector: " & " } } + assert_equal "a & b", %w[a b].to_sentence + I18n.backend.store_translations "en", support: { array: { last_word_connector: " and " } } + assert_equal "a, b and c", %w[a b c].to_sentence ensure - I18n.backend.store_translations 'en', :support => { :array => { :two_words_connector => default_two_words_connector } } - I18n.backend.store_translations 'en', :support => { :array => { :last_word_connector => default_last_word_connector } } + I18n.backend.store_translations "en", support: { array: { two_words_connector: default_two_words_connector } } + I18n.backend.store_translations "en", support: { array: { last_word_connector: default_last_word_connector } } end def test_to_sentence_with_empty_i18n_store - assert_equal 'a, b, and c', %w[a b c].to_sentence(locale: 'empty') + assert_equal "a, b, and c", %w[a b c].to_sentence(locale: "empty") end end diff --git a/activesupport/test/inflector_test.rb b/activesupport/test/inflector_test.rb index 06cd41c86d..1c5a4f378c 100644 --- a/activesupport/test/inflector_test.rb +++ b/activesupport/test/inflector_test.rb @@ -1,8 +1,8 @@ -require 'abstract_unit' -require 'active_support/inflector' +require "abstract_unit" +require "active_support/inflector" -require 'inflector_test_cases' -require 'constantize_test_cases' +require "inflector_test_cases" +require "constantize_test_cases" class InflectorTest < ActiveSupport::TestCase include InflectorTestCases @@ -80,7 +80,6 @@ class InflectorTest < ActiveSupport::TestCase end end - def test_overwrite_previous_inflectors assert_equal("series", ActiveSupport::Inflector.singularize("series")) ActiveSupport::Inflector.inflections.singular "series", "serie" @@ -101,11 +100,11 @@ class InflectorTest < ActiveSupport::TestCase end def test_camelize_with_lower_downcases_the_first_letter - assert_equal('capital', ActiveSupport::Inflector.camelize('Capital', false)) + assert_equal("capital", ActiveSupport::Inflector.camelize("Capital", false)) end def test_camelize_with_underscores - assert_equal("CamelCase", ActiveSupport::Inflector.camelize('Camel_Case')) + assert_equal("CamelCase", ActiveSupport::Inflector.camelize("Camel_Case")) end def test_acronyms @@ -246,12 +245,12 @@ class InflectorTest < ActiveSupport::TestCase end end -# FIXME: get following tests to pass on jruby, currently skipped -# -# Currently this fails because ActiveSupport::Multibyte::Unicode#tidy_bytes -# required a specific Encoding::Converter(UTF-8 to UTF8-MAC) which unavailable on JRuby -# causing our tests to error out. -# related bug http://jira.codehaus.org/browse/JRUBY-7194 + # FIXME: get following tests to pass on jruby, currently skipped + # + # Currently this fails because ActiveSupport::Multibyte::Unicode#tidy_bytes + # required a specific Encoding::Converter(UTF-8 to UTF8-MAC) which unavailable on JRuby + # causing our tests to error out. + # related bug http://jira.codehaus.org/browse/JRUBY-7194 def test_parameterize jruby_skip "UTF-8 to UTF8-MAC Converter is unavailable" StringToParameterized.each do |some_string, parameterized_string| @@ -269,7 +268,7 @@ class InflectorTest < ActiveSupport::TestCase def test_parameterize_with_custom_separator jruby_skip "UTF-8 to UTF8-MAC Converter is unavailable" StringToParameterizeWithUnderscore.each do |some_string, parameterized_string| - assert_equal(parameterized_string, ActiveSupport::Inflector.parameterize(some_string, separator: '_')) + assert_equal(parameterized_string, ActiveSupport::Inflector.parameterize(some_string, separator: "_")) end end @@ -277,7 +276,7 @@ class InflectorTest < ActiveSupport::TestCase jruby_skip "UTF-8 to UTF8-MAC Converter is unavailable" StringToParameterizeWithUnderscore.each do |some_string, parameterized_string| assert_deprecated(/Passing the separator argument as a positional parameter is deprecated and will soon be removed. Use `separator: '_'` instead./i) do - assert_equal(parameterized_string, ActiveSupport::Inflector.parameterize(some_string, '_')) + assert_equal(parameterized_string, ActiveSupport::Inflector.parameterize(some_string, "_")) end end end @@ -285,7 +284,7 @@ class InflectorTest < ActiveSupport::TestCase def test_parameterize_with_multi_character_separator jruby_skip "UTF-8 to UTF8-MAC Converter is unavailable" StringToParameterized.each do |some_string, parameterized_string| - assert_equal(parameterized_string.gsub('-', '__sep__'), ActiveSupport::Inflector.parameterize(some_string, separator: '__sep__')) + assert_equal(parameterized_string.gsub("-", "__sep__"), ActiveSupport::Inflector.parameterize(some_string, separator: "__sep__")) end end @@ -293,7 +292,7 @@ class InflectorTest < ActiveSupport::TestCase jruby_skip "UTF-8 to UTF8-MAC Converter is unavailable" StringToParameterized.each do |some_string, parameterized_string| assert_deprecated(/Passing the separator argument as a positional parameter is deprecated and will soon be removed. Use `separator: '__sep__'` instead./i) do - assert_equal(parameterized_string.gsub('-', '__sep__'), ActiveSupport::Inflector.parameterize(some_string, '__sep__')) + assert_equal(parameterized_string.gsub("-", "__sep__"), ActiveSupport::Inflector.parameterize(some_string, "__sep__")) end end end @@ -307,12 +306,12 @@ class InflectorTest < ActiveSupport::TestCase def test_classify_with_symbol assert_nothing_raised do - assert_equal 'FooBar', ActiveSupport::Inflector.classify(:foo_bars) + assert_equal "FooBar", ActiveSupport::Inflector.classify(:foo_bars) end end def test_classify_with_leading_schema_name - assert_equal 'FooBar', ActiveSupport::Inflector.classify('schema.foo_bar') + assert_equal "FooBar", ActiveSupport::Inflector.classify("schema.foo_bar") end def test_humanize @@ -403,24 +402,24 @@ class InflectorTest < ActiveSupport::TestCase def test_inflector_locality ActiveSupport::Inflector.inflections(:es) do |inflect| - inflect.plural(/$/, 's') - inflect.plural(/z$/i, 'ces') + inflect.plural(/$/, "s") + inflect.plural(/z$/i, "ces") - inflect.singular(/s$/, '') - inflect.singular(/es$/, '') + inflect.singular(/s$/, "") + inflect.singular(/es$/, "") - inflect.irregular('el', 'los') + inflect.irregular("el", "los") end - assert_equal('hijos', 'hijo'.pluralize(:es)) - assert_equal('luces', 'luz'.pluralize(:es)) - assert_equal('luzs', 'luz'.pluralize) + assert_equal("hijos", "hijo".pluralize(:es)) + assert_equal("luces", "luz".pluralize(:es)) + assert_equal("luzs", "luz".pluralize) - assert_equal('sociedad', 'sociedades'.singularize(:es)) - assert_equal('sociedade', 'sociedades'.singularize) + assert_equal("sociedad", "sociedades".singularize(:es)) + assert_equal("sociedade", "sociedades".singularize) - assert_equal('los', 'el'.pluralize(:es)) - assert_equal('els', 'el'.pluralize) + assert_equal("los", "el".pluralize(:es)) + assert_equal("els", "el".pluralize) ActiveSupport::Inflector.inflections(:es) { |inflect| inflect.clear } @@ -435,7 +434,7 @@ class InflectorTest < ActiveSupport::TestCase # ensure any data is present inflect.plural(/(quiz)$/i, '\1zes') inflect.singular(/(database)s$/i, '\1') - inflect.uncountable('series') + inflect.uncountable("series") inflect.human("col_rpted_bugs", "Reported bugs") inflect.clear :all @@ -452,7 +451,7 @@ class InflectorTest < ActiveSupport::TestCase # ensure any data is present inflect.plural(/(quiz)$/i, '\1zes') inflect.singular(/(database)s$/i, '\1') - inflect.uncountable('series') + inflect.uncountable("series") inflect.human("col_rpted_bugs", "Reported bugs") inflect.clear diff --git a/activesupport/test/inflector_test_cases.rb b/activesupport/test/inflector_test_cases.rb index 14fe97a986..a8283301b3 100644 --- a/activesupport/test/inflector_test_cases.rb +++ b/activesupport/test/inflector_test_cases.rb @@ -128,10 +128,10 @@ module InflectorTestCases } SymbolToLowerCamel = { - :product => 'product', - :special_guest => 'specialGuest', - :application_controller => 'applicationController', - :area51_controller => 'area51Controller' + product: "product", + special_guest: "specialGuest", + application_controller: "applicationController", + area51_controller: "area51Controller" } CamelToUnderscoreWithoutReverse = { @@ -176,12 +176,12 @@ module InflectorTestCases StringToParameterizedPreserveCase = { "Donald E. Knuth" => "Donald-E-Knuth", - "Random text with *(bad)* characters" => "Random-text-with-bad-characters", - "Allow_Under_Scores" => "Allow_Under_Scores", - "Trailing bad characters!@#" => "Trailing-bad-characters", - "!@#Leading bad characters" => "Leading-bad-characters", - "Squeeze separators" => "Squeeze-separators", - "Test with + sign" => "Test-with-sign", + "Random text with *(bad)* characters" => "Random-text-with-bad-characters", + "Allow_Under_Scores" => "Allow_Under_Scores", + "Trailing bad characters!@#" => "Trailing-bad-characters", + "!@#Leading bad characters" => "Leading-bad-characters", + "Squeeze separators" => "Squeeze-separators", + "Test with + sign" => "Test-with-sign", "Test with malformed utf8 \xA9" => "Test-with-malformed-utf8" } @@ -199,11 +199,11 @@ module InflectorTestCases StringToParameterizePreserveCaseWithNoSeparator = { "Donald E. Knuth" => "DonaldEKnuth", "With-some-dashes" => "With-some-dashes", - "Random text with *(bad)* characters" => "Randomtextwithbadcharacters", - "Trailing bad characters!@#" => "Trailingbadcharacters", - "!@#Leading bad characters" => "Leadingbadcharacters", - "Squeeze separators" => "Squeezeseparators", - "Test with + sign" => "Testwithsign", + "Random text with *(bad)* characters" => "Randomtextwithbadcharacters", + "Trailing bad characters!@#" => "Trailingbadcharacters", + "!@#Leading bad characters" => "Leadingbadcharacters", + "Squeeze separators" => "Squeezeseparators", + "Test with + sign" => "Testwithsign", "Test with malformed utf8 \xA9" => "Testwithmalformedutf8" } @@ -220,14 +220,14 @@ module InflectorTestCases } StringToParameterizePreserceCaseWithUnderscore = { - "Donald E. Knuth" => "Donald_E_Knuth", + "Donald E. Knuth" => "Donald_E_Knuth", "Random text with *(bad)* characters" => "Random_text_with_bad_characters", - "With-some-dashes" => "With-some-dashes", - "Allow_Under_Scores" => "Allow_Under_Scores", - "Trailing bad characters!@#" => "Trailing_bad_characters", - "!@#Leading bad characters" => "Leading_bad_characters", - "Squeeze separators" => "Squeeze_separators", - "Test with + sign" => "Test_with_sign", + "With-some-dashes" => "With-some-dashes", + "Allow_Under_Scores" => "Allow_Under_Scores", + "Trailing bad characters!@#" => "Trailing_bad_characters", + "!@#Leading bad characters" => "Leading_bad_characters", + "Squeeze separators" => "Squeeze_separators", + "Test with + sign" => "Test_with_sign", "Test with malformed utf8 \xA9" => "Test_with_malformed_utf8" } @@ -241,11 +241,11 @@ module InflectorTestCases } UnderscoreToHuman = { - 'employee_salary' => 'Employee salary', - 'employee_id' => 'Employee', - 'underground' => 'Underground', - '_id' => 'Id', - '_external_id' => 'External' + "employee_salary" => "Employee salary", + "employee_id" => "Employee", + "underground" => "Underground", + "_id" => "Id", + "_external_id" => "External" } UnderscoreToHumanWithoutCapitalize = { @@ -255,22 +255,23 @@ module InflectorTestCases } MixtureToTitleCase = { - 'active_record' => 'Active Record', - 'ActiveRecord' => 'Active Record', - 'action web service' => 'Action Web Service', - 'Action Web Service' => 'Action Web Service', - 'Action web service' => 'Action Web Service', - 'actionwebservice' => 'Actionwebservice', - 'Actionwebservice' => 'Actionwebservice', + "active_record" => "Active Record", + "ActiveRecord" => "Active Record", + "action web service" => "Action Web Service", + "Action Web Service" => "Action Web Service", + "Action web service" => "Action Web Service", + "actionwebservice" => "Actionwebservice", + "Actionwebservice" => "Actionwebservice", "david's code" => "David's Code", "David's code" => "David's Code", "david's Code" => "David's Code", "sgt. pepper's" => "Sgt. Pepper's", "i've just seen a face" => "I've Just Seen A Face", "maybe you'll be there" => "Maybe You'll Be There", - "¿por qué?" => '¿Por Qué?', + "¿por qué?" => "¿Por Qué?", "Fred’s" => "Fred’s", - "Fred`s" => "Fred`s" + "Fred`s" => "Fred`s", + ActiveSupport::SafeBuffer.new("confirmation num") => "Confirmation Num" } OrdinalNumbers = { @@ -344,13 +345,13 @@ module InflectorTestCases } Irregularities = { - 'person' => 'people', - 'man' => 'men', - 'child' => 'children', - 'sex' => 'sexes', - 'move' => 'moves', - 'cow' => 'kine', # Test inflections with different starting letters - 'zombie' => 'zombies', - 'genus' => 'genera' + "person" => "people", + "man" => "men", + "child" => "children", + "sex" => "sexes", + "move" => "moves", + "cow" => "kine", # Test inflections with different starting letters + "zombie" => "zombies", + "genus" => "genera" } end diff --git a/activesupport/test/json/decoding_test.rb b/activesupport/test/json/decoding_test.rb index f2fc456f4b..dd8382754b 100644 --- a/activesupport/test/json/decoding_test.rb +++ b/activesupport/test/json/decoding_test.rb @@ -1,8 +1,11 @@ -require 'abstract_unit' -require 'active_support/json' -require 'active_support/time' +require "abstract_unit" +require "active_support/json" +require "active_support/time" +require "time_zone_test_helpers" class TestJSONDecoding < ActiveSupport::TestCase + include TimeZoneTestHelpers + class Foo def self.json_create(object) "Foo" @@ -10,72 +13,75 @@ class TestJSONDecoding < ActiveSupport::TestCase end TESTS = { - %q({"returnTo":{"\/categories":"\/"}}) => {"returnTo" => {"/categories" => "/"}}, - %q({"return\\"To\\":":{"\/categories":"\/"}}) => {"return\"To\":" => {"/categories" => "/"}}, - %q({"returnTo":{"\/categories":1}}) => {"returnTo" => {"/categories" => 1}}, - %({"returnTo":[1,"a"]}) => {"returnTo" => [1, "a"]}, - %({"returnTo":[1,"\\"a\\",", "b"]}) => {"returnTo" => [1, "\"a\",", "b"]}, - %({"a": "'", "b": "5,000"}) => {"a" => "'", "b" => "5,000"}, - %({"a": "a's, b's and c's", "b": "5,000"}) => {"a" => "a's, b's and c's", "b" => "5,000"}, + %q({"returnTo":{"\/categories":"\/"}}) => { "returnTo" => { "/categories" => "/" } }, + %q({"return\\"To\\":":{"\/categories":"\/"}}) => { "return\"To\":" => { "/categories" => "/" } }, + %q({"returnTo":{"\/categories":1}}) => { "returnTo" => { "/categories" => 1 } }, + %({"returnTo":[1,"a"]}) => { "returnTo" => [1, "a"] }, + %({"returnTo":[1,"\\"a\\",", "b"]}) => { "returnTo" => [1, "\"a\",", "b"] }, + %({"a": "'", "b": "5,000"}) => { "a" => "'", "b" => "5,000" }, + %({"a": "a's, b's and c's", "b": "5,000"}) => { "a" => "a's, b's and c's", "b" => "5,000" }, # multibyte - %({"matzue": "松江", "asakusa": "浅草"}) => {"matzue" => "松江", "asakusa" => "浅草"}, - %({"a": "2007-01-01"}) => {'a' => Date.new(2007, 1, 1)}, - %({"a": "2007-01-01 01:12:34 Z"}) => {'a' => Time.utc(2007, 1, 1, 1, 12, 34)}, + %({"matzue": "松江", "asakusa": "浅草"}) => { "matzue" => "松江", "asakusa" => "浅草" }, + %({"a": "2007-01-01"}) => { "a" => Date.new(2007, 1, 1) }, + %({"a": "2007-01-01 01:12:34 Z"}) => { "a" => Time.utc(2007, 1, 1, 1, 12, 34) }, %(["2007-01-01 01:12:34 Z"]) => [Time.utc(2007, 1, 1, 1, 12, 34)], %(["2007-01-01 01:12:34 Z", "2007-01-01 01:12:35 Z"]) => [Time.utc(2007, 1, 1, 1, 12, 34), Time.utc(2007, 1, 1, 1, 12, 35)], # no time zone - %({"a": "2007-01-01 01:12:34"}) => {'a' => "2007-01-01 01:12:34"}, + %({"a": "2007-01-01 01:12:34"}) => { "a" => Time.new(2007, 1, 1, 1, 12, 34, "-05:00") }, # invalid date - %({"a": "1089-10-40"}) => {'a' => "1089-10-40"}, + %({"a": "1089-10-40"}) => { "a" => "1089-10-40" }, # xmlschema date notation - %({"a": "2009-08-10T19:01:02Z"}) => {'a' => Time.utc(2009, 8, 10, 19, 1, 2)}, - %({"a": "2009-08-10T19:01:02+02:00"}) => {'a' => Time.utc(2009, 8, 10, 17, 1, 2)}, - %({"a": "2009-08-10T19:01:02-05:00"}) => {'a' => Time.utc(2009, 8, 11, 00, 1, 2)}, + %({"a": "2009-08-10T19:01:02"}) => { "a" => Time.new(2009, 8, 10, 19, 1, 2, "-04:00") }, + %({"a": "2009-08-10T19:01:02Z"}) => { "a" => Time.utc(2009, 8, 10, 19, 1, 2) }, + %({"a": "2009-08-10T19:01:02+02:00"}) => { "a" => Time.utc(2009, 8, 10, 17, 1, 2) }, + %({"a": "2009-08-10T19:01:02-05:00"}) => { "a" => Time.utc(2009, 8, 11, 00, 1, 2) }, # needs to be *exact* - %({"a": " 2007-01-01 01:12:34 Z "}) => {'a' => " 2007-01-01 01:12:34 Z "}, - %({"a": "2007-01-01 : it's your birthday"}) => {'a' => "2007-01-01 : it's your birthday"}, + %({"a": " 2007-01-01 01:12:34 Z "}) => { "a" => " 2007-01-01 01:12:34 Z " }, + %({"a": "2007-01-01 : it's your birthday"}) => { "a" => "2007-01-01 : it's your birthday" }, %([]) => [], %({}) => {}, - %({"a":1}) => {"a" => 1}, - %({"a": ""}) => {"a" => ""}, - %({"a":"\\""}) => {"a" => "\""}, - %({"a": null}) => {"a" => nil}, - %({"a": true}) => {"a" => true}, - %({"a": false}) => {"a" => false}, - %q({"bad":"\\\\","trailing":""}) => {"bad" => "\\", "trailing" => ""}, - %q({"a": "http:\/\/test.host\/posts\/1"}) => {"a" => "http://test.host/posts/1"}, - %q({"a": "\u003cunicode\u0020escape\u003e"}) => {"a" => "<unicode escape>"}, - %q({"a": "\\\\u0020skip double backslashes"}) => {"a" => "\\u0020skip double backslashes"}, - %q({"a": "\u003cbr /\u003e"}) => {'a' => "<br />"}, - %q({"b":["\u003ci\u003e","\u003cb\u003e","\u003cu\u003e"]}) => {'b' => ["<i>","<b>","<u>"]}, + %({"a":1}) => { "a" => 1 }, + %({"a": ""}) => { "a" => "" }, + %({"a":"\\""}) => { "a" => "\"" }, + %({"a": null}) => { "a" => nil }, + %({"a": true}) => { "a" => true }, + %({"a": false}) => { "a" => false }, + '{"bad":"\\\\","trailing":""}' => { "bad" => "\\", "trailing" => "" }, + %q({"a": "http:\/\/test.host\/posts\/1"}) => { "a" => "http://test.host/posts/1" }, + %q({"a": "\u003cunicode\u0020escape\u003e"}) => { "a" => "<unicode escape>" }, + '{"a": "\\\\u0020skip double backslashes"}' => { "a" => "\\u0020skip double backslashes" }, + %q({"a": "\u003cbr /\u003e"}) => { "a" => "<br />" }, + %q({"b":["\u003ci\u003e","\u003cb\u003e","\u003cu\u003e"]}) => { "b" => ["<i>","<b>","<u>"] }, # test combination of dates and escaped or unicode encoded data in arrays %q([{"d":"1970-01-01", "s":"\u0020escape"},{"d":"1970-01-01", "s":"\u0020escape"}]) => - [{'d' => Date.new(1970, 1, 1), 's' => ' escape'},{'d' => Date.new(1970, 1, 1), 's' => ' escape'}], + [{ "d" => Date.new(1970, 1, 1), "s" => " escape" },{ "d" => Date.new(1970, 1, 1), "s" => " escape" }], %q([{"d":"1970-01-01","s":"http:\/\/example.com"},{"d":"1970-01-01","s":"http:\/\/example.com"}]) => - [{'d' => Date.new(1970, 1, 1), 's' => 'http://example.com'}, - {'d' => Date.new(1970, 1, 1), 's' => 'http://example.com'}], + [{ "d" => Date.new(1970, 1, 1), "s" => "http://example.com" }, + { "d" => Date.new(1970, 1, 1), "s" => "http://example.com" }], # tests escaping of "\n" char with Yaml backend - %q({"a":"\n"}) => {"a"=>"\n"}, - %q({"a":"\u000a"}) => {"a"=>"\n"}, - %q({"a":"Line1\u000aLine2"}) => {"a"=>"Line1\nLine2"}, + %q({"a":"\n"}) => { "a"=>"\n" }, + %q({"a":"\u000a"}) => { "a"=>"\n" }, + %q({"a":"Line1\u000aLine2"}) => { "a"=>"Line1\nLine2" }, # prevent json unmarshalling - %q({"json_class":"TestJSONDecoding::Foo"}) => {"json_class"=>"TestJSONDecoding::Foo"}, + '{"json_class":"TestJSONDecoding::Foo"}' => { "json_class"=>"TestJSONDecoding::Foo" }, # json "fragments" - these are invalid JSON, but ActionPack relies on this - %q("a string") => "a string", - %q(1.1) => 1.1, - %q(1) => 1, - %q(-1) => -1, - %q(true) => true, - %q(false) => false, - %q(null) => nil + '"a string"' => "a string", + "1.1" => 1.1, + "1" => 1, + "-1" => -1, + "true" => true, + "false" => false, + "null" => nil } TESTS.each_with_index do |(json, expected), index| test "json decodes #{index}" do - with_parse_json_times(true) do - silence_warnings do - assert_equal expected, ActiveSupport::JSON.decode(json), "JSON decoding \ - failed for #{json}" + with_tz_default "Eastern Time (US & Canada)" do + with_parse_json_times(true) do + silence_warnings do + assert_equal expected, ActiveSupport::JSON.decode(json), "JSON decoding \ + failed for #{json}" + end end end end @@ -83,7 +89,7 @@ class TestJSONDecoding < ActiveSupport::TestCase test "json decodes time json with time parsing disabled" do with_parse_json_times(false) do - expected = {"a" => "2007-01-01 01:12:34 Z"} + expected = { "a" => "2007-01-01 01:12:34 Z" } assert_equal expected, ActiveSupport::JSON.decode(%({"a": "2007-01-01 01:12:34 Z"})) end end @@ -101,12 +107,11 @@ class TestJSONDecoding < ActiveSupport::TestCase private - def with_parse_json_times(value) - old_value = ActiveSupport.parse_json_times - ActiveSupport.parse_json_times = value - yield - ensure - ActiveSupport.parse_json_times = old_value - end + def with_parse_json_times(value) + old_value = ActiveSupport.parse_json_times + ActiveSupport.parse_json_times = value + yield + ensure + ActiveSupport.parse_json_times = old_value + end end - diff --git a/activesupport/test/json/encoding_test.rb b/activesupport/test/json/encoding_test.rb index 9f4b62fd8b..d125cc939f 100644 --- a/activesupport/test/json/encoding_test.rb +++ b/activesupport/test/json/encoding_test.rb @@ -1,17 +1,21 @@ -require 'securerandom' -require 'abstract_unit' -require 'active_support/core_ext/string/inflections' -require 'active_support/json' -require 'active_support/time' -require 'time_zone_test_helpers' -require 'json/encoding_test_cases' +require "securerandom" +require "abstract_unit" +require "active_support/core_ext/string/inflections" +require "active_support/core_ext/regexp" +require "active_support/json" +require "active_support/time" +require "time_zone_test_helpers" +require "json/encoding_test_cases" class TestJSONEncoding < ActiveSupport::TestCase include TimeZoneTestHelpers def sorted_json(json) - return json unless json =~ /^\{.*\}$/ - '{' + json[1..-2].split(',').sort.join(',') + '}' + if json.start_with?("{") && json.end_with?("}") + "{" + json[1..-2].split(",").sort.join(",") + "}" + else + json + end end JSONTest::EncodingTestCases.constants.each do |class_tests| @@ -19,8 +23,10 @@ class TestJSONEncoding < ActiveSupport::TestCase begin prev = ActiveSupport.use_standard_json_time_format - ActiveSupport.escape_html_entities_in_json = class_tests !~ /^Standard/ - ActiveSupport.use_standard_json_time_format = class_tests =~ /^Standard/ + standard_class_tests = /Standard/.match?(class_tests) + + ActiveSupport.escape_html_entities_in_json = !standard_class_tests + ActiveSupport.use_standard_json_time_format = standard_class_tests JSONTest::EncodingTestCases.const_get(class_tests).each do |pair| assert_equal pair.last, sorted_json(ActiveSupport::JSON.encode(pair.first)) end @@ -41,12 +47,12 @@ class TestJSONEncoding < ActiveSupport::TestCase end def test_hash_encoding - assert_equal %({\"a\":\"b\"}), ActiveSupport::JSON.encode(:a => :b) - assert_equal %({\"a\":1}), ActiveSupport::JSON.encode('a' => 1) - assert_equal %({\"a\":[1,2]}), ActiveSupport::JSON.encode('a' => [1,2]) + assert_equal %({\"a\":\"b\"}), ActiveSupport::JSON.encode(a: :b) + assert_equal %({\"a\":1}), ActiveSupport::JSON.encode("a" => 1) + assert_equal %({\"a\":[1,2]}), ActiveSupport::JSON.encode("a" => [1,2]) assert_equal %({"1":2}), ActiveSupport::JSON.encode(1 => 2) - assert_equal %({\"a\":\"b\",\"c\":\"d\"}), sorted_json(ActiveSupport::JSON.encode(:a => :b, :c => :d)) + assert_equal %({\"a\":\"b\",\"c\":\"d\"}), sorted_json(ActiveSupport::JSON.encode(a: :b, c: :d)) end def test_hash_keys_encoding @@ -57,24 +63,24 @@ class TestJSONEncoding < ActiveSupport::TestCase end def test_utf8_string_encoded_properly - result = ActiveSupport::JSON.encode('€2.99') + result = ActiveSupport::JSON.encode("€2.99") assert_equal '"€2.99"', result assert_equal(Encoding::UTF_8, result.encoding) - result = ActiveSupport::JSON.encode('✎☺') + result = ActiveSupport::JSON.encode("✎☺") assert_equal '"✎☺"', result assert_equal(Encoding::UTF_8, result.encoding) end def test_non_utf8_string_transcodes - s = '二'.encode('Shift_JIS') + s = "二".encode("Shift_JIS") result = ActiveSupport::JSON.encode(s) assert_equal '"二"', result assert_equal Encoding::UTF_8, result.encoding end def test_wide_utf8_chars - w = '𠜎' + w = "𠜎" result = ActiveSupport::JSON.encode(w) assert_equal '"𠜎"', result end @@ -83,25 +89,25 @@ class TestJSONEncoding < ActiveSupport::TestCase hash = { string: "𐒑" } json = ActiveSupport::JSON.encode(hash) decoded_hash = ActiveSupport::JSON.decode(json) - assert_equal "𐒑", decoded_hash['string'] + assert_equal "𐒑", decoded_hash["string"] end def test_hash_key_identifiers_are_always_quoted - values = {0 => 0, 1 => 1, :_ => :_, "$" => "$", "a" => "a", :A => :A, :A0 => :A0, "A0B" => "A0B"} + values = { 0 => 0, 1 => 1, :_ => :_, "$" => "$", "a" => "a", :A => :A, :A0 => :A0, "A0B" => "A0B" } assert_equal %w( "$" "A" "A0" "A0B" "_" "a" "0" "1" ).sort, object_keys(ActiveSupport::JSON.encode(values)) end def test_hash_should_allow_key_filtering_with_only - assert_equal %({"a":1}), ActiveSupport::JSON.encode({'a' => 1, :b => 2, :c => 3}, :only => 'a') + assert_equal %({"a":1}), ActiveSupport::JSON.encode({ "a" => 1, :b => 2, :c => 3 }, only: "a") end def test_hash_should_allow_key_filtering_with_except - assert_equal %({"b":2}), ActiveSupport::JSON.encode({'foo' => 'bar', :b => 2, :c => 3}, :except => ['foo', :c]) + assert_equal %({"b":2}), ActiveSupport::JSON.encode({ "foo" => "bar", :b => 2, :c => 3 }, except: ["foo", :c]) end def test_time_to_json_includes_local_offset with_standard_json_time_format(true) do - with_env_tz 'US/Eastern' do + with_env_tz "US/Eastern" do assert_equal %("2005-02-01T15:15:10.000-05:00"), ActiveSupport::JSON.encode(Time.local(2005,2,1,15,15,10)) end end @@ -109,7 +115,7 @@ class TestJSONEncoding < ActiveSupport::TestCase def test_hash_with_time_to_json with_standard_json_time_format(false) do - assert_equal '{"time":"2009/01/01 00:00:00 +0000"}', { :time => Time.utc(2009) }.to_json + assert_equal '{"time":"2009/01/01 00:00:00 +0000"}', { time: Time.utc(2009) }.to_json end end @@ -117,8 +123,8 @@ class TestJSONEncoding < ActiveSupport::TestCase assert_nothing_raised do hash = { "CHI" => { - :display_name => "chicago", - :latitude => 123.234 + display_name: "chicago", + latitude: 123.234 } } ActiveSupport::JSON.encode(hash) @@ -127,64 +133,64 @@ class TestJSONEncoding < ActiveSupport::TestCase def test_hash_like_with_options h = JSONTest::Hashlike.new - json = h.to_json :only => [:foo] + json = h.to_json only: [:foo] - assert_equal({"foo"=>"hello"}, JSON.parse(json)) + assert_equal({ "foo"=>"hello" }, JSON.parse(json)) end def test_object_to_json_with_options obj = Object.new obj.instance_variable_set :@foo, "hello" obj.instance_variable_set :@bar, "world" - json = obj.to_json :only => ["foo"] + json = obj.to_json only: ["foo"] - assert_equal({"foo"=>"hello"}, JSON.parse(json)) + assert_equal({ "foo"=>"hello" }, JSON.parse(json)) end def test_struct_to_json_with_options struct = Struct.new(:foo, :bar).new struct.foo = "hello" struct.bar = "world" - json = struct.to_json :only => [:foo] + json = struct.to_json only: [:foo] - assert_equal({"foo"=>"hello"}, JSON.parse(json)) + assert_equal({ "foo"=>"hello" }, JSON.parse(json)) end def test_hash_should_pass_encoding_options_to_children_in_as_json person = { - :name => 'John', - :address => { - :city => 'London', - :country => 'UK' + name: "John", + address: { + city: "London", + country: "UK" } } - json = person.as_json :only => [:address, :city] + json = person.as_json only: [:address, :city] - assert_equal({ 'address' => { 'city' => 'London' }}, json) + assert_equal({ "address" => { "city" => "London" } }, json) end def test_hash_should_pass_encoding_options_to_children_in_to_json person = { - :name => 'John', - :address => { - :city => 'London', - :country => 'UK' + name: "John", + address: { + city: "London", + country: "UK" } } - json = person.to_json :only => [:address, :city] + json = person.to_json only: [:address, :city] assert_equal(%({"address":{"city":"London"}}), json) end def test_array_should_pass_encoding_options_to_children_in_as_json people = [ - { :name => 'John', :address => { :city => 'London', :country => 'UK' }}, - { :name => 'Jean', :address => { :city => 'Paris' , :country => 'France' }} + { name: "John", address: { city: "London", country: "UK" } }, + { name: "Jean", address: { city: "Paris" , country: "France" } } ] - json = people.as_json :only => [:address, :city] + json = people.as_json only: [:address, :city] expected = [ - { 'address' => { 'city' => 'London' }}, - { 'address' => { 'city' => 'Paris' }} + { "address" => { "city" => "London" } }, + { "address" => { "city" => "Paris" } } ] assert_equal(expected, json) @@ -192,10 +198,10 @@ class TestJSONEncoding < ActiveSupport::TestCase def test_array_should_pass_encoding_options_to_children_in_to_json people = [ - { :name => 'John', :address => { :city => 'London', :country => 'UK' }}, - { :name => 'Jean', :address => { :city => 'Paris' , :country => 'France' }} + { name: "John", address: { city: "London", country: "UK" } }, + { name: "Jean", address: { city: "Paris" , country: "France" } } ] - json = people.to_json :only => [:address, :city] + json = people.to_json only: [:address, :city] assert_equal(%([{"address":{"city":"London"}},{"address":{"city":"Paris"}}]), json) end @@ -204,8 +210,8 @@ class TestJSONEncoding < ActiveSupport::TestCase include Enumerable def initialize() @people = [ - { :name => 'John', :address => { :city => 'London', :country => 'UK' }}, - { :name => 'Jean', :address => { :city => 'Paris' , :country => 'France' }} + { name: "John", address: { city: "London", country: "UK" } }, + { name: "Jean", address: { city: "Paris" , country: "France" } } ] end def each(*, &blk) @@ -217,32 +223,32 @@ class TestJSONEncoding < ActiveSupport::TestCase end def test_enumerable_should_generate_json_with_as_json - json = People.new.as_json :only => [:address, :city] + json = People.new.as_json only: [:address, :city] expected = [ - { 'address' => { 'city' => 'London' }}, - { 'address' => { 'city' => 'Paris' }} + { "address" => { "city" => "London" } }, + { "address" => { "city" => "Paris" } } ] assert_equal(expected, json) end def test_enumerable_should_generate_json_with_to_json - json = People.new.to_json :only => [:address, :city] + json = People.new.to_json only: [:address, :city] assert_equal(%([{"address":{"city":"London"}},{"address":{"city":"Paris"}}]), json) end def test_enumerable_should_pass_encoding_options_to_children_in_as_json - json = People.new.each.as_json :only => [:address, :city] + json = People.new.each.as_json only: [:address, :city] expected = [ - { 'address' => { 'city' => 'London' }}, - { 'address' => { 'city' => 'Paris' }} + { "address" => { "city" => "London" } }, + { "address" => { "city" => "Paris" } } ] assert_equal(expected, json) end def test_enumerable_should_pass_encoding_options_to_children_in_to_json - json = People.new.each.to_json :only => [:address, :city] + json = People.new.each.to_json only: [:address, :city] assert_equal(%([{"address":{"city":"London"}},{"address":{"city":"Paris"}}]), json) end @@ -261,9 +267,9 @@ class TestJSONEncoding < ActiveSupport::TestCase f.foo = "hello" f.bar = "world" - hash = {"foo" => f, "other_hash" => {"foo" => "other_foo", "test" => "other_test"}} - assert_equal({"foo"=>{"foo"=>"hello","bar"=>"world"}, - "other_hash" => {"foo"=>"other_foo","test"=>"other_test"}}, ActiveSupport::JSON.decode(hash.to_json)) + hash = { "foo" => f, "other_hash" => { "foo" => "other_foo", "test" => "other_test" } } + assert_equal({ "foo"=>{ "foo"=>"hello","bar"=>"world" }, + "other_hash" => { "foo"=>"other_foo","test"=>"other_test" } }, ActiveSupport::JSON.decode(hash.to_json)) end def test_array_to_json_should_not_keep_options_around @@ -271,9 +277,9 @@ class TestJSONEncoding < ActiveSupport::TestCase f.foo = "hello" f.bar = "world" - array = [f, {"foo" => "other_foo", "test" => "other_test"}] - assert_equal([{"foo"=>"hello","bar"=>"world"}, - {"foo"=>"other_foo","test"=>"other_test"}], ActiveSupport::JSON.decode(array.to_json)) + array = [f, { "foo" => "other_foo", "test" => "other_test" }] + assert_equal([{ "foo"=>"hello","bar"=>"world" }, + { "foo"=>"other_foo","test"=>"other_test" }], ActiveSupport::JSON.decode(array.to_json)) end class OptionsTest @@ -284,7 +290,7 @@ class TestJSONEncoding < ActiveSupport::TestCase def test_hash_as_json_without_options json = { foo: OptionsTest.new }.as_json - assert_equal({"foo" => :default}, json) + assert_equal({ "foo" => :default }, json) end def test_array_as_json_without_options @@ -293,13 +299,12 @@ class TestJSONEncoding < ActiveSupport::TestCase end def test_struct_encoding - Struct.new('UserNameAndEmail', :name, :email) - Struct.new('UserNameAndDate', :name, :date) - Struct.new('Custom', :name, :sub) - user_email = Struct::UserNameAndEmail.new 'David', 'sample@example.com' - user_birthday = Struct::UserNameAndDate.new 'David', Date.new(2010, 01, 01) - custom = Struct::Custom.new 'David', user_birthday - + Struct.new("UserNameAndEmail", :name, :email) + Struct.new("UserNameAndDate", :name, :date) + Struct.new("Custom", :name, :sub) + user_email = Struct::UserNameAndEmail.new "David", "sample@example.com" + user_birthday = Struct::UserNameAndDate.new "David", Date.new(2010, 01, 01) + custom = Struct::Custom.new "David", user_birthday json_strings = "" json_string_and_date = "" @@ -311,15 +316,15 @@ class TestJSONEncoding < ActiveSupport::TestCase json_custom = custom.to_json end - assert_equal({"name" => "David", + assert_equal({ "name" => "David", "sub" => { "name" => "David", - "date" => "2010-01-01" }}, ActiveSupport::JSON.decode(json_custom)) + "date" => "2010-01-01" } }, ActiveSupport::JSON.decode(json_custom)) - assert_equal({"name" => "David", "email" => "sample@example.com"}, + assert_equal({ "name" => "David", "email" => "sample@example.com" }, ActiveSupport::JSON.decode(json_strings)) - assert_equal({"name" => "David", "date" => "2010-01-01"}, + assert_equal({ "name" => "David", "date" => "2010-01-01" }, ActiveSupport::JSON.decode(json_string_and_date)) end @@ -376,7 +381,7 @@ EXPECTED def test_twz_to_json_with_use_standard_json_time_format_config_set_to_false with_standard_json_time_format(false) do - zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)'] + zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"] time = ActiveSupport::TimeWithZone.new(Time.utc(2000), zone) assert_equal "\"1999/12/31 19:00:00 -0500\"", ActiveSupport::JSON.encode(time) end @@ -384,7 +389,7 @@ EXPECTED def test_twz_to_json_with_use_standard_json_time_format_config_set_to_true with_standard_json_time_format(true) do - zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)'] + zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"] time = ActiveSupport::TimeWithZone.new(Time.utc(2000), zone) assert_equal "\"1999-12-31T19:00:00.000-05:00\"", ActiveSupport::JSON.encode(time) end @@ -393,7 +398,7 @@ EXPECTED def test_twz_to_json_with_custom_time_precision with_standard_json_time_format(true) do with_time_precision(0) do - zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)'] + zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"] time = ActiveSupport::TimeWithZone.new(Time.utc(2000), zone) assert_equal "\"1999-12-31T19:00:00-05:00\"", ActiveSupport::JSON.encode(time) end @@ -417,11 +422,16 @@ EXPECTED end def test_twz_to_json_when_wrapping_a_date_time - zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)'] + zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"] time = ActiveSupport::TimeWithZone.new(DateTime.new(2000), zone) assert_equal '"1999-12-31T19:00:00.000-05:00"', ActiveSupport::JSON.encode(time) end + def test_exception_to_json + exception = Exception.new("foo") + assert_equal '"foo"', ActiveSupport::JSON.encode(exception) + end + protected def object_keys(json_object) diff --git a/activesupport/test/json/encoding_test_cases.rb b/activesupport/test/json/encoding_test_cases.rb index 0159ba8606..ff2ed3a788 100644 --- a/activesupport/test/json/encoding_test_cases.rb +++ b/activesupport/test/json/encoding_test_cases.rb @@ -1,4 +1,4 @@ -require 'bigdecimal' +require "bigdecimal" module JSONTest class Foo @@ -9,7 +9,7 @@ module JSONTest class Hashlike def to_hash - { :foo => "hello", :bar => "world" } + { foo: "hello", bar: "world" } end end @@ -39,20 +39,20 @@ module JSONTest [ 0.0/0.0, %(null) ], [ 1.0/0.0, %(null) ], [ -1.0/0.0, %(null) ], - [ BigDecimal('0.0')/BigDecimal('0.0'), %(null) ], - [ BigDecimal('2.5'), %("#{BigDecimal('2.5')}") ]] + [ BigDecimal("0.0")/BigDecimal("0.0"), %(null) ], + [ BigDecimal("2.5"), %("#{BigDecimal('2.5')}") ]] - StringTests = [[ 'this is the <string>', %("this is the \\u003cstring\\u003e")], + StringTests = [[ "this is the <string>", %("this is the \\u003cstring\\u003e")], [ 'a "string" with quotes & an ampersand', %("a \\"string\\" with quotes \\u0026 an ampersand") ], - [ 'http://test.host/posts/1', %("http://test.host/posts/1")], + [ "http://test.host/posts/1", %("http://test.host/posts/1")], [ "Control characters: \x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\u2028\u2029", %("Control characters: \\u0000\\u0001\\u0002\\u0003\\u0004\\u0005\\u0006\\u0007\\b\\t\\n\\u000b\\f\\r\\u000e\\u000f\\u0010\\u0011\\u0012\\u0013\\u0014\\u0015\\u0016\\u0017\\u0018\\u0019\\u001a\\u001b\\u001c\\u001d\\u001e\\u001f\\u2028\\u2029") ]] - ArrayTests = [[ ['a', 'b', 'c'], %([\"a\",\"b\",\"c\"]) ], - [ [1, 'a', :b, nil, false], %([1,\"a\",\"b\",null,false]) ]] + ArrayTests = [[ ["a", "b", "c"], %([\"a\",\"b\",\"c\"]) ], + [ [1, "a", :b, nil, false], %([1,\"a\",\"b\",null,false]) ]] - HashTests = [[ {foo: "bar"}, %({\"foo\":\"bar\"}) ], - [ {1 => 1, 2 => 'a', 3 => :b, 4 => nil, 5 => false}, %({\"1\":1,\"2\":\"a\",\"3\":\"b\",\"4\":null,\"5\":false}) ]] + HashTests = [[ { foo: "bar" }, %({\"foo\":\"bar\"}) ], + [ { 1 => 1, 2 => "a", 3 => :b, 4 => nil, 5 => false }, %({\"1\":1,\"2\":\"a\",\"3\":\"b\",\"4\":null,\"5\":false}) ]] RangeTests = [[ 1..2, %("1..2")], [ 1...2, %("1...2")], @@ -67,15 +67,19 @@ module JSONTest StructTests = [[ MyStruct.new(:foo, "bar"), %({\"name\":\"foo\",\"value\":\"bar\"}) ], [ MyStruct.new(nil, nil), %({\"name\":null,\"value\":null}) ]] CustomTests = [[ Custom.new("custom"), '"custom"' ], - [ Custom.new(nil), 'null' ], + [ Custom.new(nil), "null" ], [ Custom.new(:a), '"a"' ], [ Custom.new([ :foo, "bar" ]), '["foo","bar"]' ], - [ Custom.new({ :foo => "hello", :bar => "world" }), '{"bar":"world","foo":"hello"}' ], + [ Custom.new(foo: "hello", bar: "world"), '{"bar":"world","foo":"hello"}' ], [ Custom.new(Hashlike.new), '{"bar":"world","foo":"hello"}' ], [ Custom.new(Custom.new(Custom.new(:a))), '"a"' ]] RegexpTests = [[ /^a/, '"(?-mix:^a)"' ], [/^\w{1,2}[a-z]+/ix, '"(?ix-m:^\\\\w{1,2}[a-z]+)"']] + URITests = [[ URI.parse("http://example.com"), %("http://example.com") ]] + + PathnameTests = [[ Pathname.new("lib/index.rb"), %("lib/index.rb") ]] + DateTests = [[ Date.new(2005,2,1), %("2005/02/01") ]] TimeTests = [[ Time.utc(2005,2,1,15,15,10), %("2005/02/01 15:15:10 +0000") ]] DateTimeTests = [[ DateTime.civil(2005,2,1,15,15,10), %("2005/02/01 15:15:10 +0000") ]] @@ -83,6 +87,6 @@ module JSONTest StandardDateTests = [[ Date.new(2005,2,1), %("2005-02-01") ]] StandardTimeTests = [[ Time.utc(2005,2,1,15,15,10), %("2005-02-01T15:15:10.000Z") ]] StandardDateTimeTests = [[ DateTime.civil(2005,2,1,15,15,10), %("2005-02-01T15:15:10.000+00:00") ]] - StandardStringTests = [[ 'this is the <string>', %("this is the <string>")]] + StandardStringTests = [[ "this is the <string>", %("this is the <string>")]] end end diff --git a/activesupport/test/key_generator_test.rb b/activesupport/test/key_generator_test.rb index f7e8e9a795..89db9563ac 100644 --- a/activesupport/test/key_generator_test.rb +++ b/activesupport/test/key_generator_test.rb @@ -1,62 +1,77 @@ -require 'abstract_unit' +require "abstract_unit" begin - require 'openssl' + require "openssl" OpenSSL::PKCS5 rescue LoadError, NameError $stderr.puts "Skipping KeyGenerator test: broken OpenSSL install" else -require 'active_support/time' -require 'active_support/json' + require "active_support/time" + require "active_support/json" -class KeyGeneratorTest < ActiveSupport::TestCase - def setup - @secret = SecureRandom.hex(64) - @generator = ActiveSupport::KeyGenerator.new(@secret, :iterations=>2) - end + class KeyGeneratorTest < ActiveSupport::TestCase + def setup + @secret = SecureRandom.hex(64) + @generator = ActiveSupport::KeyGenerator.new(@secret, iterations: 2) + end - test "Generating a key of the default length" do - derived_key = @generator.generate_key("some_salt") - assert_kind_of String, derived_key - assert_equal OpenSSL::Digest::SHA1.new.block_length, derived_key.length, "Should have generated a key of the default size" - end + test "Generating a key of the default length" do + derived_key = @generator.generate_key("some_salt") + assert_kind_of String, derived_key + assert_equal 64, derived_key.length, "Should have generated a key of the default size" + end - test "Generating a key of an alternative length" do - derived_key = @generator.generate_key("some_salt", 32) - assert_kind_of String, derived_key - assert_equal 32, derived_key.length, "Should have generated a key of the right size" - end -end + test "Generating a key of an alternative length" do + derived_key = @generator.generate_key("some_salt", 32) + assert_kind_of String, derived_key + assert_equal 32, derived_key.length, "Should have generated a key of the right size" + end -class CachingKeyGeneratorTest < ActiveSupport::TestCase - def setup - @secret = SecureRandom.hex(64) - @generator = ActiveSupport::KeyGenerator.new(@secret, :iterations=>2) - @caching_generator = ActiveSupport::CachingKeyGenerator.new(@generator) - end + test "Expected results" do + # For any given set of inputs, this method must continue to return + # the same output: if it changes, any existing values relying on a + # key would break. + + expected = "b129376f68f1ecae788d7433310249d65ceec090ecacd4c872a3a9e9ec78e055739be5cc6956345d5ae38e7e1daa66f1de587dc8da2bf9e8b965af4b3918a122" + assert_equal expected, ActiveSupport::KeyGenerator.new("0" * 64).generate_key("some_salt").unpack("H*").first - test "Generating a cached key for same salt and key size" do - derived_key = @caching_generator.generate_key("some_salt", 32) - cached_key = @caching_generator.generate_key("some_salt", 32) + expected = "b129376f68f1ecae788d7433310249d65ceec090ecacd4c872a3a9e9ec78e055" + assert_equal expected, ActiveSupport::KeyGenerator.new("0" * 64).generate_key("some_salt", 32).unpack("H*").first - assert_equal derived_key, cached_key - assert_equal derived_key.object_id, cached_key.object_id + expected = "cbea7f7f47df705967dc508f4e446fd99e7797b1d70011c6899cd39bbe62907b8508337d678505a7dc8184e037f1003ba3d19fc5d829454668e91d2518692eae" + assert_equal expected, ActiveSupport::KeyGenerator.new("0" * 64, iterations: 2).generate_key("some_salt").unpack("H*").first + end end - test "Does not cache key for different salt" do - derived_key = @caching_generator.generate_key("some_salt", 32) - different_salt_key = @caching_generator.generate_key("other_salt", 32) + class CachingKeyGeneratorTest < ActiveSupport::TestCase + def setup + @secret = SecureRandom.hex(64) + @generator = ActiveSupport::KeyGenerator.new(@secret, iterations: 2) + @caching_generator = ActiveSupport::CachingKeyGenerator.new(@generator) + end - assert_not_equal derived_key, different_salt_key - end + test "Generating a cached key for same salt and key size" do + derived_key = @caching_generator.generate_key("some_salt", 32) + cached_key = @caching_generator.generate_key("some_salt", 32) + + assert_equal derived_key, cached_key + assert_equal derived_key.object_id, cached_key.object_id + end + + test "Does not cache key for different salt" do + derived_key = @caching_generator.generate_key("some_salt", 32) + different_salt_key = @caching_generator.generate_key("other_salt", 32) - test "Does not cache key for different length" do - derived_key = @caching_generator.generate_key("some_salt", 32) - different_length_key = @caching_generator.generate_key("some_salt", 64) + assert_not_equal derived_key, different_salt_key + end - assert_not_equal derived_key, different_length_key + test "Does not cache key for different length" do + derived_key = @caching_generator.generate_key("some_salt", 32) + different_length_key = @caching_generator.generate_key("some_salt", 64) + + assert_not_equal derived_key, different_length_key + end end -end end diff --git a/activesupport/test/lazy_load_hooks_test.rb b/activesupport/test/lazy_load_hooks_test.rb index 7851634dbf..3b1959a1c9 100644 --- a/activesupport/test/lazy_load_hooks_test.rb +++ b/activesupport/test/lazy_load_hooks_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" class LazyLoadHooksTest < ActiveSupport::TestCase def test_basic_hook @@ -63,7 +63,7 @@ class LazyLoadHooksTest < ActiveSupport::TestCase def test_hook_with_yield_true i = 0 - ActiveSupport.on_load(:contextual_yield, :yield => true) do |obj| + ActiveSupport.on_load(:contextual_yield, yield: true) do |obj| i += obj.incr + incr_amt end assert_equal 0, i @@ -75,7 +75,7 @@ class LazyLoadHooksTest < ActiveSupport::TestCase i = 0 ActiveSupport.run_load_hooks(:contextual_yield_after, FakeContext.new(2)) assert_equal 0, i - ActiveSupport.on_load(:contextual_yield_after, :yield => true) do |obj| + ActiveSupport.on_load(:contextual_yield_after, yield: true) do |obj| i += obj.incr + incr_amt end assert_equal 7, i @@ -93,4 +93,4 @@ private @incr = incr end end -end
\ No newline at end of file +end diff --git a/activesupport/test/load_paths_test.rb b/activesupport/test/load_paths_test.rb deleted file mode 100644 index ac617a9fd8..0000000000 --- a/activesupport/test/load_paths_test.rb +++ /dev/null @@ -1,16 +0,0 @@ -require 'abstract_unit' - -class LoadPathsTest < ActiveSupport::TestCase - def test_uniq_load_paths - load_paths_count = $LOAD_PATH.inject({}) { |paths, path| - expanded_path = File.expand_path(path) - paths[expanded_path] ||= 0 - paths[expanded_path] += 1 - paths - } - load_paths_count[File.expand_path('../../lib', __FILE__)] -= 1 - - load_paths_count.select! { |k, v| v > 1 } - assert load_paths_count.empty?, load_paths_count.inspect - end -end diff --git a/activesupport/test/log_subscriber_test.rb b/activesupport/test/log_subscriber_test.rb index 998a6887c5..f6496ef7d6 100644 --- a/activesupport/test/log_subscriber_test.rb +++ b/activesupport/test/log_subscriber_test.rb @@ -1,5 +1,5 @@ -require 'abstract_unit' -require 'active_support/log_subscriber/test_helper' +require "abstract_unit" +require "active_support/log_subscriber/test_helper" class MyLogSubscriber < ActiveSupport::LogSubscriber attr_reader :event @@ -116,7 +116,7 @@ class SyncLogSubscriberTest < ActiveSupport::TestCase wait assert_equal 1, @logger.logged(:info).size - assert_equal 'some_event.my_log_subscriber', @logger.logged(:info).last + assert_equal "some_event.my_log_subscriber", @logger.logged(:info).last assert_equal 1, @logger.logged(:error).size assert_match 'Could not log "puke.my_log_subscriber" event. RuntimeError: puke', @logger.logged(:error).last diff --git a/activesupport/test/logger_test.rb b/activesupport/test/logger_test.rb index 317e09b7f2..3f04783401 100644 --- a/activesupport/test/logger_test.rb +++ b/activesupport/test/logger_test.rb @@ -1,9 +1,9 @@ -require 'abstract_unit' -require 'multibyte_test_helpers' -require 'stringio' -require 'fileutils' -require 'tempfile' -require 'concurrent/atomics' +require "abstract_unit" +require "multibyte_test_helpers" +require "stringio" +require "fileutils" +require "tempfile" +require "concurrent/atomics" class LoggerTest < ActiveSupport::TestCase include MultibyteTestHelpers @@ -26,12 +26,12 @@ class LoggerTest < ActiveSupport::TestCase end def test_write_binary_data_to_existing_file - t = Tempfile.new ['development', 'log'] + t = Tempfile.new ["development", "log"] t.binmode - t.write 'hi mom!' + t.write "hi mom!" t.close - f = File.open(t.path, 'w') + f = File.open(t.path, "w") f.binmode logger = Logger.new f @@ -47,9 +47,9 @@ class LoggerTest < ActiveSupport::TestCase end def test_write_binary_data_create_file - fname = File.join Dir.tmpdir, 'lol', 'rofl.log' + fname = File.join Dir.tmpdir, "lol", "rofl.log" FileUtils.mkdir_p File.dirname(fname) - f = File.open(fname, 'w') + f = File.open(fname, "w") f.binmode logger = Logger.new f @@ -67,7 +67,7 @@ class LoggerTest < ActiveSupport::TestCase def test_should_log_debugging_message_when_debugging @logger.level = Logger::DEBUG @logger.add(Logger::DEBUG, @message) - assert @output.string.include?(@message) + assert_includes @output.string, @message end def test_should_not_log_debug_messages_when_log_level_is_info @@ -78,32 +78,32 @@ class LoggerTest < ActiveSupport::TestCase def test_should_add_message_passed_as_block_when_using_add @logger.level = Logger::INFO - @logger.add(Logger::INFO) {@message} - assert @output.string.include?(@message) + @logger.add(Logger::INFO) { @message } + assert_includes @output.string, @message end def test_should_add_message_passed_as_block_when_using_shortcut @logger.level = Logger::INFO - @logger.info {@message} - assert @output.string.include?(@message) + @logger.info { @message } + assert_includes @output.string, @message end def test_should_convert_message_to_string @logger.level = Logger::INFO @logger.info @integer_message - assert @output.string.include?(@integer_message.to_s) + assert_includes @output.string, @integer_message.to_s end def test_should_convert_message_to_string_when_passed_in_block @logger.level = Logger::INFO - @logger.info {@integer_message} - assert @output.string.include?(@integer_message.to_s) + @logger.info { @integer_message } + assert_includes @output.string, @integer_message.to_s end def test_should_not_evaluate_block_if_message_wont_be_logged @logger.level = Logger::INFO evaluated = false - @logger.add(Logger::DEBUG) {evaluated = true} + @logger.add(Logger::DEBUG) { evaluated = true } assert evaluated == false end @@ -115,7 +115,7 @@ class LoggerTest < ActiveSupport::TestCase def test_should_know_if_its_loglevel_is_below_a_given_level Logger::Severity.constants.each do |level| - next if level.to_s == 'UNKNOWN' + next if level.to_s == "UNKNOWN" @logger.level = Logger::Severity.const_get(level) - 1 assert @logger.send("#{level.downcase}?"), "didn't know if it was #{level.downcase}? or below" end @@ -125,10 +125,10 @@ class LoggerTest < ActiveSupport::TestCase @logger.level = Logger::INFO @logger.info(UNICODE_STRING) @logger.info(BYTE_STRING) - assert @output.string.include?(UNICODE_STRING) + assert_includes @output.string, UNICODE_STRING byte_string = @output.string.dup byte_string.force_encoding("ASCII-8BIT") - assert byte_string.include?(BYTE_STRING) + assert_includes byte_string, BYTE_STRING end def test_silencing_everything_but_errors @@ -138,7 +138,53 @@ class LoggerTest < ActiveSupport::TestCase end assert_not @output.string.include?("NOT THERE") - assert @output.string.include?("THIS IS HERE") + assert_includes @output.string, "THIS IS HERE" + end + + def test_logger_silencing_works_for_broadcast + another_output = StringIO.new + another_logger = ActiveSupport::Logger.new(another_output) + + @logger.extend ActiveSupport::Logger.broadcast(another_logger) + + @logger.debug "CORRECT DEBUG" + @logger.silence do |logger| + assert_kind_of ActiveSupport::Logger, logger + @logger.debug "FAILURE" + @logger.error "CORRECT ERROR" + end + + assert_includes @output.string, "CORRECT DEBUG" + assert_includes @output.string, "CORRECT ERROR" + assert_not @output.string.include?("FAILURE") + + assert_includes another_output.string, "CORRECT DEBUG" + assert_includes another_output.string, "CORRECT ERROR" + assert_not another_output.string.include?("FAILURE") + end + + def test_broadcast_silencing_does_not_break_plain_ruby_logger + another_output = StringIO.new + another_logger = ::Logger.new(another_output) + + @logger.extend ActiveSupport::Logger.broadcast(another_logger) + + @logger.debug "CORRECT DEBUG" + @logger.silence do |logger| + assert_kind_of ActiveSupport::Logger, logger + @logger.debug "FAILURE" + @logger.error "CORRECT ERROR" + end + + assert_includes @output.string, "CORRECT DEBUG" + assert_includes @output.string, "CORRECT ERROR" + assert_not @output.string.include?("FAILURE") + + assert_includes another_output.string, "CORRECT DEBUG" + assert_includes another_output.string, "CORRECT ERROR" + assert_includes another_output.string, "FAILURE" + # We can't silence plain ruby Logger cause with thread safety + # but at least we don't break it end def test_logger_level_per_object_thread_safety diff --git a/activesupport/test/message_encryptor_test.rb b/activesupport/test/message_encryptor_test.rb index eb71369397..f8282c89ca 100644 --- a/activesupport/test/message_encryptor_test.rb +++ b/activesupport/test/message_encryptor_test.rb @@ -1,7 +1,7 @@ -require 'abstract_unit' -require 'openssl' -require 'active_support/time' -require 'active_support/json' +require "abstract_unit" +require "openssl" +require "active_support/time" +require "active_support/json" class MessageEncryptorTest < ActiveSupport::TestCase class JSONSerializer @@ -15,10 +15,10 @@ class MessageEncryptorTest < ActiveSupport::TestCase end def setup - @secret = SecureRandom.hex(64) - @verifier = ActiveSupport::MessageVerifier.new(@secret, :serializer => ActiveSupport::MessageEncryptor::NullSerializer) + @secret = SecureRandom.random_bytes(32) + @verifier = ActiveSupport::MessageVerifier.new(@secret, serializer: ActiveSupport::MessageEncryptor::NullSerializer) @encryptor = ActiveSupport::MessageEncryptor.new(@secret) - @data = { :some => "data", :now => Time.local(2010) } + @data = { some: "data", now: Time.local(2010) } end def test_encrypting_twice_yields_differing_cipher_text @@ -48,11 +48,21 @@ class MessageEncryptorTest < ActiveSupport::TestCase assert_equal @data, @encryptor.decrypt_and_verify(message) end + def test_backwards_compat_for_64_bytes_key + # 64 bit key + secret = ["3942b1bf81e622559ed509e3ff274a780784fe9e75b065866bd270438c74da822219de3156473cc27df1fd590e4baf68c95eeb537b6e4d4c5a10f41635b5597e"].pack("H*") + # Encryptor with 32 bit key, 64 bit secret for verifier + encryptor = ActiveSupport::MessageEncryptor.new(secret[0..31], secret) + # Message generated with 64 bit key + message = "eHdGeExnZEwvMSt3U3dKaFl1WFo0TjVvYzA0eGpjbm5WSkt5MXlsNzhpZ0ZnbWhBWFlQZTRwaXE1bVJCS2oxMDZhYVp2dVN3V0lNZUlWQ3c2eVhQbnhnVjFmeVVubmhRKzF3WnZyWHVNMDg9LS1HSisyakJVSFlPb05ISzRMaXRzcFdBPT0=--831a1d54a3cda8a0658dc668a03dedcbce13b5ca" + assert_equal "data", encryptor.decrypt_and_verify(message)[:some] + end + def test_alternative_serialization_method prev = ActiveSupport.use_standard_json_time_format ActiveSupport.use_standard_json_time_format = true - encryptor = ActiveSupport::MessageEncryptor.new(SecureRandom.hex(64), SecureRandom.hex(64), :serializer => JSONSerializer.new) - message = encryptor.encrypt_and_sign({ :foo => 123, 'bar' => Time.utc(2010) }) + encryptor = ActiveSupport::MessageEncryptor.new(SecureRandom.random_bytes(32), SecureRandom.random_bytes(128), serializer: JSONSerializer.new) + message = encryptor.encrypt_and_sign(:foo => 123, "bar" => Time.utc(2010)) exp = { "foo" => 123, "bar" => "2010-01-01T00:00:00.000Z" } assert_equal exp, encryptor.decrypt_and_verify(message) ensure @@ -70,23 +80,41 @@ class MessageEncryptorTest < ActiveSupport::TestCase assert_not_verified([iv, message] * bad_encoding_characters) end + def test_aead_mode_encryption + encryptor = ActiveSupport::MessageEncryptor.new(@secret, cipher: "aes-256-gcm") + message = encryptor.encrypt_and_sign(@data) + assert_equal @data, encryptor.decrypt_and_verify(message) + end + + def test_messing_with_aead_values_causes_failures + encryptor = ActiveSupport::MessageEncryptor.new(@secret, cipher: "aes-256-gcm") + text, iv, auth_tag = encryptor.encrypt_and_sign(@data).split("--") + assert_not_decrypted([iv, text, auth_tag] * "--") + assert_not_decrypted([munge(text), iv, auth_tag] * "--") + assert_not_decrypted([text, munge(iv), auth_tag] * "--") + assert_not_decrypted([text, iv, munge(auth_tag)] * "--") + assert_not_decrypted([munge(text), munge(iv), munge(auth_tag)] * "--") + assert_not_decrypted([text, iv] * "--") + assert_not_decrypted([text, iv, auth_tag[0..-2]] * "--") + end + private - def assert_not_decrypted(value) - assert_raise(ActiveSupport::MessageEncryptor::InvalidMessage) do - @encryptor.decrypt_and_verify(@verifier.generate(value)) + def assert_not_decrypted(value) + assert_raise(ActiveSupport::MessageEncryptor::InvalidMessage) do + @encryptor.decrypt_and_verify(@verifier.generate(value)) + end end - end - def assert_not_verified(value) - assert_raise(ActiveSupport::MessageVerifier::InvalidSignature) do - @encryptor.decrypt_and_verify(value) + def assert_not_verified(value) + assert_raise(ActiveSupport::MessageVerifier::InvalidSignature) do + @encryptor.decrypt_and_verify(value) + end end - end - def munge(base64_string) - bits = ::Base64.strict_decode64(base64_string) - bits.reverse! - ::Base64.strict_encode64(bits) - end + def munge(base64_string) + bits = ::Base64.strict_decode64(base64_string) + bits.reverse! + ::Base64.strict_encode64(bits) + end end diff --git a/activesupport/test/message_verifier_test.rb b/activesupport/test/message_verifier_test.rb index 668d78492e..d56a46b250 100644 --- a/activesupport/test/message_verifier_test.rb +++ b/activesupport/test/message_verifier_test.rb @@ -1,10 +1,9 @@ -require 'abstract_unit' -require 'openssl' -require 'active_support/time' -require 'active_support/json' +require "abstract_unit" +require "openssl" +require "active_support/time" +require "active_support/json" class MessageVerifierTest < ActiveSupport::TestCase - class JSONSerializer def dump(value) ActiveSupport::JSON.encode(value) @@ -17,7 +16,7 @@ class MessageVerifierTest < ActiveSupport::TestCase def setup @verifier = ActiveSupport::MessageVerifier.new("Hey, I'm a secret!") - @data = { :some => "data", :now => Time.local(2010) } + @data = { some: "data", now: Time.local(2010) } end def test_valid_message @@ -49,8 +48,8 @@ class MessageVerifierTest < ActiveSupport::TestCase def test_alternative_serialization_method prev = ActiveSupport.use_standard_json_time_format ActiveSupport.use_standard_json_time_format = true - verifier = ActiveSupport::MessageVerifier.new("Hey, I'm a secret!", :serializer => JSONSerializer.new) - message = verifier.generate({ :foo => 123, 'bar' => Time.utc(2010) }) + verifier = ActiveSupport::MessageVerifier.new("Hey, I'm a secret!", serializer: JSONSerializer.new) + message = verifier.generate(:foo => 123, "bar" => Time.utc(2010)) exp = { "foo" => 123, "bar" => "2010-01-01T00:00:00.000Z" } assert_equal exp, verifier.verified(message) assert_equal exp, verifier.verify(message) @@ -81,6 +80,6 @@ class MessageVerifierTest < ActiveSupport::TestCase exception = assert_raise(ArgumentError) do ActiveSupport::MessageVerifier.new(nil) end - assert_equal exception.message, 'Secret should not be nil.' + assert_equal exception.message, "Secret should not be nil." end end diff --git a/activesupport/test/multibyte_chars_test.rb b/activesupport/test/multibyte_chars_test.rb index c1e0b19248..5ff1543328 100644 --- a/activesupport/test/multibyte_chars_test.rb +++ b/activesupport/test/multibyte_chars_test.rb @@ -1,6 +1,6 @@ -require 'abstract_unit' -require 'multibyte_test_helpers' -require 'active_support/core_ext/string/multibyte' +require "abstract_unit" +require "multibyte_test_helpers" +require "active_support/core_ext/string/multibyte" class MultibyteCharsTest < ActiveSupport::TestCase include MultibyteTestHelpers @@ -16,7 +16,7 @@ class MultibyteCharsTest < ActiveSupport::TestCase end def test_should_allow_method_calls_to_string - @chars.wrapped_string.singleton_class.class_eval { def __method_for_multibyte_testing; 'result'; end } + @chars.wrapped_string.singleton_class.class_eval { def __method_for_multibyte_testing; "result"; end } assert_nothing_raised do @chars.__method_for_multibyte_testing @@ -27,14 +27,14 @@ class MultibyteCharsTest < ActiveSupport::TestCase end def test_forwarded_method_calls_should_return_new_chars_instance - @chars.wrapped_string.singleton_class.class_eval { def __method_for_multibyte_testing; 'result'; end } + @chars.wrapped_string.singleton_class.class_eval { def __method_for_multibyte_testing; "result"; end } assert_kind_of @proxy_class, @chars.__method_for_multibyte_testing assert_not_equal @chars.object_id, @chars.__method_for_multibyte_testing.object_id end def test_forwarded_bang_method_calls_should_return_the_original_chars_instance_when_result_is_not_nil - @chars.wrapped_string.singleton_class.class_eval { def __method_for_multibyte_testing!; 'result'; end } + @chars.wrapped_string.singleton_class.class_eval { def __method_for_multibyte_testing!; "result"; end } assert_kind_of @proxy_class, @chars.__method_for_multibyte_testing! assert_equal @chars.object_id, @chars.__method_for_multibyte_testing!.object_id @@ -51,7 +51,7 @@ class MultibyteCharsTest < ActiveSupport::TestCase end def test_forwarded_method_with_non_string_result_should_be_returned_vertabim - str = '' + str = "" str.singleton_class.class_eval { def __method_for_multibyte_testing_with_integer_result; 1; end } @chars.wrapped_string.singleton_class.class_eval { def __method_for_multibyte_testing_with_integer_result; 1; end } @@ -59,15 +59,15 @@ class MultibyteCharsTest < ActiveSupport::TestCase end def test_should_concatenate - mb_a = 'a'.mb_chars - mb_b = 'b'.mb_chars - assert_equal 'ab', mb_a + 'b' - assert_equal 'ab', 'a' + mb_b - assert_equal 'ab', mb_a + mb_b + mb_a = "a".mb_chars + mb_b = "b".mb_chars + assert_equal "ab", mb_a + "b" + assert_equal "ab", "a" + mb_b + assert_equal "ab", mb_a + mb_b - assert_equal 'ab', mb_a << 'b' - assert_equal 'ab', 'a' << mb_b - assert_equal 'abb', mb_a << mb_b + assert_equal "ab", mb_a << "b" + assert_equal "ab", "a" << mb_b + assert_equal "abb", mb_a << mb_b end def test_consumes_utf8_strings @@ -77,8 +77,8 @@ class MultibyteCharsTest < ActiveSupport::TestCase end def test_concatenation_should_return_a_proxy_class_instance - assert_equal ActiveSupport::Multibyte.proxy_class, ('a'.mb_chars + 'b').class - assert_equal ActiveSupport::Multibyte.proxy_class, ('a'.mb_chars << 'b').class + assert_equal ActiveSupport::Multibyte.proxy_class, ("a".mb_chars + "b").class + assert_equal ActiveSupport::Multibyte.proxy_class, ("a".mb_chars << "b").class end def test_ascii_strings_are_treated_at_utf8_strings @@ -86,10 +86,10 @@ class MultibyteCharsTest < ActiveSupport::TestCase end def test_concatenate_should_return_proxy_instance - assert(('a'.mb_chars + 'b').kind_of?(@proxy_class)) - assert(('a'.mb_chars + 'b'.mb_chars).kind_of?(@proxy_class)) - assert(('a'.mb_chars << 'b').kind_of?(@proxy_class)) - assert(('a'.mb_chars << 'b'.mb_chars).kind_of?(@proxy_class)) + assert(("a".mb_chars + "b").kind_of?(@proxy_class)) + assert(("a".mb_chars + "b".mb_chars).kind_of?(@proxy_class)) + assert(("a".mb_chars << "b").kind_of?(@proxy_class)) + assert(("a".mb_chars << "b".mb_chars).kind_of?(@proxy_class)) end def test_should_return_string_as_json @@ -150,24 +150,24 @@ class MultibyteCharsUTF8BehaviourTest < ActiveSupport::TestCase end def test_string_methods_are_chainable - assert chars('').insert(0, '').kind_of?(ActiveSupport::Multibyte.proxy_class) - assert chars('').rjust(1).kind_of?(ActiveSupport::Multibyte.proxy_class) - assert chars('').ljust(1).kind_of?(ActiveSupport::Multibyte.proxy_class) - assert chars('').center(1).kind_of?(ActiveSupport::Multibyte.proxy_class) - assert chars('').rstrip.kind_of?(ActiveSupport::Multibyte.proxy_class) - assert chars('').lstrip.kind_of?(ActiveSupport::Multibyte.proxy_class) - assert chars('').strip.kind_of?(ActiveSupport::Multibyte.proxy_class) - assert chars('').reverse.kind_of?(ActiveSupport::Multibyte.proxy_class) - assert chars(' ').slice(0).kind_of?(ActiveSupport::Multibyte.proxy_class) - assert chars('').limit(0).kind_of?(ActiveSupport::Multibyte.proxy_class) - assert chars('').upcase.kind_of?(ActiveSupport::Multibyte.proxy_class) - assert chars('').downcase.kind_of?(ActiveSupport::Multibyte.proxy_class) - assert chars('').capitalize.kind_of?(ActiveSupport::Multibyte.proxy_class) - assert chars('').normalize.kind_of?(ActiveSupport::Multibyte.proxy_class) - assert chars('').decompose.kind_of?(ActiveSupport::Multibyte.proxy_class) - assert chars('').compose.kind_of?(ActiveSupport::Multibyte.proxy_class) - assert chars('').tidy_bytes.kind_of?(ActiveSupport::Multibyte.proxy_class) - assert chars('').swapcase.kind_of?(ActiveSupport::Multibyte.proxy_class) + assert chars("").insert(0, "").kind_of?(ActiveSupport::Multibyte.proxy_class) + assert chars("").rjust(1).kind_of?(ActiveSupport::Multibyte.proxy_class) + assert chars("").ljust(1).kind_of?(ActiveSupport::Multibyte.proxy_class) + assert chars("").center(1).kind_of?(ActiveSupport::Multibyte.proxy_class) + assert chars("").rstrip.kind_of?(ActiveSupport::Multibyte.proxy_class) + assert chars("").lstrip.kind_of?(ActiveSupport::Multibyte.proxy_class) + assert chars("").strip.kind_of?(ActiveSupport::Multibyte.proxy_class) + assert chars("").reverse.kind_of?(ActiveSupport::Multibyte.proxy_class) + assert chars(" ").slice(0).kind_of?(ActiveSupport::Multibyte.proxy_class) + assert chars("").limit(0).kind_of?(ActiveSupport::Multibyte.proxy_class) + assert chars("").upcase.kind_of?(ActiveSupport::Multibyte.proxy_class) + assert chars("").downcase.kind_of?(ActiveSupport::Multibyte.proxy_class) + assert chars("").capitalize.kind_of?(ActiveSupport::Multibyte.proxy_class) + assert chars("").normalize.kind_of?(ActiveSupport::Multibyte.proxy_class) + assert chars("").decompose.kind_of?(ActiveSupport::Multibyte.proxy_class) + assert chars("").compose.kind_of?(ActiveSupport::Multibyte.proxy_class) + assert chars("").tidy_bytes.kind_of?(ActiveSupport::Multibyte.proxy_class) + assert chars("").swapcase.kind_of?(ActiveSupport::Multibyte.proxy_class) end def test_should_be_equal_to_the_wrapped_string @@ -176,8 +176,8 @@ class MultibyteCharsUTF8BehaviourTest < ActiveSupport::TestCase end def test_should_not_be_equal_to_an_other_string - assert_not_equal @chars, 'other' - assert_not_equal 'other', @chars + assert_not_equal @chars, "other" + assert_not_equal "other", @chars end def test_sortability @@ -195,29 +195,29 @@ class MultibyteCharsUTF8BehaviourTest < ActiveSupport::TestCase end def test_should_use_character_offsets_for_insert_offsets - assert_equal '', ''.mb_chars.insert(0, '') - assert_equal 'こわにちわ', @chars.insert(1, 'わ') - assert_equal 'こわわわにちわ', @chars.insert(2, 'わわ') - assert_equal 'わこわわわにちわ', @chars.insert(0, 'わ') - assert_equal 'わこわわわにちわ', @chars.wrapped_string + assert_equal "", "".mb_chars.insert(0, "") + assert_equal "こわにちわ", @chars.insert(1, "わ") + assert_equal "こわわわにちわ", @chars.insert(2, "わわ") + assert_equal "わこわわわにちわ", @chars.insert(0, "わ") + assert_equal "わこわわわにちわ", @chars.wrapped_string end def test_insert_should_be_destructive - @chars.insert(1, 'わ') - assert_equal 'こわにちわ', @chars + @chars.insert(1, "わ") + assert_equal "こわにちわ", @chars end def test_insert_throws_index_error - assert_raise(IndexError) { @chars.insert(-12, 'わ')} - assert_raise(IndexError) { @chars.insert(12, 'わ') } + assert_raise(IndexError) { @chars.insert(-12, "わ") } + assert_raise(IndexError) { @chars.insert(12, "わ") } end def test_should_know_if_one_includes_the_other - assert @chars.include?('') - assert @chars.include?('ち') - assert @chars.include?('わ') - assert !@chars.include?('こちわ') - assert !@chars.include?('a') + assert_includes @chars, "" + assert_includes @chars, "ち" + assert_includes @chars, "わ" + assert_not_includes @chars, "こちわ" + assert_not_includes @chars, "a" end def test_include_raises_when_nil_is_passed @@ -227,62 +227,62 @@ class MultibyteCharsUTF8BehaviourTest < ActiveSupport::TestCase end def test_index_should_return_character_offset - assert_nil @chars.index('u') - assert_equal 0, @chars.index('こに') - assert_equal 2, @chars.index('ち') - assert_equal 2, @chars.index('ち', -2) - assert_equal nil, @chars.index('ち', -1) - assert_equal 3, @chars.index('わ') - assert_equal 5, 'ééxééx'.mb_chars.index('x', 4) + assert_nil @chars.index("u") + assert_equal 0, @chars.index("こに") + assert_equal 2, @chars.index("ち") + assert_equal 2, @chars.index("ち", -2) + assert_equal nil, @chars.index("ち", -1) + assert_equal 3, @chars.index("わ") + assert_equal 5, "ééxééx".mb_chars.index("x", 4) end def test_rindex_should_return_character_offset - assert_nil @chars.rindex('u') - assert_equal 1, @chars.rindex('に') - assert_equal 2, @chars.rindex('ち', -2) - assert_nil @chars.rindex('ち', -3) - assert_equal 6, 'Café périferôl'.mb_chars.rindex('é') - assert_equal 13, 'Café périferôl'.mb_chars.rindex(/\w/u) + assert_nil @chars.rindex("u") + assert_equal 1, @chars.rindex("に") + assert_equal 2, @chars.rindex("ち", -2) + assert_nil @chars.rindex("ち", -3) + assert_equal 6, "Café périferôl".mb_chars.rindex("é") + assert_equal 13, "Café périferôl".mb_chars.rindex(/\w/u) end def test_indexed_insert_should_take_character_offsets - @chars[2] = 'a' - assert_equal 'こにaわ', @chars - @chars[2] = 'ηη' - assert_equal 'こにηηわ', @chars - @chars[3, 2] = 'λλλ' - assert_equal 'こにηλλλ', @chars + @chars[2] = "a" + assert_equal "こにaわ", @chars + @chars[2] = "ηη" + assert_equal "こにηηわ", @chars + @chars[3, 2] = "λλλ" + assert_equal "こにηλλλ", @chars @chars[1, 0] = "λ" - assert_equal 'こλにηλλλ', @chars + assert_equal "こλにηλλλ", @chars @chars[4..6] = "ηη" - assert_equal 'こλにηηη', @chars + assert_equal "こλにηηη", @chars @chars[/ηη/] = "λλλ" - assert_equal 'こλにλλλη', @chars + assert_equal "こλにλλλη", @chars @chars[/(λλ)(.)/, 2] = "α" - assert_equal 'こλにλλαη', @chars + assert_equal "こλにλλαη", @chars @chars["α"] = "¢" - assert_equal 'こλにλλ¢η', @chars + assert_equal "こλにλλ¢η", @chars @chars["λλ"] = "ααα" - assert_equal 'こλにααα¢η', @chars + assert_equal "こλにααα¢η", @chars end def test_indexed_insert_should_raise_on_index_overflow before = @chars.to_s - assert_raise(IndexError) { @chars[10] = 'a' } - assert_raise(IndexError) { @chars[10, 4] = 'a' } - assert_raise(IndexError) { @chars[/ii/] = 'a' } - assert_raise(IndexError) { @chars[/()/, 10] = 'a' } + assert_raise(IndexError) { @chars[10] = "a" } + assert_raise(IndexError) { @chars[10, 4] = "a" } + assert_raise(IndexError) { @chars[/ii/] = "a" } + assert_raise(IndexError) { @chars[/()/, 10] = "a" } assert_equal before, @chars end def test_indexed_insert_should_raise_on_range_overflow before = @chars.to_s - assert_raise(RangeError) { @chars[10..12] = 'a' } + assert_raise(RangeError) { @chars[10..12] = "a" } assert_equal before, @chars end def test_rjust_should_raise_argument_errors_on_bad_arguments - assert_raise(ArgumentError) { @chars.rjust(10, '') } + assert_raise(ArgumentError) { @chars.rjust(10, "") } assert_raise(ArgumentError) { @chars.rjust } end @@ -292,15 +292,15 @@ class MultibyteCharsUTF8BehaviourTest < ActiveSupport::TestCase assert_equal UNICODE_STRING, @chars.rjust(4) assert_equal " #{UNICODE_STRING}", @chars.rjust(5) assert_equal " #{UNICODE_STRING}", @chars.rjust(7) - assert_equal "---#{UNICODE_STRING}", @chars.rjust(7, '-') - assert_equal "ααα#{UNICODE_STRING}", @chars.rjust(7, 'α') - assert_equal "aba#{UNICODE_STRING}", @chars.rjust(7, 'ab') - assert_equal "αηα#{UNICODE_STRING}", @chars.rjust(7, 'αη') - assert_equal "αηαη#{UNICODE_STRING}", @chars.rjust(8, 'αη') + assert_equal "---#{UNICODE_STRING}", @chars.rjust(7, "-") + assert_equal "ααα#{UNICODE_STRING}", @chars.rjust(7, "α") + assert_equal "aba#{UNICODE_STRING}", @chars.rjust(7, "ab") + assert_equal "αηα#{UNICODE_STRING}", @chars.rjust(7, "αη") + assert_equal "αηαη#{UNICODE_STRING}", @chars.rjust(8, "αη") end def test_ljust_should_raise_argument_errors_on_bad_arguments - assert_raise(ArgumentError) { @chars.ljust(10, '') } + assert_raise(ArgumentError) { @chars.ljust(10, "") } assert_raise(ArgumentError) { @chars.ljust } end @@ -310,15 +310,15 @@ class MultibyteCharsUTF8BehaviourTest < ActiveSupport::TestCase assert_equal UNICODE_STRING, @chars.ljust(4) assert_equal "#{UNICODE_STRING} ", @chars.ljust(5) assert_equal "#{UNICODE_STRING} ", @chars.ljust(7) - assert_equal "#{UNICODE_STRING}---", @chars.ljust(7, '-') - assert_equal "#{UNICODE_STRING}ααα", @chars.ljust(7, 'α') - assert_equal "#{UNICODE_STRING}aba", @chars.ljust(7, 'ab') - assert_equal "#{UNICODE_STRING}αηα", @chars.ljust(7, 'αη') - assert_equal "#{UNICODE_STRING}αηαη", @chars.ljust(8, 'αη') + assert_equal "#{UNICODE_STRING}---", @chars.ljust(7, "-") + assert_equal "#{UNICODE_STRING}ααα", @chars.ljust(7, "α") + assert_equal "#{UNICODE_STRING}aba", @chars.ljust(7, "ab") + assert_equal "#{UNICODE_STRING}αηα", @chars.ljust(7, "αη") + assert_equal "#{UNICODE_STRING}αηαη", @chars.ljust(8, "αη") end def test_center_should_raise_argument_errors_on_bad_arguments - assert_raise(ArgumentError) { @chars.center(10, '') } + assert_raise(ArgumentError) { @chars.center(10, "") } assert_raise(ArgumentError) { @chars.center } end @@ -329,15 +329,15 @@ class MultibyteCharsUTF8BehaviourTest < ActiveSupport::TestCase assert_equal "#{UNICODE_STRING} ", @chars.center(5) assert_equal " #{UNICODE_STRING} ", @chars.center(6) assert_equal " #{UNICODE_STRING} ", @chars.center(7) - assert_equal "--#{UNICODE_STRING}--", @chars.center(8, '-') - assert_equal "--#{UNICODE_STRING}---", @chars.center(9, '-') - assert_equal "αα#{UNICODE_STRING}αα", @chars.center(8, 'α') - assert_equal "αα#{UNICODE_STRING}ααα", @chars.center(9, 'α') - assert_equal "a#{UNICODE_STRING}ab", @chars.center(7, 'ab') - assert_equal "ab#{UNICODE_STRING}ab", @chars.center(8, 'ab') - assert_equal "abab#{UNICODE_STRING}abab", @chars.center(12, 'ab') - assert_equal "α#{UNICODE_STRING}αη", @chars.center(7, 'αη') - assert_equal "αη#{UNICODE_STRING}αη", @chars.center(8, 'αη') + assert_equal "--#{UNICODE_STRING}--", @chars.center(8, "-") + assert_equal "--#{UNICODE_STRING}---", @chars.center(9, "-") + assert_equal "αα#{UNICODE_STRING}αα", @chars.center(8, "α") + assert_equal "αα#{UNICODE_STRING}ααα", @chars.center(9, "α") + assert_equal "a#{UNICODE_STRING}ab", @chars.center(7, "ab") + assert_equal "ab#{UNICODE_STRING}ab", @chars.center(8, "ab") + assert_equal "abab#{UNICODE_STRING}abab", @chars.center(12, "ab") + assert_equal "α#{UNICODE_STRING}αη", @chars.center(7, "αη") + assert_equal "αη#{UNICODE_STRING}αη", @chars.center(8, "αη") end def test_lstrip_strips_whitespace_from_the_left_of_the_string @@ -367,20 +367,20 @@ class MultibyteCharsUTF8BehaviourTest < ActiveSupport::TestCase end def test_size_returns_characters_instead_of_bytes - assert_equal 0, ''.mb_chars.size + assert_equal 0, "".mb_chars.size assert_equal 4, @chars.size assert_equal 4, @chars.length assert_equal 5, ASCII_STRING.mb_chars.size end def test_reverse_reverses_characters - assert_equal '', ''.mb_chars.reverse - assert_equal 'わちにこ', @chars.reverse + assert_equal "", "".mb_chars.reverse + assert_equal "わちにこ", @chars.reverse end def test_reverse_should_work_with_normalized_strings - str = 'bös' - reversed_str = 'söb' + str = "bös" + reversed_str = "söb" assert_equal chars(reversed_str).normalize(:kc), chars(str).normalize(:kc).reverse assert_equal chars(reversed_str).normalize(:c), chars(str).normalize(:c).reverse assert_equal chars(reversed_str).normalize(:d), chars(str).normalize(:d).reverse @@ -390,27 +390,27 @@ class MultibyteCharsUTF8BehaviourTest < ActiveSupport::TestCase end def test_slice_should_take_character_offsets - assert_equal nil, ''.mb_chars.slice(0) - assert_equal 'こ', @chars.slice(0) - assert_equal 'わ', @chars.slice(3) - assert_equal nil, ''.mb_chars.slice(-1..1) - assert_equal nil, ''.mb_chars.slice(-1, 1) - assert_equal '', ''.mb_chars.slice(0..10) - assert_equal 'にちわ', @chars.slice(1..3) - assert_equal 'にちわ', @chars.slice(1, 3) - assert_equal 'こ', @chars.slice(0, 1) - assert_equal 'ちわ', @chars.slice(2..10) - assert_equal '', @chars.slice(4..10) - assert_equal 'に', @chars.slice(/に/u) - assert_equal 'にち', @chars.slice(/に./u) + assert_equal nil, "".mb_chars.slice(0) + assert_equal "こ", @chars.slice(0) + assert_equal "わ", @chars.slice(3) + assert_equal nil, "".mb_chars.slice(-1..1) + assert_equal nil, "".mb_chars.slice(-1, 1) + assert_equal "", "".mb_chars.slice(0..10) + assert_equal "にちわ", @chars.slice(1..3) + assert_equal "にちわ", @chars.slice(1, 3) + assert_equal "こ", @chars.slice(0, 1) + assert_equal "ちわ", @chars.slice(2..10) + assert_equal "", @chars.slice(4..10) + assert_equal "に", @chars.slice(/に/u) + assert_equal "にち", @chars.slice(/に./u) assert_equal nil, @chars.slice(/unknown/u) - assert_equal 'にち', @chars.slice(/(にち)/u, 1) + assert_equal "にち", @chars.slice(/(にち)/u, 1) assert_equal nil, @chars.slice(/(にち)/u, 2) assert_equal nil, @chars.slice(7..6) end def test_slice_bang_returns_sliced_out_substring - assert_equal 'にち', @chars.slice!(1..2) + assert_equal "にち", @chars.slice!(1..2) end def test_slice_bang_returns_nil_on_out_of_bound_arguments @@ -418,17 +418,17 @@ class MultibyteCharsUTF8BehaviourTest < ActiveSupport::TestCase end def test_slice_bang_removes_the_slice_from_the_receiver - chars = 'úüù'.mb_chars + chars = "úüù".mb_chars chars.slice!(0,2) - assert_equal 'ù', chars + assert_equal "ù", chars end def test_slice_bang_returns_nil_and_does_not_modify_receiver_if_out_of_bounds - string = 'úüù' + string = "úüù" chars = string.mb_chars assert_nil chars.slice!(4, 5) - assert_equal 'úüù', chars - assert_equal 'úüù', string + assert_equal "úüù", chars + assert_equal "úüù", string end def test_slice_should_throw_exceptions_on_invalid_arguments @@ -442,48 +442,48 @@ class MultibyteCharsUTF8BehaviourTest < ActiveSupport::TestCase end def test_upcase_should_upcase_ascii_characters - assert_equal '', ''.mb_chars.upcase - assert_equal 'ABC', 'aBc'.mb_chars.upcase + assert_equal "", "".mb_chars.upcase + assert_equal "ABC", "aBc".mb_chars.upcase end def test_downcase_should_downcase_ascii_characters - assert_equal '', ''.mb_chars.downcase - assert_equal 'abc', 'aBc'.mb_chars.downcase + assert_equal "", "".mb_chars.downcase + assert_equal "abc", "aBc".mb_chars.downcase end def test_swapcase_should_swap_ascii_characters - assert_equal '', ''.mb_chars.swapcase - assert_equal 'AbC', 'aBc'.mb_chars.swapcase + assert_equal "", "".mb_chars.swapcase + assert_equal "AbC", "aBc".mb_chars.swapcase end def test_capitalize_should_work_on_ascii_characters - assert_equal '', ''.mb_chars.capitalize - assert_equal 'Abc', 'abc'.mb_chars.capitalize + assert_equal "", "".mb_chars.capitalize + assert_equal "Abc", "abc".mb_chars.capitalize end def test_titleize_should_work_on_ascii_characters - assert_equal '', ''.mb_chars.titleize - assert_equal 'Abc Abc', 'abc abc'.mb_chars.titleize + assert_equal "", "".mb_chars.titleize + assert_equal "Abc Abc", "abc abc".mb_chars.titleize end def test_respond_to_knows_which_methods_the_proxy_responds_to - assert ''.mb_chars.respond_to?(:slice) # Defined on Chars - assert ''.mb_chars.respond_to?(:capitalize!) # Defined on Chars - assert ''.mb_chars.respond_to?(:gsub) # Defined on String - assert !''.mb_chars.respond_to?(:undefined_method) # Not defined + assert "".mb_chars.respond_to?(:slice) # Defined on Chars + assert "".mb_chars.respond_to?(:capitalize!) # Defined on Chars + assert "".mb_chars.respond_to?(:gsub) # Defined on String + assert !"".mb_chars.respond_to?(:undefined_method) # Not defined end def test_method_works_for_proxyed_methods - assert_equal 'll', 'hello'.mb_chars.method(:slice).call(2..3) # Defined on Chars - chars = 'hello'.mb_chars - assert_equal 'Hello', chars.method(:capitalize!).call # Defined on Chars - assert_equal 'Hello', chars - assert_equal 'jello', 'hello'.mb_chars.method(:gsub).call(/h/, 'j') # Defined on String - assert_raise(NameError){ ''.mb_chars.method(:undefined_method) } # Not defined + assert_equal "ll", "hello".mb_chars.method(:slice).call(2..3) # Defined on Chars + chars = "hello".mb_chars + assert_equal "Hello", chars.method(:capitalize!).call # Defined on Chars + assert_equal "Hello", chars + assert_equal "jello", "hello".mb_chars.method(:gsub).call(/h/, "j") # Defined on String + assert_raise(NameError) { "".mb_chars.method(:undefined_method) } # Not defined end def test_acts_like_string - assert 'Bambi'.mb_chars.acts_like_string? + assert "Bambi".mb_chars.acts_like_string? end end @@ -495,25 +495,25 @@ class MultibyteCharsExtrasTest < ActiveSupport::TestCase def test_upcase_should_be_unicode_aware assert_equal "АБВГД\0F", chars("аБвгд\0f").upcase - assert_equal 'こにちわ', chars('こにちわ').upcase + assert_equal "こにちわ", chars("こにちわ").upcase end def test_downcase_should_be_unicode_aware assert_equal "абвгд\0f", chars("аБвгд\0F").downcase - assert_equal 'こにちわ', chars('こにちわ').downcase + assert_equal "こにちわ", chars("こにちわ").downcase end def test_swapcase_should_be_unicode_aware assert_equal "аaéÜ\0f", chars("АAÉü\0F").swapcase - assert_equal 'こにちわ', chars('こにちわ').swapcase + assert_equal "こにちわ", chars("こにちわ").swapcase end def test_capitalize_should_be_unicode_aware - { 'аБвг аБвг' => 'Абвг абвг', - 'аБвг АБВГ' => 'Абвг абвг', - 'АБВГ АБВГ' => 'Абвг абвг', - '' => '' }.each do |f,t| - assert_equal t, chars(f).capitalize + { "аБвг аБвг" => "Абвг абвг", + "аБвг АБВГ" => "Абвг абвг", + "АБВГ АБВГ" => "Абвг абвг", + "" => "" }.each do |f,t| + assert_equal t, chars(f).capitalize end end @@ -527,7 +527,7 @@ class MultibyteCharsExtrasTest < ActiveSupport::TestCase end def test_limit_should_not_break_on_blank_strings - example = chars('') + example = chars("") assert_equal example, example.limit(0) assert_equal example, example.limit(1) end @@ -537,23 +537,23 @@ class MultibyteCharsExtrasTest < ActiveSupport::TestCase bytesize = UNICODE_STRING.bytesize assert_equal UNICODE_STRING, example.limit(bytesize) - assert_equal '', example.limit(0) - assert_equal '', example.limit(1) - assert_equal 'こ', example.limit(3) - assert_equal 'こに', example.limit(6) - assert_equal 'こに', example.limit(8) - assert_equal 'こにち', example.limit(9) - assert_equal 'こにちわ', example.limit(50) + assert_equal "", example.limit(0) + assert_equal "", example.limit(1) + assert_equal "こ", example.limit(3) + assert_equal "こに", example.limit(6) + assert_equal "こに", example.limit(8) + assert_equal "こにち", example.limit(9) + assert_equal "こにちわ", example.limit(50) end def test_limit_should_work_on_an_ascii_string ascii = chars(ASCII_STRING) assert_equal ASCII_STRING, ascii.limit(ASCII_STRING.length) - assert_equal '', ascii.limit(0) - assert_equal 'o', ascii.limit(1) - assert_equal 'oh', ascii.limit(2) - assert_equal 'ohay', ascii.limit(4) - assert_equal 'ohayo', ascii.limit(50) + assert_equal "", ascii.limit(0) + assert_equal "o", ascii.limit(1) + assert_equal "oh", ascii.limit(2) + assert_equal "ohay", ascii.limit(4) + assert_equal "ohayo", ascii.limit(50) end def test_limit_should_keep_under_the_specified_byte_limit @@ -565,7 +565,7 @@ class MultibyteCharsExtrasTest < ActiveSupport::TestCase def test_composition_exclusion_is_set_up_properly # Normalization of DEVANAGARI LETTER QA breaks when composition exclusion isn't used correctly - qa = [0x915, 0x93c].pack('U*') + qa = [0x915, 0x93c].pack("U*") assert_equal qa, chars(qa).normalize(:c) end @@ -575,7 +575,7 @@ class MultibyteCharsExtrasTest < ActiveSupport::TestCase [ [0x0B47, 0x0300, 0x0B3E], [0x1100, 0x0300, 0x1161] - ].map { |c| c.pack('U*') }.each do |c| + ].map { |c| c.pack("U*") }.each do |c| assert_equal_codepoints c, chars(c).normalize(:c) end end @@ -599,7 +599,7 @@ class MultibyteCharsExtrasTest < ActiveSupport::TestCase 323 # COMBINING DOT BELOW ].pack("U*") - assert_equal_codepoints '', chars('').normalize + assert_equal_codepoints "", chars("").normalize assert_equal_codepoints [44,105,106,328,323].pack("U*"), chars(comp_str).normalize(:kc).to_s assert_equal_codepoints [44,307,328,323].pack("U*"), chars(comp_str).normalize(:c).to_s assert_equal_codepoints [44,307,110,780,78,769].pack("U*"), chars(comp_str).normalize(:d).to_s @@ -608,10 +608,10 @@ class MultibyteCharsExtrasTest < ActiveSupport::TestCase def test_should_compute_grapheme_length [ - ['', 0], - ['abc', 3], - ['こにちわ', 4], - [[0x0924, 0x094D, 0x0930].pack('U*'), 2], + ["", 0], + ["abc", 3], + ["こにちわ", 4], + [[0x0924, 0x094D, 0x0930].pack("U*"), 2], # GB3 [%w(cr lf), 1], # GB4 @@ -699,9 +699,9 @@ class MultibyteCharsExtrasTest < ActiveSupport::TestCase end byte_string = "\270\236\010\210\245" - tidy_string = [0xb8, 0x17e, 0x8, 0x2c6, 0xa5].pack('U*') + tidy_string = [0xb8, 0x17e, 0x8, 0x2c6, 0xa5].pack("U*") assert_equal_codepoints tidy_string, chars(byte_string).tidy_bytes - assert_nothing_raised { chars(byte_string).tidy_bytes.to_s.unpack('U*') } + assert_nothing_raised { chars(byte_string).tidy_bytes.to_s.unpack("U*") } # UTF-8 leading byte followed by too few continuation bytes assert_equal_codepoints "\xc3\xb0\xc2\xa5\xc2\xa4\x21", chars("\xf0\xa5\xa4\x21").tidy_bytes @@ -720,16 +720,16 @@ class MultibyteCharsExtrasTest < ActiveSupport::TestCase private - def string_from_classes(classes) - # Characters from the character classes as described in UAX #29 - character_from_class = { - :l => 0x1100, :v => 0x1160, :t => 0x11A8, :lv => 0xAC00, :lvt => 0xAC01, :cr => 0x000D, :lf => 0x000A, - :extend => 0x094D, :n => 0x64, :spacingmark => 0x0903, :r => 0x1F1E6, :control => 0x0001 - } - classes.collect do |k| - character_from_class[k.intern] - end.pack('U*') - end + def string_from_classes(classes) + # Characters from the character classes as described in UAX #29 + character_from_class = { + l: 0x1100, v: 0x1160, t: 0x11A8, lv: 0xAC00, lvt: 0xAC01, cr: 0x000D, lf: 0x000A, + extend: 0x094D, n: 0x64, spacingmark: 0x0903, r: 0x1F1E6, control: 0x0001 + } + classes.collect do |k| + character_from_class[k.intern] + end.pack("U*") + end end class MultibyteInternalsTest < ActiveSupport::TestCase diff --git a/activesupport/test/multibyte_conformance_test.rb b/activesupport/test/multibyte_conformance_test.rb index 5df8f32e46..bf004d7924 100644 --- a/activesupport/test/multibyte_conformance_test.rb +++ b/activesupport/test/multibyte_conformance_test.rb @@ -1,34 +1,14 @@ -require 'abstract_unit' -require 'multibyte_test_helpers' +require "abstract_unit" +require "multibyte_test_helpers" -require 'fileutils' -require 'open-uri' -require 'tmpdir' +require "fileutils" +require "open-uri" +require "tmpdir" class MultibyteConformanceTest < ActiveSupport::TestCase - class Downloader - def self.download(from, to) - unless File.exist?(to) - unless File.exist?(File.dirname(to)) - system "mkdir -p #{File.dirname(to)}" - end - open(from) do |source| - File.open(to, 'w') do |target| - source.each_line do |l| - target.write l - end - end - end - end - true - end - end - include MultibyteTestHelpers - UNIDATA_URL = "http://www.unicode.org/Public/#{ActiveSupport::Multibyte::Unicode::UNICODE_VERSION}/ucd" - UNIDATA_FILE = '/NormalizationTest.txt' - CACHE_DIR = File.join(Dir.tmpdir, 'cache') + UNIDATA_FILE = "/NormalizationTest.txt" FileUtils.mkdir_p(CACHE_DIR) RUN_P = begin Downloader.download(UNIDATA_URL + UNIDATA_FILE, CACHE_DIR + UNIDATA_FILE) @@ -104,17 +84,17 @@ class MultibyteConformanceTest < ActiveSupport::TestCase protected def each_line_of_norm_tests(&block) - File.open(File.join(CACHE_DIR, UNIDATA_FILE), 'r') do | f | + File.open(File.join(CACHE_DIR, UNIDATA_FILE), "r") do | f | until f.eof? line = f.gets.chomp! - next if (line.empty? || line =~ /^\#/) + next if line.empty? || line.start_with?("#") cols, comment = line.split("#") cols = cols.split(";").map(&:strip).reject(&:empty?) next unless cols.length == 5 # codepoints are in hex in the test suite, pack wants them as integers - cols.map!{|c| c.split.map{|codepoint| codepoint.to_i(16)}.pack("U*") } + cols.map! { |c| c.split.map { |codepoint| codepoint.to_i(16) }.pack("U*") } cols << comment yield(*cols) @@ -123,6 +103,6 @@ class MultibyteConformanceTest < ActiveSupport::TestCase end def inspect_codepoints(str) - str.to_s.unpack("U*").map{|cp| cp.to_s(16) }.join(' ') + str.to_s.unpack("U*").map { |cp| cp.to_s(16) }.join(" ") end end diff --git a/activesupport/test/multibyte_grapheme_break_conformance_test.rb b/activesupport/test/multibyte_grapheme_break_conformance_test.rb index 229f24990e..04a7d290d9 100644 --- a/activesupport/test/multibyte_grapheme_break_conformance_test.rb +++ b/activesupport/test/multibyte_grapheme_break_conformance_test.rb @@ -1,37 +1,23 @@ # encoding: utf-8 -require 'abstract_unit' +require "abstract_unit" +require "multibyte_test_helpers" -require 'fileutils' -require 'open-uri' -require 'tmpdir' +require "fileutils" +require "open-uri" +require "tmpdir" class MultibyteGraphemeBreakConformanceTest < ActiveSupport::TestCase - class Downloader - def self.download(from, to) - unless File.exist?(to) - $stderr.puts "Downloading #{from} to #{to}" - unless File.exist?(File.dirname(to)) - system "mkdir -p #{File.dirname(to)}" - end - open(from) do |source| - File.open(to, 'w') do |target| - source.each_line do |l| - target.write l - end - end - end - end - end - end + include MultibyteTestHelpers - TEST_DATA_URL = "http://www.unicode.org/Public/#{ActiveSupport::Multibyte::Unicode::UNICODE_VERSION}/ucd/auxiliary" - TEST_DATA_FILE = '/GraphemeBreakTest.txt' - CACHE_DIR = File.join(Dir.tmpdir, 'cache') + UNIDATA_FILE = "/auxiliary/GraphemeBreakTest.txt" + RUN_P = begin + Downloader.download(UNIDATA_URL + UNIDATA_FILE, CACHE_DIR + UNIDATA_FILE) + rescue + end def setup - FileUtils.mkdir_p(CACHE_DIR) - Downloader.download(TEST_DATA_URL + TEST_DATA_FILE, CACHE_DIR + TEST_DATA_FILE) + skip "Unable to download test data" unless RUN_P end def test_breaks @@ -46,20 +32,20 @@ class MultibyteGraphemeBreakConformanceTest < ActiveSupport::TestCase def each_line_of_break_tests(&block) lines = 0 max_test_lines = 0 # Don't limit below 21, because that's the header of the testfile - File.open(File.join(CACHE_DIR, TEST_DATA_FILE), 'r') do | f | - until f.eof? || (max_test_lines > 21 and lines > max_test_lines) + File.open(File.join(CACHE_DIR, UNIDATA_FILE), "r") do | f | + until f.eof? || (max_test_lines > 21 && lines > max_test_lines) lines += 1 line = f.gets.chomp! - next if (line.empty? || line =~ /^\#/) + next if line.empty? || line.start_with?("#") cols, comment = line.split("#") # Cluster breaks are represented by ÷ - clusters = cols.split("÷").map{|e| e.strip}.reject{|e| e.empty? } + clusters = cols.split("÷").map { |e| e.strip }.reject { |e| e.empty? } clusters = clusters.map do |cluster| # Codepoints within each cluster are separated by × - codepoints = cluster.split("×").map{|e| e.strip}.reject{|e| e.empty? } + codepoints = cluster.split("×").map { |e| e.strip }.reject { |e| e.empty? } # codepoints are in hex in the test suite, pack wants them as integers - codepoints.map{|codepoint| codepoint.to_i(16)} + codepoints.map { |codepoint| codepoint.to_i(16) } end # The tests contain a solitary U+D800 <Non Private Use High diff --git a/activesupport/test/multibyte_normalization_conformance_test.rb b/activesupport/test/multibyte_normalization_conformance_test.rb index 8bc91ef708..e013bd578f 100644 --- a/activesupport/test/multibyte_normalization_conformance_test.rb +++ b/activesupport/test/multibyte_normalization_conformance_test.rb @@ -1,41 +1,24 @@ # encoding: utf-8 -require 'abstract_unit' -require 'multibyte_test_helpers' +require "abstract_unit" +require "multibyte_test_helpers" -require 'fileutils' -require 'open-uri' -require 'tmpdir' +require "fileutils" +require "open-uri" +require "tmpdir" class MultibyteNormalizationConformanceTest < ActiveSupport::TestCase - class Downloader - def self.download(from, to) - unless File.exist?(to) - $stderr.puts "Downloading #{from} to #{to}" - unless File.exist?(File.dirname(to)) - system "mkdir -p #{File.dirname(to)}" - end - open(from) do |source| - File.open(to, 'w') do |target| - source.each_line do |l| - target.write l - end - end - end - end - end - end - include MultibyteTestHelpers - UNIDATA_URL = "http://www.unicode.org/Public/#{ActiveSupport::Multibyte::Unicode::UNICODE_VERSION}/ucd" - UNIDATA_FILE = '/NormalizationTest.txt' - CACHE_DIR = File.join(Dir.tmpdir, 'cache') + UNIDATA_FILE = "/NormalizationTest.txt" + RUN_P = begin + Downloader.download(UNIDATA_URL + UNIDATA_FILE, CACHE_DIR + UNIDATA_FILE) + rescue + end def setup - FileUtils.mkdir_p(CACHE_DIR) - Downloader.download(UNIDATA_URL + UNIDATA_FILE, CACHE_DIR + UNIDATA_FILE) @proxy = ActiveSupport::Multibyte::Chars + skip "Unable to download test data" unless RUN_P end def test_normalizations_C @@ -104,18 +87,18 @@ class MultibyteNormalizationConformanceTest < ActiveSupport::TestCase def each_line_of_norm_tests(&block) lines = 0 max_test_lines = 0 # Don't limit below 38, because that's the header of the testfile - File.open(File.join(CACHE_DIR, UNIDATA_FILE), 'r') do | f | - until f.eof? || (max_test_lines > 38 and lines > max_test_lines) + File.open(File.join(CACHE_DIR, UNIDATA_FILE), "r") do | f | + until f.eof? || (max_test_lines > 38 && lines > max_test_lines) lines += 1 line = f.gets.chomp! - next if (line.empty? || line =~ /^\#/) + next if line.empty? || line.start_with?("#") cols, comment = line.split("#") - cols = cols.split(";").map{|e| e.strip}.reject{|e| e.empty? } + cols = cols.split(";").map { |e| e.strip }.reject { |e| e.empty? } next unless cols.length == 5 # codepoints are in hex in the test suite, pack wants them as integers - cols.map!{|c| c.split.map{|codepoint| codepoint.to_i(16)}.pack("U*") } + cols.map! { |c| c.split.map { |codepoint| codepoint.to_i(16) }.pack("U*") } cols << comment yield(*cols) @@ -124,6 +107,6 @@ class MultibyteNormalizationConformanceTest < ActiveSupport::TestCase end def inspect_codepoints(str) - str.to_s.unpack("U*").map{|cp| cp.to_s(16) }.join(' ') + str.to_s.unpack("U*").map { |cp| cp.to_s(16) }.join(" ") end end diff --git a/activesupport/test/multibyte_proxy_test.rb b/activesupport/test/multibyte_proxy_test.rb index 360cf57302..c303097f80 100644 --- a/activesupport/test/multibyte_proxy_test.rb +++ b/activesupport/test/multibyte_proxy_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" class MultibyteProxyText < ActiveSupport::TestCase class AsciiOnlyEncoder @@ -6,7 +6,7 @@ class MultibyteProxyText < ActiveSupport::TestCase alias to_s wrapped_string def initialize(string) - @wrapped_string = string.gsub(/[^\u0000-\u007F]/, '?') + @wrapped_string = string.gsub(/[^\u0000-\u007F]/, "?") end end diff --git a/activesupport/test/multibyte_test_helpers.rb b/activesupport/test/multibyte_test_helpers.rb index 58cf5488cd..22c586c50d 100644 --- a/activesupport/test/multibyte_test_helpers.rb +++ b/activesupport/test/multibyte_test_helpers.rb @@ -1,6 +1,28 @@ module MultibyteTestHelpers - UNICODE_STRING = 'こにちわ'.freeze - ASCII_STRING = 'ohayo'.freeze + class Downloader + def self.download(from, to) + unless File.exist?(to) + unless File.exist?(File.dirname(to)) + system "mkdir -p #{File.dirname(to)}" + end + open(from) do |source| + File.open(to, "w") do |target| + source.each_line do |l| + target.write l + end + end + end + end + true + end + end + + UNIDATA_URL = "http://www.unicode.org/Public/#{ActiveSupport::Multibyte::Unicode::UNICODE_VERSION}/ucd" + CACHE_DIR = "#{Dir.tmpdir}/cache/unicode_conformance" + FileUtils.mkdir_p(CACHE_DIR) + + UNICODE_STRING = "こにちわ".freeze + ASCII_STRING = "ohayo".freeze BYTE_STRING = "\270\236\010\210\245".force_encoding("ASCII-8BIT").freeze def chars(str) @@ -8,7 +30,7 @@ module MultibyteTestHelpers end def inspect_codepoints(str) - str.to_s.unpack("U*").map{|cp| cp.to_s(16) }.join(' ') + str.to_s.unpack("U*").map { |cp| cp.to_s(16) }.join(" ") end def assert_equal_codepoints(expected, actual, message=nil) diff --git a/activesupport/test/multibyte_unicode_database_test.rb b/activesupport/test/multibyte_unicode_database_test.rb index dd33641ec2..3724782930 100644 --- a/activesupport/test/multibyte_unicode_database_test.rb +++ b/activesupport/test/multibyte_unicode_database_test.rb @@ -1,8 +1,6 @@ -require 'abstract_unit' - +require "abstract_unit" class MultibyteUnicodeDatabaseTest < ActiveSupport::TestCase - include ActiveSupport::Multibyte::Unicode def setup diff --git a/activesupport/test/notifications/evented_notification_test.rb b/activesupport/test/notifications/evented_notification_test.rb index f690ad43fc..688971c858 100644 --- a/activesupport/test/notifications/evented_notification_test.rb +++ b/activesupport/test/notifications/evented_notification_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" module ActiveSupport module Notifications @@ -28,26 +28,26 @@ module ActiveSupport def test_evented_listener notifier = Fanout.new listener = Listener.new - notifier.subscribe 'hi', listener - notifier.start 'hi', 1, {} - notifier.start 'hi', 2, {} - notifier.finish 'hi', 2, {} - notifier.finish 'hi', 1, {} + notifier.subscribe "hi", listener + notifier.start "hi", 1, {} + notifier.start "hi", 2, {} + notifier.finish "hi", 2, {} + notifier.finish "hi", 1, {} assert_equal 4, listener.events.length assert_equal [ - [:start, 'hi', 1, {}], - [:start, 'hi', 2, {}], - [:finish, 'hi', 2, {}], - [:finish, 'hi', 1, {}], + [:start, "hi", 1, {}], + [:start, "hi", 2, {}], + [:finish, "hi", 2, {}], + [:finish, "hi", 1, {}], ], listener.events end def test_evented_listener_no_events notifier = Fanout.new listener = Listener.new - notifier.subscribe 'hi', listener - notifier.start 'world', 1, {} + notifier.subscribe "hi", listener + notifier.start "world", 1, {} assert_equal 0, listener.events.length end @@ -55,31 +55,31 @@ module ActiveSupport notifier = Fanout.new listener = Listener.new notifier.subscribe nil, listener - notifier.start 'hello', 1, {} - notifier.start 'world', 1, {} - notifier.finish 'world', 1, {} - notifier.finish 'hello', 1, {} + notifier.start "hello", 1, {} + notifier.start "world", 1, {} + notifier.finish "world", 1, {} + notifier.finish "hello", 1, {} assert_equal 4, listener.events.length assert_equal [ - [:start, 'hello', 1, {}], - [:start, 'world', 1, {}], - [:finish, 'world', 1, {}], - [:finish, 'hello', 1, {}], + [:start, "hello", 1, {}], + [:start, "world", 1, {}], + [:finish, "world", 1, {}], + [:finish, "hello", 1, {}], ], listener.events end def test_evented_listener_priority notifier = Fanout.new listener = ListenerWithTimedSupport.new - notifier.subscribe 'hi', listener + notifier.subscribe "hi", listener - notifier.start 'hi', 1, {} - notifier.finish 'hi', 1, {} + notifier.start "hi", 1, {} + notifier.finish "hi", 1, {} assert_equal [ - [:start, 'hi', 1, {}], - [:finish, 'hi', 1, {}] + [:start, "hi", 1, {}], + [:finish, "hi", 1, {}] ], listener.events end end diff --git a/activesupport/test/notifications/instrumenter_test.rb b/activesupport/test/notifications/instrumenter_test.rb index f46e96f636..e454e6897b 100644 --- a/activesupport/test/notifications/instrumenter_test.rb +++ b/activesupport/test/notifications/instrumenter_test.rb @@ -1,5 +1,5 @@ -require 'abstract_unit' -require 'active_support/notifications/instrumenter' +require "abstract_unit" +require "active_support/notifications/instrumenter" module ActiveSupport module Notifications @@ -22,7 +22,7 @@ module ActiveSupport super @notifier = TestNotifier.new @instrumenter = Instrumenter.new @notifier - @payload = { :foo => Object.new } + @payload = { foo: Object.new } end def test_instrument @@ -39,7 +39,7 @@ module ActiveSupport assert_equal 1, notifier.finishes.size name, _, payload = notifier.finishes.first assert_equal "awesome", name - assert_equal Hash[:result => 2], payload + assert_equal Hash[result: 2], payload end def test_start diff --git a/activesupport/test/notifications_test.rb b/activesupport/test/notifications_test.rb index 1cb17e6197..a6f0d82e8a 100644 --- a/activesupport/test/notifications_test.rb +++ b/activesupport/test/notifications_test.rb @@ -1,5 +1,5 @@ -require 'abstract_unit' -require 'active_support/core_ext/module/delegation' +require "abstract_unit" +require "active_support/core_ext/module/delegation" module Notifications class TestCase < ActiveSupport::TestCase @@ -31,7 +31,7 @@ module Notifications expected = [name, name] events = [] - callback = lambda {|*_| events << _.first} + callback = lambda { |*_| events << _.first } ActiveSupport::Notifications.subscribed(callback, name) do ActiveSupport::Notifications.instrument(name) ActiveSupport::Notifications.instrument(name2) @@ -49,10 +49,10 @@ module Notifications old_notifier = ActiveSupport::Notifications.notifier ActiveSupport::Notifications.notifier = ActiveSupport::Notifications::Fanout.new - ActiveSupport::Notifications.subscribe('foo', TestSubscriber.new) + ActiveSupport::Notifications.subscribe("foo", TestSubscriber.new) - ActiveSupport::Notifications.instrument('foo') do - ActiveSupport::Notifications.subscribe('foo') {} + ActiveSupport::Notifications.instrument("foo") do + ActiveSupport::Notifications.subscribe("foo") {} end ensure ActiveSupport::Notifications.notifier = old_notifier @@ -141,26 +141,26 @@ module Notifications def test_log_subscriber_with_string events = [] - @notifier.subscribe('1') { |*args| events << args } + @notifier.subscribe("1") { |*args| events << args } - @notifier.publish '1' - @notifier.publish '1.a' - @notifier.publish 'a.1' + @notifier.publish "1" + @notifier.publish "1.a" + @notifier.publish "a.1" @notifier.wait - assert_equal [['1']], events + assert_equal [["1"]], events end def test_log_subscriber_with_pattern events = [] @notifier.subscribe(/\d/) { |*args| events << args } - @notifier.publish '1' - @notifier.publish 'a.1' - @notifier.publish '1.a' + @notifier.publish "1" + @notifier.publish "a.1" + @notifier.publish "1.a" @notifier.wait - assert_equal [['1'], ['a.1'], ['1.a']], events + assert_equal [["1"], ["a.1"], ["1.a"]], events end def test_multiple_log_subscribers @@ -188,7 +188,7 @@ module Notifications end class InstrumentationTest < TestCase - delegate :instrument, :to => ActiveSupport::Notifications + delegate :instrument, to: ActiveSupport::Notifications def test_instrument_returns_block_result assert_equal 2, instrument(:awesome) { 1 + 1 } @@ -198,7 +198,7 @@ module Notifications assert_equal 2, instrument(:awesome) { |p| p[:result] = 1 + 1 } assert_equal 1, @events.size assert_equal :awesome, @events.first.name - assert_equal Hash[:result => 2], @events.first.payload + assert_equal Hash[result: 2], @events.first.payload end def test_instrumenter_exposes_its_id @@ -206,24 +206,24 @@ module Notifications end def test_nested_events_can_be_instrumented - instrument(:awesome, :payload => "notifications") do - instrument(:wot, :payload => "child") do + instrument(:awesome, payload: "notifications") do + instrument(:wot, payload: "child") do 1 + 1 end assert_equal 1, @events.size assert_equal :wot, @events.first.name - assert_equal Hash[:payload => "child"], @events.first.payload + assert_equal Hash[payload: "child"], @events.first.payload end assert_equal 2, @events.size assert_equal :awesome, @events.last.name - assert_equal Hash[:payload => "notifications"], @events.last.payload + assert_equal Hash[payload: "notifications"], @events.last.payload end def test_instrument_publishes_when_exception_is_raised begin - instrument(:awesome, :payload => "notifications") do + instrument(:awesome, payload: "notifications") do raise "FAIL" end rescue RuntimeError => e @@ -231,15 +231,15 @@ module Notifications end assert_equal 1, @events.size - assert_equal Hash[:payload => "notifications", - :exception => ["RuntimeError", "FAIL"], :exception_object => e], @events.last.payload + assert_equal Hash[payload: "notifications", + exception: ["RuntimeError", "FAIL"], exception_object: e], @events.last.payload end def test_event_is_pushed_even_without_block - instrument(:awesome, :payload => "notifications") + instrument(:awesome, payload: "notifications") assert_equal 1, @events.size assert_equal :awesome, @events.last.name - assert_equal Hash[:payload => "notifications"], @events.last.payload + assert_equal Hash[payload: "notifications"], @events.last.payload end end @@ -254,8 +254,8 @@ module Notifications end def test_events_consumes_information_given_as_payload - event = event(:foo, Time.now, Time.now + 1, random_id, :payload => :bar) - assert_equal Hash[:payload => :bar], event.payload + event = event(:foo, Time.now, Time.now + 1, random_id, payload: :bar) + assert_equal Hash[payload: :bar], event.payload end def test_event_is_parent_based_on_children diff --git a/activesupport/test/number_helper_i18n_test.rb b/activesupport/test/number_helper_i18n_test.rb index e6925e9083..4f58e6607a 100644 --- a/activesupport/test/number_helper_i18n_test.rb +++ b/activesupport/test/number_helper_i18n_test.rb @@ -1,46 +1,46 @@ -require 'abstract_unit' -require 'active_support/number_helper' +require "abstract_unit" +require "active_support/number_helper" module ActiveSupport class NumberHelperI18nTest < ActiveSupport::TestCase include ActiveSupport::NumberHelper def setup - I18n.backend.store_translations 'ts', - :number => { - :format => { :precision => 3, :delimiter => ',', :separator => '.', :significant => false, :strip_insignificant_zeros => false }, - :currency => { :format => { :unit => '&$', :format => '%u - %n', :negative_format => '(%u - %n)', :precision => 2 } }, - :human => { - :format => { - :precision => 2, - :significant => true, - :strip_insignificant_zeros => true + I18n.backend.store_translations "ts", + number: { + format: { precision: 3, delimiter: ",", separator: ".", significant: false, strip_insignificant_zeros: false }, + currency: { format: { unit: "&$", format: "%u - %n", negative_format: "(%u - %n)", precision: 2 } }, + human: { + format: { + precision: 2, + significant: true, + strip_insignificant_zeros: true }, - :storage_units => { - :format => "%n %u", - :units => { - :byte => "b", - :kb => "k" + storage_units: { + format: "%n %u", + units: { + byte: "b", + kb: "k" } }, - :decimal_units => { - :format => "%n %u", - :units => { - :deci => {:one => "Tenth", :other => "Tenths"}, - :unit => "u", - :ten => {:one => "Ten", :other => "Tens"}, - :thousand => "t", - :million => "m", - :billion =>"b", - :trillion =>"t" , - :quadrillion =>"q" + decimal_units: { + format: "%n %u", + units: { + deci: { one: "Tenth", other: "Tenths" }, + unit: "u", + ten: { one: "Ten", other: "Tens" }, + thousand: "t", + million: "m", + billion: "b", + trillion: "t" , + quadrillion: "q" } } }, - :percentage => { :format => {:delimiter => '', :precision => 2, :strip_insignificant_zeros => true} }, - :precision => { :format => {:delimiter => '', :significant => true} } + percentage: { format: { delimiter: "", precision: 2, strip_insignificant_zeros: true } }, + precision: { format: { delimiter: "", significant: true } } }, - :custom_units_for_number_to_human => {:mili => "mm", :centi => "cm", :deci => "dm", :unit => "m", :ten => "dam", :hundred => "hm", :thousand => "km"} + custom_units_for_number_to_human: { mili: "mm", centi: "cm", deci: "dm", unit: "m", ten: "dam", hundred: "hm", thousand: "km" } end def teardown @@ -48,101 +48,101 @@ module ActiveSupport end def test_number_to_i18n_currency - assert_equal("&$ - 10.00", number_to_currency(10, :locale => 'ts')) - assert_equal("(&$ - 10.00)", number_to_currency(-10, :locale => 'ts')) - assert_equal("-10.00 - &$", number_to_currency(-10, :locale => 'ts', :format => "%n - %u")) + assert_equal("&$ - 10.00", number_to_currency(10, locale: "ts")) + assert_equal("(&$ - 10.00)", number_to_currency(-10, locale: "ts")) + assert_equal("-10.00 - &$", number_to_currency(-10, locale: "ts", format: "%n - %u")) end def test_number_to_currency_with_empty_i18n_store - assert_equal("$10.00", number_to_currency(10, :locale => 'empty')) - assert_equal("-$10.00", number_to_currency(-10, :locale => 'empty')) + assert_equal("$10.00", number_to_currency(10, locale: "empty")) + assert_equal("-$10.00", number_to_currency(-10, locale: "empty")) end def test_locale_default_format_has_precedence_over_helper_defaults - I18n.backend.store_translations 'ts', - { :number => { :format => { :separator => ";" } } } + I18n.backend.store_translations "ts", + number: { format: { separator: ";" } } - assert_equal("&$ - 10;00", number_to_currency(10, :locale => 'ts')) + assert_equal("&$ - 10;00", number_to_currency(10, locale: "ts")) end def test_number_to_currency_without_currency_negative_format - I18n.backend.store_translations 'no_negative_format', :number => { - :currency => { :format => { :unit => '@', :format => '%n %u' } } + I18n.backend.store_translations "no_negative_format", number: { + currency: { format: { unit: "@", format: "%n %u" } } } - assert_equal("-10.00 @", number_to_currency(-10, :locale => 'no_negative_format')) + assert_equal("-10.00 @", number_to_currency(-10, locale: "no_negative_format")) end def test_number_with_i18n_precision #Delimiter was set to "" - assert_equal("10000", number_to_rounded(10000, :locale => 'ts')) + assert_equal("10000", number_to_rounded(10000, locale: "ts")) #Precision inherited and significant was set - assert_equal("1.00", number_to_rounded(1.0, :locale => 'ts')) + assert_equal("1.00", number_to_rounded(1.0, locale: "ts")) end def test_number_with_i18n_precision_and_empty_i18n_store - assert_equal("123456789.123", number_to_rounded(123456789.123456789, :locale => 'empty')) - assert_equal("1.000", number_to_rounded(1.0000, :locale => 'empty')) + assert_equal("123456789.123", number_to_rounded(123456789.123456789, locale: "empty")) + assert_equal("1.000", number_to_rounded(1.0000, locale: "empty")) end def test_number_with_i18n_delimiter #Delimiter "," and separator "." - assert_equal("1,000,000.234", number_to_delimited(1000000.234, :locale => 'ts')) + assert_equal("1,000,000.234", number_to_delimited(1000000.234, locale: "ts")) end def test_number_with_i18n_delimiter_and_empty_i18n_store - assert_equal("1,000,000.234", number_to_delimited(1000000.234, :locale => 'empty')) + assert_equal("1,000,000.234", number_to_delimited(1000000.234, locale: "empty")) end def test_number_to_i18n_percentage # to see if strip_insignificant_zeros is true - assert_equal("1%", number_to_percentage(1, :locale => 'ts')) + assert_equal("1%", number_to_percentage(1, locale: "ts")) # precision is 2, significant should be inherited - assert_equal("1.24%", number_to_percentage(1.2434, :locale => 'ts')) + assert_equal("1.24%", number_to_percentage(1.2434, locale: "ts")) # no delimiter - assert_equal("12434%", number_to_percentage(12434, :locale => 'ts')) + assert_equal("12434%", number_to_percentage(12434, locale: "ts")) end def test_number_to_i18n_percentage_and_empty_i18n_store - assert_equal("1.000%", number_to_percentage(1, :locale => 'empty')) - assert_equal("1.243%", number_to_percentage(1.2434, :locale => 'empty')) - assert_equal("12434.000%", number_to_percentage(12434, :locale => 'empty')) + assert_equal("1.000%", number_to_percentage(1, locale: "empty")) + assert_equal("1.243%", number_to_percentage(1.2434, locale: "empty")) + assert_equal("12434.000%", number_to_percentage(12434, locale: "empty")) end def test_number_to_i18n_human_size #b for bytes and k for kbytes - assert_equal("2 k", number_to_human_size(2048, :locale => 'ts')) - assert_equal("42 b", number_to_human_size(42, :locale => 'ts')) + assert_equal("2 k", number_to_human_size(2048, locale: "ts")) + assert_equal("42 b", number_to_human_size(42, locale: "ts")) end def test_number_to_i18n_human_size_with_empty_i18n_store - assert_equal("2 KB", number_to_human_size(2048, :locale => 'empty')) - assert_equal("42 Bytes", number_to_human_size(42, :locale => 'empty')) + assert_equal("2 KB", number_to_human_size(2048, locale: "empty")) + assert_equal("42 Bytes", number_to_human_size(42, locale: "empty")) end def test_number_to_human_with_default_translation_scope #Using t for thousand - assert_equal "2 t", number_to_human(2000, :locale => 'ts') + assert_equal "2 t", number_to_human(2000, locale: "ts") #Significant was set to true with precision 2, using b for billion - assert_equal "1.2 b", number_to_human(1234567890, :locale => 'ts') + assert_equal "1.2 b", number_to_human(1234567890, locale: "ts") #Using pluralization (Ten/Tens and Tenth/Tenths) - assert_equal "1 Tenth", number_to_human(0.1, :locale => 'ts') - assert_equal "1.3 Tenth", number_to_human(0.134, :locale => 'ts') - assert_equal "2 Tenths", number_to_human(0.2, :locale => 'ts') - assert_equal "1 Ten", number_to_human(10, :locale => 'ts') - assert_equal "1.2 Ten", number_to_human(12, :locale => 'ts') - assert_equal "2 Tens", number_to_human(20, :locale => 'ts') + assert_equal "1 Tenth", number_to_human(0.1, locale: "ts") + assert_equal "1.3 Tenth", number_to_human(0.134, locale: "ts") + assert_equal "2 Tenths", number_to_human(0.2, locale: "ts") + assert_equal "1 Ten", number_to_human(10, locale: "ts") + assert_equal "1.2 Ten", number_to_human(12, locale: "ts") + assert_equal "2 Tens", number_to_human(20, locale: "ts") end def test_number_to_human_with_empty_i18n_store - assert_equal "2 Thousand", number_to_human(2000, :locale => 'empty') - assert_equal "1.23 Billion", number_to_human(1234567890, :locale => 'empty') + assert_equal "2 Thousand", number_to_human(2000, locale: "empty") + assert_equal "1.23 Billion", number_to_human(1234567890, locale: "empty") end def test_number_to_human_with_custom_translation_scope #Significant was set to true with precision 2, with custom translated units - assert_equal "4.3 cm", number_to_human(0.0432, :locale => 'ts', :units => :custom_units_for_number_to_human) + assert_equal "4.3 cm", number_to_human(0.0432, locale: "ts", units: :custom_units_for_number_to_human) end end end diff --git a/activesupport/test/number_helper_test.rb b/activesupport/test/number_helper_test.rb index 6696111476..1a59210018 100644 --- a/activesupport/test/number_helper_test.rb +++ b/activesupport/test/number_helper_test.rb @@ -1,11 +1,10 @@ -require 'abstract_unit' -require 'active_support/number_helper' -require 'active_support/core_ext/string/output_safety' +require "abstract_unit" +require "active_support/number_helper" +require "active_support/core_ext/string/output_safety" module ActiveSupport module NumberHelper class NumberHelperTest < ActiveSupport::TestCase - class TestClassWithInstanceNumberHelpers include ActiveSupport::NumberHelper end @@ -46,17 +45,19 @@ module ActiveSupport [@instance_with_helpers, TestClassWithClassNumberHelpers, ActiveSupport::NumberHelper].each do |number_helper| assert_equal("555-1234", number_helper.number_to_phone(5551234)) assert_equal("800-555-1212", number_helper.number_to_phone(8005551212)) - assert_equal("(800) 555-1212", number_helper.number_to_phone(8005551212, {:area_code => true})) - assert_equal("", number_helper.number_to_phone("", {:area_code => true})) - assert_equal("800 555 1212", number_helper.number_to_phone(8005551212, {:delimiter => " "})) - assert_equal("(800) 555-1212 x 123", number_helper.number_to_phone(8005551212, {:area_code => true, :extension => 123})) - assert_equal("800-555-1212", number_helper.number_to_phone(8005551212, :extension => " ")) - assert_equal("555.1212", number_helper.number_to_phone(5551212, :delimiter => '.')) + assert_equal("(800) 555-1212", number_helper.number_to_phone(8005551212, area_code: true)) + assert_equal("", number_helper.number_to_phone("", area_code: true)) + assert_equal("800 555 1212", number_helper.number_to_phone(8005551212, delimiter: " ")) + assert_equal("(800) 555-1212 x 123", number_helper.number_to_phone(8005551212, area_code: true, extension: 123)) + assert_equal("800-555-1212", number_helper.number_to_phone(8005551212, extension: " ")) + assert_equal("555.1212", number_helper.number_to_phone(5551212, delimiter: ".")) assert_equal("800-555-1212", number_helper.number_to_phone("8005551212")) - assert_equal("+1-800-555-1212", number_helper.number_to_phone(8005551212, :country_code => 1)) - assert_equal("+18005551212", number_helper.number_to_phone(8005551212, :country_code => 1, :delimiter => '')) + assert_equal("+1-800-555-1212", number_helper.number_to_phone(8005551212, country_code: 1)) + assert_equal("+18005551212", number_helper.number_to_phone(8005551212, country_code: 1, delimiter: "")) assert_equal("22-555-1212", number_helper.number_to_phone(225551212)) - assert_equal("+45-22-555-1212", number_helper.number_to_phone(225551212, :country_code => 45)) + assert_equal("+45-22-555-1212", number_helper.number_to_phone(225551212, country_code: 45)) + assert_equal("(755) 6123-4567", number_helper.number_to_phone(75561234567, pattern: /(\d{3,4})(\d{4})(\d{4})/, area_code: true)) + assert_equal("133-1234-5678", number_helper.number_to_phone(13312345678, pattern: /(\d{3})(\d{4})(\d{4})/)) end end @@ -65,28 +66,28 @@ module ActiveSupport assert_equal("$1,234,567,890.50", number_helper.number_to_currency(1234567890.50)) assert_equal("$1,234,567,890.51", number_helper.number_to_currency(1234567890.506)) assert_equal("-$1,234,567,890.50", number_helper.number_to_currency(-1234567890.50)) - assert_equal("-$ 1,234,567,890.50", number_helper.number_to_currency(-1234567890.50, {:format => "%u %n"})) - assert_equal("($1,234,567,890.50)", number_helper.number_to_currency(-1234567890.50, {:negative_format => "(%u%n)"})) - assert_equal("$1,234,567,892", number_helper.number_to_currency(1234567891.50, {:precision => 0})) - assert_equal("$1,234,567,890.5", number_helper.number_to_currency(1234567890.50, {:precision => 1})) - assert_equal("£1234567890,50", number_helper.number_to_currency(1234567890.50, {:unit => "£", :separator => ",", :delimiter => ""})) + assert_equal("-$ 1,234,567,890.50", number_helper.number_to_currency(-1234567890.50, format: "%u %n")) + assert_equal("($1,234,567,890.50)", number_helper.number_to_currency(-1234567890.50, negative_format: "(%u%n)")) + assert_equal("$1,234,567,892", number_helper.number_to_currency(1234567891.50, precision: 0)) + assert_equal("$1,234,567,890.5", number_helper.number_to_currency(1234567890.50, precision: 1)) + assert_equal("£1234567890,50", number_helper.number_to_currency(1234567890.50, unit: "£", separator: ",", delimiter: "")) assert_equal("$1,234,567,890.50", number_helper.number_to_currency("1234567890.50")) - assert_equal("1,234,567,890.50 Kč", number_helper.number_to_currency("1234567890.50", {:unit => "Kč", :format => "%n %u"})) - assert_equal("1,234,567,890.50 - Kč", number_helper.number_to_currency("-1234567890.50", {:unit => "Kč", :format => "%n %u", :negative_format => "%n - %u"})) - assert_equal("0.00", number_helper.number_to_currency(+0.0, {:unit => "", :negative_format => "(%n)"})) + assert_equal("1,234,567,890.50 Kč", number_helper.number_to_currency("1234567890.50", unit: "Kč", format: "%n %u")) + assert_equal("1,234,567,890.50 - Kč", number_helper.number_to_currency("-1234567890.50", unit: "Kč", format: "%n %u", negative_format: "%n - %u")) + assert_equal("0.00", number_helper.number_to_currency(+0.0, unit: "", negative_format: "(%n)")) end end def test_number_to_percentage [@instance_with_helpers, TestClassWithClassNumberHelpers, ActiveSupport::NumberHelper].each do |number_helper| assert_equal("100.000%", number_helper.number_to_percentage(100)) - assert_equal("100%", number_helper.number_to_percentage(100, {:precision => 0})) - assert_equal("302.06%", number_helper.number_to_percentage(302.0574, {:precision => 2})) + assert_equal("100%", number_helper.number_to_percentage(100, precision: 0)) + assert_equal("302.06%", number_helper.number_to_percentage(302.0574, precision: 2)) assert_equal("100.000%", number_helper.number_to_percentage("100")) assert_equal("1000.000%", number_helper.number_to_percentage("1000")) - assert_equal("123.4%", number_helper.number_to_percentage(123.400, :precision => 3, :strip_insignificant_zeros => true)) - assert_equal("1.000,000%", number_helper.number_to_percentage(1000, :delimiter => '.', :separator => ',')) - assert_equal("1000.000 %", number_helper.number_to_percentage(1000, :format => "%n %")) + assert_equal("123.4%", number_helper.number_to_percentage(123.400, precision: 3, strip_insignificant_zeros: true)) + assert_equal("1.000,000%", number_helper.number_to_percentage(1000, delimiter: ".", separator: ",")) + assert_equal("1000.000 %", number_helper.number_to_percentage(1000, format: "%n %")) assert_equal("98a%", number_helper.number_to_percentage("98a")) assert_equal("NaN%", number_helper.number_to_percentage(Float::NAN)) assert_equal("Inf%", number_helper.number_to_percentage(Float::INFINITY)) @@ -120,9 +121,9 @@ module ActiveSupport def test_to_delimited_with_options_hash [@instance_with_helpers, TestClassWithClassNumberHelpers, ActiveSupport::NumberHelper].each do |number_helper| - assert_equal '12 345 678', number_helper.number_to_delimited(12345678, :delimiter => ' ') - assert_equal '12,345,678-05', number_helper.number_to_delimited(12345678.05, :separator => '-') - assert_equal '12.345.678,05', number_helper.number_to_delimited(12345678.05, :separator => ',', :delimiter => '.') + assert_equal "12 345 678", number_helper.number_to_delimited(12345678, delimiter: " ") + assert_equal "12,345,678-05", number_helper.number_to_delimited(12345678.05, separator: "-") + assert_equal "12.345.678,05", number_helper.number_to_delimited(12345678.05, separator: ",", delimiter: ".") end end @@ -130,77 +131,77 @@ module ActiveSupport [@instance_with_helpers, TestClassWithClassNumberHelpers, ActiveSupport::NumberHelper].each do |number_helper| assert_equal("-111.235", number_helper.number_to_rounded(-111.2346)) assert_equal("111.235", number_helper.number_to_rounded(111.2346)) - assert_equal("31.83", number_helper.number_to_rounded(31.825, :precision => 2)) - assert_equal("111.23", number_helper.number_to_rounded(111.2346, :precision => 2)) - assert_equal("111.00", number_helper.number_to_rounded(111, :precision => 2)) + assert_equal("31.83", number_helper.number_to_rounded(31.825, precision: 2)) + assert_equal("111.23", number_helper.number_to_rounded(111.2346, precision: 2)) + assert_equal("111.00", number_helper.number_to_rounded(111, precision: 2)) assert_equal("111.235", number_helper.number_to_rounded("111.2346")) - assert_equal("31.83", number_helper.number_to_rounded("31.825", :precision => 2)) - assert_equal("3268", number_helper.number_to_rounded((32.6751 * 100.00), :precision => 0)) - assert_equal("112", number_helper.number_to_rounded(111.50, :precision => 0)) - assert_equal("1234567892", number_helper.number_to_rounded(1234567891.50, :precision => 0)) - assert_equal("0", number_helper.number_to_rounded(0, :precision => 0)) - assert_equal("0.00100", number_helper.number_to_rounded(0.001, :precision => 5)) - assert_equal("0.001", number_helper.number_to_rounded(0.00111, :precision => 3)) - assert_equal("10.00", number_helper.number_to_rounded(9.995, :precision => 2)) - assert_equal("11.00", number_helper.number_to_rounded(10.995, :precision => 2)) - assert_equal("0.00", number_helper.number_to_rounded(-0.001, :precision => 2)) - - assert_equal("111.23460000000000000000", number_helper.number_to_rounded(111.2346, :precision => 20)) - assert_equal("111.23460000000000000000", number_helper.number_to_rounded(Rational(1112346, 10000), :precision => 20)) - assert_equal("111.23460000000000000000", number_helper.number_to_rounded('111.2346', :precision => 20)) - assert_equal("111.23460000000000000000", number_helper.number_to_rounded(BigDecimal(111.2346, Float::DIG), :precision => 20)) - assert_equal("111.2346" + "0"*96, number_helper.number_to_rounded('111.2346', :precision => 100)) - assert_equal("111.2346", number_helper.number_to_rounded(Rational(1112346, 10000), :precision => 4)) - assert_equal('0.00', number_helper.number_to_rounded(Rational(0, 1), :precision => 2)) + assert_equal("31.83", number_helper.number_to_rounded("31.825", precision: 2)) + assert_equal("3268", number_helper.number_to_rounded((32.6751 * 100.00), precision: 0)) + assert_equal("112", number_helper.number_to_rounded(111.50, precision: 0)) + assert_equal("1234567892", number_helper.number_to_rounded(1234567891.50, precision: 0)) + assert_equal("0", number_helper.number_to_rounded(0, precision: 0)) + assert_equal("0.00100", number_helper.number_to_rounded(0.001, precision: 5)) + assert_equal("0.001", number_helper.number_to_rounded(0.00111, precision: 3)) + assert_equal("10.00", number_helper.number_to_rounded(9.995, precision: 2)) + assert_equal("11.00", number_helper.number_to_rounded(10.995, precision: 2)) + assert_equal("0.00", number_helper.number_to_rounded(-0.001, precision: 2)) + + assert_equal("111.23460000000000000000", number_helper.number_to_rounded(111.2346, precision: 20)) + assert_equal("111.23460000000000000000", number_helper.number_to_rounded(Rational(1112346, 10000), precision: 20)) + assert_equal("111.23460000000000000000", number_helper.number_to_rounded("111.2346", precision: 20)) + assert_equal("111.23460000000000000000", number_helper.number_to_rounded(BigDecimal(111.2346, Float::DIG), precision: 20)) + assert_equal("111.2346" + "0"*96, number_helper.number_to_rounded("111.2346", precision: 100)) + assert_equal("111.2346", number_helper.number_to_rounded(Rational(1112346, 10000), precision: 4)) + assert_equal("0.00", number_helper.number_to_rounded(Rational(0, 1), precision: 2)) end end def test_to_rounded_with_custom_delimiter_and_separator [@instance_with_helpers, TestClassWithClassNumberHelpers, ActiveSupport::NumberHelper].each do |number_helper| - assert_equal '31,83', number_helper.number_to_rounded(31.825, :precision => 2, :separator => ',') - assert_equal '1.231,83', number_helper.number_to_rounded(1231.825, :precision => 2, :separator => ',', :delimiter => '.') + assert_equal "31,83", number_helper.number_to_rounded(31.825, precision: 2, separator: ",") + assert_equal "1.231,83", number_helper.number_to_rounded(1231.825, precision: 2, separator: ",", delimiter: ".") end end def test_to_rounded_with_significant_digits [@instance_with_helpers, TestClassWithClassNumberHelpers, ActiveSupport::NumberHelper].each do |number_helper| - assert_equal "124000", number_helper.number_to_rounded(123987, :precision => 3, :significant => true) - assert_equal "120000000", number_helper.number_to_rounded(123987876, :precision => 2, :significant => true ) - assert_equal "40000", number_helper.number_to_rounded("43523", :precision => 1, :significant => true ) - assert_equal "9775", number_helper.number_to_rounded(9775, :precision => 4, :significant => true ) - assert_equal "5.4", number_helper.number_to_rounded(5.3923, :precision => 2, :significant => true ) - assert_equal "5", number_helper.number_to_rounded(5.3923, :precision => 1, :significant => true ) - assert_equal "1", number_helper.number_to_rounded(1.232, :precision => 1, :significant => true ) - assert_equal "7", number_helper.number_to_rounded(7, :precision => 1, :significant => true ) - assert_equal "1", number_helper.number_to_rounded(1, :precision => 1, :significant => true ) - assert_equal "53", number_helper.number_to_rounded(52.7923, :precision => 2, :significant => true ) - assert_equal "9775.00", number_helper.number_to_rounded(9775, :precision => 6, :significant => true ) - assert_equal "5.392900", number_helper.number_to_rounded(5.3929, :precision => 7, :significant => true ) - assert_equal "0.0", number_helper.number_to_rounded(0, :precision => 2, :significant => true ) - assert_equal "0", number_helper.number_to_rounded(0, :precision => 1, :significant => true ) - assert_equal "0.0001", number_helper.number_to_rounded(0.0001, :precision => 1, :significant => true ) - assert_equal "0.000100", number_helper.number_to_rounded(0.0001, :precision => 3, :significant => true ) - assert_equal "0.0001", number_helper.number_to_rounded(0.0001111, :precision => 1, :significant => true ) - assert_equal "10.0", number_helper.number_to_rounded(9.995, :precision => 3, :significant => true) - assert_equal "9.99", number_helper.number_to_rounded(9.994, :precision => 3, :significant => true) - assert_equal "11.0", number_helper.number_to_rounded(10.995, :precision => 3, :significant => true) - - assert_equal "9775.0000000000000000", number_helper.number_to_rounded(9775, :precision => 20, :significant => true ) - assert_equal "9775.0000000000000000", number_helper.number_to_rounded(9775.0, :precision => 20, :significant => true ) - assert_equal "9775.0000000000000000", number_helper.number_to_rounded(Rational(9775, 1), :precision => 20, :significant => true ) - assert_equal "97.750000000000000000", number_helper.number_to_rounded(Rational(9775, 100), :precision => 20, :significant => true ) - assert_equal "9775.0000000000000000", number_helper.number_to_rounded(BigDecimal(9775), :precision => 20, :significant => true ) - assert_equal "9775.0000000000000000", number_helper.number_to_rounded("9775", :precision => 20, :significant => true ) - assert_equal "9775." + "0"*96, number_helper.number_to_rounded("9775", :precision => 100, :significant => true ) - assert_equal("97.7", number_helper.number_to_rounded(Rational(9772, 100), :precision => 3, :significant => true)) + assert_equal "124000", number_helper.number_to_rounded(123987, precision: 3, significant: true) + assert_equal "120000000", number_helper.number_to_rounded(123987876, precision: 2, significant: true ) + assert_equal "40000", number_helper.number_to_rounded("43523", precision: 1, significant: true ) + assert_equal "9775", number_helper.number_to_rounded(9775, precision: 4, significant: true ) + assert_equal "5.4", number_helper.number_to_rounded(5.3923, precision: 2, significant: true ) + assert_equal "5", number_helper.number_to_rounded(5.3923, precision: 1, significant: true ) + assert_equal "1", number_helper.number_to_rounded(1.232, precision: 1, significant: true ) + assert_equal "7", number_helper.number_to_rounded(7, precision: 1, significant: true ) + assert_equal "1", number_helper.number_to_rounded(1, precision: 1, significant: true ) + assert_equal "53", number_helper.number_to_rounded(52.7923, precision: 2, significant: true ) + assert_equal "9775.00", number_helper.number_to_rounded(9775, precision: 6, significant: true ) + assert_equal "5.392900", number_helper.number_to_rounded(5.3929, precision: 7, significant: true ) + assert_equal "0.0", number_helper.number_to_rounded(0, precision: 2, significant: true ) + assert_equal "0", number_helper.number_to_rounded(0, precision: 1, significant: true ) + assert_equal "0.0001", number_helper.number_to_rounded(0.0001, precision: 1, significant: true ) + assert_equal "0.000100", number_helper.number_to_rounded(0.0001, precision: 3, significant: true ) + assert_equal "0.0001", number_helper.number_to_rounded(0.0001111, precision: 1, significant: true ) + assert_equal "10.0", number_helper.number_to_rounded(9.995, precision: 3, significant: true) + assert_equal "9.99", number_helper.number_to_rounded(9.994, precision: 3, significant: true) + assert_equal "11.0", number_helper.number_to_rounded(10.995, precision: 3, significant: true) + + assert_equal "9775.0000000000000000", number_helper.number_to_rounded(9775, precision: 20, significant: true ) + assert_equal "9775.0000000000000000", number_helper.number_to_rounded(9775.0, precision: 20, significant: true ) + assert_equal "9775.0000000000000000", number_helper.number_to_rounded(Rational(9775, 1), precision: 20, significant: true ) + assert_equal "97.750000000000000000", number_helper.number_to_rounded(Rational(9775, 100), precision: 20, significant: true ) + assert_equal "9775.0000000000000000", number_helper.number_to_rounded(BigDecimal(9775), precision: 20, significant: true ) + assert_equal "9775.0000000000000000", number_helper.number_to_rounded("9775", precision: 20, significant: true ) + assert_equal "9775." + "0"*96, number_helper.number_to_rounded("9775", precision: 100, significant: true ) + assert_equal("97.7", number_helper.number_to_rounded(Rational(9772, 100), precision: 3, significant: true)) end end def test_to_rounded_with_strip_insignificant_zeros [@instance_with_helpers, TestClassWithClassNumberHelpers, ActiveSupport::NumberHelper].each do |number_helper| - assert_equal "9775.43", number_helper.number_to_rounded(9775.43, :precision => 4, :strip_insignificant_zeros => true ) - assert_equal "9775.2", number_helper.number_to_rounded(9775.2, :precision => 6, :significant => true, :strip_insignificant_zeros => true ) - assert_equal "0", number_helper.number_to_rounded(0, :precision => 6, :significant => true, :strip_insignificant_zeros => true ) + assert_equal "9775.43", number_helper.number_to_rounded(9775.43, precision: 4, strip_insignificant_zeros: true ) + assert_equal "9775.2", number_helper.number_to_rounded(9775.2, precision: 6, significant: true, strip_insignificant_zeros: true ) + assert_equal "0", number_helper.number_to_rounded(0, precision: 6, significant: true, strip_insignificant_zeros: true ) end end @@ -208,156 +209,156 @@ module ActiveSupport [@instance_with_helpers, TestClassWithClassNumberHelpers, ActiveSupport::NumberHelper].each do |number_helper| # Zero precision with significant is a mistake (would always return zero), # so we treat it as if significant was false (increases backwards compatibility for number_to_human_size) - assert_equal "124", number_helper.number_to_rounded(123.987, :precision => 0, :significant => true) - assert_equal "12", number_helper.number_to_rounded(12, :precision => 0, :significant => true ) - assert_equal "12", number_helper.number_to_rounded("12.3", :precision => 0, :significant => true ) + assert_equal "124", number_helper.number_to_rounded(123.987, precision: 0, significant: true) + assert_equal "12", number_helper.number_to_rounded(12, precision: 0, significant: true ) + assert_equal "12", number_helper.number_to_rounded("12.3", precision: 0, significant: true ) end end def test_number_number_to_human_size [@instance_with_helpers, TestClassWithClassNumberHelpers, ActiveSupport::NumberHelper].each do |number_helper| - assert_equal '0 Bytes', number_helper.number_to_human_size(0) - assert_equal '1 Byte', number_helper.number_to_human_size(1) - assert_equal '3 Bytes', number_helper.number_to_human_size(3.14159265) - assert_equal '123 Bytes', number_helper.number_to_human_size(123.0) - assert_equal '123 Bytes', number_helper.number_to_human_size(123) - assert_equal '1.21 KB', number_helper.number_to_human_size(1234) - assert_equal '12.1 KB', number_helper.number_to_human_size(12345) - assert_equal '1.18 MB', number_helper.number_to_human_size(1234567) - assert_equal '1.15 GB', number_helper.number_to_human_size(1234567890) - assert_equal '1.12 TB', number_helper.number_to_human_size(1234567890123) - assert_equal '1.1 PB', number_helper.number_to_human_size(1234567890123456) - assert_equal '1.07 EB', number_helper.number_to_human_size(1234567890123456789) - assert_equal '1030 EB', number_helper.number_to_human_size(exabytes(1026)) - assert_equal '444 KB', number_helper.number_to_human_size(kilobytes(444)) - assert_equal '1020 MB', number_helper.number_to_human_size(megabytes(1023)) - assert_equal '3 TB', number_helper.number_to_human_size(terabytes(3)) - assert_equal '1.2 MB', number_helper.number_to_human_size(1234567, :precision => 2) - assert_equal '3 Bytes', number_helper.number_to_human_size(3.14159265, :precision => 4) - assert_equal '123 Bytes', number_helper.number_to_human_size('123') - assert_equal '1 KB', number_helper.number_to_human_size(kilobytes(1.0123), :precision => 2) - assert_equal '1.01 KB', number_helper.number_to_human_size(kilobytes(1.0100), :precision => 4) - assert_equal '10 KB', number_helper.number_to_human_size(kilobytes(10.000), :precision => 4) - assert_equal '1 Byte', number_helper.number_to_human_size(1.1) - assert_equal '10 Bytes', number_helper.number_to_human_size(10) + assert_equal "0 Bytes", number_helper.number_to_human_size(0) + assert_equal "1 Byte", number_helper.number_to_human_size(1) + assert_equal "3 Bytes", number_helper.number_to_human_size(3.14159265) + assert_equal "123 Bytes", number_helper.number_to_human_size(123.0) + assert_equal "123 Bytes", number_helper.number_to_human_size(123) + assert_equal "1.21 KB", number_helper.number_to_human_size(1234) + assert_equal "12.1 KB", number_helper.number_to_human_size(12345) + assert_equal "1.18 MB", number_helper.number_to_human_size(1234567) + assert_equal "1.15 GB", number_helper.number_to_human_size(1234567890) + assert_equal "1.12 TB", number_helper.number_to_human_size(1234567890123) + assert_equal "1.1 PB", number_helper.number_to_human_size(1234567890123456) + assert_equal "1.07 EB", number_helper.number_to_human_size(1234567890123456789) + assert_equal "1030 EB", number_helper.number_to_human_size(exabytes(1026)) + assert_equal "444 KB", number_helper.number_to_human_size(kilobytes(444)) + assert_equal "1020 MB", number_helper.number_to_human_size(megabytes(1023)) + assert_equal "3 TB", number_helper.number_to_human_size(terabytes(3)) + assert_equal "1.2 MB", number_helper.number_to_human_size(1234567, precision: 2) + assert_equal "3 Bytes", number_helper.number_to_human_size(3.14159265, precision: 4) + assert_equal "123 Bytes", number_helper.number_to_human_size("123") + assert_equal "1 KB", number_helper.number_to_human_size(kilobytes(1.0123), precision: 2) + assert_equal "1.01 KB", number_helper.number_to_human_size(kilobytes(1.0100), precision: 4) + assert_equal "10 KB", number_helper.number_to_human_size(kilobytes(10.000), precision: 4) + assert_equal "1 Byte", number_helper.number_to_human_size(1.1) + assert_equal "10 Bytes", number_helper.number_to_human_size(10) end end def test_number_to_human_size_with_si_prefix assert_deprecated do [@instance_with_helpers, TestClassWithClassNumberHelpers, ActiveSupport::NumberHelper].each do |number_helper| - assert_equal '3 Bytes', number_helper.number_to_human_size(3.14159265, :prefix => :si) - assert_equal '123 Bytes', number_helper.number_to_human_size(123.0, :prefix => :si) - assert_equal '123 Bytes', number_helper.number_to_human_size(123, :prefix => :si) - assert_equal '1.23 KB', number_helper.number_to_human_size(1234, :prefix => :si) - assert_equal '12.3 KB', number_helper.number_to_human_size(12345, :prefix => :si) - assert_equal '1.23 MB', number_helper.number_to_human_size(1234567, :prefix => :si) - assert_equal '1.23 GB', number_helper.number_to_human_size(1234567890, :prefix => :si) - assert_equal '1.23 TB', number_helper.number_to_human_size(1234567890123, :prefix => :si) - assert_equal '1.23 PB', number_helper.number_to_human_size(1234567890123456, :prefix => :si) - assert_equal '1.23 EB', number_helper.number_to_human_size(1234567890123456789, :prefix => :si) + assert_equal "3 Bytes", number_helper.number_to_human_size(3.14159265, prefix: :si) + assert_equal "123 Bytes", number_helper.number_to_human_size(123.0, prefix: :si) + assert_equal "123 Bytes", number_helper.number_to_human_size(123, prefix: :si) + assert_equal "1.23 KB", number_helper.number_to_human_size(1234, prefix: :si) + assert_equal "12.3 KB", number_helper.number_to_human_size(12345, prefix: :si) + assert_equal "1.23 MB", number_helper.number_to_human_size(1234567, prefix: :si) + assert_equal "1.23 GB", number_helper.number_to_human_size(1234567890, prefix: :si) + assert_equal "1.23 TB", number_helper.number_to_human_size(1234567890123, prefix: :si) + assert_equal "1.23 PB", number_helper.number_to_human_size(1234567890123456, prefix: :si) + assert_equal "1.23 EB", number_helper.number_to_human_size(1234567890123456789, prefix: :si) end end end def test_number_to_human_size_with_options_hash [@instance_with_helpers, TestClassWithClassNumberHelpers, ActiveSupport::NumberHelper].each do |number_helper| - assert_equal '1.2 MB', number_helper.number_to_human_size(1234567, :precision => 2) - assert_equal '3 Bytes', number_helper.number_to_human_size(3.14159265, :precision => 4) - assert_equal '1 KB', number_helper.number_to_human_size(kilobytes(1.0123), :precision => 2) - assert_equal '1.01 KB', number_helper.number_to_human_size(kilobytes(1.0100), :precision => 4) - assert_equal '10 KB', number_helper.number_to_human_size(kilobytes(10.000), :precision => 4) - assert_equal '1 TB', number_helper.number_to_human_size(1234567890123, :precision => 1) - assert_equal '500 MB', number_helper.number_to_human_size(524288000, :precision=>3) - assert_equal '10 MB', number_helper.number_to_human_size(9961472, :precision=>0) - assert_equal '40 KB', number_helper.number_to_human_size(41010, :precision => 1) - assert_equal '40 KB', number_helper.number_to_human_size(41100, :precision => 2) - assert_equal '1.0 KB', number_helper.number_to_human_size(kilobytes(1.0123), :precision => 2, :strip_insignificant_zeros => false) - assert_equal '1.012 KB', number_helper.number_to_human_size(kilobytes(1.0123), :precision => 3, :significant => false) - assert_equal '1 KB', number_helper.number_to_human_size(kilobytes(1.0123), :precision => 0, :significant => true) #ignores significant it precision is 0 + assert_equal "1.2 MB", number_helper.number_to_human_size(1234567, precision: 2) + assert_equal "3 Bytes", number_helper.number_to_human_size(3.14159265, precision: 4) + assert_equal "1 KB", number_helper.number_to_human_size(kilobytes(1.0123), precision: 2) + assert_equal "1.01 KB", number_helper.number_to_human_size(kilobytes(1.0100), precision: 4) + assert_equal "10 KB", number_helper.number_to_human_size(kilobytes(10.000), precision: 4) + assert_equal "1 TB", number_helper.number_to_human_size(1234567890123, precision: 1) + assert_equal "500 MB", number_helper.number_to_human_size(524288000, precision: 3) + assert_equal "10 MB", number_helper.number_to_human_size(9961472, precision: 0) + assert_equal "40 KB", number_helper.number_to_human_size(41010, precision: 1) + assert_equal "40 KB", number_helper.number_to_human_size(41100, precision: 2) + assert_equal "1.0 KB", number_helper.number_to_human_size(kilobytes(1.0123), precision: 2, strip_insignificant_zeros: false) + assert_equal "1.012 KB", number_helper.number_to_human_size(kilobytes(1.0123), precision: 3, significant: false) + assert_equal "1 KB", number_helper.number_to_human_size(kilobytes(1.0123), precision: 0, significant: true) #ignores significant it precision is 0 end end def test_number_to_human_size_with_custom_delimiter_and_separator [@instance_with_helpers, TestClassWithClassNumberHelpers, ActiveSupport::NumberHelper].each do |number_helper| - assert_equal '1,01 KB', number_helper.number_to_human_size(kilobytes(1.0123), :precision => 3, :separator => ',') - assert_equal '1,01 KB', number_helper.number_to_human_size(kilobytes(1.0100), :precision => 4, :separator => ',') - assert_equal '1.000,1 TB', number_helper.number_to_human_size(terabytes(1000.1), :precision => 5, :delimiter => '.', :separator => ',') + assert_equal "1,01 KB", number_helper.number_to_human_size(kilobytes(1.0123), precision: 3, separator: ",") + assert_equal "1,01 KB", number_helper.number_to_human_size(kilobytes(1.0100), precision: 4, separator: ",") + assert_equal "1.000,1 TB", number_helper.number_to_human_size(terabytes(1000.1), precision: 5, delimiter: ".", separator: ",") end end def test_number_to_human [@instance_with_helpers, TestClassWithClassNumberHelpers, ActiveSupport::NumberHelper].each do |number_helper| - assert_equal '-123', number_helper.number_to_human(-123) - assert_equal '-0.5', number_helper.number_to_human(-0.5) - assert_equal '0', number_helper.number_to_human(0) - assert_equal '0.5', number_helper.number_to_human(0.5) - assert_equal '123', number_helper.number_to_human(123) - assert_equal '1.23 Thousand', number_helper.number_to_human(1234) - assert_equal '12.3 Thousand', number_helper.number_to_human(12345) - assert_equal '1.23 Million', number_helper.number_to_human(1234567) - assert_equal '1.23 Billion', number_helper.number_to_human(1234567890) - assert_equal '1.23 Trillion', number_helper.number_to_human(1234567890123) - assert_equal '1.23 Quadrillion', number_helper.number_to_human(1234567890123456) - assert_equal '1230 Quadrillion', number_helper.number_to_human(1234567890123456789) - assert_equal '490 Thousand', number_helper.number_to_human(489939, :precision => 2) - assert_equal '489.9 Thousand', number_helper.number_to_human(489939, :precision => 4) - assert_equal '489 Thousand', number_helper.number_to_human(489000, :precision => 4) - assert_equal '489.0 Thousand', number_helper.number_to_human(489000, :precision => 4, :strip_insignificant_zeros => false) - assert_equal '1.2346 Million', number_helper.number_to_human(1234567, :precision => 4, :significant => false) - assert_equal '1,2 Million', number_helper.number_to_human(1234567, :precision => 1, :significant => false, :separator => ',') - assert_equal '1 Million', number_helper.number_to_human(1234567, :precision => 0, :significant => true, :separator => ',') #significant forced to false - assert_equal '1 Million', number_helper.number_to_human(999999) - assert_equal '1 Billion', number_helper.number_to_human(999999999) + assert_equal "-123", number_helper.number_to_human(-123) + assert_equal "-0.5", number_helper.number_to_human(-0.5) + assert_equal "0", number_helper.number_to_human(0) + assert_equal "0.5", number_helper.number_to_human(0.5) + assert_equal "123", number_helper.number_to_human(123) + assert_equal "1.23 Thousand", number_helper.number_to_human(1234) + assert_equal "12.3 Thousand", number_helper.number_to_human(12345) + assert_equal "1.23 Million", number_helper.number_to_human(1234567) + assert_equal "1.23 Billion", number_helper.number_to_human(1234567890) + assert_equal "1.23 Trillion", number_helper.number_to_human(1234567890123) + assert_equal "1.23 Quadrillion", number_helper.number_to_human(1234567890123456) + assert_equal "1230 Quadrillion", number_helper.number_to_human(1234567890123456789) + assert_equal "490 Thousand", number_helper.number_to_human(489939, precision: 2) + assert_equal "489.9 Thousand", number_helper.number_to_human(489939, precision: 4) + assert_equal "489 Thousand", number_helper.number_to_human(489000, precision: 4) + assert_equal "489.0 Thousand", number_helper.number_to_human(489000, precision: 4, strip_insignificant_zeros: false) + assert_equal "1.2346 Million", number_helper.number_to_human(1234567, precision: 4, significant: false) + assert_equal "1,2 Million", number_helper.number_to_human(1234567, precision: 1, significant: false, separator: ",") + assert_equal "1 Million", number_helper.number_to_human(1234567, precision: 0, significant: true, separator: ",") #significant forced to false + assert_equal "1 Million", number_helper.number_to_human(999999) + assert_equal "1 Billion", number_helper.number_to_human(999999999) end end def test_number_to_human_with_custom_units [@instance_with_helpers, TestClassWithClassNumberHelpers, ActiveSupport::NumberHelper].each do |number_helper| #Only integers - volume = {:unit => "ml", :thousand => "lt", :million => "m3"} - assert_equal '123 lt', number_helper.number_to_human(123456, :units => volume) - assert_equal '12 ml', number_helper.number_to_human(12, :units => volume) - assert_equal '1.23 m3', number_helper.number_to_human(1234567, :units => volume) + volume = { unit: "ml", thousand: "lt", million: "m3" } + assert_equal "123 lt", number_helper.number_to_human(123456, units: volume) + assert_equal "12 ml", number_helper.number_to_human(12, units: volume) + assert_equal "1.23 m3", number_helper.number_to_human(1234567, units: volume) #Including fractionals - distance = {:mili => "mm", :centi => "cm", :deci => "dm", :unit => "m", :ten => "dam", :hundred => "hm", :thousand => "km"} - assert_equal '1.23 mm', number_helper.number_to_human(0.00123, :units => distance) - assert_equal '1.23 cm', number_helper.number_to_human(0.0123, :units => distance) - assert_equal '1.23 dm', number_helper.number_to_human(0.123, :units => distance) - assert_equal '1.23 m', number_helper.number_to_human(1.23, :units => distance) - assert_equal '1.23 dam', number_helper.number_to_human(12.3, :units => distance) - assert_equal '1.23 hm', number_helper.number_to_human(123, :units => distance) - assert_equal '1.23 km', number_helper.number_to_human(1230, :units => distance) - assert_equal '1.23 km', number_helper.number_to_human(1230, :units => distance) - assert_equal '1.23 km', number_helper.number_to_human(1230, :units => distance) - assert_equal '12.3 km', number_helper.number_to_human(12300, :units => distance) + distance = { mili: "mm", centi: "cm", deci: "dm", unit: "m", ten: "dam", hundred: "hm", thousand: "km" } + assert_equal "1.23 mm", number_helper.number_to_human(0.00123, units: distance) + assert_equal "1.23 cm", number_helper.number_to_human(0.0123, units: distance) + assert_equal "1.23 dm", number_helper.number_to_human(0.123, units: distance) + assert_equal "1.23 m", number_helper.number_to_human(1.23, units: distance) + assert_equal "1.23 dam", number_helper.number_to_human(12.3, units: distance) + assert_equal "1.23 hm", number_helper.number_to_human(123, units: distance) + assert_equal "1.23 km", number_helper.number_to_human(1230, units: distance) + assert_equal "1.23 km", number_helper.number_to_human(1230, units: distance) + assert_equal "1.23 km", number_helper.number_to_human(1230, units: distance) + assert_equal "12.3 km", number_helper.number_to_human(12300, units: distance) #The quantifiers don't need to be a continuous sequence - gangster = {:hundred => "hundred bucks", :million => "thousand quids"} - assert_equal '1 hundred bucks', number_helper.number_to_human(100, :units => gangster) - assert_equal '25 hundred bucks', number_helper.number_to_human(2500, :units => gangster) - assert_equal '25 thousand quids', number_helper.number_to_human(25000000, :units => gangster) - assert_equal '12300 thousand quids', number_helper.number_to_human(12345000000, :units => gangster) + gangster = { hundred: "hundred bucks", million: "thousand quids" } + assert_equal "1 hundred bucks", number_helper.number_to_human(100, units: gangster) + assert_equal "25 hundred bucks", number_helper.number_to_human(2500, units: gangster) + assert_equal "25 thousand quids", number_helper.number_to_human(25000000, units: gangster) + assert_equal "12300 thousand quids", number_helper.number_to_human(12345000000, units: gangster) #Spaces are stripped from the resulting string - assert_equal '4', number_helper.number_to_human(4, :units => {:unit => "", :ten => 'tens '}) - assert_equal '4.5 tens', number_helper.number_to_human(45, :units => {:unit => "", :ten => ' tens '}) + assert_equal "4", number_helper.number_to_human(4, units: { unit: "", ten: "tens " }) + assert_equal "4.5 tens", number_helper.number_to_human(45, units: { unit: "", ten: " tens " }) end end def test_number_to_human_with_custom_units_that_are_missing_the_needed_key [@instance_with_helpers, TestClassWithClassNumberHelpers, ActiveSupport::NumberHelper].each do |number_helper| - assert_equal '123', number_helper.number_to_human(123, units: { thousand: 'k'}) - assert_equal '123', number_helper.number_to_human(123, units: {}) + assert_equal "123", number_helper.number_to_human(123, units: { thousand: "k" }) + assert_equal "123", number_helper.number_to_human(123, units: {}) end end def test_number_to_human_with_custom_format [@instance_with_helpers, TestClassWithClassNumberHelpers, ActiveSupport::NumberHelper].each do |number_helper| - assert_equal '123 times Thousand', number_helper.number_to_human(123456, :format => "%n times %u") - volume = {:unit => "ml", :thousand => "lt", :million => "m3"} - assert_equal '123.lt', number_helper.number_to_human(123456, :units => volume, :format => "%n.%u") + assert_equal "123 times Thousand", number_helper.number_to_human(123456, format: "%n times %u") + volume = { unit: "ml", thousand: "lt", million: "m3" } + assert_equal "123.lt", number_helper.number_to_human(123456, units: volume, format: "%n.%u") end end @@ -375,34 +376,34 @@ module ActiveSupport def test_number_helpers_do_not_mutate_options_hash [@instance_with_helpers, TestClassWithClassNumberHelpers, ActiveSupport::NumberHelper].each do |number_helper| - options = { 'raise' => true } + options = { "raise" => true } number_helper.number_to_phone(1, options) - assert_equal({ 'raise' => true }, options) + assert_equal({ "raise" => true }, options) number_helper.number_to_currency(1, options) - assert_equal({ 'raise' => true }, options) + assert_equal({ "raise" => true }, options) number_helper.number_to_percentage(1, options) - assert_equal({ 'raise' => true }, options) + assert_equal({ "raise" => true }, options) number_helper.number_to_delimited(1, options) - assert_equal({ 'raise' => true }, options) + assert_equal({ "raise" => true }, options) number_helper.number_to_rounded(1, options) - assert_equal({ 'raise' => true }, options) + assert_equal({ "raise" => true }, options) number_helper.number_to_human_size(1, options) - assert_equal({ 'raise' => true }, options) + assert_equal({ "raise" => true }, options) number_helper.number_to_human(1, options) - assert_equal({ 'raise' => true }, options) + assert_equal({ "raise" => true }, options) end end def test_number_helpers_should_return_non_numeric_param_unchanged [@instance_with_helpers, TestClassWithClassNumberHelpers, ActiveSupport::NumberHelper].each do |number_helper| - assert_equal("+1-x x 123", number_helper.number_to_phone("x", :country_code => 1, :extension => 123)) + assert_equal("+1-x x 123", number_helper.number_to_phone("x", country_code: 1, extension: 123)) assert_equal("x", number_helper.number_to_phone("x")) assert_equal("$x.", number_helper.number_to_currency("x.")) assert_equal("$x", number_helper.number_to_currency("x")) @@ -410,11 +411,10 @@ module ActiveSupport assert_equal("x", number_helper.number_to_delimited("x")) assert_equal("x.", number_helper.number_to_rounded("x.")) assert_equal("x", number_helper.number_to_rounded("x")) - assert_equal "x", number_helper.number_to_human_size('x') - assert_equal "x", number_helper.number_to_human('x') + assert_equal "x", number_helper.number_to_human_size("x") + assert_equal "x", number_helper.number_to_human("x") end end - end end end diff --git a/activesupport/test/option_merger_test.rb b/activesupport/test/option_merger_test.rb index 4c0364e68b..c5a6d304ee 100644 --- a/activesupport/test/option_merger_test.rb +++ b/activesupport/test/option_merger_test.rb @@ -1,13 +1,13 @@ -require 'abstract_unit' -require 'active_support/core_ext/object/with_options' +require "abstract_unit" +require "active_support/core_ext/object/with_options" class OptionMergerTest < ActiveSupport::TestCase def setup - @options = {:hello => 'world'} + @options = { hello: "world" } end def test_method_with_options_merges_options_when_options_are_present - local_options = {:cool => true} + local_options = { cool: true } with_options(@options) do |o| assert_equal local_options, method_with_options(local_options) @@ -24,7 +24,7 @@ class OptionMergerTest < ActiveSupport::TestCase end def test_method_with_options_allows_to_overwrite_options - local_options = {:hello => 'moon'} + local_options = { hello: "moon" } assert_equal @options.keys, local_options.keys with_options(@options) do |o| @@ -40,34 +40,34 @@ class OptionMergerTest < ActiveSupport::TestCase end def test_nested_method_with_options_containing_hashes_merge - with_options :conditions => { :method => :get } do |outer| - outer.with_options :conditions => { :domain => "www" } do |inner| - expected = { :conditions => { :method => :get, :domain => "www" } } + with_options conditions: { method: :get } do |outer| + outer.with_options conditions: { domain: "www" } do |inner| + expected = { conditions: { method: :get, domain: "www" } } assert_equal expected, inner.method_with_options end end end def test_nested_method_with_options_containing_hashes_overwrite - with_options :conditions => { :method => :get, :domain => "www" } do |outer| - outer.with_options :conditions => { :method => :post } do |inner| - expected = { :conditions => { :method => :post, :domain => "www" } } + with_options conditions: { method: :get, domain: "www" } do |outer| + outer.with_options conditions: { method: :post } do |inner| + expected = { conditions: { method: :post, domain: "www" } } assert_equal expected, inner.method_with_options end end end def test_nested_method_with_options_containing_hashes_going_deep - with_options :html => { :class => "foo", :style => { :margin => 0, :display => "block" } } do |outer| - outer.with_options :html => { :title => "bar", :style => { :margin => "1em", :color => "#fff" } } do |inner| - expected = { :html => { :class => "foo", :title => "bar", :style => { :margin => "1em", :display => "block", :color => "#fff" } } } + with_options html: { class: "foo", style: { margin: 0, display: "block" } } do |outer| + outer.with_options html: { title: "bar", style: { margin: "1em", color: "#fff" } } do |inner| + expected = { html: { class: "foo", title: "bar", style: { margin: "1em", display: "block", color: "#fff" } } } assert_equal expected, inner.method_with_options end end end def test_nested_method_with_options_using_lambda - local_lambda = lambda { { :lambda => true } } + local_lambda = lambda { { lambda: true } } with_options(@options) do |o| assert_equal @options.merge(local_lambda.call), o.method_with_options(local_lambda).call @@ -76,7 +76,7 @@ class OptionMergerTest < ActiveSupport::TestCase # Needed when counting objects with the ObjectSpace def test_option_merger_class_method - assert_equal ActiveSupport::OptionMerger, ActiveSupport::OptionMerger.new('', '').class + assert_equal ActiveSupport::OptionMerger, ActiveSupport::OptionMerger.new("", "").class end def test_option_merger_implicit_receiver diff --git a/activesupport/test/ordered_hash_test.rb b/activesupport/test/ordered_hash_test.rb index 460a61613e..86da9f193a 100644 --- a/activesupport/test/ordered_hash_test.rb +++ b/activesupport/test/ordered_hash_test.rb @@ -1,8 +1,8 @@ -require 'abstract_unit' -require 'active_support/json' -require 'active_support/core_ext/object/json' -require 'active_support/core_ext/hash/indifferent_access' -require 'active_support/core_ext/array/extract_options' +require "abstract_unit" +require "active_support/json" +require "active_support/core_ext/object/json" +require "active_support/core_ext/hash/indifferent_access" +require "active_support/core_ext/array/extract_options" class OrderedHashTest < ActiveSupport::TestCase def setup @@ -27,7 +27,7 @@ class OrderedHashTest < ActiveSupport::TestCase end def test_assignment - key, value = 'purple', '5422a8' + key, value = "purple", "5422a8" @ordered_hash[key] = value assert_equal @keys.length + 1, @ordered_hash.length @@ -37,8 +37,8 @@ class OrderedHashTest < ActiveSupport::TestCase end def test_delete - key, value = 'white', 'ffffff' - bad_key = 'black' + key, value = "white", "ffffff" + bad_key = "black" @ordered_hash[key] = value assert_equal @keys.length + 1, @ordered_hash.length @@ -60,22 +60,22 @@ class OrderedHashTest < ActiveSupport::TestCase end def test_has_key - assert_equal true, @ordered_hash.has_key?('blue') - assert_equal true, @ordered_hash.key?('blue') - assert_equal true, @ordered_hash.include?('blue') - assert_equal true, @ordered_hash.member?('blue') + assert_equal true, @ordered_hash.has_key?("blue") + assert_equal true, @ordered_hash.key?("blue") + assert_equal true, @ordered_hash.include?("blue") + assert_equal true, @ordered_hash.member?("blue") - assert_equal false, @ordered_hash.has_key?('indigo') - assert_equal false, @ordered_hash.key?('indigo') - assert_equal false, @ordered_hash.include?('indigo') - assert_equal false, @ordered_hash.member?('indigo') + assert_equal false, @ordered_hash.has_key?("indigo") + assert_equal false, @ordered_hash.key?("indigo") + assert_equal false, @ordered_hash.include?("indigo") + assert_equal false, @ordered_hash.member?("indigo") end def test_has_value - assert_equal true, @ordered_hash.has_value?('000099') - assert_equal true, @ordered_hash.value?('000099') - assert_equal false, @ordered_hash.has_value?('ABCABC') - assert_equal false, @ordered_hash.value?('ABCABC') + assert_equal true, @ordered_hash.has_value?("000099") + assert_equal true, @ordered_hash.value?("000099") + assert_equal false, @ordered_hash.has_value?("ABCABC") + assert_equal false, @ordered_hash.value?("ABCABC") end def test_each_key @@ -94,13 +94,13 @@ class OrderedHashTest < ActiveSupport::TestCase def test_each values = [] - assert_equal @ordered_hash, @ordered_hash.each {|key, value| values << value} + assert_equal @ordered_hash, @ordered_hash.each { |key, value| values << value } assert_equal @values, values assert_kind_of Enumerator, @ordered_hash.each end def test_each_with_index - @ordered_hash.each_with_index { |pair, index| assert_equal [@keys[index], @values[index]], pair} + @ordered_hash.each_with_index { |pair, index| assert_equal [@keys[index], @values[index]], pair } end def test_each_pair @@ -127,24 +127,24 @@ class OrderedHashTest < ActiveSupport::TestCase def test_delete_if copy = @ordered_hash.dup - copy.delete('pink') - assert_equal copy, @ordered_hash.delete_if { |k, _| k == 'pink' } - assert !@ordered_hash.keys.include?('pink') + copy.delete("pink") + assert_equal copy, @ordered_hash.delete_if { |k, _| k == "pink" } + assert_not_includes @ordered_hash.keys, "pink" end def test_reject! - (copy = @ordered_hash.dup).delete('pink') - @ordered_hash.reject! { |k, _| k == 'pink' } + (copy = @ordered_hash.dup).delete("pink") + @ordered_hash.reject! { |k, _| k == "pink" } assert_equal copy, @ordered_hash - assert !@ordered_hash.keys.include?('pink') + assert_not_includes @ordered_hash.keys, "pink" end def test_reject copy = @ordered_hash.dup - new_ordered_hash = @ordered_hash.reject { |k, _| k == 'pink' } + new_ordered_hash = @ordered_hash.reject { |k, _| k == "pink" } assert_equal copy, @ordered_hash - assert !new_ordered_hash.keys.include?('pink') - assert @ordered_hash.keys.include?('pink') + assert_not_includes new_ordered_hash.keys, "pink" + assert_includes @ordered_hash.keys, "pink" assert_instance_of ActiveSupport::OrderedHash, new_ordered_hash end @@ -155,18 +155,18 @@ class OrderedHashTest < ActiveSupport::TestCase def test_merge other_hash = ActiveSupport::OrderedHash.new - other_hash['purple'] = '800080' - other_hash['violet'] = 'ee82ee' + other_hash["purple"] = "800080" + other_hash["violet"] = "ee82ee" merged = @ordered_hash.merge other_hash assert_equal merged.length, @ordered_hash.length + other_hash.length - assert_equal @keys + ['purple', 'violet'], merged.keys + assert_equal @keys + ["purple", "violet"], merged.keys end def test_merge_with_block hash = ActiveSupport::OrderedHash.new hash[:a] = 0 hash[:b] = 0 - merged = hash.merge(:b => 2, :c => 7) do |key, old_value, new_value| + merged = hash.merge(b: 2, c: 7) do |key, old_value, new_value| new_value + 1 end @@ -179,7 +179,7 @@ class OrderedHashTest < ActiveSupport::TestCase hash = ActiveSupport::OrderedHash.new hash[:a] = 0 hash[:b] = 0 - hash.merge!(:a => 1, :c => 7) do |key, old_value, new_value| + hash.merge!(a: 1, c: 7) do |key, old_value, new_value| new_value + 3 end @@ -191,7 +191,7 @@ class OrderedHashTest < ActiveSupport::TestCase def test_shift pair = @ordered_hash.shift assert_equal [@keys.first, @values.first], pair - assert !@ordered_hash.keys.include?(pair.first) + assert_not_includes @ordered_hash.keys, pair.first end def test_keys @@ -201,7 +201,7 @@ class OrderedHashTest < ActiveSupport::TestCase end def test_inspect - assert @ordered_hash.inspect.include?(@hash.inspect) + assert_includes @ordered_hash.inspect, @hash.inspect end def test_json @@ -220,11 +220,11 @@ class OrderedHashTest < ActiveSupport::TestCase alternate = ActiveSupport::OrderedHash[ [ [1, 2], [3, 4], - [ 'missing value' ] + [ "missing value" ] ]] assert_kind_of ActiveSupport::OrderedHash, alternate - assert_equal [1, 3, 'missing value'], alternate.keys + assert_equal [1, 3, "missing value"], alternate.keys assert_equal [2, 4, nil ], alternate.values end @@ -235,14 +235,14 @@ class OrderedHashTest < ActiveSupport::TestCase end def test_replace_updates_keys - @other_ordered_hash = ActiveSupport::OrderedHash[:black, '000000', :white, '000000'] + @other_ordered_hash = ActiveSupport::OrderedHash[:black, "000000", :white, "000000"] original = @ordered_hash.replace(@other_ordered_hash) assert_same original, @ordered_hash assert_equal @other_ordered_hash.keys, @ordered_hash.keys end def test_nested_under_indifferent_access - flash = {:a => ActiveSupport::OrderedHash[:b, 1, :c, 2]}.with_indifferent_access + flash = { a: ActiveSupport::OrderedHash[:b, 1, :c, 2] }.with_indifferent_access assert_kind_of ActiveSupport::OrderedHash, flash[:a] end @@ -295,17 +295,17 @@ class OrderedHashTest < ActiveSupport::TestCase def test_psych_serialize_tag yaml = Psych.dump(@ordered_hash) - assert_match '!omap', yaml + assert_match "!omap", yaml end def test_has_yaml_tag @ordered_hash[:array] = %w(a b c) - assert_match '!omap', YAML.dump(@ordered_hash) + assert_match "!omap", YAML.dump(@ordered_hash) end def test_update_sets_keys @updated_ordered_hash = ActiveSupport::OrderedHash.new - @updated_ordered_hash.update(:name => "Bob") + @updated_ordered_hash.update(name: "Bob") assert_equal [:name], @updated_ordered_hash.keys end diff --git a/activesupport/test/ordered_options_test.rb b/activesupport/test/ordered_options_test.rb index 18767a3536..0417911289 100644 --- a/activesupport/test/ordered_options_test.rb +++ b/activesupport/test/ordered_options_test.rb @@ -1,5 +1,5 @@ -require 'abstract_unit' -require 'active_support/ordered_options' +require "abstract_unit" +require "active_support/ordered_options" class OrderedOptionsTest < ActiveSupport::TestCase def test_usage diff --git a/activesupport/test/reloader_test.rb b/activesupport/test/reloader_test.rb new file mode 100644 index 0000000000..67d8c4b0e3 --- /dev/null +++ b/activesupport/test/reloader_test.rb @@ -0,0 +1,85 @@ +require "abstract_unit" + +class ReloaderTest < ActiveSupport::TestCase + def test_prepare_callback + prepared = false + reloader.to_prepare { prepared = true } + + assert !prepared + reloader.prepare! + assert prepared + + prepared = false + reloader.wrap do + assert prepared + prepared = false + end + assert !prepared + end + + def test_only_run_when_check_passes + r = new_reloader { true } + invoked = false + r.to_run { invoked = true } + r.wrap {} + assert invoked + + r = new_reloader { false } + invoked = false + r.to_run { invoked = true } + r.wrap {} + assert !invoked + end + + def test_full_reload_sequence + called = [] + reloader.to_prepare { called << :prepare } + reloader.to_run { called << :reloader_run } + reloader.to_complete { called << :reloader_complete } + reloader.executor.to_run { called << :executor_run } + reloader.executor.to_complete { called << :executor_complete } + + reloader.wrap {} + assert_equal [:executor_run, :reloader_run, :prepare, :reloader_complete, :executor_complete], called + + called = [] + reloader.reload! + assert_equal [:executor_run, :reloader_run, :prepare, :reloader_complete, :executor_complete, :prepare], called + + reloader.check = lambda { false } + + called = [] + reloader.wrap {} + assert_equal [:executor_run, :executor_complete], called + + called = [] + reloader.reload! + assert_equal [:executor_run, :reloader_run, :prepare, :reloader_complete, :executor_complete, :prepare], called + end + + def test_class_unload_block + called = [] + reloader.before_class_unload { called << :before_unload } + reloader.after_class_unload { called << :after_unload } + reloader.to_run do + class_unload! do + called << :unload + end + end + reloader.wrap { called << :body } + + assert_equal [:before_unload, :unload, :after_unload, :body], called + end + + private + def new_reloader(&check) + Class.new(ActiveSupport::Reloader).tap do |r| + r.check = check + r.executor = Class.new(ActiveSupport::Executor) + end + end + + def reloader + @reloader ||= new_reloader { true } + end +end diff --git a/activesupport/test/rescuable_test.rb b/activesupport/test/rescuable_test.rb index bd43ad0797..7e5c3d1a8f 100644 --- a/activesupport/test/rescuable_test.rb +++ b/activesupport/test/rescuable_test.rb @@ -1,11 +1,8 @@ -require 'abstract_unit' +require "abstract_unit" class WraithAttack < StandardError end -class NuclearExplosion < StandardError -end - class MadRonon < StandardError end @@ -19,16 +16,20 @@ module WeirdError end class Stargate + # Nest this so the 'NuclearExplosion' handler needs a lexical const_get + # to find it. + class NuclearExplosion < StandardError; end + attr_accessor :result include ActiveSupport::Rescuable - rescue_from WraithAttack, :with => :sos_first + rescue_from WraithAttack, with: :sos_first - rescue_from WraithAttack, :with => :sos + rescue_from WraithAttack, with: :sos - rescue_from 'NuclearExplosion' do - @result = 'alldead' + rescue_from "NuclearExplosion" do + @result = "alldead" end rescue_from MadRonon do |e| @@ -36,7 +37,7 @@ class Stargate end rescue_from WeirdError do - @result = 'weird' + @result = "weird" end def dispatch(method) @@ -57,6 +58,14 @@ class Stargate raise MadRonon.new("dex") end + def fall_back_to_cause + # This exception is the cause and has a handler. + ronanize + rescue + # This is the exception we'll handle that doesn't have a cause. + raise "unhandled RuntimeError with a handleable cause" + end + def weird StandardError.new.tap do |exc| def exc.weird? @@ -68,13 +77,12 @@ class Stargate end def sos - @result = 'killed' + @result = "killed" end def sos_first - @result = 'sos_first' + @result = "sos_first" end - end class CoolStargate < Stargate @@ -82,14 +90,13 @@ class CoolStargate < Stargate include ActiveSupport::Rescuable - rescue_from CoolError, :with => :sos_cool_error + rescue_from CoolError, with: :sos_cool_error def sos_cool_error - @result = 'sos_cool_error' + @result = "sos_cool_error" end end - class RescuableTest < ActiveSupport::TestCase def setup @stargate = Stargate.new @@ -98,22 +105,22 @@ class RescuableTest < ActiveSupport::TestCase def test_rescue_from_with_method @stargate.dispatch :attack - assert_equal 'killed', @stargate.result + assert_equal "killed", @stargate.result end def test_rescue_from_with_block @stargate.dispatch :nuke - assert_equal 'alldead', @stargate.result + assert_equal "alldead", @stargate.result end def test_rescue_from_with_block_with_args @stargate.dispatch :ronanize - assert_equal 'dex', @stargate.result + assert_equal "dex", @stargate.result end def test_rescue_from_error_dispatchers_with_case_operator @stargate.dispatch :weird - assert_equal 'weird', @stargate.result + assert_equal "weird", @stargate.result end def test_rescues_defined_later_are_added_at_end_of_the_rescue_handlers_array @@ -127,4 +134,9 @@ class RescuableTest < ActiveSupport::TestCase result = @cool_stargate.send(:rescue_handlers).collect(&:first) assert_equal expected, result end + + def test_rescue_falls_back_to_exception_cause + @stargate.dispatch :fall_back_to_cause + assert_equal "unhandled RuntimeError with a handleable cause", @stargate.result + end end diff --git a/activesupport/test/safe_buffer_test.rb b/activesupport/test/safe_buffer_test.rb index 18fb6d2fbf..4d083ab773 100644 --- a/activesupport/test/safe_buffer_test.rb +++ b/activesupport/test/safe_buffer_test.rb @@ -1,6 +1,6 @@ -require 'abstract_unit' -require 'active_support/core_ext/string/inflections' -require 'yaml' +require "abstract_unit" +require "active_support/core_ext/string/inflections" +require "yaml" class SafeBufferTest < ActiveSupport::TestCase def setup @@ -8,7 +8,7 @@ class SafeBufferTest < ActiveSupport::TestCase end def test_titleize - assert_equal 'Foo', "foo".html_safe.titleize + assert_equal "Foo", "foo".html_safe.titleize end test "Should look like a string" do @@ -46,26 +46,26 @@ class SafeBufferTest < ActiveSupport::TestCase end test "Should be converted to_yaml" do - str = 'hello!' + str = "hello!" buf = ActiveSupport::SafeBuffer.new str yaml = buf.to_yaml assert_match(/^--- #{str}/, yaml) - assert_equal 'hello!', YAML.load(yaml) + assert_equal "hello!", YAML.load(yaml) end test "Should work in nested to_yaml conversion" do - str = 'hello!' - data = { 'str' => ActiveSupport::SafeBuffer.new(str) } + str = "hello!" + data = { "str" => ActiveSupport::SafeBuffer.new(str) } yaml = YAML.dump data - assert_equal({'str' => str}, YAML.load(yaml)) + assert_equal({ "str" => str }, YAML.load(yaml)) end test "Should work with primitive-like-strings in to_yaml conversion" do - assert_equal 'true', YAML.load(ActiveSupport::SafeBuffer.new('true').to_yaml) - assert_equal 'false', YAML.load(ActiveSupport::SafeBuffer.new('false').to_yaml) - assert_equal '1', YAML.load(ActiveSupport::SafeBuffer.new('1').to_yaml) - assert_equal '1.1', YAML.load(ActiveSupport::SafeBuffer.new('1.1').to_yaml) + assert_equal "true", YAML.load(ActiveSupport::SafeBuffer.new("true").to_yaml) + assert_equal "false", YAML.load(ActiveSupport::SafeBuffer.new("false").to_yaml) + assert_equal "1", YAML.load(ActiveSupport::SafeBuffer.new("1").to_yaml) + assert_equal "1.1", YAML.load(ActiveSupport::SafeBuffer.new("1.1").to_yaml) end test "Should work with underscore" do @@ -74,31 +74,31 @@ class SafeBufferTest < ActiveSupport::TestCase end test "Should not return safe buffer from gsub" do - altered_buffer = @buffer.gsub('', 'asdf') - assert_equal 'asdf', altered_buffer + altered_buffer = @buffer.gsub("", "asdf") + assert_equal "asdf", altered_buffer assert !altered_buffer.html_safe? end test "Should not return safe buffer from gsub!" do - @buffer.gsub!('', 'asdf') - assert_equal 'asdf', @buffer + @buffer.gsub!("", "asdf") + assert_equal "asdf", @buffer assert !@buffer.html_safe? end test "Should escape dirty buffers on add" do clean = "hello".html_safe - @buffer.gsub!('', '<>') + @buffer.gsub!("", "<>") assert_equal "hello<>", clean + @buffer end test "Should concat as a normal string when safe" do clean = "hello".html_safe - @buffer.gsub!('', '<>') + @buffer.gsub!("", "<>") assert_equal "<>hello", @buffer + clean end test "Should preserve html_safe? status on copy" do - @buffer.gsub!('', '<>') + @buffer.gsub!("", "<>") assert !@buffer.dup.html_safe? end @@ -110,7 +110,7 @@ class SafeBufferTest < ActiveSupport::TestCase end test "Should raise an error when safe_concat is called on unsafe buffers" do - @buffer.gsub!('', '<>') + @buffer.gsub!("", "<>") assert_raise ActiveSupport::SafeBuffer::SafeConcatError do @buffer.safe_concat "BUSTED" end @@ -121,12 +121,12 @@ class SafeBufferTest < ActiveSupport::TestCase end test "clone_empty returns an empty buffer" do - assert_equal '', ActiveSupport::SafeBuffer.new('foo').clone_empty + assert_equal "", ActiveSupport::SafeBuffer.new("foo").clone_empty end test "clone_empty keeps the original dirtyness" do assert @buffer.clone_empty.html_safe? - assert !@buffer.gsub!('', '').clone_empty.html_safe? + assert !@buffer.gsub!("", "").clone_empty.html_safe? end test "Should be safe when sliced if original value was safe" do @@ -136,7 +136,7 @@ class SafeBufferTest < ActiveSupport::TestCase end test "Should continue unsafe on slice" do - x = 'foo'.html_safe.gsub!('f', '<script>alert("lolpwnd");</script>') + x = "foo".html_safe.gsub!("f", '<script>alert("lolpwnd");</script>') # calling gsub! makes the dirty flag true assert !x.html_safe?, "should not be safe" @@ -148,33 +148,33 @@ class SafeBufferTest < ActiveSupport::TestCase assert !y.html_safe?, "should not be safe" end - test 'Should work with interpolation (array argument)' do - x = 'foo %s bar'.html_safe % ['qux'] - assert_equal 'foo qux bar', x + test "Should work with interpolation (array argument)" do + x = "foo %s bar".html_safe % ["qux"] + assert_equal "foo qux bar", x end - test 'Should work with interpolation (hash argument)' do - x = 'foo %{x} bar'.html_safe % { x: 'qux' } - assert_equal 'foo qux bar', x + test "Should work with interpolation (hash argument)" do + x = "foo %{x} bar".html_safe % { x: "qux" } + assert_equal "foo qux bar", x end - test 'Should escape unsafe interpolated args' do - x = 'foo %{x} bar'.html_safe % { x: '<br/>' } - assert_equal 'foo <br/> bar', x + test "Should escape unsafe interpolated args" do + x = "foo %{x} bar".html_safe % { x: "<br/>" } + assert_equal "foo <br/> bar", x end - test 'Should not escape safe interpolated args' do - x = 'foo %{x} bar'.html_safe % { x: '<br/>'.html_safe } - assert_equal 'foo <br/> bar', x + test "Should not escape safe interpolated args" do + x = "foo %{x} bar".html_safe % { x: "<br/>".html_safe } + assert_equal "foo <br/> bar", x end - test 'Should interpolate to a safe string' do - x = 'foo %{x} bar'.html_safe % { x: 'qux' } - assert x.html_safe?, 'should be safe' + test "Should interpolate to a safe string" do + x = "foo %{x} bar".html_safe % { x: "qux" } + assert x.html_safe?, "should be safe" end - test 'Should not affect frozen objects when accessing characters' do - x = 'Hello'.html_safe + test "Should not affect frozen objects when accessing characters" do + x = "Hello".html_safe assert_equal x[/a/, 1], nil end end diff --git a/activesupport/test/security_utils_test.rb b/activesupport/test/security_utils_test.rb index 08d2e3baa6..842bdd469d 100644 --- a/activesupport/test/security_utils_test.rb +++ b/activesupport/test/security_utils_test.rb @@ -1,9 +1,9 @@ -require 'abstract_unit' -require 'active_support/security_utils' +require "abstract_unit" +require "active_support/security_utils" class SecurityUtilsTest < ActiveSupport::TestCase def test_secure_compare_should_perform_string_comparison - assert ActiveSupport::SecurityUtils.secure_compare('a', 'a') - assert !ActiveSupport::SecurityUtils.secure_compare('a', 'b') + assert ActiveSupport::SecurityUtils.secure_compare("a", "a") + assert !ActiveSupport::SecurityUtils.secure_compare("a", "b") end end diff --git a/activesupport/test/share_lock_test.rb b/activesupport/test/share_lock_test.rb index acefa185a8..a5970591fa 100644 --- a/activesupport/test/share_lock_test.rb +++ b/activesupport/test/share_lock_test.rb @@ -1,6 +1,6 @@ -require 'abstract_unit' -require 'concurrent/atomic/count_down_latch' -require 'active_support/concurrency/share_lock' +require "abstract_unit" +require "concurrent/atomic/count_down_latch" +require "active_support/concurrency/share_lock" class ShareLockTest < ActiveSupport::TestCase def setup @@ -17,7 +17,7 @@ class ShareLockTest < ActiveSupport::TestCase def test_sharing_doesnt_block with_thread_waiting_in_lock_section(:sharing) do |sharing_thread_latch| - assert_threads_not_stuck(Thread.new {@lock.sharing {} }) + assert_threads_not_stuck(Thread.new { @lock.sharing {} }) end end @@ -489,90 +489,90 @@ class ShareLockTest < ActiveSupport::TestCase private - module CustomAssertions - SUFFICIENT_TIMEOUT = 0.2 + module CustomAssertions + SUFFICIENT_TIMEOUT = 0.2 - private + private - def assert_threads_stuck_but_releasable_by_latch(threads, latch) - assert_threads_stuck threads - latch.count_down - assert_threads_not_stuck threads - end + def assert_threads_stuck_but_releasable_by_latch(threads, latch) + assert_threads_stuck threads + latch.count_down + assert_threads_not_stuck threads + end - def assert_threads_stuck(threads) - sleep(SUFFICIENT_TIMEOUT) # give threads time to do their business - assert(Array(threads).all? { |t| t.join(0.001).nil? }) - end + def assert_threads_stuck(threads) + sleep(SUFFICIENT_TIMEOUT) # give threads time to do their business + assert(Array(threads).all? { |t| t.join(0.001).nil? }) + end - def assert_threads_not_stuck(threads) - assert(Array(threads).all? { |t| t.join(SUFFICIENT_TIMEOUT) }) + def assert_threads_not_stuck(threads) + assert(Array(threads).all? { |t| t.join(SUFFICIENT_TIMEOUT) }) + end end - end - class CustomAssertionsTest < ActiveSupport::TestCase - include CustomAssertions + class CustomAssertionsTest < ActiveSupport::TestCase + include CustomAssertions - def setup - @latch = Concurrent::CountDownLatch.new - @thread = Thread.new { @latch.wait } - end + def setup + @latch = Concurrent::CountDownLatch.new + @thread = Thread.new { @latch.wait } + end - def teardown - @latch.count_down - @thread.join - end + def teardown + @latch.count_down + @thread.join + end - def test_happy_path - assert_threads_stuck_but_releasable_by_latch @thread, @latch - end + def test_happy_path + assert_threads_stuck_but_releasable_by_latch @thread, @latch + end - def test_detects_stuck_thread - assert_raises(Minitest::Assertion) do - assert_threads_not_stuck @thread + def test_detects_stuck_thread + assert_raises(Minitest::Assertion) do + assert_threads_not_stuck @thread + end end - end - def test_detects_free_thread - @latch.count_down - assert_raises(Minitest::Assertion) do - assert_threads_stuck @thread + def test_detects_free_thread + @latch.count_down + assert_raises(Minitest::Assertion) do + assert_threads_stuck @thread + end end - end - def test_detects_already_released - @latch.count_down - assert_raises(Minitest::Assertion) do - assert_threads_stuck_but_releasable_by_latch @thread, @latch + def test_detects_already_released + @latch.count_down + assert_raises(Minitest::Assertion) do + assert_threads_stuck_but_releasable_by_latch @thread, @latch + end end - end - def test_detects_remains_latched - another_latch = Concurrent::CountDownLatch.new - assert_raises(Minitest::Assertion) do - assert_threads_stuck_but_releasable_by_latch @thread, another_latch + def test_detects_remains_latched + another_latch = Concurrent::CountDownLatch.new + assert_raises(Minitest::Assertion) do + assert_threads_stuck_but_releasable_by_latch @thread, another_latch + end end end - end - include CustomAssertions + include CustomAssertions - def with_thread_waiting_in_lock_section(lock_section) - in_section = Concurrent::CountDownLatch.new - section_release = Concurrent::CountDownLatch.new + def with_thread_waiting_in_lock_section(lock_section) + in_section = Concurrent::CountDownLatch.new + section_release = Concurrent::CountDownLatch.new - stuck_thread = Thread.new do - @lock.send(lock_section) do - in_section.count_down - section_release.wait + stuck_thread = Thread.new do + @lock.send(lock_section) do + in_section.count_down + section_release.wait + end end - end - in_section.wait + in_section.wait - yield section_release - ensure - section_release.count_down - stuck_thread.join # clean up - end + yield section_release + ensure + section_release.count_down + stuck_thread.join # clean up + end end diff --git a/activesupport/test/string_inquirer_test.rb b/activesupport/test/string_inquirer_test.rb index a2ed577eb0..d41e4d6800 100644 --- a/activesupport/test/string_inquirer_test.rb +++ b/activesupport/test/string_inquirer_test.rb @@ -1,8 +1,8 @@ -require 'abstract_unit' +require "abstract_unit" class StringInquirerTest < ActiveSupport::TestCase def setup - @string_inquirer = ActiveSupport::StringInquirer.new('production') + @string_inquirer = ActiveSupport::StringInquirer.new("production") end def test_match diff --git a/activesupport/test/subscriber_test.rb b/activesupport/test/subscriber_test.rb index a88d8d9eba..9127da35d4 100644 --- a/activesupport/test/subscriber_test.rb +++ b/activesupport/test/subscriber_test.rb @@ -1,5 +1,5 @@ -require 'abstract_unit' -require 'active_support/subscriber' +require "abstract_unit" +require "active_support/subscriber" class TestSubscriber < ActiveSupport::Subscriber attach_to :doodle @@ -16,9 +16,9 @@ class TestSubscriber < ActiveSupport::Subscriber private - def private_party(event) - events << event - end + def private_party(event) + events << event + end end # Monkey patch subscriber to test that only one subscriber per method is added. diff --git a/activesupport/test/tagged_logging_test.rb b/activesupport/test/tagged_logging_test.rb index 917fa46c96..2469e827d4 100644 --- a/activesupport/test/tagged_logging_test.rb +++ b/activesupport/test/tagged_logging_test.rb @@ -1,6 +1,6 @@ -require 'abstract_unit' -require 'active_support/logger' -require 'active_support/tagged_logging' +require "abstract_unit" +require "active_support/logger" +require "active_support/tagged_logging" class TaggedLoggingTest < ActiveSupport::TestCase class MyLogger < ::ActiveSupport::Logger @@ -14,7 +14,7 @@ class TaggedLoggingTest < ActiveSupport::TestCase @logger = ActiveSupport::TaggedLogging.new(MyLogger.new(@output)) end - test 'sets logger.formatter if missing and extends it with a tagging API' do + test "sets logger.formatter if missing and extends it with a tagging API" do logger = Logger.new(StringIO.new) assert_nil logger.formatter ActiveSupport::TaggedLogging.new(logger) @@ -43,14 +43,14 @@ class TaggedLoggingTest < ActiveSupport::TestCase end test "push and pop tags directly" do - assert_equal %w(A B C), @logger.push_tags('A', ['B', ' ', ['C']]) - @logger.info 'a' + assert_equal %w(A B C), @logger.push_tags("A", ["B", " ", ["C"]]) + @logger.info "a" assert_equal %w(C), @logger.pop_tags - @logger.info 'b' + @logger.info "b" assert_equal %w(B), @logger.pop_tags(1) - @logger.info 'c' + @logger.info "c" assert_equal [], @logger.clear_tags! - @logger.info 'd' + @logger.info "d" assert_equal "[A] [B] [C] a\n[A] [B] b\n[A] c\nd\n", @output.string end diff --git a/activesupport/test/test_case_test.rb b/activesupport/test/test_case_test.rb index 18228a2ac5..d769a8c145 100644 --- a/activesupport/test/test_case_test.rb +++ b/activesupport/test/test_case_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" class AssertDifferenceTest < ActiveSupport::TestCase def setup @@ -20,21 +20,21 @@ class AssertDifferenceTest < ActiveSupport::TestCase assert_equal true, assert_not(false) e = assert_raises(Minitest::Assertion) { assert_not true } - assert_equal 'Expected true to be nil or false', e.message + assert_equal "Expected true to be nil or false", e.message - e = assert_raises(Minitest::Assertion) { assert_not true, 'custom' } - assert_equal 'custom', e.message + e = assert_raises(Minitest::Assertion) { assert_not true, "custom" } + assert_equal "custom", e.message end def test_assert_no_difference_pass - assert_no_difference '@object.num' do + assert_no_difference "@object.num" do # ... end end def test_assert_no_difference_fail error = assert_raises(Minitest::Assertion) do - assert_no_difference '@object.num' do + assert_no_difference "@object.num" do @object.increment end end @@ -43,7 +43,7 @@ class AssertDifferenceTest < ActiveSupport::TestCase def test_assert_no_difference_with_message_fail error = assert_raises(Minitest::Assertion) do - assert_no_difference '@object.num', 'Object Changed' do + assert_no_difference "@object.num", "Object Changed" do @object.increment end end @@ -51,13 +51,13 @@ class AssertDifferenceTest < ActiveSupport::TestCase end def test_assert_difference - assert_difference '@object.num', +1 do + assert_difference "@object.num", +1 do @object.increment end end def test_assert_difference_retval - incremented = assert_difference '@object.num', +1 do + incremented = assert_difference "@object.num", +1 do @object.increment end @@ -65,40 +65,40 @@ class AssertDifferenceTest < ActiveSupport::TestCase end def test_assert_difference_with_implicit_difference - assert_difference '@object.num' do + assert_difference "@object.num" do @object.increment end end def test_arbitrary_expression - assert_difference '@object.num + 1', +2 do + assert_difference "@object.num + 1", +2 do @object.increment @object.increment end end def test_negative_differences - assert_difference '@object.num', -1 do + assert_difference "@object.num", -1 do @object.decrement end end def test_expression_is_evaluated_in_the_appropriate_scope silence_warnings do - local_scope = local_scope = 'foo' - assert_difference('local_scope; @object.num') { @object.increment } + local_scope = local_scope = "foo" + assert_difference("local_scope; @object.num") { @object.increment } end end def test_array_of_expressions - assert_difference [ '@object.num', '@object.num + 1' ], +1 do + assert_difference [ "@object.num", "@object.num + 1" ], +1 do @object.increment end end def test_array_of_expressions_identify_failure assert_raises(Minitest::Assertion) do - assert_difference ['@object.num', '1 + 1'] do + assert_difference ["@object.num", "1 + 1"] do @object.increment end end @@ -106,11 +106,135 @@ class AssertDifferenceTest < ActiveSupport::TestCase def test_array_of_expressions_identify_failure_when_message_provided assert_raises(Minitest::Assertion) do - assert_difference ['@object.num', '1 + 1'], 1, 'something went wrong' do + assert_difference ["@object.num", "1 + 1"], 1, "something went wrong" do @object.increment end end end + + def test_assert_changes_pass + assert_changes "@object.num" do + @object.increment + end + end + + def test_assert_changes_pass_with_lambda + assert_changes -> { @object.num } do + @object.increment + end + end + + def test_assert_changes_with_from_option + assert_changes "@object.num", from: 0 do + @object.increment + end + end + + def test_assert_changes_with_from_option_with_wrong_value + assert_raises Minitest::Assertion do + assert_changes "@object.num", from: -1 do + @object.increment + end + end + end + + def test_assert_changes_with_from_option_with_nil + error = assert_raises Minitest::Assertion do + assert_changes "@object.num", from: nil do + @object.increment + end + end + assert_equal "\"@object.num\" isn't nil", error.message + end + + def test_assert_changes_with_to_option + assert_changes "@object.num", to: 1 do + @object.increment + end + end + + def test_assert_changes_with_wrong_to_option + assert_raises Minitest::Assertion do + assert_changes "@object.num", to: 2 do + @object.increment + end + end + end + + def test_assert_changes_with_from_option_and_to_option + assert_changes "@object.num", from: 0, to: 1 do + @object.increment + end + end + + def test_assert_changes_with_from_and_to_options_and_wrong_to_value + assert_raises Minitest::Assertion do + assert_changes "@object.num", from: 0, to: 2 do + @object.increment + end + end + end + + def test_assert_changes_works_with_any_object + retval = silence_warnings do + assert_changes :@new_object, from: nil, to: 42 do + @new_object = 42 + end + end + + assert_equal 42, retval + end + + def test_assert_changes_works_with_nil + oldval = @object + + retval = assert_changes :@object, from: oldval, to: nil do + @object = nil + end + + assert_nil retval + end + + def test_assert_changes_with_to_and_case_operator + token = nil + + assert_changes "token", to: /\w{32}/ do + token = SecureRandom.hex + end + end + + def test_assert_changes_with_to_and_from_and_case_operator + token = SecureRandom.hex + + assert_changes "token", from: /\w{32}/, to: /\w{32}/ do + token = SecureRandom.hex + end + end + + def test_assert_changes_with_message + error = assert_raises Minitest::Assertion do + assert_changes "@object.num", "@object.num should 1", to: 1 do + end + end + + assert_equal "@object.num should 1.\n\"@object.num\" didn't change to 1", error.message + end + + def test_assert_no_changes_pass + assert_no_changes "@object.num" do + # ... + end + end + + def test_assert_no_changes_with_message + error = assert_raises Minitest::Assertion do + assert_no_changes "@object.num", "@object.num should not change" do + @object.increment + end + end + + assert_equal "@object.num should not change.\n\"@object.num\" did change to 1.\nExpected: 0\n Actual: 1", error.message + end end class AlsoDoingNothingTest < ActiveSupport::TestCase @@ -170,7 +294,7 @@ end class TestCaseTaggedLoggingTest < ActiveSupport::TestCase def before_setup - require 'stringio' + require "stringio" @out = StringIO.new self.tagged_logger = ActiveSupport::TaggedLogging.new(Logger.new(@out)) super diff --git a/activesupport/test/testing/constant_lookup_test.rb b/activesupport/test/testing/constant_lookup_test.rb index 0f16419c8b..00e69fcdb5 100644 --- a/activesupport/test/testing/constant_lookup_test.rb +++ b/activesupport/test/testing/constant_lookup_test.rb @@ -1,5 +1,5 @@ -require 'abstract_unit' -require 'dependencies_test_helpers' +require "abstract_unit" +require "dependencies_test_helpers" class Foo; end class Bar < Foo @@ -69,7 +69,7 @@ class ConstantLookupTest < ActiveSupport::TestCase def test_does_not_swallow_exception_on_no_name_error_within_constant assert_raises(NameError) do with_autoloading_fixtures do - self.class.determine_constant_from_test_name('RaisesNameError') + self.class.determine_constant_from_test_name("RaisesNameError") end end end diff --git a/activesupport/test/testing/file_fixtures_test.rb b/activesupport/test/testing/file_fixtures_test.rb index 91b8a9071c..e44fe58ce9 100644 --- a/activesupport/test/testing/file_fixtures_test.rb +++ b/activesupport/test/testing/file_fixtures_test.rb @@ -1,4 +1,6 @@ -require 'abstract_unit' +require "abstract_unit" + +require "pathname" class FileFixturesTest < ActiveSupport::TestCase self.file_fixture_path = File.expand_path("../../file_fixtures", __FILE__) @@ -6,7 +8,7 @@ class FileFixturesTest < ActiveSupport::TestCase test "#file_fixture returns Pathname to file fixture" do path = file_fixture("sample.txt") assert_kind_of Pathname, path - assert_match %r{activesupport/test/file_fixtures/sample.txt$}, path.to_s + assert_match %r{.*/test/file_fixtures/sample.txt$}, path.to_s end test "raises an exception when the fixture file does not exist" do @@ -23,6 +25,6 @@ class FileFixturesPathnameDirectoryTest < ActiveSupport::TestCase test "#file_fixture_path returns Pathname to file fixture" do path = file_fixture("sample.txt") assert_kind_of Pathname, path - assert_match %r{activesupport/test/file_fixtures/sample.txt$}, path.to_s + assert_match %r{.*/test/file_fixtures/sample.txt$}, path.to_s end end diff --git a/activesupport/test/testing/method_call_assertions_test.rb b/activesupport/test/testing/method_call_assertions_test.rb index 3e5ba7c079..7887933b15 100644 --- a/activesupport/test/testing/method_call_assertions_test.rb +++ b/activesupport/test/testing/method_call_assertions_test.rb @@ -1,5 +1,5 @@ -require 'abstract_unit' -require 'active_support/testing/method_call_assertions' +require "abstract_unit" +require "active_support/testing/method_call_assertions" class MethodCallAssertionsTest < ActiveSupport::TestCase include ActiveSupport::Testing::MethodCallAssertions @@ -51,7 +51,7 @@ class MethodCallAssertionsTest < ActiveSupport::TestCase def test_assert_called_with_message error = assert_raises(Minitest::Assertion) do - assert_called(@object, :increment, 'dang it') do + assert_called(@object, :increment, "dang it") do # Call nothing... end end diff --git a/activesupport/test/time_travel_test.rb b/activesupport/test/time_travel_test.rb index 59c3e52c2f..c68be329bc 100644 --- a/activesupport/test/time_travel_test.rb +++ b/activesupport/test/time_travel_test.rb @@ -1,20 +1,20 @@ -require 'abstract_unit' -require 'active_support/core_ext/date_time' -require 'active_support/core_ext/numeric/time' +require "abstract_unit" +require "active_support/core_ext/date_time" +require "active_support/core_ext/numeric/time" class TimeTravelTest < ActiveSupport::TestCase - teardown do - travel_back - end - def test_time_helper_travel Time.stub(:now, Time.now) do - expected_time = Time.now + 1.day - travel 1.day + begin + expected_time = Time.now + 1.day + travel 1.day - assert_equal expected_time.to_s(:db), Time.now.to_s(:db) - assert_equal expected_time.to_date, Date.today - assert_equal expected_time.to_datetime.to_s(:db), DateTime.now.to_s(:db) + assert_equal expected_time.to_s(:db), Time.now.to_s(:db) + assert_equal expected_time.to_date, Date.today + assert_equal expected_time.to_datetime.to_s(:db), DateTime.now.to_s(:db) + ensure + travel_back + end end end @@ -36,12 +36,16 @@ class TimeTravelTest < ActiveSupport::TestCase def test_time_helper_travel_to Time.stub(:now, Time.now) do - expected_time = Time.new(2004, 11, 24, 01, 04, 44) - travel_to expected_time + begin + expected_time = Time.new(2004, 11, 24, 01, 04, 44) + travel_to expected_time - assert_equal expected_time, Time.now - assert_equal Date.new(2004, 11, 24), Date.today - assert_equal expected_time.to_datetime, DateTime.now + assert_equal expected_time, Time.now + assert_equal Date.new(2004, 11, 24), Date.today + assert_equal expected_time.to_datetime, DateTime.now + ensure + travel_back + end end end @@ -63,17 +67,68 @@ class TimeTravelTest < ActiveSupport::TestCase def test_time_helper_travel_back Time.stub(:now, Time.now) do - expected_time = Time.new(2004, 11, 24, 01, 04, 44) + begin + expected_time = Time.new(2004, 11, 24, 01, 04, 44) - travel_to expected_time - assert_equal expected_time, Time.now - assert_equal Date.new(2004, 11, 24), Date.today - assert_equal expected_time.to_datetime, DateTime.now - travel_back + travel_to expected_time + assert_equal expected_time, Time.now + assert_equal Date.new(2004, 11, 24), Date.today + assert_equal expected_time.to_datetime, DateTime.now + travel_back - assert_not_equal expected_time, Time.now - assert_not_equal Date.new(2004, 11, 24), Date.today - assert_not_equal expected_time.to_datetime, DateTime.now + assert_not_equal expected_time, Time.now + assert_not_equal Date.new(2004, 11, 24), Date.today + assert_not_equal expected_time.to_datetime, DateTime.now + ensure + travel_back + end + end + end + + def test_time_helper_travel_to_with_nested_calls_with_blocks + Time.stub(:now, Time.now) do + outer_expected_time = Time.new(2004, 11, 24, 01, 04, 44) + inner_expected_time = Time.new(2004, 10, 24, 01, 04, 44) + travel_to outer_expected_time do + assert_raises(RuntimeError, /Calling `travel_to` with a block, when we have previously already made a call to `travel_to`, can lead to confusing time stubbing./) do + travel_to(inner_expected_time) do + #noop + end + end + end + end + end + + def test_time_helper_travel_to_with_nested_calls + Time.stub(:now, Time.now) do + outer_expected_time = Time.new(2004, 11, 24, 01, 04, 44) + inner_expected_time = Time.new(2004, 10, 24, 01, 04, 44) + travel_to outer_expected_time do + assert_nothing_raised do + travel_to(inner_expected_time) + + assert_equal inner_expected_time, Time.now + end + end + end + end + + def test_time_helper_travel_to_with_subsequent_calls + Time.stub(:now, Time.now) do + begin + initial_expected_time = Time.new(2004, 11, 24, 01, 04, 44) + subsequent_expected_time = Time.new(2004, 10, 24, 01, 04, 44) + assert_nothing_raised do + travel_to initial_expected_time + travel_to subsequent_expected_time + + assert_equal subsequent_expected_time, Time.now + + travel_back + end + ensure + travel_back + end end end diff --git a/activesupport/test/time_zone_test.rb b/activesupport/test/time_zone_test.rb index 00d40c4497..bd29584478 100644 --- a/activesupport/test/time_zone_test.rb +++ b/activesupport/test/time_zone_test.rb @@ -1,25 +1,25 @@ -require 'abstract_unit' -require 'active_support/time' -require 'time_zone_test_helpers' -require 'yaml' +require "abstract_unit" +require "active_support/time" +require "time_zone_test_helpers" +require "yaml" class TimeZoneTest < ActiveSupport::TestCase include TimeZoneTestHelpers def test_utc_to_local - zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)'] + zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"] assert_equal Time.utc(1999, 12, 31, 19), zone.utc_to_local(Time.utc(2000, 1)) # standard offset -0500 assert_equal Time.utc(2000, 6, 30, 20), zone.utc_to_local(Time.utc(2000, 7)) # dst offset -0400 end def test_local_to_utc - zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)'] + zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"] assert_equal Time.utc(2000, 1, 1, 5), zone.local_to_utc(Time.utc(2000, 1)) # standard offset -0500 assert_equal Time.utc(2000, 7, 1, 4), zone.local_to_utc(Time.utc(2000, 7)) # dst offset -0400 end def test_period_for_local - zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)'] + zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"] assert_instance_of TZInfo::TimezonePeriod, zone.period_for_local(Time.utc(2000)) end @@ -39,7 +39,7 @@ class TimeZoneTest < ActiveSupport::TestCase end ActiveSupport::TimeZone.all.each do |zone| - name = zone.name.downcase.gsub(/[^a-z]/, '_') + name = zone.name.downcase.gsub(/[^a-z]/, "_") define_method("test_from_#{name}_to_map") do assert_instance_of ActiveSupport::TimeZone, ActiveSupport::TimeZone[zone.name] end @@ -51,8 +51,8 @@ class TimeZoneTest < ActiveSupport::TestCase end def test_now - with_env_tz 'US/Eastern' do - zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)'].dup + with_env_tz "US/Eastern" do + zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"].dup def zone.time_now; Time.local(2000); end assert_instance_of ActiveSupport::TimeWithZone, zone.now assert_equal Time.utc(2000,1,1,5), zone.now.utc @@ -62,8 +62,8 @@ class TimeZoneTest < ActiveSupport::TestCase end def test_now_enforces_spring_dst_rules - with_env_tz 'US/Eastern' do - zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)'].dup + with_env_tz "US/Eastern" do + zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"].dup def zone.time_now Time.local(2006,4,2,2) # 2AM springs forward to 3AM end @@ -74,8 +74,8 @@ class TimeZoneTest < ActiveSupport::TestCase end def test_now_enforces_fall_dst_rules - with_env_tz 'US/Eastern' do - zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)'].dup + with_env_tz "US/Eastern" do + zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"].dup def zone.time_now Time.at(1162098000) # equivalent to 1AM DST end @@ -85,52 +85,52 @@ class TimeZoneTest < ActiveSupport::TestCase end def test_unknown_timezones_delegation_to_tzinfo - zone = ActiveSupport::TimeZone['America/Montevideo'] + zone = ActiveSupport::TimeZone["America/Montevideo"] assert_equal ActiveSupport::TimeZone, zone.class - assert_equal zone.object_id, ActiveSupport::TimeZone['America/Montevideo'].object_id + assert_equal zone.object_id, ActiveSupport::TimeZone["America/Montevideo"].object_id assert_equal Time.utc(2010, 1, 31, 22), zone.utc_to_local(Time.utc(2010, 2)) # daylight saving offset -0200 assert_equal Time.utc(2010, 3, 31, 21), zone.utc_to_local(Time.utc(2010, 4)) # standard offset -0300 end def test_today travel_to(Time.utc(2000, 1, 1, 4, 59, 59)) # 1 sec before midnight Jan 1 EST - assert_equal Date.new(1999, 12, 31), ActiveSupport::TimeZone['Eastern Time (US & Canada)'].today + assert_equal Date.new(1999, 12, 31), ActiveSupport::TimeZone["Eastern Time (US & Canada)"].today travel_to(Time.utc(2000, 1, 1, 5)) # midnight Jan 1 EST - assert_equal Date.new(2000, 1, 1), ActiveSupport::TimeZone['Eastern Time (US & Canada)'].today + assert_equal Date.new(2000, 1, 1), ActiveSupport::TimeZone["Eastern Time (US & Canada)"].today travel_to(Time.utc(2000, 1, 2, 4, 59, 59)) # 1 sec before midnight Jan 2 EST - assert_equal Date.new(2000, 1, 1), ActiveSupport::TimeZone['Eastern Time (US & Canada)'].today + assert_equal Date.new(2000, 1, 1), ActiveSupport::TimeZone["Eastern Time (US & Canada)"].today travel_to(Time.utc(2000, 1, 2, 5)) # midnight Jan 2 EST - assert_equal Date.new(2000, 1, 2), ActiveSupport::TimeZone['Eastern Time (US & Canada)'].today + assert_equal Date.new(2000, 1, 2), ActiveSupport::TimeZone["Eastern Time (US & Canada)"].today travel_back end def test_tomorrow travel_to(Time.utc(2000, 1, 1, 4, 59, 59)) # 1 sec before midnight Jan 1 EST - assert_equal Date.new(2000, 1, 1), ActiveSupport::TimeZone['Eastern Time (US & Canada)'].tomorrow + assert_equal Date.new(2000, 1, 1), ActiveSupport::TimeZone["Eastern Time (US & Canada)"].tomorrow travel_to(Time.utc(2000, 1, 1, 5)) # midnight Jan 1 EST - assert_equal Date.new(2000, 1, 2), ActiveSupport::TimeZone['Eastern Time (US & Canada)'].tomorrow + assert_equal Date.new(2000, 1, 2), ActiveSupport::TimeZone["Eastern Time (US & Canada)"].tomorrow travel_to(Time.utc(2000, 1, 2, 4, 59, 59)) # 1 sec before midnight Jan 2 EST - assert_equal Date.new(2000, 1, 2), ActiveSupport::TimeZone['Eastern Time (US & Canada)'].tomorrow + assert_equal Date.new(2000, 1, 2), ActiveSupport::TimeZone["Eastern Time (US & Canada)"].tomorrow travel_to(Time.utc(2000, 1, 2, 5)) # midnight Jan 2 EST - assert_equal Date.new(2000, 1, 3), ActiveSupport::TimeZone['Eastern Time (US & Canada)'].tomorrow + assert_equal Date.new(2000, 1, 3), ActiveSupport::TimeZone["Eastern Time (US & Canada)"].tomorrow travel_back end def test_yesterday travel_to(Time.utc(2000, 1, 1, 4, 59, 59)) # 1 sec before midnight Jan 1 EST - assert_equal Date.new(1999, 12, 30), ActiveSupport::TimeZone['Eastern Time (US & Canada)'].yesterday + assert_equal Date.new(1999, 12, 30), ActiveSupport::TimeZone["Eastern Time (US & Canada)"].yesterday travel_to(Time.utc(2000, 1, 1, 5)) # midnight Jan 1 EST - assert_equal Date.new(1999, 12, 31), ActiveSupport::TimeZone['Eastern Time (US & Canada)'].yesterday + assert_equal Date.new(1999, 12, 31), ActiveSupport::TimeZone["Eastern Time (US & Canada)"].yesterday travel_to(Time.utc(2000, 1, 2, 4, 59, 59)) # 1 sec before midnight Jan 2 EST - assert_equal Date.new(1999, 12, 31), ActiveSupport::TimeZone['Eastern Time (US & Canada)'].yesterday + assert_equal Date.new(1999, 12, 31), ActiveSupport::TimeZone["Eastern Time (US & Canada)"].yesterday travel_to(Time.utc(2000, 1, 2, 5)) # midnight Jan 2 EST - assert_equal Date.new(2000, 1, 1), ActiveSupport::TimeZone['Eastern Time (US & Canada)'].yesterday + assert_equal Date.new(2000, 1, 1), ActiveSupport::TimeZone["Eastern Time (US & Canada)"].yesterday travel_back end def test_travel_to_a_date with_env_tz do - Time.use_zone('Hawaii') do + Time.use_zone("Hawaii") do date = Date.new(2014, 2, 18) time = date.midnight @@ -167,37 +167,37 @@ class TimeZoneTest < ActiveSupport::TestCase end def test_local_enforces_spring_dst_rules - zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)'] + zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"] twz = zone.local(2006,4,2,1,59,59) # 1 second before DST start assert_equal Time.utc(2006,4,2,1,59,59), twz.time assert_equal Time.utc(2006,4,2,6,59,59), twz.utc assert_equal false, twz.dst? - assert_equal 'EST', twz.zone + assert_equal "EST", twz.zone twz2 = zone.local(2006,4,2,2) # 2AM does not exist because at 2AM, time springs forward to 3AM assert_equal Time.utc(2006,4,2,3), twz2.time # twz is created for 3AM assert_equal Time.utc(2006,4,2,7), twz2.utc assert_equal true, twz2.dst? - assert_equal 'EDT', twz2.zone + assert_equal "EDT", twz2.zone twz3 = zone.local(2006,4,2,2,30) # 2:30AM does not exist because at 2AM, time springs forward to 3AM assert_equal Time.utc(2006,4,2,3,30), twz3.time # twz is created for 3:30AM assert_equal Time.utc(2006,4,2,7,30), twz3.utc assert_equal true, twz3.dst? - assert_equal 'EDT', twz3.zone + assert_equal "EDT", twz3.zone end def test_local_enforces_fall_dst_rules # 1AM during fall DST transition is ambiguous, it could be either DST or non-DST 1AM # Mirroring Time.local behavior, this method selects the DST time - zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)'] + zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"] twz = zone.local(2006,10,29,1) assert_equal Time.utc(2006,10,29,1), twz.time assert_equal Time.utc(2006,10,29,5), twz.utc assert_equal true, twz.dst? - assert_equal 'EDT', twz.zone + assert_equal "EDT", twz.zone end def test_at - zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)'] + zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"] secs = 946684800.0 twz = zone.at(secs) assert_equal Time.utc(1999,12,31,19), twz.time @@ -207,7 +207,7 @@ class TimeZoneTest < ActiveSupport::TestCase end def test_at_with_old_date - zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)'] + zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"] secs = DateTime.civil(1850).to_f twz = zone.at(secs) assert_equal [1850, 1, 1, 0], [twz.utc.year, twz.utc.mon, twz.utc.day, twz.utc.hour] @@ -216,8 +216,8 @@ class TimeZoneTest < ActiveSupport::TestCase end def test_parse - zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)'] - twz = zone.parse('1999-12-31 19:00:00') + zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"] + twz = zone.parse("1999-12-31 19:00:00") assert_equal Time.utc(1999,12,31,19), twz.time assert_equal Time.utc(2000), twz.utc assert_equal zone, twz.time_zone @@ -226,97 +226,97 @@ class TimeZoneTest < ActiveSupport::TestCase def test_parse_string_with_timezone (-11..13).each do |timezone_offset| zone = ActiveSupport::TimeZone[timezone_offset] - twz = zone.parse('1999-12-31 19:00:00') + twz = zone.parse("1999-12-31 19:00:00") assert_equal twz, zone.parse(twz.to_s) end end def test_parse_with_old_date - zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)'] - twz = zone.parse('1883-12-31 19:00:00') + zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"] + twz = zone.parse("1883-12-31 19:00:00") assert_equal [0,0,19,31,12,1883], twz.to_a[0,6] assert_equal zone, twz.time_zone end def test_parse_far_future_date_with_time_zone_offset_in_string - zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)'] - twz = zone.parse('2050-12-31 19:00:00 -10:00') # i.e., 2050-01-01 05:00:00 UTC + zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"] + twz = zone.parse("2050-12-31 19:00:00 -10:00") # i.e., 2050-01-01 05:00:00 UTC assert_equal [0,0,0,1,1,2051], twz.to_a[0,6] assert_equal zone, twz.time_zone end def test_parse_returns_nil_when_string_without_date_information_is_passed_in - zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)'] - assert_nil zone.parse('foobar') - assert_nil zone.parse(' ') + zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"] + assert_nil zone.parse("foobar") + assert_nil zone.parse(" ") end def test_parse_with_incomplete_date - zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)'] + zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"] zone.stub(:now, zone.local(1999,12,31)) do - twz = zone.parse('19:00:00') + twz = zone.parse("19:00:00") assert_equal Time.utc(1999,12,31,19), twz.time end end def test_parse_with_day_omitted - with_env_tz 'US/Eastern' do - zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)'] - assert_equal Time.local(2000, 2, 1), zone.parse('Feb', Time.local(2000, 1, 1)) - assert_equal Time.local(2005, 2, 1), zone.parse('Feb 2005', Time.local(2000, 1, 1)) - assert_equal Time.local(2005, 2, 2), zone.parse('2 Feb 2005', Time.local(2000, 1, 1)) + with_env_tz "US/Eastern" do + zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"] + assert_equal Time.local(2000, 2, 1), zone.parse("Feb", Time.local(2000, 1, 1)) + assert_equal Time.local(2005, 2, 1), zone.parse("Feb 2005", Time.local(2000, 1, 1)) + assert_equal Time.local(2005, 2, 2), zone.parse("2 Feb 2005", Time.local(2000, 1, 1)) end end def test_parse_should_not_black_out_system_timezone_dst_jump - with_env_tz('EET') do - zone = ActiveSupport::TimeZone['Pacific Time (US & Canada)'] - twz = zone.parse('2012-03-25 03:29:00') + with_env_tz("EET") do + zone = ActiveSupport::TimeZone["Pacific Time (US & Canada)"] + twz = zone.parse("2012-03-25 03:29:00") assert_equal [0, 29, 3, 25, 3, 2012], twz.to_a[0,6] end end def test_parse_should_black_out_app_timezone_dst_jump - with_env_tz('EET') do - zone = ActiveSupport::TimeZone['Pacific Time (US & Canada)'] - twz = zone.parse('2012-03-11 02:29:00') + with_env_tz("EET") do + zone = ActiveSupport::TimeZone["Pacific Time (US & Canada)"] + twz = zone.parse("2012-03-11 02:29:00") assert_equal [0, 29, 3, 11, 3, 2012], twz.to_a[0,6] end end def test_parse_with_missing_time_components - zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)'] + zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"] zone.stub(:now, zone.local(1999, 12, 31, 12, 59, 59)) do - twz = zone.parse('2012-12-01') + twz = zone.parse("2012-12-01") assert_equal Time.utc(2012, 12, 1), twz.time end end def test_parse_with_javascript_date - zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)'] + zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"] twz = zone.parse("Mon May 28 2012 00:00:00 GMT-0700 (PDT)") assert_equal Time.utc(2012, 5, 28, 7, 0, 0), twz.utc end def test_parse_doesnt_use_local_dst - with_env_tz 'US/Eastern' do - zone = ActiveSupport::TimeZone['UTC'] - twz = zone.parse('2013-03-10 02:00:00') + with_env_tz "US/Eastern" do + zone = ActiveSupport::TimeZone["UTC"] + twz = zone.parse("2013-03-10 02:00:00") assert_equal Time.utc(2013, 3, 10, 2, 0, 0), twz.time end end def test_parse_handles_dst_jump - with_env_tz 'US/Eastern' do - zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)'] - twz = zone.parse('2013-03-10 02:00:00') + with_env_tz "US/Eastern" do + zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"] + twz = zone.parse("2013-03-10 02:00:00") assert_equal Time.utc(2013, 3, 10, 3, 0, 0), twz.time end end def test_strptime - zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)'] - twz = zone.strptime('1999-12-31 12:00:00', '%Y-%m-%d %H:%M:%S') + zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"] + twz = zone.strptime("1999-12-31 12:00:00", "%Y-%m-%d %H:%M:%S") assert_equal Time.utc(1999,12,31,17), twz assert_equal Time.utc(1999,12,31,12), twz.time assert_equal Time.utc(1999,12,31,17), twz.utc @@ -324,9 +324,9 @@ class TimeZoneTest < ActiveSupport::TestCase end def test_strptime_with_nondefault_time_zone - with_tz_default ActiveSupport::TimeZone['Pacific Time (US & Canada)'] do - zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)'] - twz = zone.strptime('1999-12-31 12:00:00', '%Y-%m-%d %H:%M:%S') + with_tz_default ActiveSupport::TimeZone["Pacific Time (US & Canada)"] do + zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"] + twz = zone.strptime("1999-12-31 12:00:00", "%Y-%m-%d %H:%M:%S") assert_equal Time.utc(1999,12,31,17), twz assert_equal Time.utc(1999,12,31,12), twz.time assert_equal Time.utc(1999,12,31,17), twz.utc @@ -335,8 +335,8 @@ class TimeZoneTest < ActiveSupport::TestCase end def test_strptime_with_explicit_time_zone_as_abbrev - zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)'] - twz = zone.strptime('1999-12-31 12:00:00 PST', '%Y-%m-%d %H:%M:%S %Z') + zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"] + twz = zone.strptime("1999-12-31 12:00:00 PST", "%Y-%m-%d %H:%M:%S %Z") assert_equal Time.utc(1999,12,31,20), twz assert_equal Time.utc(1999,12,31,15), twz.time assert_equal Time.utc(1999,12,31,20), twz.utc @@ -344,8 +344,8 @@ class TimeZoneTest < ActiveSupport::TestCase end def test_strptime_with_explicit_time_zone_as_h_offset - zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)'] - twz = zone.strptime('1999-12-31 12:00:00 -08', '%Y-%m-%d %H:%M:%S %:::z') + zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"] + twz = zone.strptime("1999-12-31 12:00:00 -08", "%Y-%m-%d %H:%M:%S %:::z") assert_equal Time.utc(1999,12,31,20), twz assert_equal Time.utc(1999,12,31,15), twz.time assert_equal Time.utc(1999,12,31,20), twz.utc @@ -353,8 +353,8 @@ class TimeZoneTest < ActiveSupport::TestCase end def test_strptime_with_explicit_time_zone_as_hm_offset - zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)'] - twz = zone.strptime('1999-12-31 12:00:00 -08:00', '%Y-%m-%d %H:%M:%S %:z') + zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"] + twz = zone.strptime("1999-12-31 12:00:00 -08:00", "%Y-%m-%d %H:%M:%S %:z") assert_equal Time.utc(1999,12,31,20), twz assert_equal Time.utc(1999,12,31,15), twz.time assert_equal Time.utc(1999,12,31,20), twz.utc @@ -362,8 +362,8 @@ class TimeZoneTest < ActiveSupport::TestCase end def test_strptime_with_explicit_time_zone_as_hms_offset - zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)'] - twz = zone.strptime('1999-12-31 12:00:00 -08:00:00', '%Y-%m-%d %H:%M:%S %::z') + zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"] + twz = zone.strptime("1999-12-31 12:00:00 -08:00:00", "%Y-%m-%d %H:%M:%S %::z") assert_equal Time.utc(1999,12,31,20), twz assert_equal Time.utc(1999,12,31,15), twz.time assert_equal Time.utc(1999,12,31,20), twz.utc @@ -371,8 +371,8 @@ class TimeZoneTest < ActiveSupport::TestCase end def test_strptime_with_almost_explicit_time_zone - zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)'] - twz = zone.strptime('1999-12-31 12:00:00 %Z', '%Y-%m-%d %H:%M:%S %%Z') + zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"] + twz = zone.strptime("1999-12-31 12:00:00 %Z", "%Y-%m-%d %H:%M:%S %%Z") assert_equal Time.utc(1999,12,31,17), twz assert_equal Time.utc(1999,12,31,12), twz.time assert_equal Time.utc(1999,12,31,17), twz.utc @@ -380,21 +380,57 @@ class TimeZoneTest < ActiveSupport::TestCase end def test_strptime_with_day_omitted - with_env_tz 'US/Eastern' do - zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)'] - assert_equal Time.local(2000, 2, 1), zone.strptime('Feb', '%b', Time.local(2000, 1, 1)) - assert_equal Time.local(2005, 2, 1), zone.strptime('Feb 2005', '%b %Y', Time.local(2000, 1, 1)) - assert_equal Time.local(2005, 2, 2), zone.strptime('2 Feb 2005', '%e %b %Y', Time.local(2000, 1, 1)) + with_env_tz "US/Eastern" do + zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"] + assert_equal Time.local(2000, 2, 1), zone.strptime("Feb", "%b", Time.local(2000, 1, 1)) + assert_equal Time.local(2005, 2, 1), zone.strptime("Feb 2005", "%b %Y", Time.local(2000, 1, 1)) + assert_equal Time.local(2005, 2, 2), zone.strptime("2 Feb 2005", "%e %b %Y", Time.local(2000, 1, 1)) + end + end + + def test_strptime_with_malformed_string + with_env_tz "US/Eastern" do + zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"] + assert_raise(ArgumentError) { zone.strptime("1999-12-31", "%Y/%m/%d") } + end + end + + def test_strptime_with_timestamp_seconds + with_env_tz "US/Eastern" do + zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"] + time_str = "1470272280" + time = zone.strptime(time_str, "%s") + assert_equal Time.at(1470272280), time + end + end + + def test_strptime_with_timestamp_milliseconds + with_env_tz "US/Eastern" do + zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"] + time_str = "1470272280000" + time = zone.strptime(time_str, "%Q") + assert_equal Time.at(1470272280), time end end def test_utc_offset_lazy_loaded_from_tzinfo_when_not_passed_in_to_initialize - tzinfo = TZInfo::Timezone.get('America/New_York') + tzinfo = TZInfo::Timezone.get("America/New_York") zone = ActiveSupport::TimeZone.create(tzinfo.name, nil, tzinfo) - assert_equal nil, zone.instance_variable_get('@utc_offset') + assert_equal nil, zone.instance_variable_get("@utc_offset") assert_equal(-18_000, zone.utc_offset) end + def test_utc_offset_is_not_cached_when_current_period_gets_stale + tz = ActiveSupport::TimeZone.create("Moscow") + travel_to(Time.utc(2014, 10, 25, 21)) do # 1 hour before TZ change + assert_equal 14400, tz.utc_offset, "utc_offset should be initialized according to current_period" + end + + travel_to(Time.utc(2014, 10, 25, 22)) do # after TZ change + assert_equal 10800, tz.utc_offset, "utc_offset should not be cached when current_period gets stale" + end + end + def test_seconds_to_utc_offset_with_colon assert_equal "-06:00", ActiveSupport::TimeZone.seconds_to_utc_offset(-21_600) assert_equal "+00:00", ActiveSupport::TimeZone.seconds_to_utc_offset(0) @@ -414,48 +450,48 @@ class TimeZoneTest < ActiveSupport::TestCase end def test_formatted_offset_positive - zone = ActiveSupport::TimeZone['New Delhi'] + zone = ActiveSupport::TimeZone["New Delhi"] assert_equal "+05:30", zone.formatted_offset assert_equal "+0530", zone.formatted_offset(false) end def test_formatted_offset_negative - zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)'] + zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"] assert_equal "-05:00", zone.formatted_offset assert_equal "-0500", zone.formatted_offset(false) end def test_z_format_strings - zone = ActiveSupport::TimeZone['Tokyo'] + zone = ActiveSupport::TimeZone["Tokyo"] twz = zone.now - assert_equal '+0900', twz.strftime('%z') - assert_equal '+09:00', twz.strftime('%:z') - assert_equal '+09:00:00', twz.strftime('%::z') + assert_equal "+0900", twz.strftime("%z") + assert_equal "+09:00", twz.strftime("%:z") + assert_equal "+09:00:00", twz.strftime("%::z") end def test_formatted_offset_zero - zone = ActiveSupport::TimeZone['London'] + zone = ActiveSupport::TimeZone["London"] assert_equal "+00:00", zone.formatted_offset - assert_equal "UTC", zone.formatted_offset(true, 'UTC') + assert_equal "UTC", zone.formatted_offset(true, "UTC") end def test_zone_compare - zone1 = ActiveSupport::TimeZone['Central Time (US & Canada)'] # offset -0600 - zone2 = ActiveSupport::TimeZone['Eastern Time (US & Canada)'] # offset -0500 + zone1 = ActiveSupport::TimeZone["Central Time (US & Canada)"] # offset -0600 + zone2 = ActiveSupport::TimeZone["Eastern Time (US & Canada)"] # offset -0500 assert zone1 < zone2 assert zone2 > zone1 assert zone1 == zone1 end def test_zone_match - zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)'] + zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"] assert zone =~ /Eastern/ assert zone =~ /New_York/ assert zone !~ /Nonexistent_Place/ end def test_to_s - assert_equal "(GMT+05:30) New Delhi", ActiveSupport::TimeZone['New Delhi'].to_s + assert_equal "(GMT+05:30) New Delhi", ActiveSupport::TimeZone["New Delhi"].to_s end def test_all_sorted @@ -487,8 +523,13 @@ class TimeZoneTest < ActiveSupport::TestCase end def test_us_zones - assert ActiveSupport::TimeZone.us_zones.include?(ActiveSupport::TimeZone["Hawaii"]) - assert !ActiveSupport::TimeZone.us_zones.include?(ActiveSupport::TimeZone["Kuala Lumpur"]) + assert_includes ActiveSupport::TimeZone.us_zones, ActiveSupport::TimeZone["Hawaii"] + assert_not_includes ActiveSupport::TimeZone.us_zones, ActiveSupport::TimeZone["Kuala Lumpur"] + end + + def test_country_zones + assert_includes ActiveSupport::TimeZone.country_zones("ru"), ActiveSupport::TimeZone["Moscow"] + assert_not_includes ActiveSupport::TimeZone.country_zones(:ru), ActiveSupport::TimeZone["Kuala Lumpur"] end def test_to_yaml diff --git a/activesupport/test/time_zone_test_helpers.rb b/activesupport/test/time_zone_test_helpers.rb index 9632b89d09..e1d615d154 100644 --- a/activesupport/test/time_zone_test_helpers.rb +++ b/activesupport/test/time_zone_test_helpers.rb @@ -7,10 +7,18 @@ module TimeZoneTestHelpers Time.zone = old_tz end - def with_env_tz(new_tz = 'US/Eastern') - old_tz, ENV['TZ'] = ENV['TZ'], new_tz + def with_env_tz(new_tz = "US/Eastern") + old_tz, ENV["TZ"] = ENV["TZ"], new_tz yield ensure - old_tz ? ENV['TZ'] = old_tz : ENV.delete('TZ') + old_tz ? ENV["TZ"] = old_tz : ENV.delete("TZ") + end + + def with_preserve_timezone(value) + old_preserve_tz = ActiveSupport.to_time_preserves_timezone + ActiveSupport.to_time_preserves_timezone = value + yield + ensure + ActiveSupport.to_time_preserves_timezone = old_preserve_tz end end diff --git a/activesupport/test/transliterate_test.rb b/activesupport/test/transliterate_test.rb index 378421fedd..040ddd25fc 100644 --- a/activesupport/test/transliterate_test.rb +++ b/activesupport/test/transliterate_test.rb @@ -1,5 +1,5 @@ -require 'abstract_unit' -require 'active_support/inflector/transliterate' +require "abstract_unit" +require "active_support/inflector/transliterate" class TransliterateTest < ActiveSupport::TestCase def test_transliterate_should_not_change_ascii_chars @@ -13,7 +13,7 @@ class TransliterateTest < ActiveSupport::TestCase # create string with range of Unicode's western characters with # diacritics, excluding the division and multiplication signs which for # some reason or other are floating in the middle of all the letters. - string = (0xC0..0x17E).to_a.reject {|c| [0xD7, 0xF7].include?(c)}.pack("U*") + string = (0xC0..0x17E).to_a.reject { |c| [0xD7, 0xF7].include?(c) }.pack("U*") string.each_char do |char| assert_match %r{^[a-zA-Z']*$}, ActiveSupport::Inflector.transliterate(char) end @@ -21,7 +21,7 @@ class TransliterateTest < ActiveSupport::TestCase def test_transliterate_should_work_with_custom_i18n_rules_and_uncomposed_utf8 char = [117, 776].pack("U*") # "ü" as ASCII "u" plus COMBINING DIAERESIS - I18n.backend.store_translations(:de, :i18n => {:transliterate => {:rule => {"ü" => "ue"}}}) + I18n.backend.store_translations(:de, i18n: { transliterate: { rule: { "ü" => "ue" } } }) default_locale, I18n.locale = I18n.locale, :de assert_equal "ue", ActiveSupport::Inflector.transliterate(char) ensure diff --git a/activesupport/test/xml_mini/jdom_engine_test.rb b/activesupport/test/xml_mini/jdom_engine_test.rb index ed4de8aba2..816d57972c 100644 --- a/activesupport/test/xml_mini/jdom_engine_test.rb +++ b/activesupport/test/xml_mini/jdom_engine_test.rb @@ -1,17 +1,16 @@ -if RUBY_PLATFORM =~ /java/ - require 'abstract_unit' - require 'active_support/xml_mini' - require 'active_support/core_ext/hash/conversions' - +if RUBY_PLATFORM.include?("java") + require "abstract_unit" + require "active_support/xml_mini" + require "active_support/core_ext/hash/conversions" class JDOMEngineTest < ActiveSupport::TestCase include ActiveSupport - FILES_DIR = File.dirname(__FILE__) + '/../fixtures/xml' + FILES_DIR = File.dirname(__FILE__) + "/../fixtures/xml" def setup @default_backend = XmlMini.backend - XmlMini.backend = 'JDOM' + XmlMini.backend = "JDOM" end def teardown @@ -19,18 +18,18 @@ if RUBY_PLATFORM =~ /java/ end def test_file_from_xml - hash = Hash.from_xml(<<-eoxml) + hash = Hash.from_xml(<<-eoxml) <blog> <logo type="file" name="logo.png" content_type="image/png"> </logo> </blog> eoxml - assert hash.has_key?('blog') - assert hash['blog'].has_key?('logo') + assert hash.has_key?("blog") + assert hash["blog"].has_key?("logo") - file = hash['blog']['logo'] - assert_equal 'logo.png', file.original_filename - assert_equal 'image/png', file.content_type + file = hash["blog"]["logo"] + assert_equal "logo.png", file.original_filename + assert_equal "image/png", file.content_type end def test_not_allowed_to_expand_entities_to_files @@ -40,7 +39,7 @@ if RUBY_PLATFORM =~ /java/ ]> <member>x&a;</member> EOT - assert_equal 'x', Hash.from_xml(attack_xml)["member"] + assert_equal "x", Hash.from_xml(attack_xml)["member"] end def test_not_allowed_to_expand_parameter_entities_to_files @@ -52,17 +51,16 @@ if RUBY_PLATFORM =~ /java/ <member>x&a;</member> EOT assert_raise Java::OrgXmlSax::SAXParseException do - assert_equal 'x', Hash.from_xml(attack_xml)["member"] + assert_equal "x", Hash.from_xml(attack_xml)["member"] end end - def test_not_allowed_to_load_external_doctypes attack_xml = <<-EOT <!DOCTYPE member SYSTEM "file://#{FILES_DIR}/jdom_doctype.dtd"> <member>x&a;</member> EOT - assert_equal 'x', Hash.from_xml(attack_xml)["member"] + assert_equal "x", Hash.from_xml(attack_xml)["member"] end def test_exception_thrown_on_expansion_attack @@ -86,13 +84,13 @@ if RUBY_PLATFORM =~ /java/ end def test_setting_JDOM_as_backend - XmlMini.backend = 'JDOM' + XmlMini.backend = "JDOM" assert_equal XmlMini_JDOM, XmlMini.backend end def test_blank_returns_empty_hash assert_equal({}, XmlMini.parse(nil)) - assert_equal({}, XmlMini.parse('')) + assert_equal({}, XmlMini.parse("")) end def test_array_type_makes_an_array @@ -178,11 +176,8 @@ if RUBY_PLATFORM =~ /java/ private def assert_equal_rexml(xml) parsed_xml = XmlMini.parse(xml) - hash = XmlMini.with_backend('REXML') { XmlMini.parse(xml) } + hash = XmlMini.with_backend("REXML") { XmlMini.parse(xml) } assert_equal(hash, parsed_xml) end end - -else - # don't run these test because we aren't running in JRuby end diff --git a/activesupport/test/xml_mini/libxml_engine_test.rb b/activesupport/test/xml_mini/libxml_engine_test.rb index a8df2e1f7b..81b0d3c407 100644 --- a/activesupport/test/xml_mini/libxml_engine_test.rb +++ b/activesupport/test/xml_mini/libxml_engine_test.rb @@ -1,58 +1,58 @@ begin - require 'libxml' + require "libxml" rescue LoadError # Skip libxml tests else -require 'abstract_unit' -require 'active_support/xml_mini' -require 'active_support/core_ext/hash/conversions' + require "abstract_unit" + require "active_support/xml_mini" + require "active_support/core_ext/hash/conversions" -class LibxmlEngineTest < ActiveSupport::TestCase - include ActiveSupport + class LibxmlEngineTest < ActiveSupport::TestCase + include ActiveSupport - def setup - @default_backend = XmlMini.backend - XmlMini.backend = 'LibXML' + def setup + @default_backend = XmlMini.backend + XmlMini.backend = "LibXML" - LibXML::XML::Error.set_handler(&lambda { |error| }) #silence libxml, exceptions will do - end + LibXML::XML::Error.set_handler(&lambda { |error| }) #silence libxml, exceptions will do + end - def teardown - XmlMini.backend = @default_backend - end + def teardown + XmlMini.backend = @default_backend + end - def test_exception_thrown_on_expansion_attack - assert_raise LibXML::XML::Error do - attack_xml = %{<?xml version="1.0" encoding="UTF-8"?> - <!DOCTYPE member [ - <!ENTITY a "&b;&b;&b;&b;&b;&b;&b;&b;&b;&b;"> - <!ENTITY b "&c;&c;&c;&c;&c;&c;&c;&c;&c;&c;"> - <!ENTITY c "&d;&d;&d;&d;&d;&d;&d;&d;&d;&d;"> - <!ENTITY d "&e;&e;&e;&e;&e;&e;&e;&e;&e;&e;"> - <!ENTITY e "&f;&f;&f;&f;&f;&f;&f;&f;&f;&f;"> - <!ENTITY f "&g;&g;&g;&g;&g;&g;&g;&g;&g;&g;"> - <!ENTITY g "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"> - ]> - <member> - &a; - </member> - } - Hash.from_xml(attack_xml) + def test_exception_thrown_on_expansion_attack + assert_raise LibXML::XML::Error do + attack_xml = %{<?xml version="1.0" encoding="UTF-8"?> + <!DOCTYPE member [ + <!ENTITY a "&b;&b;&b;&b;&b;&b;&b;&b;&b;&b;"> + <!ENTITY b "&c;&c;&c;&c;&c;&c;&c;&c;&c;&c;"> + <!ENTITY c "&d;&d;&d;&d;&d;&d;&d;&d;&d;&d;"> + <!ENTITY d "&e;&e;&e;&e;&e;&e;&e;&e;&e;&e;"> + <!ENTITY e "&f;&f;&f;&f;&f;&f;&f;&f;&f;&f;"> + <!ENTITY f "&g;&g;&g;&g;&g;&g;&g;&g;&g;&g;"> + <!ENTITY g "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"> + ]> + <member> + &a; + </member> + } + Hash.from_xml(attack_xml) + end end - end - def test_setting_libxml_as_backend - XmlMini.backend = 'LibXML' - assert_equal XmlMini_LibXML, XmlMini.backend - end + def test_setting_libxml_as_backend + XmlMini.backend = "LibXML" + assert_equal XmlMini_LibXML, XmlMini.backend + end - def test_blank_returns_empty_hash - assert_equal({}, XmlMini.parse(nil)) - assert_equal({}, XmlMini.parse('')) - end + def test_blank_returns_empty_hash + assert_equal({}, XmlMini.parse(nil)) + assert_equal({}, XmlMini.parse("")) + end - def test_array_type_makes_an_array - assert_equal_rexml(<<-eoxml) + def test_array_type_makes_an_array + assert_equal_rexml(<<-eoxml) <blog> <posts type="array"> <post>a post</post> @@ -60,67 +60,67 @@ class LibxmlEngineTest < ActiveSupport::TestCase </posts> </blog> eoxml - end + end - def test_one_node_document_as_hash - assert_equal_rexml(<<-eoxml) - <products/> - eoxml - end + def test_one_node_document_as_hash + assert_equal_rexml(<<-eoxml) + <products/> + eoxml + end - def test_one_node_with_attributes_document_as_hash - assert_equal_rexml(<<-eoxml) - <products foo="bar"/> - eoxml - end + def test_one_node_with_attributes_document_as_hash + assert_equal_rexml(<<-eoxml) + <products foo="bar"/> + eoxml + end - def test_products_node_with_book_node_as_hash - assert_equal_rexml(<<-eoxml) + def test_products_node_with_book_node_as_hash + assert_equal_rexml(<<-eoxml) <products> <book name="awesome" id="12345" /> </products> eoxml - end + end - def test_products_node_with_two_book_nodes_as_hash - assert_equal_rexml(<<-eoxml) + def test_products_node_with_two_book_nodes_as_hash + assert_equal_rexml(<<-eoxml) <products> <book name="awesome" id="12345" /> <book name="america" id="67890" /> </products> eoxml - end + end - def test_single_node_with_content_as_hash - assert_equal_rexml(<<-eoxml) + def test_single_node_with_content_as_hash + assert_equal_rexml(<<-eoxml) <products> hello world </products> eoxml - end + end - def test_children_with_children - assert_equal_rexml(<<-eoxml) + def test_children_with_children + assert_equal_rexml(<<-eoxml) <root> <products> <book name="america" id="67890" /> </products> </root> eoxml - end + end - def test_children_with_text - assert_equal_rexml(<<-eoxml) + def test_children_with_text + assert_equal_rexml(<<-eoxml) <root> <products> hello everyone </products> </root> eoxml - end + end - def test_children_with_non_adjacent_text - assert_equal_rexml(<<-eoxml) + def test_children_with_non_adjacent_text + assert_equal_rexml(<<-eoxml) <root> good <products> @@ -129,10 +129,10 @@ class LibxmlEngineTest < ActiveSupport::TestCase morning </root> eoxml - end + end - def test_parse_from_io - io = StringIO.new(<<-eoxml) + def test_parse_from_io + io = StringIO.new(<<-eoxml) <root> good <products> @@ -141,31 +141,31 @@ class LibxmlEngineTest < ActiveSupport::TestCase morning </root> eoxml - assert_equal_rexml(io) - end + assert_equal_rexml(io) + end - def test_children_with_simple_cdata - assert_equal_rexml(<<-eoxml) + def test_children_with_simple_cdata + assert_equal_rexml(<<-eoxml) <root> <products> <![CDATA[cdatablock]]> </products> </root> eoxml - end + end - def test_children_with_multiple_cdata - assert_equal_rexml(<<-eoxml) + def test_children_with_multiple_cdata + assert_equal_rexml(<<-eoxml) <root> <products> <![CDATA[cdatablock1]]><![CDATA[cdatablock2]]> </products> </root> eoxml - end + end - def test_children_with_text_and_cdata - assert_equal_rexml(<<-eoxml) + def test_children_with_text_and_cdata + assert_equal_rexml(<<-eoxml) <root> <products> hello <![CDATA[cdatablock]]> @@ -173,32 +173,31 @@ class LibxmlEngineTest < ActiveSupport::TestCase </products> </root> eoxml - end + end - def test_children_with_blank_text - assert_equal_rexml(<<-eoxml) + def test_children_with_blank_text + assert_equal_rexml(<<-eoxml) <root> <products> </products> </root> eoxml - end + end - def test_children_with_blank_text_and_attribute - assert_equal_rexml(<<-eoxml) + def test_children_with_blank_text_and_attribute + assert_equal_rexml(<<-eoxml) <root> <products type="file"> </products> </root> eoxml - end - - - private - def assert_equal_rexml(xml) - parsed_xml = XmlMini.parse(xml) - xml.rewind if xml.respond_to?(:rewind) - hash = XmlMini.with_backend('REXML') { XmlMini.parse(xml) } - assert_equal(hash, parsed_xml) end -end + + private + def assert_equal_rexml(xml) + parsed_xml = XmlMini.parse(xml) + xml.rewind if xml.respond_to?(:rewind) + hash = XmlMini.with_backend("REXML") { XmlMini.parse(xml) } + assert_equal(hash, parsed_xml) + end + end end diff --git a/activesupport/test/xml_mini/libxmlsax_engine_test.rb b/activesupport/test/xml_mini/libxmlsax_engine_test.rb index d6d90639e2..e25fa2813c 100644 --- a/activesupport/test/xml_mini/libxmlsax_engine_test.rb +++ b/activesupport/test/xml_mini/libxmlsax_engine_test.rb @@ -1,27 +1,27 @@ begin - require 'libxml' + require "libxml" rescue LoadError # Skip libxml tests else -require 'abstract_unit' -require 'active_support/xml_mini' -require 'active_support/core_ext/hash/conversions' + require "abstract_unit" + require "active_support/xml_mini" + require "active_support/core_ext/hash/conversions" -class LibXMLSAXEngineTest < ActiveSupport::TestCase - include ActiveSupport + class LibXMLSAXEngineTest < ActiveSupport::TestCase + include ActiveSupport - def setup - @default_backend = XmlMini.backend - XmlMini.backend = 'LibXMLSAX' - end + def setup + @default_backend = XmlMini.backend + XmlMini.backend = "LibXMLSAX" + end - def teardown - XmlMini.backend = @default_backend - end + def teardown + XmlMini.backend = @default_backend + end - def test_exception_thrown_on_expansion_attack - assert_raise LibXML::XML::Error do - attack_xml = <<-EOT + def test_exception_thrown_on_expansion_attack + assert_raise LibXML::XML::Error do + attack_xml = <<-EOT <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE member [ <!ENTITY a "&b;&b;&b;&b;&b;&b;&b;&b;&b;&b;"> @@ -37,22 +37,22 @@ class LibXMLSAXEngineTest < ActiveSupport::TestCase </member> EOT - Hash.from_xml(attack_xml) + Hash.from_xml(attack_xml) + end end - end - def test_setting_libxml_as_backend - XmlMini.backend = 'LibXMLSAX' - assert_equal XmlMini_LibXMLSAX, XmlMini.backend - end + def test_setting_libxml_as_backend + XmlMini.backend = "LibXMLSAX" + assert_equal XmlMini_LibXMLSAX, XmlMini.backend + end - def test_blank_returns_empty_hash - assert_equal({}, XmlMini.parse(nil)) - assert_equal({}, XmlMini.parse('')) - end + def test_blank_returns_empty_hash + assert_equal({}, XmlMini.parse(nil)) + assert_equal({}, XmlMini.parse("")) + end - def test_array_type_makes_an_array - assert_equal_rexml(<<-eoxml) + def test_array_type_makes_an_array + assert_equal_rexml(<<-eoxml) <blog> <posts type="array"> <post>a post</post> @@ -60,67 +60,67 @@ class LibXMLSAXEngineTest < ActiveSupport::TestCase </posts> </blog> eoxml - end + end - def test_one_node_document_as_hash - assert_equal_rexml(<<-eoxml) - <products/> - eoxml - end + def test_one_node_document_as_hash + assert_equal_rexml(<<-eoxml) + <products/> + eoxml + end - def test_one_node_with_attributes_document_as_hash - assert_equal_rexml(<<-eoxml) - <products foo="bar"/> - eoxml - end + def test_one_node_with_attributes_document_as_hash + assert_equal_rexml(<<-eoxml) + <products foo="bar"/> + eoxml + end - def test_products_node_with_book_node_as_hash - assert_equal_rexml(<<-eoxml) + def test_products_node_with_book_node_as_hash + assert_equal_rexml(<<-eoxml) <products> <book name="awesome" id="12345" /> </products> eoxml - end + end - def test_products_node_with_two_book_nodes_as_hash - assert_equal_rexml(<<-eoxml) + def test_products_node_with_two_book_nodes_as_hash + assert_equal_rexml(<<-eoxml) <products> <book name="awesome" id="12345" /> <book name="america" id="67890" /> </products> eoxml - end + end - def test_single_node_with_content_as_hash - assert_equal_rexml(<<-eoxml) + def test_single_node_with_content_as_hash + assert_equal_rexml(<<-eoxml) <products> hello world </products> eoxml - end + end - def test_children_with_children - assert_equal_rexml(<<-eoxml) + def test_children_with_children + assert_equal_rexml(<<-eoxml) <root> <products> <book name="america" id="67890" /> </products> </root> eoxml - end + end - def test_children_with_text - assert_equal_rexml(<<-eoxml) + def test_children_with_text + assert_equal_rexml(<<-eoxml) <root> <products> hello everyone </products> </root> eoxml - end + end - def test_children_with_non_adjacent_text - assert_equal_rexml(<<-eoxml) + def test_children_with_non_adjacent_text + assert_equal_rexml(<<-eoxml) <root> good <products> @@ -129,10 +129,10 @@ class LibXMLSAXEngineTest < ActiveSupport::TestCase morning </root> eoxml - end + end - def test_parse_from_io - io = StringIO.new(<<-eoxml) + def test_parse_from_io + io = StringIO.new(<<-eoxml) <root> good <products> @@ -141,31 +141,31 @@ class LibXMLSAXEngineTest < ActiveSupport::TestCase morning </root> eoxml - assert_equal_rexml(io) - end + assert_equal_rexml(io) + end - def test_children_with_simple_cdata - assert_equal_rexml(<<-eoxml) + def test_children_with_simple_cdata + assert_equal_rexml(<<-eoxml) <root> <products> <![CDATA[cdatablock]]> </products> </root> eoxml - end + end - def test_children_with_multiple_cdata - assert_equal_rexml(<<-eoxml) + def test_children_with_multiple_cdata + assert_equal_rexml(<<-eoxml) <root> <products> <![CDATA[cdatablock1]]><![CDATA[cdatablock2]]> </products> </root> eoxml - end + end - def test_children_with_text_and_cdata - assert_equal_rexml(<<-eoxml) + def test_children_with_text_and_cdata + assert_equal_rexml(<<-eoxml) <root> <products> hello <![CDATA[cdatablock]]> @@ -173,23 +173,23 @@ class LibXMLSAXEngineTest < ActiveSupport::TestCase </products> </root> eoxml - end + end - def test_children_with_blank_text - assert_equal_rexml(<<-eoxml) + def test_children_with_blank_text + assert_equal_rexml(<<-eoxml) <root> <products> </products> </root> eoxml - end - - private - def assert_equal_rexml(xml) - parsed_xml = XmlMini.parse(xml) - xml.rewind if xml.respond_to?(:rewind) - hash = XmlMini.with_backend('REXML') { XmlMini.parse(xml) } - assert_equal(hash, parsed_xml) end -end + + private + def assert_equal_rexml(xml) + parsed_xml = XmlMini.parse(xml) + xml.rewind if xml.respond_to?(:rewind) + hash = XmlMini.with_backend("REXML") { XmlMini.parse(xml) } + assert_equal(hash, parsed_xml) + end + end end diff --git a/activesupport/test/xml_mini/nokogiri_engine_test.rb b/activesupport/test/xml_mini/nokogiri_engine_test.rb index 1314c9065a..44b82da4e4 100644 --- a/activesupport/test/xml_mini/nokogiri_engine_test.rb +++ b/activesupport/test/xml_mini/nokogiri_engine_test.rb @@ -1,40 +1,40 @@ begin - require 'nokogiri' + require "nokogiri" rescue LoadError # Skip nokogiri tests else -require 'abstract_unit' -require 'active_support/xml_mini' -require 'active_support/core_ext/hash/conversions' - -class NokogiriEngineTest < ActiveSupport::TestCase - def setup - @default_backend = ActiveSupport::XmlMini.backend - ActiveSupport::XmlMini.backend = 'Nokogiri' - end + require "abstract_unit" + require "active_support/xml_mini" + require "active_support/core_ext/hash/conversions" + + class NokogiriEngineTest < ActiveSupport::TestCase + def setup + @default_backend = ActiveSupport::XmlMini.backend + ActiveSupport::XmlMini.backend = "Nokogiri" + end - def teardown - ActiveSupport::XmlMini.backend = @default_backend - end + def teardown + ActiveSupport::XmlMini.backend = @default_backend + end - def test_file_from_xml - hash = Hash.from_xml(<<-eoxml) + def test_file_from_xml + hash = Hash.from_xml(<<-eoxml) <blog> <logo type="file" name="logo.png" content_type="image/png"> </logo> </blog> eoxml - assert hash.has_key?('blog') - assert hash['blog'].has_key?('logo') + assert hash.has_key?("blog") + assert hash["blog"].has_key?("logo") - file = hash['blog']['logo'] - assert_equal 'logo.png', file.original_filename - assert_equal 'image/png', file.content_type - end + file = hash["blog"]["logo"] + assert_equal "logo.png", file.original_filename + assert_equal "image/png", file.content_type + end - def test_exception_thrown_on_expansion_attack - assert_raise Nokogiri::XML::SyntaxError do - attack_xml = <<-EOT + def test_exception_thrown_on_expansion_attack + assert_raise Nokogiri::XML::SyntaxError do + attack_xml = <<-EOT <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE member [ <!ENTITY a "&b;&b;&b;&b;&b;&b;&b;&b;&b;&b;"> @@ -49,22 +49,22 @@ class NokogiriEngineTest < ActiveSupport::TestCase &a; </member> EOT - Hash.from_xml(attack_xml) + Hash.from_xml(attack_xml) + end end - end - def test_setting_nokogiri_as_backend - ActiveSupport::XmlMini.backend = 'Nokogiri' - assert_equal ActiveSupport::XmlMini_Nokogiri, ActiveSupport::XmlMini.backend - end + def test_setting_nokogiri_as_backend + ActiveSupport::XmlMini.backend = "Nokogiri" + assert_equal ActiveSupport::XmlMini_Nokogiri, ActiveSupport::XmlMini.backend + end - def test_blank_returns_empty_hash - assert_equal({}, ActiveSupport::XmlMini.parse(nil)) - assert_equal({}, ActiveSupport::XmlMini.parse('')) - end + def test_blank_returns_empty_hash + assert_equal({}, ActiveSupport::XmlMini.parse(nil)) + assert_equal({}, ActiveSupport::XmlMini.parse("")) + end - def test_array_type_makes_an_array - assert_equal_rexml(<<-eoxml) + def test_array_type_makes_an_array + assert_equal_rexml(<<-eoxml) <blog> <posts type="array"> <post>a post</post> @@ -72,67 +72,67 @@ class NokogiriEngineTest < ActiveSupport::TestCase </posts> </blog> eoxml - end + end - def test_one_node_document_as_hash - assert_equal_rexml(<<-eoxml) - <products/> - eoxml - end + def test_one_node_document_as_hash + assert_equal_rexml(<<-eoxml) + <products/> + eoxml + end - def test_one_node_with_attributes_document_as_hash - assert_equal_rexml(<<-eoxml) - <products foo="bar"/> - eoxml - end + def test_one_node_with_attributes_document_as_hash + assert_equal_rexml(<<-eoxml) + <products foo="bar"/> + eoxml + end - def test_products_node_with_book_node_as_hash - assert_equal_rexml(<<-eoxml) + def test_products_node_with_book_node_as_hash + assert_equal_rexml(<<-eoxml) <products> <book name="awesome" id="12345" /> </products> eoxml - end + end - def test_products_node_with_two_book_nodes_as_hash - assert_equal_rexml(<<-eoxml) + def test_products_node_with_two_book_nodes_as_hash + assert_equal_rexml(<<-eoxml) <products> <book name="awesome" id="12345" /> <book name="america" id="67890" /> </products> eoxml - end + end - def test_single_node_with_content_as_hash - assert_equal_rexml(<<-eoxml) + def test_single_node_with_content_as_hash + assert_equal_rexml(<<-eoxml) <products> hello world </products> eoxml - end + end - def test_children_with_children - assert_equal_rexml(<<-eoxml) + def test_children_with_children + assert_equal_rexml(<<-eoxml) <root> <products> <book name="america" id="67890" /> </products> </root> eoxml - end + end - def test_children_with_text - assert_equal_rexml(<<-eoxml) + def test_children_with_text + assert_equal_rexml(<<-eoxml) <root> <products> hello everyone </products> </root> eoxml - end + end - def test_children_with_non_adjacent_text - assert_equal_rexml(<<-eoxml) + def test_children_with_non_adjacent_text + assert_equal_rexml(<<-eoxml) <root> good <products> @@ -141,10 +141,10 @@ class NokogiriEngineTest < ActiveSupport::TestCase morning </root> eoxml - end + end - def test_parse_from_io - io = StringIO.new(<<-eoxml) + def test_parse_from_io + io = StringIO.new(<<-eoxml) <root> good <products> @@ -153,31 +153,31 @@ class NokogiriEngineTest < ActiveSupport::TestCase morning </root> eoxml - assert_equal_rexml(io) - end + assert_equal_rexml(io) + end - def test_children_with_simple_cdata - assert_equal_rexml(<<-eoxml) + def test_children_with_simple_cdata + assert_equal_rexml(<<-eoxml) <root> <products> <![CDATA[cdatablock]]> </products> </root> eoxml - end + end - def test_children_with_multiple_cdata - assert_equal_rexml(<<-eoxml) + def test_children_with_multiple_cdata + assert_equal_rexml(<<-eoxml) <root> <products> <![CDATA[cdatablock1]]><![CDATA[cdatablock2]]> </products> </root> eoxml - end + end - def test_children_with_text_and_cdata - assert_equal_rexml(<<-eoxml) + def test_children_with_text_and_cdata + assert_equal_rexml(<<-eoxml) <root> <products> hello <![CDATA[cdatablock]]> @@ -185,31 +185,31 @@ class NokogiriEngineTest < ActiveSupport::TestCase </products> </root> eoxml - end + end - def test_children_with_blank_text - assert_equal_rexml(<<-eoxml) + def test_children_with_blank_text + assert_equal_rexml(<<-eoxml) <root> <products> </products> </root> eoxml - end + end - def test_children_with_blank_text_and_attribute - assert_equal_rexml(<<-eoxml) + def test_children_with_blank_text_and_attribute + assert_equal_rexml(<<-eoxml) <root> <products type="file"> </products> </root> eoxml - end - - private - def assert_equal_rexml(xml) - parsed_xml = ActiveSupport::XmlMini.parse(xml) - xml.rewind if xml.respond_to?(:rewind) - hash = ActiveSupport::XmlMini.with_backend('REXML') { ActiveSupport::XmlMini.parse(xml) } - assert_equal(hash, parsed_xml) end -end + + private + def assert_equal_rexml(xml) + parsed_xml = ActiveSupport::XmlMini.parse(xml) + xml.rewind if xml.respond_to?(:rewind) + hash = ActiveSupport::XmlMini.with_backend("REXML") { ActiveSupport::XmlMini.parse(xml) } + assert_equal(hash, parsed_xml) + end + end end diff --git a/activesupport/test/xml_mini/nokogirisax_engine_test.rb b/activesupport/test/xml_mini/nokogirisax_engine_test.rb index 7978a50921..24b35cadf6 100644 --- a/activesupport/test/xml_mini/nokogirisax_engine_test.rb +++ b/activesupport/test/xml_mini/nokogirisax_engine_test.rb @@ -1,40 +1,40 @@ begin - require 'nokogiri' + require "nokogiri" rescue LoadError # Skip nokogiri tests else -require 'abstract_unit' -require 'active_support/xml_mini' -require 'active_support/core_ext/hash/conversions' - -class NokogiriSAXEngineTest < ActiveSupport::TestCase - def setup - @default_backend = ActiveSupport::XmlMini.backend - ActiveSupport::XmlMini.backend = 'NokogiriSAX' - end + require "abstract_unit" + require "active_support/xml_mini" + require "active_support/core_ext/hash/conversions" + + class NokogiriSAXEngineTest < ActiveSupport::TestCase + def setup + @default_backend = ActiveSupport::XmlMini.backend + ActiveSupport::XmlMini.backend = "NokogiriSAX" + end - def teardown - ActiveSupport::XmlMini.backend = @default_backend - end + def teardown + ActiveSupport::XmlMini.backend = @default_backend + end - def test_file_from_xml - hash = Hash.from_xml(<<-eoxml) + def test_file_from_xml + hash = Hash.from_xml(<<-eoxml) <blog> <logo type="file" name="logo.png" content_type="image/png"> </logo> </blog> eoxml - assert hash.has_key?('blog') - assert hash['blog'].has_key?('logo') + assert hash.has_key?("blog") + assert hash["blog"].has_key?("logo") - file = hash['blog']['logo'] - assert_equal 'logo.png', file.original_filename - assert_equal 'image/png', file.content_type - end + file = hash["blog"]["logo"] + assert_equal "logo.png", file.original_filename + assert_equal "image/png", file.content_type + end - def test_exception_thrown_on_expansion_attack - assert_raise RuntimeError do - attack_xml = <<-EOT + def test_exception_thrown_on_expansion_attack + assert_raise RuntimeError do + attack_xml = <<-EOT <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE member [ <!ENTITY a "&b;&b;&b;&b;&b;&b;&b;&b;&b;&b;"> @@ -50,22 +50,22 @@ class NokogiriSAXEngineTest < ActiveSupport::TestCase </member> EOT - Hash.from_xml(attack_xml) + Hash.from_xml(attack_xml) + end end - end - def test_setting_nokogirisax_as_backend - ActiveSupport::XmlMini.backend = 'NokogiriSAX' - assert_equal ActiveSupport::XmlMini_NokogiriSAX, ActiveSupport::XmlMini.backend - end + def test_setting_nokogirisax_as_backend + ActiveSupport::XmlMini.backend = "NokogiriSAX" + assert_equal ActiveSupport::XmlMini_NokogiriSAX, ActiveSupport::XmlMini.backend + end - def test_blank_returns_empty_hash - assert_equal({}, ActiveSupport::XmlMini.parse(nil)) - assert_equal({}, ActiveSupport::XmlMini.parse('')) - end + def test_blank_returns_empty_hash + assert_equal({}, ActiveSupport::XmlMini.parse(nil)) + assert_equal({}, ActiveSupport::XmlMini.parse("")) + end - def test_array_type_makes_an_array - assert_equal_rexml(<<-eoxml) + def test_array_type_makes_an_array + assert_equal_rexml(<<-eoxml) <blog> <posts type="array"> <post>a post</post> @@ -73,67 +73,67 @@ class NokogiriSAXEngineTest < ActiveSupport::TestCase </posts> </blog> eoxml - end + end - def test_one_node_document_as_hash - assert_equal_rexml(<<-eoxml) - <products/> - eoxml - end + def test_one_node_document_as_hash + assert_equal_rexml(<<-eoxml) + <products/> + eoxml + end - def test_one_node_with_attributes_document_as_hash - assert_equal_rexml(<<-eoxml) - <products foo="bar"/> - eoxml - end + def test_one_node_with_attributes_document_as_hash + assert_equal_rexml(<<-eoxml) + <products foo="bar"/> + eoxml + end - def test_products_node_with_book_node_as_hash - assert_equal_rexml(<<-eoxml) + def test_products_node_with_book_node_as_hash + assert_equal_rexml(<<-eoxml) <products> <book name="awesome" id="12345" /> </products> eoxml - end + end - def test_products_node_with_two_book_nodes_as_hash - assert_equal_rexml(<<-eoxml) + def test_products_node_with_two_book_nodes_as_hash + assert_equal_rexml(<<-eoxml) <products> <book name="awesome" id="12345" /> <book name="america" id="67890" /> </products> eoxml - end + end - def test_single_node_with_content_as_hash - assert_equal_rexml(<<-eoxml) + def test_single_node_with_content_as_hash + assert_equal_rexml(<<-eoxml) <products> hello world </products> eoxml - end + end - def test_children_with_children - assert_equal_rexml(<<-eoxml) + def test_children_with_children + assert_equal_rexml(<<-eoxml) <root> <products> <book name="america" id="67890" /> </products> </root> eoxml - end + end - def test_children_with_text - assert_equal_rexml(<<-eoxml) + def test_children_with_text + assert_equal_rexml(<<-eoxml) <root> <products> hello everyone </products> </root> eoxml - end + end - def test_children_with_non_adjacent_text - assert_equal_rexml(<<-eoxml) + def test_children_with_non_adjacent_text + assert_equal_rexml(<<-eoxml) <root> good <products> @@ -142,10 +142,10 @@ class NokogiriSAXEngineTest < ActiveSupport::TestCase morning </root> eoxml - end + end - def test_parse_from_io - io = StringIO.new(<<-eoxml) + def test_parse_from_io + io = StringIO.new(<<-eoxml) <root> good <products> @@ -154,31 +154,31 @@ class NokogiriSAXEngineTest < ActiveSupport::TestCase morning </root> eoxml - assert_equal_rexml(io) - end + assert_equal_rexml(io) + end - def test_children_with_simple_cdata - assert_equal_rexml(<<-eoxml) + def test_children_with_simple_cdata + assert_equal_rexml(<<-eoxml) <root> <products> <![CDATA[cdatablock]]> </products> </root> eoxml - end + end - def test_children_with_multiple_cdata - assert_equal_rexml(<<-eoxml) + def test_children_with_multiple_cdata + assert_equal_rexml(<<-eoxml) <root> <products> <![CDATA[cdatablock1]]><![CDATA[cdatablock2]]> </products> </root> eoxml - end + end - def test_children_with_text_and_cdata - assert_equal_rexml(<<-eoxml) + def test_children_with_text_and_cdata + assert_equal_rexml(<<-eoxml) <root> <products> hello <![CDATA[cdatablock]]> @@ -186,31 +186,31 @@ class NokogiriSAXEngineTest < ActiveSupport::TestCase </products> </root> eoxml - end + end - def test_children_with_blank_text - assert_equal_rexml(<<-eoxml) + def test_children_with_blank_text + assert_equal_rexml(<<-eoxml) <root> <products> </products> </root> eoxml - end + end - def test_children_with_blank_text_and_attribute - assert_equal_rexml(<<-eoxml) + def test_children_with_blank_text_and_attribute + assert_equal_rexml(<<-eoxml) <root> <products type="file"> </products> </root> eoxml - end - - private - def assert_equal_rexml(xml) - parsed_xml = ActiveSupport::XmlMini.parse(xml) - xml.rewind if xml.respond_to?(:rewind) - hash = ActiveSupport::XmlMini.with_backend('REXML') { ActiveSupport::XmlMini.parse(xml) } - assert_equal(hash, parsed_xml) end -end + + private + def assert_equal_rexml(xml) + parsed_xml = ActiveSupport::XmlMini.parse(xml) + xml.rewind if xml.respond_to?(:rewind) + hash = ActiveSupport::XmlMini.with_backend("REXML") { ActiveSupport::XmlMini.parse(xml) } + assert_equal(hash, parsed_xml) + end + end end diff --git a/activesupport/test/xml_mini/rexml_engine_test.rb b/activesupport/test/xml_mini/rexml_engine_test.rb index f0067ca656..dc62f3f671 100644 --- a/activesupport/test/xml_mini/rexml_engine_test.rb +++ b/activesupport/test/xml_mini/rexml_engine_test.rb @@ -1,5 +1,5 @@ -require 'abstract_unit' -require 'active_support/xml_mini' +require "abstract_unit" +require "active_support/xml_mini" class REXMLEngineTest < ActiveSupport::TestCase def test_default_is_rexml @@ -7,12 +7,12 @@ class REXMLEngineTest < ActiveSupport::TestCase end def test_set_rexml_as_backend - ActiveSupport::XmlMini.backend = 'REXML' + ActiveSupport::XmlMini.backend = "REXML" assert_equal ActiveSupport::XmlMini_REXML, ActiveSupport::XmlMini.backend end def test_parse_from_io - ActiveSupport::XmlMini.backend = 'REXML' + ActiveSupport::XmlMini.backend = "REXML" io = StringIO.new(<<-eoxml) <root> good @@ -22,14 +22,23 @@ class REXMLEngineTest < ActiveSupport::TestCase morning </root> eoxml - assert_equal_rexml(io) + hash = ActiveSupport::XmlMini.parse(io) + assert hash.has_key?("root") + assert hash["root"].has_key?("products") + assert_match "good", hash["root"]["__content__"] + products = hash["root"]["products"] + assert products.has_key?("__content__") + assert_match "hello everyone", products["__content__"] end - private - def assert_equal_rexml(xml) - parsed_xml = ActiveSupport::XmlMini.parse(xml) - xml.rewind if xml.respond_to?(:rewind) - hash = ActiveSupport::XmlMini.with_backend('REXML') { ActiveSupport::XmlMini.parse(xml) } - assert_equal(hash, parsed_xml) - end + def test_parse_from_empty_string + ActiveSupport::XmlMini.backend = "REXML" + assert_equal({}, ActiveSupport::XmlMini.parse("")) + end + + def test_parse_from_frozen_string + ActiveSupport::XmlMini.backend = "REXML" + xml_string = "<root></root>".freeze + assert_equal({ "root" => {} }, ActiveSupport::XmlMini.parse(xml_string)) + end end diff --git a/activesupport/test/xml_mini_test.rb b/activesupport/test/xml_mini_test.rb index 55e8181b54..b15ccfb764 100644 --- a/activesupport/test/xml_mini_test.rb +++ b/activesupport/test/xml_mini_test.rb @@ -1,9 +1,9 @@ -require 'abstract_unit' -require 'active_support/xml_mini' -require 'active_support/builder' -require 'active_support/core_ext/hash' -require 'active_support/core_ext/big_decimal' -require 'yaml' +require "abstract_unit" +require "active_support/xml_mini" +require "active_support/builder" +require "active_support/core_ext/hash" +require "active_support/core_ext/big_decimal" +require "yaml" module XmlMiniTest class RenameKeyTest < ActiveSupport::TestCase @@ -12,23 +12,23 @@ module XmlMiniTest end def test_rename_key_dasherizes_with_dasherize_true - assert_equal "my-key", ActiveSupport::XmlMini.rename_key("my_key", :dasherize => true) + assert_equal "my-key", ActiveSupport::XmlMini.rename_key("my_key", dasherize: true) end def test_rename_key_does_nothing_with_dasherize_false - assert_equal "my_key", ActiveSupport::XmlMini.rename_key("my_key", :dasherize => false) + assert_equal "my_key", ActiveSupport::XmlMini.rename_key("my_key", dasherize: false) end def test_rename_key_camelizes_with_camelize_true - assert_equal "MyKey", ActiveSupport::XmlMini.rename_key("my_key", :camelize => true) + assert_equal "MyKey", ActiveSupport::XmlMini.rename_key("my_key", camelize: true) end def test_rename_key_lower_camelizes_with_camelize_lower - assert_equal "myKey", ActiveSupport::XmlMini.rename_key("my_key", :camelize => :lower) + assert_equal "myKey", ActiveSupport::XmlMini.rename_key("my_key", camelize: :lower) end def test_rename_key_lower_camelizes_with_camelize_upper - assert_equal "MyKey", ActiveSupport::XmlMini.rename_key("my_key", :camelize => :upper) + assert_equal "MyKey", ActiveSupport::XmlMini.rename_key("my_key", camelize: :upper) end def test_rename_key_does_not_dasherize_leading_underscores @@ -63,16 +63,16 @@ module XmlMiniTest def setup @xml = ActiveSupport::XmlMini - @options = {:skip_instruct => true, :builder => Builder::XmlMarkup.new} + @options = { skip_instruct: true, builder: Builder::XmlMarkup.new } end test "#to_tag accepts a callable object and passes options with the builder" do - @xml.to_tag(:some_tag, lambda {|o| o[:builder].br }, @options) + @xml.to_tag(:some_tag, lambda { |o| o[:builder].br }, @options) assert_xml "<br/>" end test "#to_tag accepts a callable object and passes options and tag name" do - @xml.to_tag(:tag, lambda {|o, t| o[:builder].b(t) }, @options) + @xml.to_tag(:tag, lambda { |o, t| o[:builder].b(t) }, @options) assert_xml "<b>tag</b>" end @@ -92,7 +92,7 @@ module XmlMiniTest end test "#to_tag should use the type value in the options hash" do - @xml.to_tag(:b, "blue", @options.merge(type: 'color')) + @xml.to_tag(:b, "blue", @options.merge(type: "color")) assert_xml( "<b type=\"color\">blue</b>" ) end @@ -122,7 +122,7 @@ module XmlMiniTest end test "#to_tag accepts datetime types" do - @xml.to_tag(:b, DateTime.new(2001,2,3,4,5,6,'+7'), @options) + @xml.to_tag(:b, DateTime.new(2001,2,3,4,5,6,"+7"), @options) assert_xml( "<b type=\"dateTime\">2001-02-03T04:05:06+07:00</b>") end @@ -233,22 +233,22 @@ module XmlMiniTest end def test_symbol - parser = @parsing['symbol'] - assert_equal :symbol, parser.call('symbol') + parser = @parsing["symbol"] + assert_equal :symbol, parser.call("symbol") assert_equal :symbol, parser.call(:symbol) assert_equal :'123', parser.call(123) assert_raises(ArgumentError) { parser.call(Date.new(2013,11,12,02,11)) } end def test_date - parser = @parsing['date'] + parser = @parsing["date"] assert_equal Date.new(2013,11,12), parser.call("2013-11-12T0211Z") assert_raises(TypeError) { parser.call(1384190018) } assert_raises(ArgumentError) { parser.call("not really a date") } end def test_datetime - parser = @parsing['datetime'] + parser = @parsing["datetime"] assert_equal Time.new(2013,11,12,02,11,00,0), parser.call("2013-11-12T02:11:00Z") assert_equal DateTime.new(2013,11,12), parser.call("2013-11-12T0211Z") assert_equal DateTime.new(2013,11,12,02,11), parser.call("2013-11-12T02:11Z") @@ -257,7 +257,7 @@ module XmlMiniTest end def test_integer - parser = @parsing['integer'] + parser = @parsing["integer"] assert_equal 123, parser.call(123) assert_equal 123, parser.call(123.003) assert_equal 123, parser.call("123") @@ -266,7 +266,7 @@ module XmlMiniTest end def test_float - parser = @parsing['float'] + parser = @parsing["float"] assert_equal 123, parser.call("123") assert_equal 123.003, parser.call("123.003") assert_equal 123.0, parser.call("123,003") @@ -277,7 +277,7 @@ module XmlMiniTest end def test_decimal - parser = @parsing['decimal'] + parser = @parsing["decimal"] assert_equal 123, parser.call("123") assert_equal 123.003, parser.call("123.003") assert_equal 123.0, parser.call("123,003") @@ -288,7 +288,7 @@ module XmlMiniTest end def test_boolean - parser = @parsing['boolean'] + parser = @parsing["boolean"] [1, true, "1"].each do |value| assert parser.call(value) end @@ -299,7 +299,7 @@ module XmlMiniTest end def test_string - parser = @parsing['string'] + parser = @parsing["string"] assert_equal "123", parser.call(123) assert_equal "123", parser.call("123") assert_equal "[]", parser.call("[]") @@ -317,13 +317,13 @@ product: YAML expected = { "product"=> [ - {"sku"=>"BL394D", "quantity"=>4, "description"=>"Basketball"} + { "sku"=>"BL394D", "quantity"=>4, "description"=>"Basketball" } ] } - parser = @parsing['yaml'] + parser = @parsing["yaml"] assert_equal(expected, parser.call(yaml)) - assert_equal({1 => 'test'}, parser.call({1 => 'test'})) - assert_equal({"1 => 'test'"=>nil}, parser.call("{1 => 'test'}")) + assert_equal({ 1 => "test" }, parser.call(1 => "test")) + assert_equal({ "1 => 'test'"=>nil }, parser.call("{1 => 'test'}")) end def test_base64Binary_and_binary @@ -341,12 +341,12 @@ in the continued and indefatigable generation of knowledge, exceeds the short vehemence of any carnal pleasure. EXPECTED - parser = @parsing['base64Binary'] + parser = @parsing["base64Binary"] assert_equal expected_base64.gsub(/\n/," ").strip, parser.call(base64) parser.call("NON BASE64 INPUT") - parser = @parsing['binary'] - assert_equal expected_base64.gsub(/\n/," ").strip, parser.call(base64, 'encoding' => 'base64') + parser = @parsing["binary"] + assert_equal expected_base64.gsub(/\n/," ").strip, parser.call(base64, "encoding" => "base64") assert_equal "IGNORED INPUT", parser.call("IGNORED INPUT", {}) end end |