activesupport 7.0.0.alpha2 → 7.0.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activesupport might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +80 -0
- data/lib/active_support/cache/mem_cache_store.rb +9 -5
- data/lib/active_support/cache/memory_store.rb +2 -2
- data/lib/active_support/cache/redis_cache_store.rb +3 -8
- data/lib/active_support/cache/strategy/local_cache.rb +6 -12
- data/lib/active_support/callbacks.rb +145 -50
- data/lib/active_support/code_generator.rb +65 -0
- data/lib/active_support/core_ext/array/conversions.rb +3 -1
- data/lib/active_support/core_ext/array/deprecated_conversions.rb +25 -0
- data/lib/active_support/core_ext/array.rb +1 -0
- data/lib/active_support/core_ext/class/subclasses.rb +4 -2
- data/lib/active_support/core_ext/date/calculations.rb +2 -2
- data/lib/active_support/core_ext/date/conversions.rb +3 -3
- data/lib/active_support/core_ext/date/deprecated_conversions.rb +26 -0
- data/lib/active_support/core_ext/date.rb +1 -0
- data/lib/active_support/core_ext/date_and_time/compatibility.rb +1 -1
- data/lib/active_support/core_ext/date_time/conversions.rb +5 -5
- data/lib/active_support/core_ext/date_time/deprecated_conversions.rb +22 -0
- data/lib/active_support/core_ext/date_time.rb +1 -0
- data/lib/active_support/core_ext/digest/uuid.rb +26 -1
- data/lib/active_support/core_ext/module/attribute_accessors.rb +2 -0
- data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +19 -10
- data/lib/active_support/core_ext/numeric/conversions.rb +78 -75
- data/lib/active_support/core_ext/numeric/deprecated_conversions.rb +60 -0
- data/lib/active_support/core_ext/numeric.rb +1 -0
- data/lib/active_support/core_ext/object/with_options.rb +20 -1
- data/lib/active_support/core_ext/pathname/existence.rb +21 -0
- data/lib/active_support/core_ext/pathname.rb +3 -0
- data/lib/active_support/core_ext/range/conversions.rb +8 -8
- data/lib/active_support/core_ext/range/deprecated_conversions.rb +26 -0
- data/lib/active_support/core_ext/range/include_time_with_zone.rb +4 -25
- data/lib/active_support/core_ext/range.rb +1 -1
- data/lib/active_support/core_ext/time/calculations.rb +1 -1
- data/lib/active_support/core_ext/time/conversions.rb +4 -3
- data/lib/active_support/core_ext/time/deprecated_conversions.rb +22 -0
- data/lib/active_support/core_ext/time/zones.rb +2 -2
- data/lib/active_support/core_ext/time.rb +1 -0
- data/lib/active_support/core_ext/uri.rb +3 -13
- data/lib/active_support/core_ext.rb +1 -0
- data/lib/active_support/current_attributes.rb +26 -25
- data/lib/active_support/descendants_tracker.rb +175 -69
- data/lib/active_support/error_reporter.rb +117 -0
- data/lib/active_support/execution_context/test_helper.rb +13 -0
- data/lib/active_support/execution_context.rb +53 -0
- data/lib/active_support/execution_wrapper.rb +30 -4
- data/lib/active_support/executor/test_helper.rb +7 -0
- data/lib/active_support/fork_tracker.rb +18 -9
- data/lib/active_support/gem_version.rb +1 -1
- data/lib/active_support/html_safe_translation.rb +43 -0
- data/lib/active_support/i18n_railtie.rb +1 -1
- data/lib/active_support/inflector/inflections.rb +12 -3
- data/lib/active_support/inflector/methods.rb +2 -2
- data/lib/active_support/isolated_execution_state.rb +56 -0
- data/lib/active_support/logger_thread_safe_level.rb +2 -3
- data/lib/active_support/message_encryptor.rb +5 -0
- data/lib/active_support/multibyte/unicode.rb +0 -12
- data/lib/active_support/notifications/fanout.rb +61 -55
- data/lib/active_support/notifications/instrumenter.rb +15 -15
- data/lib/active_support/notifications.rb +5 -21
- data/lib/active_support/option_merger.rb +4 -0
- data/lib/active_support/per_thread_registry.rb +4 -0
- data/lib/active_support/railtie.rb +38 -11
- data/lib/active_support/ruby_features.rb +7 -0
- data/lib/active_support/subscriber.rb +2 -18
- data/lib/active_support/tagged_logging.rb +1 -1
- data/lib/active_support/testing/deprecation.rb +52 -1
- data/lib/active_support/testing/isolation.rb +1 -1
- data/lib/active_support/time_with_zone.rb +34 -6
- data/lib/active_support/values/time_zone.rb +5 -0
- data/lib/active_support/xml_mini.rb +3 -3
- data/lib/active_support.rb +7 -4
- metadata +23 -6
@@ -4,4 +4,5 @@ require "active_support/core_ext/date/acts_like"
|
|
4
4
|
require "active_support/core_ext/date/blank"
|
5
5
|
require "active_support/core_ext/date/calculations"
|
6
6
|
require "active_support/core_ext/date/conversions"
|
7
|
+
require "active_support/core_ext/date/deprecated_conversions" unless ENV["RAILS_DISABLE_DEPRECATED_TO_S_CONVERSION"]
|
7
8
|
require "active_support/core_ext/date/zones"
|
@@ -15,7 +15,7 @@ module DateAndTime
|
|
15
15
|
|
16
16
|
# Change the output of <tt>ActiveSupport::TimeZone.utc_to_local</tt>.
|
17
17
|
#
|
18
|
-
# When `true`, it returns local times with
|
18
|
+
# When `true`, it returns local times with a UTC offset, with `false` local
|
19
19
|
# times are returned as UTC.
|
20
20
|
#
|
21
21
|
# # Given this zone:
|
@@ -9,14 +9,14 @@ require "active_support/values/time_zone"
|
|
9
9
|
class DateTime
|
10
10
|
# Convert to a formatted string. See Time::DATE_FORMATS for predefined formats.
|
11
11
|
#
|
12
|
-
# This method is aliased to <tt>
|
12
|
+
# This method is aliased to <tt>to_fs</tt>.
|
13
13
|
#
|
14
14
|
# === Examples
|
15
15
|
# datetime = DateTime.civil(2007, 12, 4, 0, 0, 0, 0) # => Tue, 04 Dec 2007 00:00:00 +0000
|
16
16
|
#
|
17
17
|
# datetime.to_formatted_s(:db) # => "2007-12-04 00:00:00"
|
18
|
-
# datetime.
|
19
|
-
# datetime.
|
18
|
+
# datetime.to_formatted_s(:db) # => "2007-12-04 00:00:00"
|
19
|
+
# datetime.to_formatted_s(:number) # => "20071204000000"
|
20
20
|
# datetime.to_formatted_s(:short) # => "04 Dec 00:00"
|
21
21
|
# datetime.to_formatted_s(:long) # => "December 04, 2007 00:00"
|
22
22
|
# datetime.to_formatted_s(:long_ordinal) # => "December 4th, 2007 00:00"
|
@@ -39,8 +39,8 @@ class DateTime
|
|
39
39
|
to_default_s
|
40
40
|
end
|
41
41
|
end
|
42
|
+
alias_method :to_fs, :to_formatted_s
|
42
43
|
alias_method :to_default_s, :to_s if instance_methods(false).include?(:to_s)
|
43
|
-
alias_method :to_s, :to_formatted_s
|
44
44
|
|
45
45
|
# Returns a formatted string of the offset from UTC, or an alternative
|
46
46
|
# string if the time zone is already UTC.
|
@@ -54,7 +54,7 @@ class DateTime
|
|
54
54
|
|
55
55
|
# Overrides the default inspect method with a human readable one, e.g., "Mon, 21 Feb 2005 14:30:00 +0000".
|
56
56
|
def readable_inspect
|
57
|
-
|
57
|
+
to_formatted_s(:rfc822)
|
58
58
|
end
|
59
59
|
alias_method :default_inspect, :inspect
|
60
60
|
alias_method :inspect, :readable_inspect
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "date"
|
4
|
+
|
5
|
+
class DateTime
|
6
|
+
NOT_SET = Object.new # :nodoc:
|
7
|
+
def to_s(format = NOT_SET) # :nodoc:
|
8
|
+
if formatter = ::Time::DATE_FORMATS[format]
|
9
|
+
ActiveSupport::Deprecation.warn(
|
10
|
+
"DateTime#to_s(#{format.inspect}) is deprecated. Please use DateTime#to_formatted_s(#{format.inspect}) instead."
|
11
|
+
)
|
12
|
+
formatter.respond_to?(:call) ? formatter.call(self).to_s : strftime(formatter)
|
13
|
+
elsif format == NOT_SET
|
14
|
+
to_default_s
|
15
|
+
else
|
16
|
+
ActiveSupport::Deprecation.warn(
|
17
|
+
"DateTime#to_s(#{format.inspect}) is deprecated. Please use DateTime#to_formatted_s(#{format.inspect}) instead."
|
18
|
+
)
|
19
|
+
to_default_s
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -5,3 +5,4 @@ require "active_support/core_ext/date_time/blank"
|
|
5
5
|
require "active_support/core_ext/date_time/calculations"
|
6
6
|
require "active_support/core_ext/date_time/compatibility"
|
7
7
|
require "active_support/core_ext/date_time/conversions"
|
8
|
+
require "active_support/core_ext/date_time/deprecated_conversions" unless ENV["RAILS_DISABLE_DEPRECATED_TO_S_CONVERSION"]
|
@@ -10,13 +10,15 @@ module Digest
|
|
10
10
|
OID_NAMESPACE = "k\xA7\xB8\x12\x9D\xAD\x11\xD1\x80\xB4\x00\xC0O\xD40\xC8" # :nodoc:
|
11
11
|
X500_NAMESPACE = "k\xA7\xB8\x14\x9D\xAD\x11\xD1\x80\xB4\x00\xC0O\xD40\xC8" # :nodoc:
|
12
12
|
|
13
|
+
mattr_accessor :use_rfc4122_namespaced_uuids, instance_accessor: false, default: false
|
14
|
+
|
13
15
|
# Generates a v5 non-random UUID (Universally Unique IDentifier).
|
14
16
|
#
|
15
17
|
# Using OpenSSL::Digest::MD5 generates version 3 UUIDs; OpenSSL::Digest::SHA1 generates version 5 UUIDs.
|
16
18
|
# uuid_from_hash always generates the same UUID for a given name and namespace combination.
|
17
19
|
#
|
18
20
|
# See RFC 4122 for details of UUID at: https://www.ietf.org/rfc/rfc4122.txt
|
19
|
-
def self.uuid_from_hash(hash_class,
|
21
|
+
def self.uuid_from_hash(hash_class, namespace, name)
|
20
22
|
if hash_class == Digest::MD5 || hash_class == OpenSSL::Digest::MD5
|
21
23
|
version = 3
|
22
24
|
elsif hash_class == Digest::SHA1 || hash_class == OpenSSL::Digest::SHA1
|
@@ -25,6 +27,8 @@ module Digest
|
|
25
27
|
raise ArgumentError, "Expected OpenSSL::Digest::SHA1 or OpenSSL::Digest::MD5, got #{hash_class.name}."
|
26
28
|
end
|
27
29
|
|
30
|
+
uuid_namespace = pack_uuid_namespace(namespace)
|
31
|
+
|
28
32
|
hash = hash_class.new
|
29
33
|
hash.update(uuid_namespace)
|
30
34
|
hash.update(name)
|
@@ -50,5 +54,26 @@ module Digest
|
|
50
54
|
def self.uuid_v4
|
51
55
|
SecureRandom.uuid
|
52
56
|
end
|
57
|
+
|
58
|
+
def self.pack_uuid_namespace(namespace)
|
59
|
+
if [DNS_NAMESPACE, OID_NAMESPACE, URL_NAMESPACE, X500_NAMESPACE].include?(namespace)
|
60
|
+
namespace
|
61
|
+
elsif use_rfc4122_namespaced_uuids == true
|
62
|
+
match_data = namespace.match(/\A(\h{8})-(\h{4})-(\h{4})-(\h{4})-(\h{4})(\h{8})\z/)
|
63
|
+
|
64
|
+
raise ArgumentError, "Only UUIDs are valid namespace identifiers" unless match_data.present?
|
65
|
+
|
66
|
+
match_data.captures.map { |s| s.to_i(16) }.pack("NnnnnN")
|
67
|
+
else
|
68
|
+
ActiveSupport::Deprecation.warn <<~WARNING.squish
|
69
|
+
Providing a namespace ID that is not one of the constants defined on Digest::UUID generates an incorrect UUID value according to RFC 4122.
|
70
|
+
To enable the correct behavior, set the Rails.application.config.active_support.use_rfc4122_namespaced_uuids configuration option to true.
|
71
|
+
WARNING
|
72
|
+
|
73
|
+
namespace
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
private_class_method :pack_uuid_namespace
|
53
78
|
end
|
54
79
|
end
|
@@ -1,11 +1,16 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
# == Attribute Accessors per Thread
|
4
|
+
#
|
3
5
|
# Extends the module object with class/module and instance accessors for
|
4
6
|
# class/module attributes, just like the native attr* accessors for instance
|
5
7
|
# attributes, but does so on a per-thread basis.
|
6
8
|
#
|
7
9
|
# So the values are scoped within the Thread.current space under the class name
|
8
10
|
# of the module.
|
11
|
+
#
|
12
|
+
# Note that it can also be scoped per-fiber if Rails.application.config.active_support.isolation_level
|
13
|
+
# is set to `:fiber`
|
9
14
|
class Module
|
10
15
|
# Defines a per-thread class attribute and creates class and instance reader methods.
|
11
16
|
# The underlying per-thread class variable is set to +nil+, if it is not previously defined.
|
@@ -14,9 +19,9 @@ class Module
|
|
14
19
|
# thread_mattr_reader :user
|
15
20
|
# end
|
16
21
|
#
|
17
|
-
# Current.user
|
18
|
-
# Thread.current[:attr_Current_user] = "DHH"
|
22
|
+
# Current.user = "DHH"
|
19
23
|
# Current.user # => "DHH"
|
24
|
+
# Thread.new { Current.user }.values # => nil
|
20
25
|
#
|
21
26
|
# The attribute name must be a valid method name in Ruby.
|
22
27
|
#
|
@@ -41,7 +46,8 @@ class Module
|
|
41
46
|
# to work with inheritance via polymorphism.
|
42
47
|
class_eval(<<-EOS, __FILE__, __LINE__ + 1)
|
43
48
|
def self.#{sym}
|
44
|
-
|
49
|
+
@__thread_mattr_#{sym} ||= "attr_\#{name}_#{sym}"
|
50
|
+
::ActiveSupport::IsolatedExecutionState[@__thread_mattr_#{sym}]
|
45
51
|
end
|
46
52
|
EOS
|
47
53
|
|
@@ -53,7 +59,7 @@ class Module
|
|
53
59
|
EOS
|
54
60
|
end
|
55
61
|
|
56
|
-
|
62
|
+
::ActiveSupport::IsolatedExecutionState["attr_#{name}_#{sym}"] = default unless default.nil?
|
57
63
|
end
|
58
64
|
end
|
59
65
|
alias :thread_cattr_reader :thread_mattr_reader
|
@@ -84,7 +90,8 @@ class Module
|
|
84
90
|
# to work with inheritance via polymorphism.
|
85
91
|
class_eval(<<-EOS, __FILE__, __LINE__ + 1)
|
86
92
|
def self.#{sym}=(obj)
|
87
|
-
|
93
|
+
@__thread_mattr_#{sym} ||= "attr_\#{name}_#{sym}"
|
94
|
+
::ActiveSupport::IsolatedExecutionState[@__thread_mattr_#{sym}] = obj
|
88
95
|
end
|
89
96
|
EOS
|
90
97
|
|
@@ -111,16 +118,18 @@ class Module
|
|
111
118
|
# Account.user # => "DHH"
|
112
119
|
# Account.new.user # => "DHH"
|
113
120
|
#
|
121
|
+
# Unlike `mattr_accessor`, values are *not* shared with subclasses or parent classes.
|
114
122
|
# If a subclass changes the value, the parent class' value is not changed.
|
115
|
-
#
|
116
|
-
# is not changed.
|
123
|
+
# If the parent class changes the value, the value of subclasses is not changed.
|
117
124
|
#
|
118
125
|
# class Customer < Account
|
119
126
|
# end
|
120
127
|
#
|
121
|
-
#
|
122
|
-
# Customer.user
|
123
|
-
#
|
128
|
+
# Account.user # => "DHH"
|
129
|
+
# Customer.user # => nil
|
130
|
+
# Customer.user = "Rafael"
|
131
|
+
# Customer.user # => "Rafael"
|
132
|
+
# Account.user # => "DHH"
|
124
133
|
#
|
125
134
|
# To omit the instance writer method, pass <tt>instance_writer: false</tt>.
|
126
135
|
# To omit the instance reader method, pass <tt>instance_reader: false</tt>.
|
@@ -9,6 +9,8 @@ module ActiveSupport
|
|
9
9
|
# Options are provided for phone numbers, currency, percentage,
|
10
10
|
# precision, positional notation, file size and pretty printing.
|
11
11
|
#
|
12
|
+
# This method is aliased to <tt>to_fs</tt>.
|
13
|
+
#
|
12
14
|
# ==== Options
|
13
15
|
#
|
14
16
|
# For details on which formats use which options, see ActiveSupport::NumberHelper
|
@@ -16,102 +18,102 @@ module ActiveSupport
|
|
16
18
|
# ==== Examples
|
17
19
|
#
|
18
20
|
# Phone Numbers:
|
19
|
-
# 5551234.
|
20
|
-
# 1235551234.
|
21
|
-
# 1235551234.
|
22
|
-
# 1235551234.
|
23
|
-
# 1235551234.
|
24
|
-
# 1235551234.
|
25
|
-
# 1235551234.
|
21
|
+
# 5551234.to_formatted_s(:phone) # => "555-1234"
|
22
|
+
# 1235551234.to_formatted_s(:phone) # => "123-555-1234"
|
23
|
+
# 1235551234.to_formatted_s(:phone, area_code: true) # => "(123) 555-1234"
|
24
|
+
# 1235551234.to_formatted_s(:phone, delimiter: ' ') # => "123 555 1234"
|
25
|
+
# 1235551234.to_formatted_s(:phone, area_code: true, extension: 555) # => "(123) 555-1234 x 555"
|
26
|
+
# 1235551234.to_formatted_s(:phone, country_code: 1) # => "+1-123-555-1234"
|
27
|
+
# 1235551234.to_formatted_s(:phone, country_code: 1, extension: 1343, delimiter: '.')
|
26
28
|
# # => "+1.123.555.1234 x 1343"
|
27
29
|
#
|
28
30
|
# Currency:
|
29
|
-
# 1234567890.50.
|
30
|
-
# 1234567890.506.
|
31
|
-
# 1234567890.506.
|
32
|
-
# 1234567890.506.
|
33
|
-
# 1234567890.506.
|
34
|
-
# -1234567890.50.
|
31
|
+
# 1234567890.50.to_formatted_s(:currency) # => "$1,234,567,890.50"
|
32
|
+
# 1234567890.506.to_formatted_s(:currency) # => "$1,234,567,890.51"
|
33
|
+
# 1234567890.506.to_formatted_s(:currency, precision: 3) # => "$1,234,567,890.506"
|
34
|
+
# 1234567890.506.to_formatted_s(:currency, round_mode: :down) # => "$1,234,567,890.50"
|
35
|
+
# 1234567890.506.to_formatted_s(:currency, locale: :fr) # => "1 234 567 890,51 €"
|
36
|
+
# -1234567890.50.to_formatted_s(:currency, negative_format: '(%u%n)')
|
35
37
|
# # => "($1,234,567,890.50)"
|
36
|
-
# 1234567890.50.
|
38
|
+
# 1234567890.50.to_formatted_s(:currency, unit: '£', separator: ',', delimiter: '')
|
37
39
|
# # => "£1234567890,50"
|
38
|
-
# 1234567890.50.
|
40
|
+
# 1234567890.50.to_formatted_s(:currency, unit: '£', separator: ',', delimiter: '', format: '%n %u')
|
39
41
|
# # => "1234567890,50 £"
|
40
42
|
#
|
41
43
|
# Percentage:
|
42
|
-
# 100.
|
43
|
-
# 100.
|
44
|
-
# 1000.
|
45
|
-
# 302.24398923423.
|
46
|
-
# 302.24398923423.
|
47
|
-
# 1000.
|
48
|
-
# 100.
|
44
|
+
# 100.to_formatted_s(:percentage) # => "100.000%"
|
45
|
+
# 100.to_formatted_s(:percentage, precision: 0) # => "100%"
|
46
|
+
# 1000.to_formatted_s(:percentage, delimiter: '.', separator: ',') # => "1.000,000%"
|
47
|
+
# 302.24398923423.to_formatted_s(:percentage, precision: 5) # => "302.24399%"
|
48
|
+
# 302.24398923423.to_formatted_s(:percentage, round_mode: :down) # => "302.243%"
|
49
|
+
# 1000.to_formatted_s(:percentage, locale: :fr) # => "1 000,000%"
|
50
|
+
# 100.to_formatted_s(:percentage, format: '%n %') # => "100.000 %"
|
49
51
|
#
|
50
52
|
# Delimited:
|
51
|
-
# 12345678.
|
52
|
-
# 12345678.05.
|
53
|
-
# 12345678.
|
54
|
-
# 12345678.
|
55
|
-
# 12345678.05.
|
56
|
-
# 12345678.05.
|
57
|
-
# 98765432.98.
|
53
|
+
# 12345678.to_formatted_s(:delimited) # => "12,345,678"
|
54
|
+
# 12345678.05.to_formatted_s(:delimited) # => "12,345,678.05"
|
55
|
+
# 12345678.to_formatted_s(:delimited, delimiter: '.') # => "12.345.678"
|
56
|
+
# 12345678.to_formatted_s(:delimited, delimiter: ',') # => "12,345,678"
|
57
|
+
# 12345678.05.to_formatted_s(:delimited, separator: ' ') # => "12,345,678 05"
|
58
|
+
# 12345678.05.to_formatted_s(:delimited, locale: :fr) # => "12 345 678,05"
|
59
|
+
# 98765432.98.to_formatted_s(:delimited, delimiter: ' ', separator: ',')
|
58
60
|
# # => "98 765 432,98"
|
59
61
|
#
|
60
62
|
# Rounded:
|
61
|
-
# 111.2345.
|
62
|
-
# 111.2345.
|
63
|
-
# 111.2345.
|
64
|
-
# 13.
|
65
|
-
# 389.32314.
|
66
|
-
# 111.2345.
|
67
|
-
# 111.2345.
|
68
|
-
# 13.
|
69
|
-
# 111.234.
|
70
|
-
# 13.
|
63
|
+
# 111.2345.to_formatted_s(:rounded) # => "111.235"
|
64
|
+
# 111.2345.to_formatted_s(:rounded, precision: 2) # => "111.23"
|
65
|
+
# 111.2345.to_formatted_s(:rounded, precision: 2, round_mode: :up) # => "111.24"
|
66
|
+
# 13.to_formatted_s(:rounded, precision: 5) # => "13.00000"
|
67
|
+
# 389.32314.to_formatted_s(:rounded, precision: 0) # => "389"
|
68
|
+
# 111.2345.to_formatted_s(:rounded, significant: true) # => "111"
|
69
|
+
# 111.2345.to_formatted_s(:rounded, precision: 1, significant: true) # => "100"
|
70
|
+
# 13.to_formatted_s(:rounded, precision: 5, significant: true) # => "13.000"
|
71
|
+
# 111.234.to_formatted_s(:rounded, locale: :fr) # => "111,234"
|
72
|
+
# 13.to_formatted_s(:rounded, precision: 5, significant: true, strip_insignificant_zeros: true)
|
71
73
|
# # => "13"
|
72
|
-
# 389.32314.
|
73
|
-
# 1111.2345.
|
74
|
+
# 389.32314.to_formatted_s(:rounded, precision: 4, significant: true) # => "389.3"
|
75
|
+
# 1111.2345.to_formatted_s(:rounded, precision: 2, separator: ',', delimiter: '.')
|
74
76
|
# # => "1.111,23"
|
75
77
|
#
|
76
78
|
# Human-friendly size in Bytes:
|
77
|
-
# 123.
|
78
|
-
# 1234.
|
79
|
-
# 12345.
|
80
|
-
# 1234567.
|
81
|
-
# 1234567890.
|
82
|
-
# 1234567890123.
|
83
|
-
# 1234567890123456.
|
84
|
-
# 1234567890123456789.
|
85
|
-
# 1234567.
|
86
|
-
# 1234567.
|
87
|
-
# 483989.
|
88
|
-
# 1234567.
|
89
|
-
# 1234567890123.
|
90
|
-
# 524288000.
|
79
|
+
# 123.to_formatted_s(:human_size) # => "123 Bytes"
|
80
|
+
# 1234.to_formatted_s(:human_size) # => "1.21 KB"
|
81
|
+
# 12345.to_formatted_s(:human_size) # => "12.1 KB"
|
82
|
+
# 1234567.to_formatted_s(:human_size) # => "1.18 MB"
|
83
|
+
# 1234567890.to_formatted_s(:human_size) # => "1.15 GB"
|
84
|
+
# 1234567890123.to_formatted_s(:human_size) # => "1.12 TB"
|
85
|
+
# 1234567890123456.to_formatted_s(:human_size) # => "1.1 PB"
|
86
|
+
# 1234567890123456789.to_formatted_s(:human_size) # => "1.07 EB"
|
87
|
+
# 1234567.to_formatted_s(:human_size, precision: 2) # => "1.2 MB"
|
88
|
+
# 1234567.to_formatted_s(:human_size, precision: 2, round_mode: :up) # => "1.3 MB"
|
89
|
+
# 483989.to_formatted_s(:human_size, precision: 2) # => "470 KB"
|
90
|
+
# 1234567.to_formatted_s(:human_size, precision: 2, separator: ',') # => "1,2 MB"
|
91
|
+
# 1234567890123.to_formatted_s(:human_size, precision: 5) # => "1.1228 TB"
|
92
|
+
# 524288000.to_formatted_s(:human_size, precision: 5) # => "500 MB"
|
91
93
|
#
|
92
94
|
# Human-friendly format:
|
93
|
-
# 123.
|
94
|
-
# 1234.
|
95
|
-
# 12345.
|
96
|
-
# 1234567.
|
97
|
-
# 1234567890.
|
98
|
-
# 1234567890123.
|
99
|
-
# 1234567890123456.
|
100
|
-
# 1234567890123456789.
|
101
|
-
# 489939.
|
102
|
-
# 489939.
|
103
|
-
# 489939.
|
104
|
-
# 1234567.
|
105
|
-
# significant: false)
|
106
|
-
# 1234567.
|
95
|
+
# 123.to_formatted_s(:human) # => "123"
|
96
|
+
# 1234.to_formatted_s(:human) # => "1.23 Thousand"
|
97
|
+
# 12345.to_formatted_s(:human) # => "12.3 Thousand"
|
98
|
+
# 1234567.to_formatted_s(:human) # => "1.23 Million"
|
99
|
+
# 1234567890.to_formatted_s(:human) # => "1.23 Billion"
|
100
|
+
# 1234567890123.to_formatted_s(:human) # => "1.23 Trillion"
|
101
|
+
# 1234567890123456.to_formatted_s(:human) # => "1.23 Quadrillion"
|
102
|
+
# 1234567890123456789.to_formatted_s(:human) # => "1230 Quadrillion"
|
103
|
+
# 489939.to_formatted_s(:human, precision: 2) # => "490 Thousand"
|
104
|
+
# 489939.to_formatted_s(:human, precision: 2, round_mode: :down) # => "480 Thousand"
|
105
|
+
# 489939.to_formatted_s(:human, precision: 4) # => "489.9 Thousand"
|
106
|
+
# 1234567.to_formatted_s(:human, precision: 4,
|
107
|
+
# significant: false) # => "1.2346 Million"
|
108
|
+
# 1234567.to_formatted_s(:human, precision: 1,
|
107
109
|
# separator: ',',
|
108
|
-
# significant: false)
|
109
|
-
def
|
110
|
-
return
|
110
|
+
# significant: false) # => "1,2 Million"
|
111
|
+
def to_formatted_s(format = nil, options = nil)
|
112
|
+
return to_s if format.nil?
|
111
113
|
|
112
114
|
case format
|
113
115
|
when Integer, String
|
114
|
-
|
116
|
+
to_s(format)
|
115
117
|
when :phone
|
116
118
|
ActiveSupport::NumberHelper.number_to_phone(self, options || {})
|
117
119
|
when :currency
|
@@ -127,11 +129,12 @@ module ActiveSupport
|
|
127
129
|
when :human_size
|
128
130
|
ActiveSupport::NumberHelper.number_to_human_size(self, options || {})
|
129
131
|
when Symbol
|
130
|
-
|
132
|
+
to_s
|
131
133
|
else
|
132
|
-
|
134
|
+
to_s(format)
|
133
135
|
end
|
134
136
|
end
|
137
|
+
alias_method :to_fs, :to_formatted_s
|
135
138
|
end
|
136
139
|
end
|
137
140
|
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveSupport
|
4
|
+
module DeprecatedNumericWithFormat # :nodoc:
|
5
|
+
def to_s(format = nil, options = nil)
|
6
|
+
return super() if format.nil?
|
7
|
+
|
8
|
+
case format
|
9
|
+
when Integer, String
|
10
|
+
super(format)
|
11
|
+
when :phone
|
12
|
+
ActiveSupport::Deprecation.warn(
|
13
|
+
"#{self.class}#to_s(#{format.inspect}) is deprecated. Please use #{self.class}#to_formatted_s(#{format.inspect}) instead."
|
14
|
+
)
|
15
|
+
ActiveSupport::NumberHelper.number_to_phone(self, options || {})
|
16
|
+
when :currency
|
17
|
+
ActiveSupport::Deprecation.warn(
|
18
|
+
"#{self.class}#to_s(#{format.inspect}) is deprecated. Please use #{self.class}#to_formatted_s(#{format.inspect}) instead."
|
19
|
+
)
|
20
|
+
ActiveSupport::NumberHelper.number_to_currency(self, options || {})
|
21
|
+
when :percentage
|
22
|
+
ActiveSupport::Deprecation.warn(
|
23
|
+
"#{self.class}#to_s(#{format.inspect}) is deprecated. Please use #{self.class}#to_formatted_s(#{format.inspect}) instead."
|
24
|
+
)
|
25
|
+
ActiveSupport::NumberHelper.number_to_percentage(self, options || {})
|
26
|
+
when :delimited
|
27
|
+
ActiveSupport::Deprecation.warn(
|
28
|
+
"#{self.class}#to_s(#{format.inspect}) is deprecated. Please use #{self.class}#to_formatted_s(#{format.inspect}) instead."
|
29
|
+
)
|
30
|
+
ActiveSupport::NumberHelper.number_to_delimited(self, options || {})
|
31
|
+
when :rounded
|
32
|
+
ActiveSupport::Deprecation.warn(
|
33
|
+
"#{self.class}#to_s(#{format.inspect}) is deprecated. Please use #{self.class}#to_formatted_s(#{format.inspect}) instead."
|
34
|
+
)
|
35
|
+
ActiveSupport::NumberHelper.number_to_rounded(self, options || {})
|
36
|
+
when :human
|
37
|
+
ActiveSupport::Deprecation.warn(
|
38
|
+
"#{self.class}#to_s(#{format.inspect}) is deprecated. Please use #{self.class}#to_formatted_s(#{format.inspect}) instead."
|
39
|
+
)
|
40
|
+
ActiveSupport::NumberHelper.number_to_human(self, options || {})
|
41
|
+
when :human_size
|
42
|
+
ActiveSupport::Deprecation.warn(
|
43
|
+
"#{self.class}#to_s(#{format.inspect}) is deprecated. Please use #{self.class}#to_formatted_s(#{format.inspect}) instead."
|
44
|
+
)
|
45
|
+
ActiveSupport::NumberHelper.number_to_human_size(self, options || {})
|
46
|
+
when Symbol
|
47
|
+
ActiveSupport::Deprecation.warn(
|
48
|
+
"#{self.class}#to_s(#{format.inspect}) is deprecated. Please use #{self.class}#to_formatted_s(#{format.inspect}) instead."
|
49
|
+
)
|
50
|
+
super()
|
51
|
+
else
|
52
|
+
super(format)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
Integer.prepend ActiveSupport::DeprecatedNumericWithFormat
|
59
|
+
Float.prepend ActiveSupport::DeprecatedNumericWithFormat
|
60
|
+
BigDecimal.prepend ActiveSupport::DeprecatedNumericWithFormat
|
@@ -3,3 +3,4 @@
|
|
3
3
|
require "active_support/core_ext/numeric/bytes"
|
4
4
|
require "active_support/core_ext/numeric/time"
|
5
5
|
require "active_support/core_ext/numeric/conversions"
|
6
|
+
require "active_support/core_ext/numeric/deprecated_conversions" unless ENV["RAILS_DISABLE_DEPRECATED_TO_S_CONVERSION"]
|
@@ -75,8 +75,27 @@ class Object
|
|
75
75
|
# end
|
76
76
|
# end
|
77
77
|
#
|
78
|
+
# When the block argument is omitted, the decorated Object instance is returned:
|
79
|
+
#
|
80
|
+
# module MyStyledHelpers
|
81
|
+
# def styled
|
82
|
+
# with_options style: "color: red;"
|
83
|
+
# end
|
84
|
+
# end
|
85
|
+
#
|
86
|
+
# # styled.link_to "I'm red", "/"
|
87
|
+
# # #=> <a href="/" style="color: red;">I'm red</a>
|
88
|
+
#
|
89
|
+
# # styled.button_tag "I'm red too!"
|
90
|
+
# # #=> <button style="color: red;">I'm red too!</button>
|
91
|
+
#
|
78
92
|
def with_options(options, &block)
|
79
93
|
option_merger = ActiveSupport::OptionMerger.new(self, options)
|
80
|
-
|
94
|
+
|
95
|
+
if block
|
96
|
+
block.arity.zero? ? option_merger.instance_eval(&block) : block.call(option_merger)
|
97
|
+
else
|
98
|
+
option_merger
|
99
|
+
end
|
81
100
|
end
|
82
101
|
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Pathname
|
4
|
+
# Returns the receiver if the named file exists otherwise returns +nil+.
|
5
|
+
# <tt>pathname.existence</tt> is equivalent to
|
6
|
+
#
|
7
|
+
# pathname.exists? ? pathname : nil
|
8
|
+
#
|
9
|
+
# For example, something like
|
10
|
+
#
|
11
|
+
# content = pathname.read if pathname.exist?
|
12
|
+
#
|
13
|
+
# becomes
|
14
|
+
#
|
15
|
+
# content = pathname.existence&.read
|
16
|
+
#
|
17
|
+
# @return [Pathname]
|
18
|
+
def existence
|
19
|
+
self if exist?
|
20
|
+
end
|
21
|
+
end
|
@@ -7,34 +7,34 @@ module ActiveSupport
|
|
7
7
|
case start
|
8
8
|
when String then "BETWEEN '#{start}' AND '#{stop}'"
|
9
9
|
else
|
10
|
-
"BETWEEN '#{start.
|
10
|
+
"BETWEEN '#{start.to_formatted_s(:db)}' AND '#{stop.to_formatted_s(:db)}'"
|
11
11
|
end
|
12
12
|
end
|
13
13
|
}
|
14
14
|
|
15
15
|
# Convert range to a formatted string. See RANGE_FORMATS for predefined formats.
|
16
16
|
#
|
17
|
+
# This method is aliased to <tt>to_fs</tt>.
|
18
|
+
#
|
17
19
|
# range = (1..100) # => 1..100
|
18
20
|
#
|
19
21
|
# range.to_s # => "1..100"
|
20
|
-
# range.
|
22
|
+
# range.to_formatted_s(:db) # => "BETWEEN '1' AND '100'"
|
21
23
|
#
|
22
24
|
# == Adding your own range formats to to_s
|
23
25
|
# You can add your own formats to the Range::RANGE_FORMATS hash.
|
24
26
|
# Use the format name as the hash key and a Proc instance.
|
25
27
|
#
|
26
28
|
# # config/initializers/range_formats.rb
|
27
|
-
# Range::RANGE_FORMATS[:short] = ->(start, stop) { "Between #{start.
|
28
|
-
def
|
29
|
+
# Range::RANGE_FORMATS[:short] = ->(start, stop) { "Between #{start.to_formatted_s(:db)} and #{stop.to_formatted_s(:db)}" }
|
30
|
+
def to_formatted_s(format = :default)
|
29
31
|
if formatter = RANGE_FORMATS[format]
|
30
32
|
formatter.call(first, last)
|
31
33
|
else
|
32
|
-
|
34
|
+
to_s
|
33
35
|
end
|
34
36
|
end
|
35
|
-
|
36
|
-
alias_method :to_default_s, :to_s
|
37
|
-
alias_method :to_formatted_s, :to_s
|
37
|
+
alias_method :to_fs, :to_formatted_s
|
38
38
|
end
|
39
39
|
end
|
40
40
|
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveSupport
|
4
|
+
module DeprecatedRangeWithFormat # :nodoc:
|
5
|
+
NOT_SET = Object.new # :nodoc:
|
6
|
+
def to_s(format = NOT_SET)
|
7
|
+
if formatter = RangeWithFormat::RANGE_FORMATS[format]
|
8
|
+
ActiveSupport::Deprecation.warn(
|
9
|
+
"Range#to_s(#{format.inspect}) is deprecated. Please use Range#to_formatted_s(#{format.inspect}) instead."
|
10
|
+
)
|
11
|
+
formatter.call(first, last)
|
12
|
+
elsif format == NOT_SET
|
13
|
+
super()
|
14
|
+
else
|
15
|
+
ActiveSupport::Deprecation.warn(
|
16
|
+
"Range#to_s(#{format.inspect}) is deprecated. Please use Range#to_formatted_s(#{format.inspect}) instead."
|
17
|
+
)
|
18
|
+
super()
|
19
|
+
end
|
20
|
+
end
|
21
|
+
alias_method :to_default_s, :to_s
|
22
|
+
deprecate :to_default_s
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
Range.prepend(ActiveSupport::DeprecatedRangeWithFormat)
|