From 0c6ddbe7b0056cb5c17d6b483c0e5a7cbd596b97 Mon Sep 17 00:00:00 2001 From: Riley Lynch Date: Wed, 15 May 2013 08:59:52 -0400 Subject: Maintain proleptic gregorian in Time#advance Time#advance uses Time#to_date and Date#advance to calculate a new date. The Date object returned by Time#to_date is constructed with the assumption that the Time object represents a proleptic gregorian date, but it is configured to observe the default julian calendar reform date (2299161j) for purposes of calculating month, date and year: Time.new(1582, 10, 4).to_date.to_s # => "1582-09-24" Time.new(1582, 10, 4).to_date.gregorian.to_s # => "1582-10-04" This patch ensures that when the intermediate Date object is advanced to yield a new Date object, that the Time object for return is contructed with a proleptic gregorian month, date and year. --- activesupport/lib/active_support/core_ext/time/calculations.rb | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'activesupport/lib/active_support') diff --git a/activesupport/lib/active_support/core_ext/time/calculations.rb b/activesupport/lib/active_support/core_ext/time/calculations.rb index a3ce7dbe3f..e86332ba3a 100644 --- a/activesupport/lib/active_support/core_ext/time/calculations.rb +++ b/activesupport/lib/active_support/core_ext/time/calculations.rb @@ -110,10 +110,11 @@ class Time end end - # Uses Date to provide precise Time calculations for years, months, and days. - # The +options+ parameter takes a hash with any of these keys: :years, - # :months, :weeks, :days, :hours, - # :minutes, :seconds. + # Uses Date to provide precise Time calculations for years, months, and days + # according to the proleptic Gregorian calendar. The +options+ parameter + # takes a hash with any of these keys: :years, :months, + # :weeks, :days, :hours, :minutes, + # :seconds. def advance(options) unless options[:weeks].nil? options[:weeks], partial_weeks = options[:weeks].divmod(1) @@ -126,6 +127,7 @@ class Time end 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) seconds_to_advance = \ options.fetch(:seconds, 0) + -- cgit v1.2.3 From a4e1e5d6329f31cb5a1ee7561fdf05dd5559ef7c Mon Sep 17 00:00:00 2001 From: Vipul A M Date: Wed, 15 May 2013 19:41:04 +0530 Subject: Use `Base.strict_decode64` instead of `Base.decode64` just as we do in encoding; Also reduce extra object allocation by creating string directly instead of join on Array --- activesupport/lib/active_support/message_encryptor.rb | 6 +++--- activesupport/lib/active_support/message_verifier.rb | 6 +++++- 2 files changed, 8 insertions(+), 4 deletions(-) (limited to 'activesupport/lib/active_support') diff --git a/activesupport/lib/active_support/message_encryptor.rb b/activesupport/lib/active_support/message_encryptor.rb index bffdfc6201..7773611e11 100644 --- a/activesupport/lib/active_support/message_encryptor.rb +++ b/activesupport/lib/active_support/message_encryptor.rb @@ -76,12 +76,12 @@ module ActiveSupport encrypted_data = cipher.update(@serializer.dump(value)) encrypted_data << cipher.final - [encrypted_data, iv].map {|v| ::Base64.strict_encode64(v)}.join("--") + "#{::Base64.strict_encode64 encrypted_data}--#{::Base64.strict_encode64 iv}" end def _decrypt(encrypted_message) cipher = new_cipher - encrypted_data, iv = encrypted_message.split("--").map {|v| ::Base64.decode64(v)} + encrypted_data, iv = encrypted_message.split("--").map {|v| ::Base64.strict_decode64(v)} cipher.decrypt cipher.key = @secret @@ -91,7 +91,7 @@ module ActiveSupport decrypted_data << cipher.final @serializer.load(decrypted_data) - rescue OpenSSLCipherError, TypeError + rescue OpenSSLCipherError, TypeError, ArgumentError raise InvalidMessage end diff --git a/activesupport/lib/active_support/message_verifier.rb b/activesupport/lib/active_support/message_verifier.rb index e0cd92ae3c..a35d5980fe 100644 --- a/activesupport/lib/active_support/message_verifier.rb +++ b/activesupport/lib/active_support/message_verifier.rb @@ -37,7 +37,11 @@ module ActiveSupport data, digest = signed_message.split("--") if data.present? && digest.present? && secure_compare(digest, generate_digest(data)) - @serializer.load(::Base64.decode64(data)) + begin + @serializer.load(::Base64.strict_decode64(data)) + rescue ArgumentError + raise InvalidSignature + end else raise InvalidSignature end -- cgit v1.2.3 From 2da9d67c278b0f37d2dea89ff557dc07cbb3a7b0 Mon Sep 17 00:00:00 2001 From: Matt Bridges Date: Wed, 12 Jun 2013 11:53:29 -0500 Subject: Extract ActiveSupport::NumberHelper methods to classes Due to the overall complexity of each method individually as well as the global shared private module methods, this pulls each helper into it's own converter class inheriting from a generic `NumberBuilder` class. * The `NumberBuilder` class contains the private methods needed for each helper method an eliminates the need for special definition of specialized private module methods. * The `ActiveSupport::NumberHelper::DEFAULTS` constant has been moved into the `NumberBuilder` class because the `NumberBuilder` is the only class which needs access to it. * For each of the builders, the `#convert` method is broken down to smaller parts and extracted into private methods for clarity of purpose. * Most of the mutation that once was necessary has now been eliminated. * Several of the mathematical operations for percentage, delimited, and rounded have been moved into private methods to ease readability and clarity. * Internationalization is still a bit crufty, and definitely could be improved, but it is functional and a bit easier to follow. The following helpers were extracted into their respective classes. * `#number_to_percentage` -> `NumberToPercentageConverter` * `#number_to_delimited` -> `NumberToDelimitedConverter` * `#number_to_phone` -> `NumberToPhoneConverter` * `#number_to_currency` -> `NumberToCurrencyConverter` * `#number_to_rounded` -> `NumberToRoundedConverter` * `#number_to_human_size` -> `NumberToHumanSizeConverter` * `#number_to_human` -> `NumberToHumanConverter` --- activesupport/lib/active_support/number_helper.rb | 323 +-------------------- .../number_helper/number_converter.rb | 175 +++++++++++ .../number_helper/number_to_currency.rb | 51 ++++ .../number_helper/number_to_delimited.rb | 25 ++ .../number_helper/number_to_human.rb | 71 +++++ .../number_helper/number_to_human_size.rb | 63 ++++ .../number_helper/number_to_percentage.rb | 17 ++ .../number_helper/number_to_phone.rb | 54 ++++ .../number_helper/number_to_rounded.rb | 62 ++++ 9 files changed, 533 insertions(+), 308 deletions(-) create mode 100644 activesupport/lib/active_support/number_helper/number_converter.rb create mode 100644 activesupport/lib/active_support/number_helper/number_to_currency.rb create mode 100644 activesupport/lib/active_support/number_helper/number_to_delimited.rb create mode 100644 activesupport/lib/active_support/number_helper/number_to_human.rb create mode 100644 activesupport/lib/active_support/number_helper/number_to_human_size.rb create mode 100644 activesupport/lib/active_support/number_helper/number_to_percentage.rb create mode 100644 activesupport/lib/active_support/number_helper/number_to_phone.rb create mode 100644 activesupport/lib/active_support/number_helper/number_to_rounded.rb (limited to 'activesupport/lib/active_support') diff --git a/activesupport/lib/active_support/number_helper.rb b/activesupport/lib/active_support/number_helper.rb index 414960d2b1..6468bf55f0 100644 --- a/activesupport/lib/active_support/number_helper.rb +++ b/activesupport/lib/active_support/number_helper.rb @@ -1,115 +1,16 @@ -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' module ActiveSupport module NumberHelper - extend self - - DEFAULTS = { - # Used in number_to_delimited - # These are also the defaults for 'currency', 'percentage', 'precision', and 'human' - format: { - # Sets the separator between the units, for more precision (e.g. 1.0 / 2.0 == 0.5) - separator: ".", - # Delimits thousands (e.g. 1,000,000 is a million) (always in groups of three) - delimiter: ",", - # Number of decimals, behind the separator (the number 1 with a precision of 2 gives: 1.00) - precision: 3, - # If set to true, precision will mean the number of significant digits instead - # of the number of decimal digits (1234 with precision 2 becomes 1200, 1.23543 becomes 1.2) - significant: false, - # If set, the zeros after the decimal separator will always be stripped (eg.: 1.200 will be 1.2) - strip_insignificant_zeros: false - }, - - # Used in number_to_currency - currency: { - format: { - format: "%u%n", - negative_format: "-%u%n", - unit: "$", - # These five are to override number.format and are optional - separator: ".", - delimiter: ",", - precision: 2, - significant: false, - strip_insignificant_zeros: false - } - }, - - # Used in number_to_percentage - percentage: { - format: { - delimiter: "", - format: "%n%" - } - }, - # Used in number_to_rounded - precision: { - format: { - delimiter: "" - } - }, + autoload :NumberToRoundedConverter, "active_support/number_helper/number_to_rounded" + autoload :NumberToDelimitedConverter, "active_support/number_helper/number_to_delimited" + autoload :NumberToHumanConverter, "active_support/number_helper/number_to_human" + autoload :NumberToHumanSizeConverter, "active_support/number_helper/number_to_human_size" + autoload :NumberToPhoneConverter, "active_support/number_helper/number_to_phone" + autoload :NumberToCurrencyConverter, "active_support/number_helper/number_to_currency" + autoload :NumberToPercentageConverter, "active_support/number_helper/number_to_percentage" - # Used in number_to_human_size and number_to_human - human: { - format: { - # These five are to override number.format and are optional - delimiter: "", - precision: 3, - significant: true, - strip_insignificant_zeros: true - }, - # Used in number_to_human_size - storage_units: { - # Storage units output formatting. - # %u is the storage unit, %n is the number (default: 2 MB) - format: "%n %u", - units: { - byte: "Bytes", - kb: "KB", - mb: "MB", - gb: "GB", - tb: "TB" - } - }, - # Used in number_to_human - decimal_units: { - format: "%n %u", - # Decimal units output formatting - # By default we will only quantify some of the exponents - # but the commented ones might be defined or overridden - # by the user. - units: { - # femto: Quadrillionth - # pico: Trillionth - # nano: Billionth - # micro: Millionth - # mili: Thousandth - # centi: Hundredth - # deci: Tenth - unit: "", - # ten: - # one: Ten - # other: Tens - # hundred: Hundred - thousand: "Thousand", - million: "Million", - billion: "Billion", - trillion: "Trillion", - quadrillion: "Quadrillion" - } - } - } - } - - DECIMAL_UNITS = { 0 => :unit, 1 => :ten, 2 => :hundred, 3 => :thousand, 6 => :million, 9 => :billion, 12 => :trillion, 15 => :quadrillion, - -1 => :deci, -2 => :centi, -3 => :mili, -6 => :micro, -9 => :nano, -12 => :pico, -15 => :femto } - - STORAGE_UNITS = [:byte, :kb, :mb, :gb, :tb] + extend self # Formats a +number+ into a US phone number (e.g., (555) # 123-9876). You can customize the format in the +options+ hash. @@ -137,27 +38,7 @@ module ActiveSupport # number_to_phone(1235551234, country_code: 1, extension: 1343, delimiter: '.') # # => +1.123.555.1234 x 1343 def number_to_phone(number, options = {}) - return unless number - options = options.symbolize_keys - - number = number.to_s.strip - area_code = options[:area_code] - delimiter = options[:delimiter] || "-" - extension = options[:extension] - country_code = options[:country_code] - - if area_code - number.gsub!(/(\d{1,3})(\d{3})(\d{4}$)/,"(\\1) \\2#{delimiter}\\3") - else - number.gsub!(/(\d{0,3})(\d{3})(\d{4})$/,"\\1#{delimiter}\\2#{delimiter}\\3") - number.slice!(0, 1) if number.start_with?(delimiter) && !delimiter.blank? - end - - str = '' - str << "+#{country_code}#{delimiter}" unless country_code.blank? - str << number - str << " x #{extension}" unless extension.blank? - str + NumberToPhoneConverter.new(number, options).execute end # Formats a +number+ into a currency string (e.g., $13.65). You @@ -199,25 +80,7 @@ module ActiveSupport # number_to_currency(1234567890.50, unit: '£', separator: ',', delimiter: '', format: '%n %u') # # => 1234567890,50 £ def number_to_currency(number, options = {}) - return unless number - options = options.symbolize_keys - - currency = i18n_format_options(options[:locale], :currency) - currency[:negative_format] ||= "-" + currency[:format] if currency[:format] - - defaults = default_format_options(:currency).merge!(currency) - defaults[:negative_format] = "-" + options[:format] if options[:format] - options = defaults.merge!(options) - - unit = options.delete(:unit) - format = options.delete(:format) - - if number.to_f.phase != 0 - format = options.delete(:negative_format) - number = number.respond_to?("abs") ? number.abs : number.sub(/^-/, '') - end - - format.gsub('%n', self.number_to_rounded(number, options)).gsub('%u', unit) + NumberToCurrencyConverter.new(number, options).execute end # Formats a +number+ as a percentage string (e.g., 65%). You can @@ -253,14 +116,7 @@ module ActiveSupport # number_to_percentage('98a') # => 98a% # number_to_percentage(100, format: '%n %') # => 100 % def number_to_percentage(number, options = {}) - return unless number - options = options.symbolize_keys - - defaults = format_options(options[:locale], :percentage) - options = defaults.merge!(options) - - format = options[:format] || "%n%" - format.gsub('%n', self.number_to_rounded(number, options)) + NumberToPercentageConverter.new(number, options).execute end # Formats a +number+ with grouped thousands using +delimiter+ @@ -289,15 +145,7 @@ module ActiveSupport # number_to_delimited(98765432.98, delimiter: ' ', separator: ',') # # => 98 765 432,98 def number_to_delimited(number, options = {}) - options = options.symbolize_keys - - return number unless valid_float?(number) - - options = format_options(options[:locale]).merge!(options) - - parts = number.to_s.split('.') - parts[0].gsub!(/(\d)(?=(\d\d\d)+(?!\d))/, "\\1#{options[:delimiter]}") - parts.join(options[:separator]) + NumberToDelimitedConverter.new(number, options).execute end # Formats a +number+ with the specified level of @@ -340,39 +188,7 @@ module ActiveSupport # number_to_rounded(1111.2345, precision: 2, separator: ',', delimiter: '.') # # => 1.111,23 def number_to_rounded(number, options = {}) - return number unless valid_float?(number) - number = Float(number) - options = options.symbolize_keys - - defaults = format_options(options[:locale], :precision) - options = defaults.merge!(options) - - precision = options.delete :precision - significant = options.delete :significant - strip_insignificant_zeros = options.delete :strip_insignificant_zeros - - if significant && precision > 0 - if number == 0 - digits, rounded_number = 1, 0 - else - digits = (Math.log10(number.abs) + 1).floor - multiplier = 10 ** (digits - precision) - rounded_number = (BigDecimal.new(number.to_s) / BigDecimal.new(multiplier.to_f.to_s)).round.to_f * multiplier - digits = (Math.log10(rounded_number.abs) + 1).floor # After rounding, the number of digits may have changed - end - precision -= digits - precision = 0 if precision < 0 # don't let it be negative - else - rounded_number = BigDecimal.new(number.to_s).round(precision).to_f - rounded_number = rounded_number.abs if rounded_number.zero? # prevent showing negative zeros - end - formatted_number = self.number_to_delimited("%01.#{precision}f" % rounded_number, options) - if strip_insignificant_zeros - escaped_separator = Regexp.escape(options[:separator]) - formatted_number.sub(/(#{escaped_separator})(\d*[1-9])?0+\z/, '\1\2').sub(/#{escaped_separator}\z/, '') - else - formatted_number - end + NumberToRoundedConverter.new(number, options).execute end # Formats the bytes in +number+ into a more understandable @@ -420,36 +236,7 @@ module ActiveSupport # number_to_human_size(1234567890123, precision: 5) # => "1.1229 TB" # number_to_human_size(524288000, precision: 5) # => "500 MB" def number_to_human_size(number, options = {}) - options = options.symbolize_keys - - return number unless valid_float?(number) - number = Float(number) - - defaults = format_options(options[:locale], :human) - options = defaults.merge!(options) - - #for backwards compatibility with those that didn't add strip_insignificant_zeros to their locale files - options[:strip_insignificant_zeros] = true if not options.key?(:strip_insignificant_zeros) - - storage_units_format = translate_number_value_with_default('human.storage_units.format', :locale => options[:locale], :raise => true) - - base = options[:prefix] == :si ? 1000 : 1024 - - if number.to_i < base - unit = translate_number_value_with_default('human.storage_units.units.byte', :locale => options[:locale], :count => number.to_i, :raise => true) - storage_units_format.gsub(/%n/, number.to_i.to_s).gsub(/%u/, unit) - else - max_exp = STORAGE_UNITS.size - 1 - exponent = (Math.log(number) / Math.log(base)).to_i # Convert to base - exponent = max_exp if exponent > max_exp # we need this to avoid overflow for the highest unit - number /= base ** exponent - - unit_key = STORAGE_UNITS[exponent] - unit = translate_number_value_with_default("human.storage_units.units.#{unit_key}", :locale => options[:locale], :count => number, :raise => true) - - formatted_number = self.number_to_rounded(number, options) - storage_units_format.gsub(/%n/, formatted_number).gsub(/%u/, unit) - end + NumberToHumanSizeConverter.new(number, options).execute end # Pretty prints (formats and approximates) a number in a way it @@ -550,88 +337,8 @@ module ActiveSupport # number_to_human(1, units: :distance) # => "1 meter" # number_to_human(0.34, units: :distance) # => "34 centimeters" def number_to_human(number, options = {}) - options = options.symbolize_keys - - return number unless valid_float?(number) - number = Float(number) - - defaults = format_options(options[:locale], :human) - options = defaults.merge!(options) - - #for backwards compatibility with those that didn't add strip_insignificant_zeros to their locale files - options[:strip_insignificant_zeros] = true if not options.key?(:strip_insignificant_zeros) - - inverted_du = DECIMAL_UNITS.invert - - units = options.delete :units - unit_exponents = case units - when Hash - units - when String, Symbol - I18n.translate(:"#{units}", :locale => options[:locale], :raise => true) - when nil - translate_number_value_with_default("human.decimal_units.units", :locale => options[:locale], :raise => true) - else - raise ArgumentError, ":units must be a Hash or String translation scope." - end.keys.map{|e_name| inverted_du[e_name] }.sort_by{|e| -e} - - number_exponent = number != 0 ? Math.log10(number.abs).floor : 0 - display_exponent = unit_exponents.find{ |e| number_exponent >= e } || 0 - number /= 10 ** display_exponent - - unit = case units - when Hash - units[DECIMAL_UNITS[display_exponent]] || '' - when String, Symbol - I18n.translate(:"#{units}.#{DECIMAL_UNITS[display_exponent]}", :locale => options[:locale], :count => number.to_i) - else - translate_number_value_with_default("human.decimal_units.units.#{DECIMAL_UNITS[display_exponent]}", :locale => options[:locale], :count => number.to_i) - end - - decimal_format = options[:format] || translate_number_value_with_default('human.decimal_units.format', :locale => options[:locale]) - formatted_number = self.number_to_rounded(number, options) - decimal_format.gsub(/%n/, formatted_number).gsub(/%u/, unit).strip + NumberToHumanConverter.new(number, options).execute end - def self.private_module_and_instance_method(method_name) #:nodoc: - private method_name - private_class_method method_name - end - private_class_method :private_module_and_instance_method - - def format_options(locale, namespace = nil) #:nodoc: - default_format_options(namespace).merge!(i18n_format_options(locale, namespace)) - end - private_module_and_instance_method :format_options - - def default_format_options(namespace = nil) #:nodoc: - options = DEFAULTS[:format].dup - options.merge!(DEFAULTS[namespace][:format]) if namespace - options - end - private_module_and_instance_method :default_format_options - - def i18n_format_options(locale, namespace = nil) #:nodoc: - options = I18n.translate(:'number.format', locale: locale, default: {}).dup - if namespace - options.merge!(I18n.translate(:"number.#{namespace}.format", locale: locale, default: {})) - end - options - end - private_module_and_instance_method :i18n_format_options - - def translate_number_value_with_default(key, i18n_options = {}) #:nodoc: - default = key.split('.').reduce(DEFAULTS) { |defaults, k| defaults[k.to_sym] } - - I18n.translate(key, { default: default, scope: :number }.merge!(i18n_options)) - end - private_module_and_instance_method :translate_number_value_with_default - - def valid_float?(number) #:nodoc: - Float(number) - rescue ArgumentError, TypeError - false - end - private_module_and_instance_method :valid_float? end end diff --git a/activesupport/lib/active_support/number_helper/number_converter.rb b/activesupport/lib/active_support/number_helper/number_converter.rb new file mode 100644 index 0000000000..39255d14a3 --- /dev/null +++ b/activesupport/lib/active_support/number_helper/number_converter.rb @@ -0,0 +1,175 @@ +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 + class NumberConverter # :nodoc: + + # Default and i18n option namespace per class + class_attribute :namespace + + # Does the object need a number that is a valid float? + class_attribute :need_valid_float + + attr_reader :number, :opts + + DEFAULTS = { + # Used in number_to_delimited + # These are also the defaults for 'currency', 'percentage', 'precision', and 'human' + format: { + # Sets the separator between the units, for more precision (e.g. 1.0 / 2.0 == 0.5) + separator: ".", + # Delimits thousands (e.g. 1,000,000 is a million) (always in groups of three) + delimiter: ",", + # Number of decimals, behind the separator (the number 1 with a precision of 2 gives: 1.00) + precision: 3, + # If set to true, precision will mean the number of significant digits instead + # of the number of decimal digits (1234 with precision 2 becomes 1200, 1.23543 becomes 1.2) + significant: false, + # If set, the zeros after the decimal separator will always be stripped (eg.: 1.200 will be 1.2) + strip_insignificant_zeros: false + }, + + # Used in number_to_currency + currency: { + format: { + format: "%u%n", + negative_format: "-%u%n", + unit: "$", + # These five are to override number.format and are optional + separator: ".", + delimiter: ",", + precision: 2, + significant: false, + strip_insignificant_zeros: false + } + }, + + # Used in number_to_percentage + percentage: { + format: { + delimiter: "", + format: "%n%" + } + }, + + # Used in number_to_rounded + precision: { + format: { + delimiter: "" + } + }, + + # Used in number_to_human_size and number_to_human + human: { + format: { + # These five are to override number.format and are optional + delimiter: "", + precision: 3, + significant: true, + strip_insignificant_zeros: true + }, + # Used in number_to_human_size + storage_units: { + # Storage units output formatting. + # %u is the storage unit, %n is the number (default: 2 MB) + format: "%n %u", + units: { + byte: "Bytes", + kb: "KB", + mb: "MB", + gb: "GB", + tb: "TB" + } + }, + # Used in number_to_human + decimal_units: { + format: "%n %u", + # Decimal units output formatting + # By default we will only quantify some of the exponents + # but the commented ones might be defined or overridden + # by the user. + units: { + # femto: Quadrillionth + # pico: Trillionth + # nano: Billionth + # micro: Millionth + # mili: Thousandth + # centi: Hundredth + # deci: Tenth + unit: "", + # ten: + # one: Ten + # other: Tens + # hundred: Hundred + thousand: "Thousand", + million: "Million", + billion: "Billion", + trillion: "Trillion", + quadrillion: "Quadrillion" + } + } + } + } + + + def initialize(number, opts = {}) + @number = number + @opts = opts.symbolize_keys + end + + def execute + return unless @number + return @number if need_valid_float? && !valid_float? + convert + end + + private + + def options + @options ||= format_options.merge(opts) + end + + def format_options #:nodoc: + default_format_options.merge!(i18n_format_options) + end + + def default_format_options #:nodoc: + options = DEFAULTS[:format].dup + options.merge!(DEFAULTS[namespace][:format]) if namespace + options + end + + def i18n_format_options #:nodoc: + locale = opts[:locale] + options = I18n.translate(:'number.format', locale: locale, default: {}).dup + if namespace + options.merge!(I18n.translate(:"number.#{namespace}.format", locale: locale, default: {})) + end + options + end + + def translate_number_value_with_default(key, i18n_options = {}) #:nodoc: + I18n.translate(key, { default: default_value(key), scope: :number }.merge!(i18n_options)) + end + + def translate_in_locale(key, i18n_options = {}) + translate_number_value_with_default(key, { locale: options[:locale] }.merge(i18n_options)) + end + + def default_value(key) + key.split('.').reduce(DEFAULTS) { |defaults, k| defaults[k.to_sym] } + end + + def valid_float? #:nodoc: + Float(@number) + rescue ArgumentError, TypeError + false + end + + end + end +end diff --git a/activesupport/lib/active_support/number_helper/number_to_currency.rb b/activesupport/lib/active_support/number_helper/number_to_currency.rb new file mode 100644 index 0000000000..402b0b56aa --- /dev/null +++ b/activesupport/lib/active_support/number_helper/number_to_currency.rb @@ -0,0 +1,51 @@ +require 'active_support/number_helper/number_converter' +require 'active_support/number_helper/number_to_rounded' + +module ActiveSupport + module NumberHelper + class NumberToCurrencyConverter < NumberConverter # :nodoc: + + self.namespace = :currency + + def convert + number = @number.to_s.strip + format = options[:format] + + if is_negative?(number) + format = options[:negative_format] + number = absolute_value(number) + end + + rounded_number = NumberToRoundedConverter.new(number, options).execute + format.gsub('%n', rounded_number).gsub('%u', options[:unit]) + end + + private + + def is_negative?(number) + number.to_f.phase != 0 + end + + def absolute_value(number) + number.respond_to?("abs") ? number.abs : number.sub(/\A-/, '') + end + + def options + @options ||= begin + defaults = default_format_options.merge(i18n_opts) + # Override negative format if format options is given + defaults[:negative_format] = "-#{opts[:format]}" if opts[:format] + defaults.merge(opts) + end + end + + def i18n_opts + # Set International negative format if not exists + i18n = i18n_format_options + i18n[:negative_format] ||= "-#{i18n[:format]}" if i18n[:format] + i18n + end + + end + end +end diff --git a/activesupport/lib/active_support/number_helper/number_to_delimited.rb b/activesupport/lib/active_support/number_helper/number_to_delimited.rb new file mode 100644 index 0000000000..b543b0c19d --- /dev/null +++ b/activesupport/lib/active_support/number_helper/number_to_delimited.rb @@ -0,0 +1,25 @@ +require 'active_support/number_helper/number_converter' + +module ActiveSupport + module NumberHelper + class NumberToDelimitedConverter < NumberConverter #:nodoc: + + self.need_valid_float = true + + DELIMITED_REGEX = /(\d)(?=(\d\d\d)+(?!\d))/ + + def convert + parts.join(options[:separator]) + end + + private + + def parts + left, right = number.to_s.split('.') + left.gsub!(DELIMITED_REGEX) { "#{$1}#{options[:delimiter]}" } + [left, right].compact + end + + end + end +end diff --git a/activesupport/lib/active_support/number_helper/number_to_human.rb b/activesupport/lib/active_support/number_helper/number_to_human.rb new file mode 100644 index 0000000000..2b57c75720 --- /dev/null +++ b/activesupport/lib/active_support/number_helper/number_to_human.rb @@ -0,0 +1,71 @@ +require 'active_support/number_helper/number_converter' +require 'active_support/number_helper/number_to_rounded' + +module ActiveSupport + module NumberHelper + class NumberToHumanConverter < NumberConverter # :nodoc: + + DECIMAL_UNITS = { 0 => :unit, 1 => :ten, 2 => :hundred, 3 => :thousand, 6 => :million, 9 => :billion, 12 => :trillion, 15 => :quadrillion, + -1 => :deci, -2 => :centi, -3 => :mili, -6 => :micro, -9 => :nano, -12 => :pico, -15 => :femto } + + self.namespace = :human + self.need_valid_float = true + + def convert # :nodoc: + @number = Float(@number) + + # for backwards compatibility with those that didn't add strip_insignificant_zeros to their locale files + unless options.key?(:strip_insignificant_zeros) + options[:strip_insignificant_zeros] = true + end + + units = opts[:units] + exponent = calculate_exponent(units) + @number = @number / (10 ** exponent) + + unit = determine_unit(units, exponent) + + rounded_number = NumberToRoundedConverter.new(@number, options).execute + format.gsub(/%n/, rounded_number).gsub(/%u/, unit).strip + end + + private + + def 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] || '' + when String, Symbol + 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 + end + + def calculate_exponent(units) + exponent = number != 0 ? Math.log10(number.abs).floor : 0 + unit_exponents(units).find { |e| exponent >= e } || 0 + end + + def unit_exponents(units) + inverted_decimal_units = DECIMAL_UNITS.invert + case units + when Hash + units + when String, Symbol + I18n.translate(units.to_s, :locale => options[:locale], :raise => true) + when nil + translate_in_locale("human.decimal_units.units", raise: true) + else + raise ArgumentError, ":units must be a Hash or String translation scope." + end.keys.map { |e_name| inverted_decimal_units[e_name] }.sort_by{ |e| -e } + end + + end + end +end diff --git a/activesupport/lib/active_support/number_helper/number_to_human_size.rb b/activesupport/lib/active_support/number_helper/number_to_human_size.rb new file mode 100644 index 0000000000..c0930564bc --- /dev/null +++ b/activesupport/lib/active_support/number_helper/number_to_human_size.rb @@ -0,0 +1,63 @@ +require 'active_support/number_helper/number_converter' +require 'active_support/number_helper/number_to_rounded' + +module ActiveSupport + module NumberHelper + class NumberToHumanSizeConverter < NumberConverter + + STORAGE_UNITS = [:byte, :kb, :mb, :gb, :tb] + + self.namespace = :human + self.need_valid_float = true + + def convert + @number = Float(@number) + + # for backwards compatibility with those that didn't add strip_insignificant_zeros to their locale files + unless options.key?(:strip_insignificant_zeros) + options[:strip_insignificant_zeros] = true + end + + if smaller_than_base? + number_to_format = @number.to_i.to_s + else + human_size = @number / (base ** exponent) + number_to_format = NumberToRoundedConverter.new(human_size, options).execute + end + conversion_format.gsub(/%n/, number_to_format).gsub(/%u/, unit) + end + + private + + def conversion_format + 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) + end + + def storage_unit_key + key_end = smaller_than_base? ? 'byte' : STORAGE_UNITS[exponent] + "human.storage_units.units.#{key_end}" + end + + def exponent + max = STORAGE_UNITS.size - 1 + exp = (Math.log(@number) / Math.log(base)).to_i + exp = max if exp > max # avoid overflow for the highest unit + exp + end + + def smaller_than_base? + @number.to_i < base + end + + def base + opts[:prefix] == :si ? 1000 : 1024 + end + + end + end +end + diff --git a/activesupport/lib/active_support/number_helper/number_to_percentage.rb b/activesupport/lib/active_support/number_helper/number_to_percentage.rb new file mode 100644 index 0000000000..25e136be60 --- /dev/null +++ b/activesupport/lib/active_support/number_helper/number_to_percentage.rb @@ -0,0 +1,17 @@ +require 'active_support/number_helper/number_converter' +require 'active_support/number_helper/number_to_rounded' + +module ActiveSupport + module NumberHelper + class NumberToPercentageConverter < NumberConverter # :nodoc: + + self.namespace = :percentage + + def convert + rounded_number = NumberToRoundedConverter.new(number, options).execute + options[:format].gsub('%n', rounded_number) + end + + end + end +end diff --git a/activesupport/lib/active_support/number_helper/number_to_phone.rb b/activesupport/lib/active_support/number_helper/number_to_phone.rb new file mode 100644 index 0000000000..171c2dff18 --- /dev/null +++ b/activesupport/lib/active_support/number_helper/number_to_phone.rb @@ -0,0 +1,54 @@ +require 'active_support/number_helper/number_converter' +require 'active_support/number_helper/number_to_rounded' + +module ActiveSupport + module NumberHelper + class NumberToPhoneConverter < NumberConverter + def convert + str = '' + str << country_code(opts[:country_code]) + str << convert_to_phone_number(@number.to_s.strip) + str << phone_ext(opts[:extension]) + end + + private + + def convert_to_phone_number(number) + if opts[:area_code] + convert_with_area_code(number) + else + convert_without_area_code(number) + end + end + + def convert_with_area_code(number) + number.gsub(/(\d{1,3})(\d{3})(\d{4}$)/,"(\\1) \\2#{delimiter}\\3") + end + + def convert_without_area_code(number) + number.tap { |n| + n.gsub!(/(\d{0,3})(\d{3})(\d{4})$/,"\\1#{delimiter}\\2#{delimiter}\\3") + n.slice!(0, 1) if begins_with_delimiter?(n) + } + end + + def begins_with_delimiter?(number) + number.start_with?(delimiter) && !delimiter.blank? + end + + def delimiter + opts[:delimiter] || "-" + end + + def country_code(code) + code.blank? ? "" : "+#{code}#{delimiter}" + end + + def phone_ext(ext) + ext.blank? ? "" : " x #{ext}" + end + + end + end +end + diff --git a/activesupport/lib/active_support/number_helper/number_to_rounded.rb b/activesupport/lib/active_support/number_helper/number_to_rounded.rb new file mode 100644 index 0000000000..817ac1ebb2 --- /dev/null +++ b/activesupport/lib/active_support/number_helper/number_to_rounded.rb @@ -0,0 +1,62 @@ +require 'active_support/number_helper/number_converter' + +module ActiveSupport + module NumberHelper + class NumberToRoundedConverter < NumberConverter # :nodoc: + + self.namespace = :precision + self.need_valid_float = true + + def convert + @number = Float(@number) + + precision = options.delete :precision + significant = options.delete :significant + + if significant && precision > 0 + digits, rounded_number = digits_and_rounded_number(precision) + precision -= digits + precision = 0 if precision < 0 # don't let it be negative + else + rounded_number = BigDecimal.new(@number.to_s).round(precision).to_f + rounded_number = rounded_number.abs if rounded_number.zero? # prevent showing negative zeros + end + delimited_number = NumberToDelimitedConverter.new("%01.#{precision}f" % rounded_number, options).execute + format_number(delimited_number) + end + + private + + def digits_and_rounded_number(precision) + return [1,0] if @number.zero? + digits = digit_count(@number) + multiplier = 10 ** (digits - precision) + rounded_number = calculate_rounded_number(multiplier) + digits = digit_count(rounded_number) # After rounding, the number of digits may have changed + [digits, rounded_number] + end + + def calculate_rounded_number(multiplier) + (BigDecimal.new(@number.to_s) / BigDecimal.new(multiplier.to_f.to_s)).round.to_f * multiplier + end + + def digit_count(number) + (Math.log10(number.abs) + 1).floor + end + + def strip_insignificant_zeros + options[:strip_insignificant_zeros] + end + + 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/, '') + else + number + end + end + + end + end +end -- cgit v1.2.3 From 548910a67a194d5daf588e3d9a8441a941809a7c Mon Sep 17 00:00:00 2001 From: thedarkone Date: Wed, 7 Aug 2013 15:11:03 +0200 Subject: Use TS::Cache instead plain Hash in TimeZone. Plain ruby Hashes are not thread safe. --- activesupport/lib/active_support/values/time_zone.rb | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'activesupport/lib/active_support') diff --git a/activesupport/lib/active_support/values/time_zone.rb b/activesupport/lib/active_support/values/time_zone.rb index 3cf82a24b9..2c78fe3ee8 100644 --- a/activesupport/lib/active_support/values/time_zone.rb +++ b/activesupport/lib/active_support/values/time_zone.rb @@ -1,3 +1,4 @@ +require 'thread_safe' require 'active_support/core_ext/object/blank' require 'active_support/core_ext/object/try' @@ -362,10 +363,11 @@ module ActiveSupport def zones_map @zones_map ||= begin - new_zones_names = MAPPING.keys - lazy_zones_map.keys - new_zones = Hash[new_zones_names.map { |place| [place, create(place)] }] - - lazy_zones_map.merge(new_zones) + map = {} + MAPPING.each_key do |place| + map[place] = lazy_zones_map.fetch(place) { create(place) } + end + map end end @@ -414,7 +416,7 @@ module ActiveSupport def lazy_zones_map require_tzinfo - @lazy_zones_map ||= Hash.new do |hash, place| + @lazy_zones_map ||= ThreadSafe::Cache.new do |hash, place| hash[place] = create(place) if MAPPING.has_key?(place) end end -- cgit v1.2.3 From c4e5db4d451e1537ab96405193150e3785f3ecf9 Mon Sep 17 00:00:00 2001 From: thedarkone Date: Wed, 7 Aug 2013 17:15:58 +0200 Subject: Unify AS::TZ's lazy init maps. There's no point in having 2 almost identical (@lazy_zones_map and @zones_map) lazy initialized TZ instance caches. --- activesupport/lib/active_support/values/time_zone.rb | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) (limited to 'activesupport/lib/active_support') diff --git a/activesupport/lib/active_support/values/time_zone.rb b/activesupport/lib/active_support/values/time_zone.rb index 2c78fe3ee8..b8e6b06087 100644 --- a/activesupport/lib/active_support/values/time_zone.rb +++ b/activesupport/lib/active_support/values/time_zone.rb @@ -185,6 +185,8 @@ module ActiveSupport UTC_OFFSET_WITH_COLON = '%s%02d:%02d' UTC_OFFSET_WITHOUT_COLON = UTC_OFFSET_WITH_COLON.sub(':', '') + @lazy_zones_map = ThreadSafe::Cache.new + # Assumes self represents an offset from UTC in seconds (as returned from # Time#utc_offset) and turns this into an +HH:MM formatted string. # @@ -363,11 +365,8 @@ module ActiveSupport def zones_map @zones_map ||= begin - map = {} - MAPPING.each_key do |place| - map[place] = lazy_zones_map.fetch(place) { create(place) } - end - map + MAPPING.each_key {|place| self[place]} # load all the zones + @lazy_zones_map end end @@ -415,10 +414,7 @@ module ActiveSupport def lazy_zones_map require_tzinfo - - @lazy_zones_map ||= ThreadSafe::Cache.new do |hash, place| - hash[place] = create(place) if MAPPING.has_key?(place) - end + @lazy_zones_map end end -- cgit v1.2.3 From 2a8c2582c9023f4ac02fe9f09f61c4f9c88e4ebd Mon Sep 17 00:00:00 2001 From: thedarkone Date: Wed, 7 Aug 2013 17:21:57 +0200 Subject: Remove AS::TZ.lookup(name). The method doesn't really make much sense (find_tzinfo will succeed for any imput provided). --- activesupport/lib/active_support/values/time_zone.rb | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'activesupport/lib/active_support') diff --git a/activesupport/lib/active_support/values/time_zone.rb b/activesupport/lib/active_support/values/time_zone.rb index b8e6b06087..b6d9257f00 100644 --- a/activesupport/lib/active_support/values/time_zone.rb +++ b/activesupport/lib/active_support/values/time_zone.rb @@ -379,7 +379,7 @@ module ActiveSupport case arg when String begin - lazy_zones_map[arg] ||= lookup(arg).tap { |tz| tz.utc_offset } + lazy_zones_map[arg] ||= create(arg).tap { |tz| tz.utc_offset } rescue TZInfo::InvalidTimezoneIdentifier nil end @@ -408,10 +408,6 @@ module ActiveSupport private - def lookup(name) - (tzinfo = find_tzinfo(name)) && create(tzinfo.name.freeze) - end - def lazy_zones_map require_tzinfo @lazy_zones_map -- cgit v1.2.3 From 9fbf4518722d09b3d86d183d882cefc7f79d73d0 Mon Sep 17 00:00:00 2001 From: Godfrey Chan Date: Sun, 1 Dec 2013 01:58:06 -0800 Subject: EscapedString is also private API [ci skip] --- activesupport/lib/active_support/json/encoding.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'activesupport/lib/active_support') diff --git a/activesupport/lib/active_support/json/encoding.rb b/activesupport/lib/active_support/json/encoding.rb index 935dd88a03..eb25ef7a4c 100644 --- a/activesupport/lib/active_support/json/encoding.rb +++ b/activesupport/lib/active_support/json/encoding.rb @@ -48,7 +48,7 @@ module ActiveSupport ESCAPE_REGEX_WITHOUT_HTML_ENTITIES = /[\u2028\u2029]/u # This class wraps all the strings we see and does the extra escaping - class EscapedString < String + class EscapedString < String #:nodoc: def to_json(*) if Encoding.escape_html_entities_in_json super.gsub ESCAPE_REGEX_WITH_HTML_ENTITIES, ESCAPED_CHARS -- cgit v1.2.3 From f046e8a70fe526ebcea88ea1d084eb4b634b653b Mon Sep 17 00:00:00 2001 From: Daniel Harrington Date: Mon, 2 Dec 2013 19:52:01 +0100 Subject: added missing require MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit we’re using .delegate and should require it. --- activesupport/lib/active_support/tagged_logging.rb | 1 + 1 file changed, 1 insertion(+) (limited to 'activesupport/lib/active_support') diff --git a/activesupport/lib/active_support/tagged_logging.rb b/activesupport/lib/active_support/tagged_logging.rb index 18bc919734..d5c2222d2e 100644 --- a/activesupport/lib/active_support/tagged_logging.rb +++ b/activesupport/lib/active_support/tagged_logging.rb @@ -1,3 +1,4 @@ +require 'active_support/core_ext/module/delegation' require 'active_support/core_ext/object/blank' require 'logger' require 'active_support/logger' -- cgit v1.2.3 From 7dfbd91b0780fbd6a1dd9bfbc176e10894871d2d Mon Sep 17 00:00:00 2001 From: Genadi Samokovarov Date: Sun, 30 Jun 2013 16:45:32 +0300 Subject: Unify cattr and mattr accessors declarations --- activesupport/lib/active_support/core_ext/class.rb | 1 - .../core_ext/class/attribute_accessors.rb | 185 +-------------------- .../core_ext/module/attribute_accessors.rb | 174 +++++++++++++++++-- 3 files changed, 165 insertions(+), 195 deletions(-) (limited to 'activesupport/lib/active_support') diff --git a/activesupport/lib/active_support/core_ext/class.rb b/activesupport/lib/active_support/core_ext/class.rb index 86b752c2f3..c750a10bb2 100644 --- a/activesupport/lib/active_support/core_ext/class.rb +++ b/activesupport/lib/active_support/core_ext/class.rb @@ -1,4 +1,3 @@ require 'active_support/core_ext/class/attribute' -require 'active_support/core_ext/class/attribute_accessors' require 'active_support/core_ext/class/delegating_attributes' require 'active_support/core_ext/class/subclasses' 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 0cf955b889..083b165dce 100644 --- a/activesupport/lib/active_support/core_ext/class/attribute_accessors.rb +++ b/activesupport/lib/active_support/core_ext/class/attribute_accessors.rb @@ -1,181 +1,6 @@ -require 'active_support/core_ext/array/extract_options' +require 'active_support/deprecation' +require 'active_support/core_ext/module/attribute_accessors' -# Extends the class object with class and instance accessors for class attributes, -# just like the native attr* accessors for instance attributes. -class Class - # Defines a class attribute if it's not defined and creates a reader method that - # returns the attribute value. - # - # class Person - # cattr_reader :hair_colors - # end - # - # Person.class_variable_set("@@hair_colors", [:brown, :black]) - # Person.hair_colors # => [:brown, :black] - # Person.new.hair_colors # => [:brown, :black] - # - # The attribute name must be a valid method name in Ruby. - # - # class Person - # cattr_reader :"1_Badname " - # end - # # => NameError: invalid attribute name - # - # If you want to opt out the instance reader method, you can pass instance_reader: false - # or instance_accessor: false. - # - # class Person - # cattr_reader :hair_colors, instance_reader: false - # end - # - # Person.new.hair_colors # => NoMethodError - # - # Also, you can pass a block to set up the attribute with a default value. - # - # class Person - # cattr_reader :hair_colors do - # [:brown, :black, :blonde, :red] - # end - # end - # - # Person.hair_colors # => [:brown, :black, :blonde, :red] - def cattr_reader(*syms) - options = syms.extract_options! - syms.each do |sym| - raise NameError.new("invalid class attribute name: #{sym}") unless sym =~ /^[_A-Za-z]\w*$/ - class_eval(<<-EOS, __FILE__, __LINE__ + 1) - unless defined? @@#{sym} - @@#{sym} = nil - end - - def self.#{sym} - @@#{sym} - end - EOS - - unless options[:instance_reader] == false || options[:instance_accessor] == false - class_eval(<<-EOS, __FILE__, __LINE__ + 1) - def #{sym} - @@#{sym} - end - EOS - end - class_variable_set("@@#{sym}", yield) if block_given? - end - end - - # Defines a class attribute if it's not defined and creates a writer method to allow - # assignment to the attribute. - # - # class Person - # cattr_writer :hair_colors - # end - # - # Person.hair_colors = [:brown, :black] - # Person.class_variable_get("@@hair_colors") # => [:brown, :black] - # Person.new.hair_colors = [:blonde, :red] - # Person.class_variable_get("@@hair_colors") # => [:blonde, :red] - # - # The attribute name must be a valid method name in Ruby. - # - # class Person - # cattr_writer :"1_Badname " - # end - # # => NameError: invalid attribute name - # - # If you want to opt out the instance writer method, pass instance_writer: false - # or instance_accessor: false. - # - # class Person - # cattr_writer :hair_colors, instance_writer: false - # end - # - # Person.new.hair_colors = [:blonde, :red] # => NoMethodError - # - # Also, you can pass a block to set up the attribute with a default value. - # - # class Person - # cattr_writer :hair_colors do - # [:brown, :black, :blonde, :red] - # end - # end - # - # Person.class_variable_get("@@hair_colors") # => [:brown, :black, :blonde, :red] - def cattr_writer(*syms) - options = syms.extract_options! - syms.each do |sym| - raise NameError.new("invalid class attribute name: #{sym}") unless sym =~ /^[_A-Za-z]\w*$/ - class_eval(<<-EOS, __FILE__, __LINE__ + 1) - unless defined? @@#{sym} - @@#{sym} = nil - end - - def self.#{sym}=(obj) - @@#{sym} = obj - end - EOS - - unless options[:instance_writer] == false || options[:instance_accessor] == false - class_eval(<<-EOS, __FILE__, __LINE__ + 1) - def #{sym}=(obj) - @@#{sym} = obj - end - EOS - end - send("#{sym}=", yield) if block_given? - end - end - - # Defines both class and instance accessors for class attributes. - # - # class Person - # cattr_accessor :hair_colors - # end - # - # Person.hair_colors = [:brown, :black, :blonde, :red] - # Person.hair_colors # => [:brown, :black, :blonde, :red] - # Person.new.hair_colors # => [:brown, :black, :blonde, :red] - # - # If a subclass changes the value then that would also change the value for - # parent class. Similarly if parent class changes the value then that would - # change the value of subclasses too. - # - # class Male < Person - # end - # - # Male.hair_colors << :blue - # Person.hair_colors # => [:brown, :black, :blonde, :red, :blue] - # - # To opt out of the instance writer method, pass instance_writer: false. - # To opt out of the instance reader method, pass instance_reader: false. - # - # class Person - # cattr_accessor :hair_colors, instance_writer: false, instance_reader: false - # end - # - # Person.new.hair_colors = [:brown] # => NoMethodError - # Person.new.hair_colors # => NoMethodError - # - # Or pass instance_accessor: false, to opt out both instance methods. - # - # class Person - # cattr_accessor :hair_colors, instance_accessor: false - # end - # - # Person.new.hair_colors = [:brown] # => NoMethodError - # Person.new.hair_colors # => NoMethodError - # - # Also you can pass a block to set up the attribute with a default value. - # - # class Person - # cattr_accessor :hair_colors do - # [:brown, :black, :blonde, :red] - # end - # end - # - # Person.class_variable_get("@@hair_colors") # => [:brown, :black, :blonde, :red] - def cattr_accessor(*syms, &blk) - cattr_reader(*syms) - cattr_writer(*syms, &blk) - end -end +ActiveSupport::Deprecation.warn( + "The cattr_* method definitions have been moved into active_support/core_ext/module/attribute_accessors. Please require that instead." +) 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 672cc0256f..f70a839074 100644 --- a/activesupport/lib/active_support/core_ext/module/attribute_accessors.rb +++ b/activesupport/lib/active_support/core_ext/module/attribute_accessors.rb @@ -1,10 +1,59 @@ require 'active_support/core_ext/array/extract_options' +# Extends the module object with class/module and instance accessors for +# class/module attributes, just like the native attr* accessors for instance +# attributes. class Module + # Defines a class attribute and creates a class and instance reader methods. + # The underlying the class variable is set to +nil+, if it is not previously + # defined. + # + # module HairColors + # mattr_reader :hair_colors + # end + # + # HairColors.hair_colors # => nil + # HairColors.class_variable_set("@@hair_colors", [:brown, :black]) + # HairColors.hair_colors # => [:brown, :black] + # + # The attribute name must be a valid method name in Ruby. + # + # module Foo + # mattr_reader :"1_Badname " + # end + # # => NameError: invalid attribute name + # + # If you want to opt out the creation on the instance reader method, pass + # instance_reader: false or instance_accessor: false. + # + # module HairColors + # mattr_writer :hair_colors, instance_reader: false + # end + # + # class Person + # include HairColors + # end + # + # Person.new.hair_colors # => NoMethodError + # + # + # Also, you can pass a block to set up the attribute with a default value. + # + # module HairColors + # cattr_reader :hair_colors do + # [:brown, :black, :blonde, :red] + # end + # end + # + # class Person + # include HairColors + # end + # + # Person.hair_colors # => [:brown, :black, :blonde, :red] + # def mattr_reader(*syms) options = syms.extract_options! syms.each do |sym| - raise NameError.new('invalid attribute name') unless sym =~ /^[_A-Za-z]\w*$/ + raise NameError.new("invalid attribute name: #{sym}") unless sym =~ /^[_A-Za-z]\w*$/ class_eval(<<-EOS, __FILE__, __LINE__ + 1) @@#{sym} = nil unless defined? @@#{sym} @@ -20,14 +69,60 @@ class Module end EOS end + class_variable_set("@@#{sym}", yield) if block_given? end end + alias :cattr_reader :mattr_reader + # Defines a class attribute and creates a class and instance writer methods to + # allow assignment to the attribute. + # + # module HairColors + # mattr_writer :hair_colors + # end + # + # class Person + # include HairColors + # end + # + # HairColors.hair_colors = [:brown, :black] + # Person.class_variable_get("@@hair_colors") # => [:brown, :black] + # Person.new.hair_colors = [:blonde, :red] + # HairColors.class_variable_get("@@hair_colors") # => [:blonde, :red] + # + # If you want to opt out the instance writer method, pass + # instance_writer: false or instance_accessor: false. + # + # module HairColors + # mattr_writer :hair_colors, instance_writer: false + # end + # + # class Person + # include HairColors + # end + # + # Person.new.hair_colors = [:blonde, :red] # => NoMethodError + # + # Also, you can pass a block to set up the attribute with a default value. + # + # class HairColors + # mattr_writer :hair_colors do + # [:brown, :black, :blonde, :red] + # end + # end + # + # class Person + # include HairColors + # end + # + # Person.class_variable_get("@@hair_colors") # => [:brown, :black, :blonde, :red] def mattr_writer(*syms) options = syms.extract_options! syms.each do |sym| - raise NameError.new('invalid attribute name') unless sym =~ /^[_A-Za-z]\w*$/ + raise NameError.new("invalid attribute name: #{sym}") unless sym =~ /^[_A-Za-z]\w*$/ class_eval(<<-EOS, __FILE__, __LINE__ + 1) + @@#{sym} = nil unless defined? @@#{sym} + def self.#{sym}=(obj) @@#{sym} = obj end @@ -40,27 +135,78 @@ class Module end EOS end + send("#{sym}=", yield) if block_given? end end + alias :cattr_writer :mattr_writer - # Extends the module object with module and instance accessors for class attributes, - # just like the native attr* accessors for instance attributes. + # Defines both class and instance accessors for class attributes. # - # module AppConfiguration - # mattr_accessor :google_api_key + # module HairColors + # mattr_accessor :hair_colors + # end # - # self.google_api_key = "123456789" + # class Person + # include HairColors # end # - # AppConfiguration.google_api_key # => "123456789" - # AppConfiguration.google_api_key = "overriding the api key!" - # AppConfiguration.google_api_key # => "overriding the api key!" + # Person.hair_colors = [:brown, :black, :blonde, :red] + # Person.hair_colors # => [:brown, :black, :blonde, :red] + # Person.new.hair_colors # => [:brown, :black, :blonde, :red] + # + # If a subclass changes the value then that would also change the value for + # parent class. Similarly if parent class changes the value then that would + # change the value of subclasses too. + # + # class Male < Person + # end + # + # Male.hair_colors << :blue + # Person.hair_colors # => [:brown, :black, :blonde, :red, :blue] # # To opt out of the instance writer method, pass instance_writer: false. # To opt out of the instance reader method, pass instance_reader: false. - # To opt out of both instance methods, pass instance_accessor: false. - def mattr_accessor(*syms) - mattr_reader(*syms) - mattr_writer(*syms) + # + # module HairColors + # mattr_accessor :hair_colors, instance_writer: false, instance_reader: false + # end + # + # class Person + # include HairColors + # end + # + # Person.new.hair_colors = [:brown] # => NoMethodError + # Person.new.hair_colors # => NoMethodError + # + # Or pass instance_accessor: false, to opt out both instance methods. + # + # module HairColors + # mattr_accessor :hair_colors, instance_acessor: false + # end + # + # class Person + # include HairColors + # end + # + # Person.new.hair_colors = [:brown] # => NoMethodError + # Person.new.hair_colors # => NoMethodError + # + # Also you can pass a block to set up the attribute with a default value. + # + # module HairColors + # mattr_accessor :hair_colors do + # [:brown, :black, :blonde, :red] + # end + # end + # + # class Person + # include HairColors + # end + # + # Person.class_variable_get("@@hair_colors") #=> [:brown, :black, :blonde, :red] + def mattr_accessor(*syms, &blk) + mattr_reader(*syms, &blk) + mattr_writer(*syms, &blk) end + alias :cattr_accessor :mattr_accessor end -- cgit v1.2.3 From 6329d9fa8b2f86a178151be264cccdb805bfaaac Mon Sep 17 00:00:00 2001 From: Genadi Samokovarov Date: Mon, 2 Dec 2013 23:36:58 +0200 Subject: Remove deprecated cattr_* requires --- activesupport/lib/active_support/cache.rb | 2 +- activesupport/lib/active_support/logger.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'activesupport/lib/active_support') diff --git a/activesupport/lib/active_support/cache.rb b/activesupport/lib/active_support/cache.rb index 5c1d473161..d584d50da8 100644 --- a/activesupport/lib/active_support/cache.rb +++ b/activesupport/lib/active_support/cache.rb @@ -3,7 +3,7 @@ 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/class/attribute_accessors' +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' diff --git a/activesupport/lib/active_support/logger.rb b/activesupport/lib/active_support/logger.rb index 4a55bbb350..33fccdcf95 100644 --- a/activesupport/lib/active_support/logger.rb +++ b/activesupport/lib/active_support/logger.rb @@ -1,4 +1,4 @@ -require 'active_support/core_ext/class/attribute_accessors' +require 'active_support/core_ext/module/attribute_accessors' require 'active_support/logger_silence' require 'logger' -- cgit v1.2.3 From d3b93e403b3d0c11607e037770ad91c062b2e897 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Mendon=C3=A7a=20Fran=C3=A7a?= Date: Mon, 2 Dec 2013 22:12:36 -0200 Subject: Make load of NumberHelper thread safe --- activesupport/lib/active_support/number_helper.rb | 18 +++--- .../number_helper/number_to_currency.rb | 51 ---------------- .../number_helper/number_to_currency_converter.rb | 48 +++++++++++++++ .../number_helper/number_to_delimited.rb | 25 -------- .../number_helper/number_to_delimited_converter.rb | 23 +++++++ .../number_helper/number_to_human.rb | 71 ---------------------- .../number_helper/number_to_human_converter.rb | 68 +++++++++++++++++++++ .../number_helper/number_to_human_size.rb | 63 ------------------- .../number_to_human_size_converter.rb | 60 ++++++++++++++++++ .../number_helper/number_to_percentage.rb | 17 ------ .../number_to_percentage_converter.rb | 14 +++++ .../number_helper/number_to_phone.rb | 54 ---------------- .../number_helper/number_to_phone_converter.rb | 51 ++++++++++++++++ .../number_helper/number_to_rounded.rb | 62 ------------------- .../number_helper/number_to_rounded_converter.rb | 60 ++++++++++++++++++ 15 files changed, 335 insertions(+), 350 deletions(-) delete mode 100644 activesupport/lib/active_support/number_helper/number_to_currency.rb create mode 100644 activesupport/lib/active_support/number_helper/number_to_currency_converter.rb delete mode 100644 activesupport/lib/active_support/number_helper/number_to_delimited.rb create mode 100644 activesupport/lib/active_support/number_helper/number_to_delimited_converter.rb delete mode 100644 activesupport/lib/active_support/number_helper/number_to_human.rb create mode 100644 activesupport/lib/active_support/number_helper/number_to_human_converter.rb delete mode 100644 activesupport/lib/active_support/number_helper/number_to_human_size.rb create mode 100644 activesupport/lib/active_support/number_helper/number_to_human_size_converter.rb delete mode 100644 activesupport/lib/active_support/number_helper/number_to_percentage.rb create mode 100644 activesupport/lib/active_support/number_helper/number_to_percentage_converter.rb delete mode 100644 activesupport/lib/active_support/number_helper/number_to_phone.rb create mode 100644 activesupport/lib/active_support/number_helper/number_to_phone_converter.rb delete mode 100644 activesupport/lib/active_support/number_helper/number_to_rounded.rb create mode 100644 activesupport/lib/active_support/number_helper/number_to_rounded_converter.rb (limited to 'activesupport/lib/active_support') diff --git a/activesupport/lib/active_support/number_helper.rb b/activesupport/lib/active_support/number_helper.rb index 53f08efae5..2df1aada50 100644 --- a/activesupport/lib/active_support/number_helper.rb +++ b/activesupport/lib/active_support/number_helper.rb @@ -1,14 +1,18 @@ module ActiveSupport module NumberHelper + extend ActiveSupport::Autoload - autoload :NumberToRoundedConverter, "active_support/number_helper/number_to_rounded" - autoload :NumberToDelimitedConverter, "active_support/number_helper/number_to_delimited" - autoload :NumberToHumanConverter, "active_support/number_helper/number_to_human" - autoload :NumberToHumanSizeConverter, "active_support/number_helper/number_to_human_size" - autoload :NumberToPhoneConverter, "active_support/number_helper/number_to_phone" - autoload :NumberToCurrencyConverter, "active_support/number_helper/number_to_currency" - autoload :NumberToPercentageConverter, "active_support/number_helper/number_to_percentage" + eager_autoload do + autoload :NumberConverter + autoload :NumberToRoundedConverter + autoload :NumberToDelimitedConverter + autoload :NumberToHumanConverter + autoload :NumberToHumanSizeConverter + autoload :NumberToPhoneConverter + autoload :NumberToCurrencyConverter + autoload :NumberToPercentageConverter + end extend self diff --git a/activesupport/lib/active_support/number_helper/number_to_currency.rb b/activesupport/lib/active_support/number_helper/number_to_currency.rb deleted file mode 100644 index 402b0b56aa..0000000000 --- a/activesupport/lib/active_support/number_helper/number_to_currency.rb +++ /dev/null @@ -1,51 +0,0 @@ -require 'active_support/number_helper/number_converter' -require 'active_support/number_helper/number_to_rounded' - -module ActiveSupport - module NumberHelper - class NumberToCurrencyConverter < NumberConverter # :nodoc: - - self.namespace = :currency - - def convert - number = @number.to_s.strip - format = options[:format] - - if is_negative?(number) - format = options[:negative_format] - number = absolute_value(number) - end - - rounded_number = NumberToRoundedConverter.new(number, options).execute - format.gsub('%n', rounded_number).gsub('%u', options[:unit]) - end - - private - - def is_negative?(number) - number.to_f.phase != 0 - end - - def absolute_value(number) - number.respond_to?("abs") ? number.abs : number.sub(/\A-/, '') - end - - def options - @options ||= begin - defaults = default_format_options.merge(i18n_opts) - # Override negative format if format options is given - defaults[:negative_format] = "-#{opts[:format]}" if opts[:format] - defaults.merge(opts) - end - end - - def i18n_opts - # Set International negative format if not exists - i18n = i18n_format_options - i18n[:negative_format] ||= "-#{i18n[:format]}" if i18n[:format] - i18n - end - - end - end -end 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 new file mode 100644 index 0000000000..113e557415 --- /dev/null +++ b/activesupport/lib/active_support/number_helper/number_to_currency_converter.rb @@ -0,0 +1,48 @@ +module ActiveSupport + module NumberHelper + class NumberToCurrencyConverter < NumberConverter # :nodoc: + + self.namespace = :currency + + def convert + number = @number.to_s.strip + format = options[:format] + + if is_negative?(number) + format = options[:negative_format] + number = absolute_value(number) + end + + rounded_number = NumberToRoundedConverter.new(number, options).execute + format.gsub('%n', rounded_number).gsub('%u', options[:unit]) + end + + private + + def is_negative?(number) + number.to_f.phase != 0 + end + + def absolute_value(number) + number.respond_to?("abs") ? number.abs : number.sub(/\A-/, '') + end + + def options + @options ||= begin + defaults = default_format_options.merge(i18n_opts) + # Override negative format if format options is given + defaults[:negative_format] = "-#{opts[:format]}" if opts[:format] + defaults.merge(opts) + end + end + + def i18n_opts + # Set International negative format if not exists + i18n = i18n_format_options + i18n[:negative_format] ||= "-#{i18n[:format]}" if i18n[:format] + i18n + end + + end + end +end diff --git a/activesupport/lib/active_support/number_helper/number_to_delimited.rb b/activesupport/lib/active_support/number_helper/number_to_delimited.rb deleted file mode 100644 index b543b0c19d..0000000000 --- a/activesupport/lib/active_support/number_helper/number_to_delimited.rb +++ /dev/null @@ -1,25 +0,0 @@ -require 'active_support/number_helper/number_converter' - -module ActiveSupport - module NumberHelper - class NumberToDelimitedConverter < NumberConverter #:nodoc: - - self.need_valid_float = true - - DELIMITED_REGEX = /(\d)(?=(\d\d\d)+(?!\d))/ - - def convert - parts.join(options[:separator]) - end - - private - - def parts - left, right = number.to_s.split('.') - left.gsub!(DELIMITED_REGEX) { "#{$1}#{options[:delimiter]}" } - [left, right].compact - end - - end - end -end 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 new file mode 100644 index 0000000000..6604b9cce4 --- /dev/null +++ b/activesupport/lib/active_support/number_helper/number_to_delimited_converter.rb @@ -0,0 +1,23 @@ +module ActiveSupport + module NumberHelper + class NumberToDelimitedConverter < NumberConverter #:nodoc: + + self.need_valid_float = true + + DELIMITED_REGEX = /(\d)(?=(\d\d\d)+(?!\d))/ + + def convert + parts.join(options[:separator]) + end + + private + + def parts + left, right = number.to_s.split('.') + left.gsub!(DELIMITED_REGEX) { "#{$1}#{options[:delimiter]}" } + [left, right].compact + end + + end + end +end diff --git a/activesupport/lib/active_support/number_helper/number_to_human.rb b/activesupport/lib/active_support/number_helper/number_to_human.rb deleted file mode 100644 index 70d669f175..0000000000 --- a/activesupport/lib/active_support/number_helper/number_to_human.rb +++ /dev/null @@ -1,71 +0,0 @@ -require 'active_support/number_helper/number_converter' -require 'active_support/number_helper/number_to_rounded' - -module ActiveSupport - module NumberHelper - class NumberToHumanConverter < NumberConverter # :nodoc: - - DECIMAL_UNITS = { 0 => :unit, 1 => :ten, 2 => :hundred, 3 => :thousand, 6 => :million, 9 => :billion, 12 => :trillion, 15 => :quadrillion, - -1 => :deci, -2 => :centi, -3 => :mili, -6 => :micro, -9 => :nano, -12 => :pico, -15 => :femto } - INVERTED_DECIMAL_UNITS = DECIMAL_UNITS.invert - - self.namespace = :human - self.need_valid_float = true - - def convert # :nodoc: - @number = Float(@number) - - # for backwards compatibility with those that didn't add strip_insignificant_zeros to their locale files - unless options.key?(:strip_insignificant_zeros) - options[:strip_insignificant_zeros] = true - end - - units = opts[:units] - exponent = calculate_exponent(units) - @number = @number / (10 ** exponent) - - unit = determine_unit(units, exponent) - - rounded_number = NumberToRoundedConverter.new(@number, options).execute - format.gsub(/%n/, rounded_number).gsub(/%u/, unit).strip - end - - private - - def 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] || '' - when String, Symbol - 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 - end - - def calculate_exponent(units) - exponent = number != 0 ? Math.log10(number.abs).floor : 0 - unit_exponents(units).find { |e| exponent >= e } || 0 - end - - def unit_exponents(units) - case units - when Hash - units - when String, Symbol - I18n.translate(units.to_s, :locale => options[:locale], :raise => true) - when nil - translate_in_locale("human.decimal_units.units", raise: true) - else - raise ArgumentError, ":units must be a Hash or String translation scope." - end.keys.map { |e_name| INVERTED_DECIMAL_UNITS[e_name] }.sort_by { |e| -e } - 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 new file mode 100644 index 0000000000..3cdf6ff9f8 --- /dev/null +++ b/activesupport/lib/active_support/number_helper/number_to_human_converter.rb @@ -0,0 +1,68 @@ +module ActiveSupport + module NumberHelper + class NumberToHumanConverter < NumberConverter # :nodoc: + + DECIMAL_UNITS = { 0 => :unit, 1 => :ten, 2 => :hundred, 3 => :thousand, 6 => :million, 9 => :billion, 12 => :trillion, 15 => :quadrillion, + -1 => :deci, -2 => :centi, -3 => :mili, -6 => :micro, -9 => :nano, -12 => :pico, -15 => :femto } + INVERTED_DECIMAL_UNITS = DECIMAL_UNITS.invert + + self.namespace = :human + self.need_valid_float = true + + def convert # :nodoc: + @number = Float(@number) + + # for backwards compatibility with those that didn't add strip_insignificant_zeros to their locale files + unless options.key?(:strip_insignificant_zeros) + options[:strip_insignificant_zeros] = true + end + + units = opts[:units] + exponent = calculate_exponent(units) + @number = @number / (10 ** exponent) + + unit = determine_unit(units, exponent) + + rounded_number = NumberToRoundedConverter.new(@number, options).execute + format.gsub(/%n/, rounded_number).gsub(/%u/, unit).strip + end + + private + + def 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] || '' + when String, Symbol + 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 + end + + def calculate_exponent(units) + exponent = number != 0 ? Math.log10(number.abs).floor : 0 + unit_exponents(units).find { |e| exponent >= e } || 0 + end + + def unit_exponents(units) + case units + when Hash + units + when String, Symbol + I18n.translate(units.to_s, :locale => options[:locale], :raise => true) + when nil + translate_in_locale("human.decimal_units.units", raise: true) + else + raise ArgumentError, ":units must be a Hash or String translation scope." + end.keys.map { |e_name| INVERTED_DECIMAL_UNITS[e_name] }.sort_by { |e| -e } + end + + end + end +end diff --git a/activesupport/lib/active_support/number_helper/number_to_human_size.rb b/activesupport/lib/active_support/number_helper/number_to_human_size.rb deleted file mode 100644 index c0930564bc..0000000000 --- a/activesupport/lib/active_support/number_helper/number_to_human_size.rb +++ /dev/null @@ -1,63 +0,0 @@ -require 'active_support/number_helper/number_converter' -require 'active_support/number_helper/number_to_rounded' - -module ActiveSupport - module NumberHelper - class NumberToHumanSizeConverter < NumberConverter - - STORAGE_UNITS = [:byte, :kb, :mb, :gb, :tb] - - self.namespace = :human - self.need_valid_float = true - - def convert - @number = Float(@number) - - # for backwards compatibility with those that didn't add strip_insignificant_zeros to their locale files - unless options.key?(:strip_insignificant_zeros) - options[:strip_insignificant_zeros] = true - end - - if smaller_than_base? - number_to_format = @number.to_i.to_s - else - human_size = @number / (base ** exponent) - number_to_format = NumberToRoundedConverter.new(human_size, options).execute - end - conversion_format.gsub(/%n/, number_to_format).gsub(/%u/, unit) - end - - private - - def conversion_format - 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) - end - - def storage_unit_key - key_end = smaller_than_base? ? 'byte' : STORAGE_UNITS[exponent] - "human.storage_units.units.#{key_end}" - end - - def exponent - max = STORAGE_UNITS.size - 1 - exp = (Math.log(@number) / Math.log(base)).to_i - exp = max if exp > max # avoid overflow for the highest unit - exp - end - - def smaller_than_base? - @number.to_i < base - end - - def base - opts[:prefix] == :si ? 1000 : 1024 - end - - end - end -end - 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 new file mode 100644 index 0000000000..6a0f6e70b7 --- /dev/null +++ b/activesupport/lib/active_support/number_helper/number_to_human_size_converter.rb @@ -0,0 +1,60 @@ +module ActiveSupport + module NumberHelper + class NumberToHumanSizeConverter < NumberConverter + + STORAGE_UNITS = [:byte, :kb, :mb, :gb, :tb] + + self.namespace = :human + self.need_valid_float = true + + def convert + @number = Float(@number) + + # for backwards compatibility with those that didn't add strip_insignificant_zeros to their locale files + unless options.key?(:strip_insignificant_zeros) + options[:strip_insignificant_zeros] = true + end + + if smaller_than_base? + number_to_format = @number.to_i.to_s + else + human_size = @number / (base ** exponent) + number_to_format = NumberToRoundedConverter.new(human_size, options).execute + end + conversion_format.gsub(/%n/, number_to_format).gsub(/%u/, unit) + end + + private + + def conversion_format + 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) + end + + def storage_unit_key + key_end = smaller_than_base? ? 'byte' : STORAGE_UNITS[exponent] + "human.storage_units.units.#{key_end}" + end + + def exponent + max = STORAGE_UNITS.size - 1 + exp = (Math.log(@number) / Math.log(base)).to_i + exp = max if exp > max # avoid overflow for the highest unit + exp + end + + def smaller_than_base? + @number.to_i < base + end + + def base + opts[:prefix] == :si ? 1000 : 1024 + end + + end + end +end + diff --git a/activesupport/lib/active_support/number_helper/number_to_percentage.rb b/activesupport/lib/active_support/number_helper/number_to_percentage.rb deleted file mode 100644 index 25e136be60..0000000000 --- a/activesupport/lib/active_support/number_helper/number_to_percentage.rb +++ /dev/null @@ -1,17 +0,0 @@ -require 'active_support/number_helper/number_converter' -require 'active_support/number_helper/number_to_rounded' - -module ActiveSupport - module NumberHelper - class NumberToPercentageConverter < NumberConverter # :nodoc: - - self.namespace = :percentage - - def convert - rounded_number = NumberToRoundedConverter.new(number, options).execute - options[:format].gsub('%n', rounded_number) - end - - 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 new file mode 100644 index 0000000000..b7926cf151 --- /dev/null +++ b/activesupport/lib/active_support/number_helper/number_to_percentage_converter.rb @@ -0,0 +1,14 @@ +module ActiveSupport + module NumberHelper + class NumberToPercentageConverter < NumberConverter # :nodoc: + + self.namespace = :percentage + + def convert + rounded_number = NumberToRoundedConverter.new(number, options).execute + options[:format].gsub('%n', rounded_number) + end + + end + end +end diff --git a/activesupport/lib/active_support/number_helper/number_to_phone.rb b/activesupport/lib/active_support/number_helper/number_to_phone.rb deleted file mode 100644 index 171c2dff18..0000000000 --- a/activesupport/lib/active_support/number_helper/number_to_phone.rb +++ /dev/null @@ -1,54 +0,0 @@ -require 'active_support/number_helper/number_converter' -require 'active_support/number_helper/number_to_rounded' - -module ActiveSupport - module NumberHelper - class NumberToPhoneConverter < NumberConverter - def convert - str = '' - str << country_code(opts[:country_code]) - str << convert_to_phone_number(@number.to_s.strip) - str << phone_ext(opts[:extension]) - end - - private - - def convert_to_phone_number(number) - if opts[:area_code] - convert_with_area_code(number) - else - convert_without_area_code(number) - end - end - - def convert_with_area_code(number) - number.gsub(/(\d{1,3})(\d{3})(\d{4}$)/,"(\\1) \\2#{delimiter}\\3") - end - - def convert_without_area_code(number) - number.tap { |n| - n.gsub!(/(\d{0,3})(\d{3})(\d{4})$/,"\\1#{delimiter}\\2#{delimiter}\\3") - n.slice!(0, 1) if begins_with_delimiter?(n) - } - end - - def begins_with_delimiter?(number) - number.start_with?(delimiter) && !delimiter.blank? - end - - def delimiter - opts[:delimiter] || "-" - end - - def country_code(code) - code.blank? ? "" : "+#{code}#{delimiter}" - end - - def phone_ext(ext) - ext.blank? ? "" : " x #{ext}" - end - - 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 new file mode 100644 index 0000000000..c4aa5c311a --- /dev/null +++ b/activesupport/lib/active_support/number_helper/number_to_phone_converter.rb @@ -0,0 +1,51 @@ +module ActiveSupport + module NumberHelper + class NumberToPhoneConverter < NumberConverter + def convert + str = '' + str << country_code(opts[:country_code]) + str << convert_to_phone_number(@number.to_s.strip) + str << phone_ext(opts[:extension]) + end + + private + + def convert_to_phone_number(number) + if opts[:area_code] + convert_with_area_code(number) + else + convert_without_area_code(number) + end + end + + def convert_with_area_code(number) + number.gsub(/(\d{1,3})(\d{3})(\d{4}$)/,"(\\1) \\2#{delimiter}\\3") + end + + def convert_without_area_code(number) + number.tap { |n| + n.gsub!(/(\d{0,3})(\d{3})(\d{4})$/,"\\1#{delimiter}\\2#{delimiter}\\3") + n.slice!(0, 1) if begins_with_delimiter?(n) + } + end + + def begins_with_delimiter?(number) + number.start_with?(delimiter) && !delimiter.blank? + end + + def delimiter + opts[:delimiter] || "-" + end + + def country_code(code) + code.blank? ? "" : "+#{code}#{delimiter}" + end + + def phone_ext(ext) + ext.blank? ? "" : " x #{ext}" + end + + end + end +end + diff --git a/activesupport/lib/active_support/number_helper/number_to_rounded.rb b/activesupport/lib/active_support/number_helper/number_to_rounded.rb deleted file mode 100644 index 817ac1ebb2..0000000000 --- a/activesupport/lib/active_support/number_helper/number_to_rounded.rb +++ /dev/null @@ -1,62 +0,0 @@ -require 'active_support/number_helper/number_converter' - -module ActiveSupport - module NumberHelper - class NumberToRoundedConverter < NumberConverter # :nodoc: - - self.namespace = :precision - self.need_valid_float = true - - def convert - @number = Float(@number) - - precision = options.delete :precision - significant = options.delete :significant - - if significant && precision > 0 - digits, rounded_number = digits_and_rounded_number(precision) - precision -= digits - precision = 0 if precision < 0 # don't let it be negative - else - rounded_number = BigDecimal.new(@number.to_s).round(precision).to_f - rounded_number = rounded_number.abs if rounded_number.zero? # prevent showing negative zeros - end - delimited_number = NumberToDelimitedConverter.new("%01.#{precision}f" % rounded_number, options).execute - format_number(delimited_number) - end - - private - - def digits_and_rounded_number(precision) - return [1,0] if @number.zero? - digits = digit_count(@number) - multiplier = 10 ** (digits - precision) - rounded_number = calculate_rounded_number(multiplier) - digits = digit_count(rounded_number) # After rounding, the number of digits may have changed - [digits, rounded_number] - end - - def calculate_rounded_number(multiplier) - (BigDecimal.new(@number.to_s) / BigDecimal.new(multiplier.to_f.to_s)).round.to_f * multiplier - end - - def digit_count(number) - (Math.log10(number.abs) + 1).floor - end - - def strip_insignificant_zeros - options[:strip_insignificant_zeros] - end - - 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/, '') - else - number - end - 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 new file mode 100644 index 0000000000..355c810dc9 --- /dev/null +++ b/activesupport/lib/active_support/number_helper/number_to_rounded_converter.rb @@ -0,0 +1,60 @@ +module ActiveSupport + module NumberHelper + class NumberToRoundedConverter < NumberConverter # :nodoc: + + self.namespace = :precision + self.need_valid_float = true + + def convert + @number = Float(@number) + + precision = options.delete :precision + significant = options.delete :significant + + if significant && precision > 0 + digits, rounded_number = digits_and_rounded_number(precision) + precision -= digits + precision = 0 if precision < 0 # don't let it be negative + else + rounded_number = BigDecimal.new(@number.to_s).round(precision).to_f + rounded_number = rounded_number.abs if rounded_number.zero? # prevent showing negative zeros + end + delimited_number = NumberToDelimitedConverter.new("%01.#{precision}f" % rounded_number, options).execute + format_number(delimited_number) + end + + private + + def digits_and_rounded_number(precision) + return [1,0] if @number.zero? + digits = digit_count(@number) + multiplier = 10 ** (digits - precision) + rounded_number = calculate_rounded_number(multiplier) + digits = digit_count(rounded_number) # After rounding, the number of digits may have changed + [digits, rounded_number] + end + + def calculate_rounded_number(multiplier) + (BigDecimal.new(@number.to_s) / BigDecimal.new(multiplier.to_f.to_s)).round.to_f * multiplier + end + + def digit_count(number) + (Math.log10(number.abs) + 1).floor + end + + def strip_insignificant_zeros + options[:strip_insignificant_zeros] + end + + 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/, '') + else + number + end + end + + end + end +end -- cgit v1.2.3 From 5c04ca87d86074e84e4ff51bcf08b113f464558b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Mendon=C3=A7a=20Fran=C3=A7a?= Date: Mon, 2 Dec 2013 22:20:35 -0200 Subject: Make execute priave API --- activesupport/lib/active_support/number_helper.rb | 14 +++++++------- .../lib/active_support/number_helper/number_converter.rb | 3 +++ .../number_helper/number_to_currency_converter.rb | 2 +- .../number_helper/number_to_human_converter.rb | 2 +- .../number_helper/number_to_human_size_converter.rb | 2 +- .../number_helper/number_to_percentage_converter.rb | 2 +- .../number_helper/number_to_rounded_converter.rb | 3 ++- 7 files changed, 16 insertions(+), 12 deletions(-) (limited to 'activesupport/lib/active_support') diff --git a/activesupport/lib/active_support/number_helper.rb b/activesupport/lib/active_support/number_helper.rb index 2df1aada50..c6658dba96 100644 --- a/activesupport/lib/active_support/number_helper.rb +++ b/activesupport/lib/active_support/number_helper.rb @@ -42,7 +42,7 @@ module ActiveSupport # number_to_phone(1235551234, country_code: 1, extension: 1343, delimiter: '.') # # => +1.123.555.1234 x 1343 def number_to_phone(number, options = {}) - NumberToPhoneConverter.new(number, options).execute + NumberToPhoneConverter.convert(number, options) end # Formats a +number+ into a currency string (e.g., $13.65). You @@ -84,7 +84,7 @@ module ActiveSupport # number_to_currency(1234567890.50, unit: '£', separator: ',', delimiter: '', format: '%n %u') # # => 1234567890,50 £ def number_to_currency(number, options = {}) - NumberToCurrencyConverter.new(number, options).execute + NumberToCurrencyConverter.convert(number, options) end # Formats a +number+ as a percentage string (e.g., 65%). You can @@ -120,7 +120,7 @@ module ActiveSupport # number_to_percentage('98a') # => 98a% # number_to_percentage(100, format: '%n %') # => 100 % def number_to_percentage(number, options = {}) - NumberToPercentageConverter.new(number, options).execute + NumberToPercentageConverter.convert(number, options) end # Formats a +number+ with grouped thousands using +delimiter+ @@ -149,7 +149,7 @@ module ActiveSupport # number_to_delimited(98765432.98, delimiter: ' ', separator: ',') # # => 98 765 432,98 def number_to_delimited(number, options = {}) - NumberToDelimitedConverter.new(number, options).execute + NumberToDelimitedConverter.convert(number, options) end # Formats a +number+ with the specified level of @@ -192,7 +192,7 @@ module ActiveSupport # number_to_rounded(1111.2345, precision: 2, separator: ',', delimiter: '.') # # => 1.111,23 def number_to_rounded(number, options = {}) - NumberToRoundedConverter.new(number, options).execute + NumberToRoundedConverter.convert(number, options) end # Formats the bytes in +number+ into a more understandable @@ -240,7 +240,7 @@ module ActiveSupport # number_to_human_size(1234567890123, precision: 5) # => "1.1229 TB" # number_to_human_size(524288000, precision: 5) # => "500 MB" def number_to_human_size(number, options = {}) - NumberToHumanSizeConverter.new(number, options).execute + NumberToHumanSizeConverter.convert(number, options) end # Pretty prints (formats and approximates) a number in a way it @@ -341,7 +341,7 @@ module ActiveSupport # number_to_human(1, units: :distance) # => "1 meter" # number_to_human(0.34, units: :distance) # => "34 centimeters" def number_to_human(number, options = {}) - NumberToHumanConverter.new(number, options).execute + NumberToHumanConverter.convert(number, options) end end diff --git a/activesupport/lib/active_support/number_helper/number_converter.rb b/activesupport/lib/active_support/number_helper/number_converter.rb index 39255d14a3..0afa08db84 100644 --- a/activesupport/lib/active_support/number_helper/number_converter.rb +++ b/activesupport/lib/active_support/number_helper/number_converter.rb @@ -115,6 +115,9 @@ module ActiveSupport } } + def self.convert(number, options) + new(number, options).execute + end def initialize(number, opts = {}) @number = number 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 113e557415..90a3cede3a 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 @@ -13,7 +13,7 @@ module ActiveSupport number = absolute_value(number) end - rounded_number = NumberToRoundedConverter.new(number, options).execute + rounded_number = NumberToRoundedConverter.convert(number, options) format.gsub('%n', rounded_number).gsub('%u', options[:unit]) 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 3cdf6ff9f8..0c1a7250e3 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 @@ -23,7 +23,7 @@ module ActiveSupport unit = determine_unit(units, exponent) - rounded_number = NumberToRoundedConverter.new(@number, options).execute + rounded_number = NumberToRoundedConverter.convert(@number, options) format.gsub(/%n/, rounded_number).gsub(/%u/, unit).strip end 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 6a0f6e70b7..467ad030b5 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 @@ -19,7 +19,7 @@ module ActiveSupport number_to_format = @number.to_i.to_s else human_size = @number / (base ** exponent) - number_to_format = NumberToRoundedConverter.new(human_size, options).execute + number_to_format = NumberToRoundedConverter.convert(human_size, options) end conversion_format.gsub(/%n/, number_to_format).gsub(/%u/, unit) 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 b7926cf151..c654bfaa3a 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 self.namespace = :percentage def convert - rounded_number = NumberToRoundedConverter.new(number, options).execute + rounded_number = NumberToRoundedConverter.convert(number, options) options[:format].gsub('%n', rounded_number) 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 355c810dc9..820e1534e2 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 @@ -19,7 +19,8 @@ module ActiveSupport rounded_number = BigDecimal.new(@number.to_s).round(precision).to_f rounded_number = rounded_number.abs if rounded_number.zero? # prevent showing negative zeros end - delimited_number = NumberToDelimitedConverter.new("%01.#{precision}f" % rounded_number, options).execute + + delimited_number = NumberToDelimitedConverter.convert("%01.#{precision}f" % rounded_number, options) format_number(delimited_number) end -- cgit v1.2.3 From d752ae16abd5f1e48983fc12e18f50cba1896131 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Mendon=C3=A7a=20Fran=C3=A7a?= Date: Mon, 2 Dec 2013 22:21:27 -0200 Subject: Options are not optional --- activesupport/lib/active_support/number_helper/number_converter.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'activesupport/lib/active_support') diff --git a/activesupport/lib/active_support/number_helper/number_converter.rb b/activesupport/lib/active_support/number_helper/number_converter.rb index 0afa08db84..157d7820c3 100644 --- a/activesupport/lib/active_support/number_helper/number_converter.rb +++ b/activesupport/lib/active_support/number_helper/number_converter.rb @@ -119,9 +119,9 @@ module ActiveSupport new(number, options).execute end - def initialize(number, opts = {}) + def initialize(number, options) @number = number - @opts = opts.symbolize_keys + @opts = options.symbolize_keys end def execute -- cgit v1.2.3 From d7d11f0dab7f2875d04c17921e12fe62ac6e9566 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Mendon=C3=A7a=20Fran=C3=A7a?= Date: Mon, 2 Dec 2013 22:31:05 -0200 Subject: :sicssors: --- activesupport/lib/active_support/number_helper/number_converter.rb | 4 ++-- .../lib/active_support/number_helper/number_to_currency_converter.rb | 2 -- .../lib/active_support/number_helper/number_to_delimited_converter.rb | 2 -- .../lib/active_support/number_helper/number_to_human_converter.rb | 2 -- .../active_support/number_helper/number_to_human_size_converter.rb | 2 -- .../active_support/number_helper/number_to_percentage_converter.rb | 2 -- .../lib/active_support/number_helper/number_to_phone_converter.rb | 1 - .../lib/active_support/number_helper/number_to_rounded_converter.rb | 2 -- 8 files changed, 2 insertions(+), 15 deletions(-) (limited to 'activesupport/lib/active_support') diff --git a/activesupport/lib/active_support/number_helper/number_converter.rb b/activesupport/lib/active_support/number_helper/number_converter.rb index 157d7820c3..4bc8b4a8e7 100644 --- a/activesupport/lib/active_support/number_helper/number_converter.rb +++ b/activesupport/lib/active_support/number_helper/number_converter.rb @@ -7,7 +7,6 @@ require 'active_support/core_ext/class/attribute' module ActiveSupport module NumberHelper class NumberConverter # :nodoc: - # Default and i18n option namespace per class class_attribute :namespace @@ -149,9 +148,11 @@ module ActiveSupport def i18n_format_options #:nodoc: locale = opts[:locale] options = I18n.translate(:'number.format', locale: locale, default: {}).dup + if namespace options.merge!(I18n.translate(:"number.#{namespace}.format", locale: locale, default: {})) end + options end @@ -172,7 +173,6 @@ module ActiveSupport rescue ArgumentError, TypeError false end - end end end 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 90a3cede3a..28f33164a5 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,7 +1,6 @@ module ActiveSupport module NumberHelper class NumberToCurrencyConverter < NumberConverter # :nodoc: - self.namespace = :currency def convert @@ -42,7 +41,6 @@ module ActiveSupport i18n[:negative_format] ||= "-#{i18n[:format]}" if i18n[:format] i18n end - end end end 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 6604b9cce4..2b5dbd1d5a 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 @@ -1,7 +1,6 @@ module ActiveSupport module NumberHelper class NumberToDelimitedConverter < NumberConverter #:nodoc: - self.need_valid_float = true DELIMITED_REGEX = /(\d)(?=(\d\d\d)+(?!\d))/ @@ -17,7 +16,6 @@ module ActiveSupport left.gsub!(DELIMITED_REGEX) { "#{$1}#{options[:delimiter]}" } [left, right].compact 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 0c1a7250e3..9cdc18c373 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 @@ -1,7 +1,6 @@ module ActiveSupport module NumberHelper class NumberToHumanConverter < NumberConverter # :nodoc: - DECIMAL_UNITS = { 0 => :unit, 1 => :ten, 2 => :hundred, 3 => :thousand, 6 => :million, 9 => :billion, 12 => :trillion, 15 => :quadrillion, -1 => :deci, -2 => :centi, -3 => :mili, -6 => :micro, -9 => :nano, -12 => :pico, -15 => :femto } INVERTED_DECIMAL_UNITS = DECIMAL_UNITS.invert @@ -62,7 +61,6 @@ module ActiveSupport raise ArgumentError, ":units must be a Hash or String translation scope." end.keys.map { |e_name| INVERTED_DECIMAL_UNITS[e_name] }.sort_by { |e| -e } end - end end end 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 467ad030b5..33fc6e3553 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 @@ -1,7 +1,6 @@ module ActiveSupport module NumberHelper class NumberToHumanSizeConverter < NumberConverter - STORAGE_UNITS = [:byte, :kb, :mb, :gb, :tb] self.namespace = :human @@ -53,7 +52,6 @@ module ActiveSupport def base opts[:prefix] == :si ? 1000 : 1024 end - 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 c654bfaa3a..eafe2844f7 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 @@ -1,14 +1,12 @@ module ActiveSupport module NumberHelper class NumberToPercentageConverter < NumberConverter # :nodoc: - self.namespace = :percentage def convert rounded_number = NumberToRoundedConverter.convert(number, options) options[:format].gsub('%n', rounded_number) end - 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 c4aa5c311a..9828bec053 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 @@ -44,7 +44,6 @@ module ActiveSupport def phone_ext(ext) ext.blank? ? "" : " x #{ext}" 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 820e1534e2..ab430bbc7a 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 @@ -1,7 +1,6 @@ module ActiveSupport module NumberHelper class NumberToRoundedConverter < NumberConverter # :nodoc: - self.namespace = :precision self.need_valid_float = true @@ -55,7 +54,6 @@ module ActiveSupport number end end - end end end -- cgit v1.2.3 From 735abe93a5590f3d6f215a645e633d9fcd8ff3b6 Mon Sep 17 00:00:00 2001 From: Carlos Antonio da Silva Date: Mon, 2 Dec 2013 22:59:40 -0200 Subject: Avoid generating more strings while iterating to create methods Use the already existing strings instead of creating a new one each time just to test if it responds to the methods. --- activesupport/lib/active_support/core_ext/string/output_safety.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'activesupport/lib/active_support') 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 dc033ed11b..c21650bb83 100644 --- a/activesupport/lib/active_support/core_ext/string/output_safety.rb +++ b/activesupport/lib/active_support/core_ext/string/output_safety.rb @@ -171,7 +171,7 @@ module ActiveSupport #:nodoc: end UNSAFE_STRING_METHODS.each do |unsafe_method| - if 'String'.respond_to?(unsafe_method) + if unsafe_method.respond_to?(unsafe_method) class_eval <<-EOT, __FILE__, __LINE__ + 1 def #{unsafe_method}(*args, &block) # def capitalize(*args, &block) to_str.#{unsafe_method}(*args, &block) # to_str.capitalize(*args, &block) -- cgit v1.2.3 From fadc02b7322c97f10d34fc04c147f3585eda1272 Mon Sep 17 00:00:00 2001 From: Godfrey Chan Date: Tue, 26 Nov 2013 14:05:12 -0800 Subject: Added back the `encode_big_decimal_as_string` option with warning Also added the missing CHANGELOG entry for #12183 @ 80e7552073 and 4d02296cfb. --- activesupport/lib/active_support/json/encoding.rb | 27 +++++++++++++++++++++++ 1 file changed, 27 insertions(+) (limited to 'activesupport/lib/active_support') diff --git a/activesupport/lib/active_support/json/encoding.rb b/activesupport/lib/active_support/json/encoding.rb index eb25ef7a4c..060dcb6995 100644 --- a/activesupport/lib/active_support/json/encoding.rb +++ b/activesupport/lib/active_support/json/encoding.rb @@ -5,6 +5,7 @@ module ActiveSupport class << self delegate :use_standard_json_time_format, :use_standard_json_time_format=, :escape_html_entities_in_json, :escape_html_entities_in_json=, + :encode_big_decimal_as_string, :encode_big_decimal_as_string=, :json_encoder, :json_encoder=, :to => :'ActiveSupport::JSON::Encoding' end @@ -113,6 +114,32 @@ module ActiveSupport # in +Object#to_json+ and +ActiveSupport::JSON.encode+. attr_accessor :json_encoder + def encode_big_decimal_as_string=(as_string) + message = \ + "The JSON encoder in Rails 4.1 no longer supports encoding BigDecimals as JSON numbers. Instead, " \ + "the new encoder will always encode them as strings.\n\n" \ + "You are seeing this error because you have 'active_support.encode_big_decimal_as_string' in " \ + "your configuration file. If you have been setting this to true, you can safely remove it from " \ + "your configuration. Otherwise, you should add the 'activesupport-json_encoder' gem to your " \ + "Gemfile in order to restore this functionality." + + raise NotImplementedError, message + end + + def encode_big_decimal_as_string + message = \ + "The JSON encoder in Rails 4.1 no longer supports encoding BigDecimals as JSON numbers. Instead, " \ + "the new encoder will always encode them as strings.\n\n" \ + "You are seeing this error because you are trying to check the value of the related configuration, " \ + "'active_support.encode_big_decimal_as_string'. If your application depends on this option, you should " \ + "add the 'activesupport-json_encoder' gem to your Gemfile. For now, this option will always be true. " \ + "In the future, it will be removed from Rails, so you should stop checking its value." + + ActiveSupport::Deprecation.warn message + + true + end + # Deprecate CircularReferenceError def const_missing(name) if name == :CircularReferenceError -- cgit v1.2.3 From 2ebf47aea21ff8ac10681e53e78dd7a0e5c31c6e Mon Sep 17 00:00:00 2001 From: Nerian Date: Sat, 27 Jul 2013 18:37:28 +0200 Subject: Modify the Hash#assert_valid_keys error message so that it shows the valid keys. Also, show the wrong value as it was entered. { :failore => "stuff", :funny => "business" }.assert_valid_keys([ :failure, :funny ]) => ArgumentError: Unknown key: failore { 'failore' => "stuff", :funny => "business" }.assert_valid_keys([ :failure, :funny ]) => ArgumentError: Unknown key: failore { 'failore' => "stuff", :funny => "business" }.assert_valid_keys([ :failure, :funny ]) => ArgumentError: Unknown key: "failore". Valid keys are: :failure, :funny { :failore => "stuff", :funny => "business" }.assert_valid_keys([ :failure, :funny ]) => ArgumentError: Unknown key: :failore. Valid keys are: :failure, :funny Conflicts: activerecord/CHANGELOG.md Closes #11624. --- activesupport/lib/active_support/core_ext/hash/keys.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'activesupport/lib/active_support') diff --git a/activesupport/lib/active_support/core_ext/hash/keys.rb b/activesupport/lib/active_support/core_ext/hash/keys.rb index f35c2be4c2..d31bbd5c88 100644 --- a/activesupport/lib/active_support/core_ext/hash/keys.rb +++ b/activesupport/lib/active_support/core_ext/hash/keys.rb @@ -61,13 +61,13 @@ class Hash # on a mismatch. Note that keys are NOT treated indifferently, meaning if you # use strings for keys but assert symbols as keys, this will fail. # - # { name: 'Rob', years: '28' }.assert_valid_keys(:name, :age) # => raises "ArgumentError: Unknown key: years" - # { name: 'Rob', age: '28' }.assert_valid_keys('name', 'age') # => raises "ArgumentError: Unknown key: name" + # { name: 'Rob', years: '28' }.assert_valid_keys(:name, :age) # => raises "ArgumentError: Unknown key: :years. Valid keys are: :name, :age" + # { name: 'Rob', age: '28' }.assert_valid_keys('name', 'age') # => raises "ArgumentError: Unknown key: :name. Valid keys are: 'name', 'age'" # { name: 'Rob', age: '28' }.assert_valid_keys(:name, :age) # => passes, raises nothing def assert_valid_keys(*valid_keys) valid_keys.flatten! each_key do |k| - raise ArgumentError.new("Unknown key: #{k}") unless valid_keys.include?(k) + raise ArgumentError.new("Unknown key: #{k.inspect}. Valid keys are: #{valid_keys.map(&:inspect).join(', ')}") unless valid_keys.include?(k) end end -- cgit v1.2.3 From c48a0cac626b4e32d7abfa9f4f1fae16568157d9 Mon Sep 17 00:00:00 2001 From: Carlos Antonio da Silva Date: Tue, 3 Dec 2013 00:15:34 -0200 Subject: Tidy up previous commit, fix message assertion and improve tests --- activesupport/lib/active_support/core_ext/hash/keys.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'activesupport/lib/active_support') diff --git a/activesupport/lib/active_support/core_ext/hash/keys.rb b/activesupport/lib/active_support/core_ext/hash/keys.rb index d31bbd5c88..93e716585b 100644 --- a/activesupport/lib/active_support/core_ext/hash/keys.rb +++ b/activesupport/lib/active_support/core_ext/hash/keys.rb @@ -67,7 +67,9 @@ class Hash def assert_valid_keys(*valid_keys) valid_keys.flatten! each_key do |k| - raise ArgumentError.new("Unknown key: #{k.inspect}. Valid keys are: #{valid_keys.map(&:inspect).join(', ')}") unless valid_keys.include?(k) + unless valid_keys.include?(k) + raise ArgumentError.new("Unknown key: #{k.inspect}. Valid keys are: #{valid_keys.map(&:inspect).join(', ')}") + end end end -- cgit v1.2.3 From b1b9a0aeca879b1c1bc2c8a74f2c9cabd143b9bb Mon Sep 17 00:00:00 2001 From: Lauro Caetano Date: Tue, 3 Dec 2013 12:04:25 -0200 Subject: Typos. return -> returns. [ci skip] --- activesupport/lib/active_support/cache.rb | 2 +- activesupport/lib/active_support/core_ext/hash/except.rb | 2 +- activesupport/lib/active_support/core_ext/hash/keys.rb | 12 ++++++------ activesupport/lib/active_support/values/time_zone.rb | 4 ++-- 4 files changed, 10 insertions(+), 10 deletions(-) (limited to 'activesupport/lib/active_support') diff --git a/activesupport/lib/active_support/cache.rb b/activesupport/lib/active_support/cache.rb index 5c1d473161..912fd1a20a 100644 --- a/activesupport/lib/active_support/cache.rb +++ b/activesupport/lib/active_support/cache.rb @@ -401,7 +401,7 @@ module ActiveSupport end end - # Return +true+ if the cache contains an entry for the given key. + # Returns +true+ if the cache contains an entry for the given key. # # Options are passed to the underlying cache implementation. def exist?(name, options = nil) diff --git a/activesupport/lib/active_support/core_ext/hash/except.rb b/activesupport/lib/active_support/core_ext/hash/except.rb index d90e996ad4..682d089881 100644 --- a/activesupport/lib/active_support/core_ext/hash/except.rb +++ b/activesupport/lib/active_support/core_ext/hash/except.rb @@ -1,5 +1,5 @@ class Hash - # Return a hash that includes everything but the given keys. This is useful for + # Returns a hash that includes everything but the given keys. This is useful for # limiting a set of parameters to everything but a few known toggles: # # @person.update(params[:person].except(:admin)) diff --git a/activesupport/lib/active_support/core_ext/hash/keys.rb b/activesupport/lib/active_support/core_ext/hash/keys.rb index f35c2be4c2..2114202eb0 100644 --- a/activesupport/lib/active_support/core_ext/hash/keys.rb +++ b/activesupport/lib/active_support/core_ext/hash/keys.rb @@ -1,5 +1,5 @@ class Hash - # Return a new hash with all keys converted using the block operation. + # Returns a new hash with all keys converted using the block operation. # # hash = { name: 'Rob', age: '28' } # @@ -22,7 +22,7 @@ class Hash self end - # Return a new hash with all keys converted to strings. + # Returns a new hash with all keys converted to strings. # # hash = { name: 'Rob', age: '28' } # @@ -38,7 +38,7 @@ class Hash transform_keys!{ |key| key.to_s } end - # Return a new hash with all keys converted to symbols, as long as + # Returns a new hash with all keys converted to symbols, as long as # they respond to +to_sym+. # # hash = { 'name' => 'Rob', 'age' => '28' } @@ -71,7 +71,7 @@ class Hash end end - # Return a new hash with all keys converted by the block operation. + # Returns a new hash with all keys converted by the block operation. # This includes the keys from the root hash and from all # nested hashes. # @@ -98,7 +98,7 @@ class Hash self end - # Return a new hash with all keys converted to strings. + # Returns a new hash with all keys converted to strings. # This includes the keys from the root hash and from all # nested hashes. # @@ -117,7 +117,7 @@ class Hash deep_transform_keys!{ |key| key.to_s } end - # Return a new hash with all keys converted to symbols, as long as + # Returns a new hash with all keys converted to symbols, as long as # they respond to +to_sym+. This includes the keys from the root hash # and from all nested hashes. # diff --git a/activesupport/lib/active_support/values/time_zone.rb b/activesupport/lib/active_support/values/time_zone.rb index 3cf82a24b9..a834e526fb 100644 --- a/activesupport/lib/active_support/values/time_zone.rb +++ b/activesupport/lib/active_support/values/time_zone.rb @@ -346,14 +346,14 @@ module ActiveSupport class << self alias_method :create, :new - # Return a TimeZone instance with the given name, or +nil+ if no + # Returns a TimeZone instance with the given name, or +nil+ if no # such TimeZone instance exists. (This exists to support the use of # this class with the +composed_of+ macro.) def new(name) self[name] end - # Return an array of all TimeZone objects. There are multiple + # Returns an array of all TimeZone objects. There are multiple # TimeZone objects per time zone, in many cases, to make it easier # for users to find their own time zone. def all -- cgit v1.2.3 From 029f24ede99e99b3c988f84b4709add754459fc6 Mon Sep 17 00:00:00 2001 From: Colin Bartlett Date: Sat, 9 Nov 2013 09:23:15 -0500 Subject: Add support for localized date references Ruby's Date class automatically gives us #yesterday, #today, and #tomorrow. And ActiveSupport has a handy Time.zone.today for getting a localized version. But there was no localized version of #yesterday or #tomorrow. Until now. --- activesupport/lib/active_support/values/time_zone.rb | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'activesupport/lib/active_support') diff --git a/activesupport/lib/active_support/values/time_zone.rb b/activesupport/lib/active_support/values/time_zone.rb index b6d9257f00..a22e61d286 100644 --- a/activesupport/lib/active_support/values/time_zone.rb +++ b/activesupport/lib/active_support/values/time_zone.rb @@ -317,6 +317,16 @@ module ActiveSupport tzinfo.now.to_date end + # Returns the next date in this time zone. + def tomorrow + today + 1 + end + + # Returns the previous date in this time zone. + def yesterday + today - 1 + end + # Adjust the given time to the simultaneous time in the time zone # represented by +self+. Returns a Time.utc() instance -- if you want an # ActiveSupport::TimeWithZone instance, use Time#in_time_zone() instead. -- cgit v1.2.3 From 18546d4e3551e21ea781dba8c69383c0538b4086 Mon Sep 17 00:00:00 2001 From: Dimko Date: Tue, 12 Mar 2013 17:18:26 +0400 Subject: Added Date#all_week/month/quarter/year for generating date ranges --- .../core_ext/date_and_time/calculations.rb | 21 +++++++++++++++++++++ .../active_support/core_ext/time/calculations.rb | 21 --------------------- 2 files changed, 21 insertions(+), 21 deletions(-) (limited to 'activesupport/lib/active_support') 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 c869a0e210..b85e49aca5 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 @@ -213,6 +213,27 @@ module DateAndTime end alias :at_end_of_year :end_of_year + # Returns a Range representing the whole week of the current date/time. + # Week starts on start_day, default is Date.week_start or config.week_start when set. + def all_week(start_day = Date.beginning_of_week) + beginning_of_week(start_day)..end_of_week(start_day) + end + + # Returns a Range representing the whole month of the current date/time. + def all_month + beginning_of_month..end_of_month + end + + # Returns a Range representing the whole quarter of the current date/time. + def all_quarter + beginning_of_quarter..end_of_quarter + end + + # Returns a Range representing the whole year of the current date/time. + def all_year + beginning_of_year..end_of_year + end + private def first_hour(date_or_time) diff --git a/activesupport/lib/active_support/core_ext/time/calculations.rb b/activesupport/lib/active_support/core_ext/time/calculations.rb index 6e0af0db4d..5ebafcc26e 100644 --- a/activesupport/lib/active_support/core_ext/time/calculations.rb +++ b/activesupport/lib/active_support/core_ext/time/calculations.rb @@ -199,27 +199,6 @@ class Time beginning_of_day..end_of_day end - # Returns a Range representing the whole week of the current time. - # Week starts on start_day, default is Date.week_start or config.week_start when set. - def all_week(start_day = Date.beginning_of_week) - beginning_of_week(start_day)..end_of_week(start_day) - end - - # Returns a Range representing the whole month of the current time. - def all_month - beginning_of_month..end_of_month - end - - # Returns a Range representing the whole quarter of the current time. - def all_quarter - beginning_of_quarter..end_of_quarter - end - - # Returns a Range representing the whole year of the current time. - def all_year - beginning_of_year..end_of_year - end - def plus_with_duration(other) #:nodoc: if ActiveSupport::Duration === other other.since(self) -- cgit v1.2.3 From 72db343334d4188a27e9c6542d6527e091f46431 Mon Sep 17 00:00:00 2001 From: Carlos Antonio da Silva Date: Tue, 3 Dec 2013 19:39:36 -0200 Subject: Rename variable that holds whether or not the class should validate a float number --- activesupport/lib/active_support/number_helper/number_converter.rb | 4 ++-- .../lib/active_support/number_helper/number_to_delimited_converter.rb | 2 +- .../lib/active_support/number_helper/number_to_human_converter.rb | 4 ++-- .../active_support/number_helper/number_to_human_size_converter.rb | 4 ++-- .../lib/active_support/number_helper/number_to_rounded_converter.rb | 4 ++-- 5 files changed, 9 insertions(+), 9 deletions(-) (limited to 'activesupport/lib/active_support') diff --git a/activesupport/lib/active_support/number_helper/number_converter.rb b/activesupport/lib/active_support/number_helper/number_converter.rb index 4bc8b4a8e7..537bf1e5b6 100644 --- a/activesupport/lib/active_support/number_helper/number_converter.rb +++ b/activesupport/lib/active_support/number_helper/number_converter.rb @@ -11,7 +11,7 @@ module ActiveSupport class_attribute :namespace # Does the object need a number that is a valid float? - class_attribute :need_valid_float + class_attribute :validate_float attr_reader :number, :opts @@ -125,7 +125,7 @@ module ActiveSupport def execute return unless @number - return @number if need_valid_float? && !valid_float? + return @number if validate_float? && !valid_float? convert end 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 2b5dbd1d5a..6405afc9a6 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 @@ -1,7 +1,7 @@ module ActiveSupport module NumberHelper class NumberToDelimitedConverter < NumberConverter #:nodoc: - self.need_valid_float = true + self.validate_float = true DELIMITED_REGEX = /(\d)(?=(\d\d\d)+(?!\d))/ 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 9cdc18c373..1ced75ed8a 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 @@ -5,8 +5,8 @@ module ActiveSupport -1 => :deci, -2 => :centi, -3 => :mili, -6 => :micro, -9 => :nano, -12 => :pico, -15 => :femto } INVERTED_DECIMAL_UNITS = DECIMAL_UNITS.invert - self.namespace = :human - self.need_valid_float = true + self.namespace = :human + self.validate_float = true def convert # :nodoc: @number = Float(@number) 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 33fc6e3553..37590c27ef 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 @@ -3,8 +3,8 @@ module ActiveSupport class NumberToHumanSizeConverter < NumberConverter STORAGE_UNITS = [:byte, :kb, :mb, :gb, :tb] - self.namespace = :human - self.need_valid_float = true + self.namespace = :human + self.validate_float = true def convert @number = Float(@number) 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 ab430bbc7a..708fb57185 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 @@ -1,8 +1,8 @@ module ActiveSupport module NumberHelper class NumberToRoundedConverter < NumberConverter # :nodoc: - self.namespace = :precision - self.need_valid_float = true + self.namespace = :precision + self.validate_float = true def convert @number = Float(@number) -- cgit v1.2.3 From 4e19ef9b25e7461be654c6e5bc085addbefc459e Mon Sep 17 00:00:00 2001 From: Carlos Antonio da Silva Date: Tue, 3 Dec 2013 19:42:49 -0200 Subject: Refactor to avoid earlier returns --- .../lib/active_support/number_helper/number_converter.rb | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 'activesupport/lib/active_support') diff --git a/activesupport/lib/active_support/number_helper/number_converter.rb b/activesupport/lib/active_support/number_helper/number_converter.rb index 537bf1e5b6..471c686997 100644 --- a/activesupport/lib/active_support/number_helper/number_converter.rb +++ b/activesupport/lib/active_support/number_helper/number_converter.rb @@ -119,14 +119,18 @@ module ActiveSupport end def initialize(number, options) - @number = number - @opts = options.symbolize_keys + @number = number + @opts = options.symbolize_keys end def execute - return unless @number - return @number if validate_float? && !valid_float? - convert + if !@number + nil + elsif validate_float? && !valid_float? + @number + else + convert + end end private -- cgit v1.2.3 From e56a553c9536225296a98f82d4625ee2b94a2b2f Mon Sep 17 00:00:00 2001 From: Carlos Antonio da Silva Date: Tue, 3 Dec 2013 19:49:19 -0200 Subject: Stop using local variables everywhere, make use of the reader --- .../lib/active_support/number_helper/number_converter.rb | 6 +++--- .../number_helper/number_to_currency_converter.rb | 4 ++-- .../number_helper/number_to_human_converter.rb | 6 +++--- .../number_helper/number_to_human_size_converter.rb | 12 ++++++------ .../number_helper/number_to_phone_converter.rb | 2 +- .../number_helper/number_to_rounded_converter.rb | 10 +++++----- 6 files changed, 20 insertions(+), 20 deletions(-) (limited to 'activesupport/lib/active_support') diff --git a/activesupport/lib/active_support/number_helper/number_converter.rb b/activesupport/lib/active_support/number_helper/number_converter.rb index 471c686997..9d976f1831 100644 --- a/activesupport/lib/active_support/number_helper/number_converter.rb +++ b/activesupport/lib/active_support/number_helper/number_converter.rb @@ -124,10 +124,10 @@ module ActiveSupport end def execute - if !@number + if !number nil elsif validate_float? && !valid_float? - @number + number else convert end @@ -173,7 +173,7 @@ module ActiveSupport end def valid_float? #:nodoc: - Float(@number) + Float(number) rescue ArgumentError, TypeError false end 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 28f33164a5..11ba0605e0 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 @@ -4,8 +4,8 @@ module ActiveSupport self.namespace = :currency def convert - number = @number.to_s.strip - format = options[:format] + number = self.number.to_s.strip + format = options[:format] if is_negative?(number) format = options[:negative_format] 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 1ced75ed8a..9a3dc526ae 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 @@ -9,7 +9,7 @@ module ActiveSupport self.validate_float = true def convert # :nodoc: - @number = Float(@number) + @number = Float(number) # for backwards compatibility with those that didn't add strip_insignificant_zeros to their locale files unless options.key?(:strip_insignificant_zeros) @@ -18,11 +18,11 @@ module ActiveSupport units = opts[:units] exponent = calculate_exponent(units) - @number = @number / (10 ** exponent) + @number = number / (10 ** exponent) unit = determine_unit(units, exponent) - rounded_number = NumberToRoundedConverter.convert(@number, options) + rounded_number = NumberToRoundedConverter.convert(number, options) format.gsub(/%n/, rounded_number).gsub(/%u/, unit).strip end 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 37590c27ef..d1335f6910 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 @@ -7,7 +7,7 @@ module ActiveSupport self.validate_float = true def convert - @number = Float(@number) + @number = Float(number) # for backwards compatibility with those that didn't add strip_insignificant_zeros to their locale files unless options.key?(:strip_insignificant_zeros) @@ -15,9 +15,9 @@ module ActiveSupport end if smaller_than_base? - number_to_format = @number.to_i.to_s + number_to_format = number.to_i.to_s else - human_size = @number / (base ** exponent) + human_size = number / (base ** exponent) number_to_format = NumberToRoundedConverter.convert(human_size, options) end conversion_format.gsub(/%n/, number_to_format).gsub(/%u/, unit) @@ -30,7 +30,7 @@ module ActiveSupport 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 @@ -40,13 +40,13 @@ module ActiveSupport def exponent max = STORAGE_UNITS.size - 1 - exp = (Math.log(@number) / Math.log(base)).to_i + exp = (Math.log(number) / Math.log(base)).to_i exp = max if exp > max # avoid overflow for the highest unit exp end def smaller_than_base? - @number.to_i < base + number.to_i < base end def base 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 9828bec053..ac51ceabc1 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 @@ -4,7 +4,7 @@ module ActiveSupport def convert str = '' str << country_code(opts[:country_code]) - str << convert_to_phone_number(@number.to_s.strip) + str << convert_to_phone_number(number.to_s.strip) str << phone_ext(opts[:extension]) 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 708fb57185..c736469355 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 @@ -5,7 +5,7 @@ module ActiveSupport self.validate_float = true def convert - @number = Float(@number) + @number = Float(number) precision = options.delete :precision significant = options.delete :significant @@ -15,7 +15,7 @@ module ActiveSupport precision -= digits precision = 0 if precision < 0 # don't let it be negative else - rounded_number = BigDecimal.new(@number.to_s).round(precision).to_f + rounded_number = BigDecimal.new(number.to_s).round(precision).to_f rounded_number = rounded_number.abs if rounded_number.zero? # prevent showing negative zeros end @@ -26,8 +26,8 @@ module ActiveSupport private def digits_and_rounded_number(precision) - return [1,0] if @number.zero? - digits = digit_count(@number) + return [1,0] if number.zero? + digits = digit_count(number) multiplier = 10 ** (digits - precision) rounded_number = calculate_rounded_number(multiplier) digits = digit_count(rounded_number) # After rounding, the number of digits may have changed @@ -35,7 +35,7 @@ module ActiveSupport end def calculate_rounded_number(multiplier) - (BigDecimal.new(@number.to_s) / BigDecimal.new(multiplier.to_f.to_s)).round.to_f * multiplier + (BigDecimal.new(number.to_s) / BigDecimal.new(multiplier.to_f.to_s)).round.to_f * multiplier end def digit_count(number) -- cgit v1.2.3 From 55afd62f2364cf86a697b7fe9913a05c2157ac92 Mon Sep 17 00:00:00 2001 From: Carlos Antonio da Silva Date: Tue, 3 Dec 2013 19:52:35 -0200 Subject: Avoid a hash creation since defaults is a new hash already --- .../lib/active_support/number_helper/number_to_currency_converter.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'activesupport/lib/active_support') 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 11ba0605e0..9ae27a896a 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 @@ -31,7 +31,7 @@ module ActiveSupport defaults = default_format_options.merge(i18n_opts) # Override negative format if format options is given defaults[:negative_format] = "-#{opts[:format]}" if opts[:format] - defaults.merge(opts) + defaults.merge!(opts) end end -- cgit v1.2.3 From da507b71f66bca61d06328a876ac1b1482e8fb81 Mon Sep 17 00:00:00 2001 From: Carlos Antonio da Silva Date: Tue, 3 Dec 2013 19:53:45 -0200 Subject: No need for #tap --- .../lib/active_support/number_helper/number_to_phone_converter.rb | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'activesupport/lib/active_support') 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 ac51ceabc1..300924bded 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 @@ -23,10 +23,9 @@ module ActiveSupport end def convert_without_area_code(number) - number.tap { |n| - n.gsub!(/(\d{0,3})(\d{3})(\d{4})$/,"\\1#{delimiter}\\2#{delimiter}\\3") - n.slice!(0, 1) if begins_with_delimiter?(n) - } + number.gsub!(/(\d{0,3})(\d{3})(\d{4})$/,"\\1#{delimiter}\\2#{delimiter}\\3") + number.slice!(0, 1) if begins_with_delimiter?(number) + number end def begins_with_delimiter?(number) -- cgit v1.2.3 From 308ed01f14d89f84793d471c40325dc5fe25efda Mon Sep 17 00:00:00 2001 From: Carlos Antonio da Silva Date: Tue, 3 Dec 2013 19:54:51 -0200 Subject: Remove useless empty string --- .../lib/active_support/number_helper/number_to_phone_converter.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'activesupport/lib/active_support') 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 300924bded..e7840e98c3 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 @@ -2,8 +2,7 @@ module ActiveSupport module NumberHelper class NumberToPhoneConverter < NumberConverter def convert - str = '' - str << country_code(opts[:country_code]) + str = country_code(opts[:country_code]) str << convert_to_phone_number(number.to_s.strip) str << phone_ext(opts[:extension]) end -- cgit v1.2.3 From a63d8cd9e165cecb3f083eb80fd0ac048464d312 Mon Sep 17 00:00:00 2001 From: Carlos Antonio da Silva Date: Tue, 3 Dec 2013 19:55:40 -0200 Subject: Make both conversion methods work similarly The conversion without area code already changed the passed number in place, so change the other method to do the same. --- .../lib/active_support/number_helper/number_to_phone_converter.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'activesupport/lib/active_support') 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 e7840e98c3..045f86c10f 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,7 +18,8 @@ module ActiveSupport end def convert_with_area_code(number) - number.gsub(/(\d{1,3})(\d{3})(\d{4}$)/,"(\\1) \\2#{delimiter}\\3") + number.gsub!(/(\d{1,3})(\d{3})(\d{4}$)/,"(\\1) \\2#{delimiter}\\3") + number end def convert_without_area_code(number) -- cgit v1.2.3 From 59ba94e8a2e6e88cdf4e13d34e18fc7c53265407 Mon Sep 17 00:00:00 2001 From: Carlos Antonio da Silva Date: Tue, 3 Dec 2013 19:57:44 -0200 Subject: Change delimiter check order: first check if it is present This reads a lot better, and we won't need to try start_with? for blank delimiters. Also rename method name to read better. --- .../lib/active_support/number_helper/number_to_phone_converter.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'activesupport/lib/active_support') 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 045f86c10f..4c33c30772 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 @@ -24,12 +24,12 @@ module ActiveSupport def convert_without_area_code(number) number.gsub!(/(\d{0,3})(\d{3})(\d{4})$/,"\\1#{delimiter}\\2#{delimiter}\\3") - number.slice!(0, 1) if begins_with_delimiter?(number) + number.slice!(0, 1) if start_with_delimiter?(number) number end - def begins_with_delimiter?(number) - number.start_with?(delimiter) && !delimiter.blank? + def start_with_delimiter?(number) + delimiter.present? && number.start_with?(delimiter) end def delimiter -- cgit v1.2.3 From d5332de37963ab41372541fc8cf66f602663abf4 Mon Sep 17 00:00:00 2001 From: Carlos Antonio da Silva Date: Tue, 3 Dec 2013 20:12:07 -0200 Subject: Remove earlier return in favor of conditional --- .../number_helper/number_to_rounded_converter.rb | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) (limited to 'activesupport/lib/active_support') 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 c736469355..273667fdae 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 @@ -26,12 +26,15 @@ module ActiveSupport private def digits_and_rounded_number(precision) - return [1,0] if number.zero? - digits = digit_count(number) - multiplier = 10 ** (digits - precision) - rounded_number = calculate_rounded_number(multiplier) - digits = digit_count(rounded_number) # After rounding, the number of digits may have changed - [digits, rounded_number] + if number.zero? + [1, 0] + else + digits = digit_count(number) + multiplier = 10 ** (digits - precision) + rounded_number = calculate_rounded_number(multiplier) + digits = digit_count(rounded_number) # After rounding, the number of digits may have changed + [digits, rounded_number] + end end def calculate_rounded_number(multiplier) -- cgit v1.2.3 From 2f1c5789c1882413df0346fec1f29eed24f37698 Mon Sep 17 00:00:00 2001 From: Godfrey Chan Date: Wed, 27 Nov 2013 02:36:10 -0800 Subject: Fixed a long-standing bug in `json_escape` that strips quotation marks --- .../core_ext/string/output_safety.rb | 61 +++++++++++++++++----- 1 file changed, 49 insertions(+), 12 deletions(-) (limited to 'activesupport/lib/active_support') 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 c21650bb83..d54265f1b1 100644 --- a/activesupport/lib/active_support/core_ext/string/output_safety.rb +++ b/activesupport/lib/active_support/core_ext/string/output_safety.rb @@ -6,7 +6,7 @@ class ERB HTML_ESCAPE = { '&' => '&', '>' => '>', '<' => '<', '"' => '"', "'" => ''' } JSON_ESCAPE = { '&' => '\u0026', '>' => '\u003E', '<' => '\u003C' } HTML_ESCAPE_ONCE_REGEXP = /["><']|&(?!([a-zA-Z]+|(#\d+));)/ - JSON_ESCAPE_REGEXP = /[&"><]/ + JSON_ESCAPE_REGEXP = /[&><]/ # A utility method for escaping HTML tag characters. # This method is also aliased as h. @@ -48,17 +48,54 @@ class ERB module_function :html_escape_once - # A utility method for escaping HTML entities in JSON strings - # using \uXXXX JavaScript escape sequences for string literals: - # - # json_escape('is a > 0 & a < 10?') - # # => is a \u003E 0 \u0026 a \u003C 10? - # - # Note that after this operation is performed the output is not - # valid JSON. In particular double quotes are removed: - # - # json_escape('{"name":"john","created_at":"2010-04-28T01:39:31Z","id":1}') - # # => {name:john,created_at:2010-04-28T01:39:31Z,id:1} + # A utility method for escaping HTML entities in JSON strings. Specifically, the + # &, > and < characters are replaced with their equivilant unicode escaped form - + # \u0026, \u003e, and \u003c. These sequences has identical meaning as the original + # characters inside the context of a JSON string, so assuming the input is a valid + # and well-formed JSON value, the output will have equivilant meaning when parsed: + # + # json = JSON.generate({ name: ""}) + # # => "{\"name\":\"\"}" + # + # json_escape(json) + # # => "{\"name\":\"\\u003C/script\\u003E\\u003Cscript\\u003Ealert('PWNED!!!')\\u003C/script\\u003E\"}" + # + # JSON.parse(json) == JSON.parse(json_escape(json)) + # # => true + # + # The intended use case for this method is to escape JSON strings before including + # them inside a script tag to avoid XSS vulnerability: + # + # + # + # WARNING: this helper only works with valid JSON. Using this on non-JSON values + # will open up serious XSS vulnerabilities. For example, if you replace the + # +current_user.to_json+ in the example above with user input instead, the browser + # will happily eval() that string as JavaScript. + # + # The escaping performed in this method is identical to those performed in the + # ActiveSupport JSON encoder when +ActiveSupport.escape_html_entities_in_json+ is + # set to true. Because this transformation is idempotent, this helper can be + # applied even if +ActiveSupport.escape_html_entities_in_json+ is already true. + # + # Therefore, when you are unsure if +ActiveSupport.escape_html_entities_in_json+ + # is enabled, or if you are unsure where your JSON string originated from, it + # is recommended that you always apply this helper (other libraries, such as the + # JSON gem, does not provide this kind of protection by default; also some gems + # might override +#to_json+ to bypass ActiveSupport's encoder). + # + # The output of this helper method is marked as HTML safe so that you can directly + # include it inside a +"}) # # => "{\"name\":\"\"}" -- cgit v1.2.3 From 0696547814057eaed3c13e70a6dc6b2b7bb3e1f9 Mon Sep 17 00:00:00 2001 From: Godfrey Chan Date: Wed, 4 Dec 2013 09:46:38 -0800 Subject: Also move html_esacpe regex to a constant (see 9d25af60) --- activesupport/lib/active_support/core_ext/string/output_safety.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'activesupport/lib/active_support') 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 1d23998b88..23f95341f8 100644 --- a/activesupport/lib/active_support/core_ext/string/output_safety.rb +++ b/activesupport/lib/active_support/core_ext/string/output_safety.rb @@ -5,6 +5,7 @@ class ERB module Util HTML_ESCAPE = { '&' => '&', '>' => '>', '<' => '<', '"' => '"', "'" => ''' } JSON_ESCAPE = { '&' => '\u0026', '>' => '\u003e', '<' => '\u003c', "\u2028" => '\u2028', "\u2029" => '\u2029' } + HTML_ESCAPE_REGEXP = /[&"'><]/ HTML_ESCAPE_ONCE_REGEXP = /["><']|&(?!([a-zA-Z]+|(#\d+));)/ JSON_ESCAPE_REGEXP = /[\u2028\u2029&><]/u @@ -21,7 +22,7 @@ class ERB if s.html_safe? s else - s.gsub(/[&"'><]/, HTML_ESCAPE).html_safe + s.gsub(HTML_ESCAPE_REGEXP, HTML_ESCAPE).html_safe end end -- cgit v1.2.3 From 556ad95b835ae80c1ba4fcb7c25c4f80e47e3dac Mon Sep 17 00:00:00 2001 From: Carlos Antonio da Silva Date: Wed, 4 Dec 2013 16:10:26 -0200 Subject: Review json_escape docs [ci skip] --- .../core_ext/string/output_safety.rb | 44 +++++++++++----------- 1 file changed, 22 insertions(+), 22 deletions(-) (limited to 'activesupport/lib/active_support') 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 23f95341f8..1b2098fc84 100644 --- a/activesupport/lib/active_support/core_ext/string/output_safety.rb +++ b/activesupport/lib/active_support/core_ext/string/output_safety.rb @@ -50,55 +50,55 @@ class ERB module_function :html_escape_once # A utility method for escaping HTML entities in JSON strings. Specifically, the - # &, > and < characters are replaced with their equivilant unicode escaped form - + # &, > and < characters are replaced with their equivalent unicode escaped form - # \u0026, \u003e, and \u003c. The Unicode sequences \u2028 and \u2029 are also - # escaped as then are treated as newline characters in some JavaScript engines. - # These sequences has identical meaning as the original characters inside the + # escaped as they are treated as newline characters in some JavaScript engines. + # These sequences have identical meaning as the original characters inside the # context of a JSON string, so assuming the input is a valid and well-formed - # JSON value, the output will have equivilant meaning when parsed: - # + # JSON value, the output will have equivalent meaning when parsed: + # # json = JSON.generate({ name: ""}) # # => "{\"name\":\"\"}" - # + # # json_escape(json) # # => "{\"name\":\"\\u003C/script\\u003E\\u003Cscript\\u003Ealert('PWNED!!!')\\u003C/script\\u003E\"}" - # + # # JSON.parse(json) == JSON.parse(json_escape(json)) # # => true - # + # # The intended use case for this method is to escape JSON strings before including # them inside a script tag to avoid XSS vulnerability: - # - # - # + # # WARNING: this helper only works with valid JSON. Using this on non-JSON values # will open up serious XSS vulnerabilities. For example, if you replace the # +current_user.to_json+ in the example above with user input instead, the browser # will happily eval() that string as JavaScript. - # + # # The escaping performed in this method is identical to those performed in the - # ActiveSupport JSON encoder when +ActiveSupport.escape_html_entities_in_json+ is + # Active Support JSON encoder when +ActiveSupport.escape_html_entities_in_json+ is # set to true. Because this transformation is idempotent, this helper can be # applied even if +ActiveSupport.escape_html_entities_in_json+ is already true. - # + # # Therefore, when you are unsure if +ActiveSupport.escape_html_entities_in_json+ # is enabled, or if you are unsure where your JSON string originated from, it # is recommended that you always apply this helper (other libraries, such as the - # JSON gem, does not provide this kind of protection by default; also some gems - # might override +#to_json+ to bypass ActiveSupport's encoder). - # + # JSON gem, do not provide this kind of protection by default; also some gems + # might override +to_json+ to bypass Active Support's encoder). + # # The output of this helper method is marked as HTML safe so that you can directly - # include it inside a +