activesupport 6.0.3.4 → 6.1.3
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 +371 -448
- data/MIT-LICENSE +1 -1
- data/README.rdoc +1 -1
- data/lib/active_support.rb +13 -1
- data/lib/active_support/array_inquirer.rb +4 -2
- data/lib/active_support/backtrace_cleaner.rb +3 -3
- data/lib/active_support/benchmarkable.rb +1 -1
- data/lib/active_support/cache.rb +85 -44
- data/lib/active_support/cache/file_store.rb +4 -3
- data/lib/active_support/cache/mem_cache_store.rb +29 -18
- data/lib/active_support/cache/memory_store.rb +46 -26
- data/lib/active_support/cache/redis_cache_store.rb +27 -27
- data/lib/active_support/cache/strategy/local_cache.rb +21 -6
- data/lib/active_support/callbacks.rb +65 -56
- data/lib/active_support/concern.rb +46 -2
- data/lib/active_support/configurable.rb +3 -3
- data/lib/active_support/configuration_file.rb +46 -0
- data/lib/active_support/core_ext.rb +1 -1
- data/lib/active_support/core_ext/benchmark.rb +2 -2
- data/lib/active_support/core_ext/class/attribute.rb +34 -44
- data/lib/active_support/core_ext/class/subclasses.rb +17 -38
- data/lib/active_support/core_ext/date/conversions.rb +2 -1
- data/lib/active_support/core_ext/date_and_time/calculations.rb +13 -0
- data/lib/active_support/core_ext/date_and_time/compatibility.rb +15 -0
- data/lib/active_support/core_ext/enumerable.rb +76 -4
- data/lib/active_support/core_ext/hash/conversions.rb +2 -2
- data/lib/active_support/core_ext/hash/deep_transform_values.rb +1 -1
- data/lib/active_support/core_ext/hash/except.rb +1 -1
- data/lib/active_support/core_ext/hash/keys.rb +1 -1
- data/lib/active_support/core_ext/hash/slice.rb +3 -2
- data/lib/active_support/core_ext/load_error.rb +1 -1
- data/lib/active_support/core_ext/marshal.rb +2 -0
- data/lib/active_support/core_ext/module/attr_internal.rb +2 -2
- data/lib/active_support/core_ext/module/attribute_accessors.rb +23 -29
- data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +8 -4
- data/lib/active_support/core_ext/module/concerning.rb +8 -2
- data/lib/active_support/core_ext/module/delegation.rb +38 -28
- data/lib/active_support/core_ext/module/introspection.rb +1 -25
- data/lib/active_support/core_ext/name_error.rb +29 -2
- data/lib/active_support/core_ext/numeric/conversions.rb +22 -18
- data/lib/active_support/core_ext/object/deep_dup.rb +1 -1
- data/lib/active_support/core_ext/object/json.rb +13 -2
- data/lib/active_support/core_ext/object/try.rb +2 -2
- data/lib/active_support/core_ext/range/compare_range.rb +9 -3
- data/lib/active_support/core_ext/range/include_time_with_zone.rb +8 -3
- data/lib/active_support/core_ext/regexp.rb +8 -1
- data/lib/active_support/core_ext/string/access.rb +5 -24
- data/lib/active_support/core_ext/string/conversions.rb +1 -0
- data/lib/active_support/core_ext/string/inflections.rb +38 -4
- data/lib/active_support/core_ext/string/inquiry.rb +1 -0
- data/lib/active_support/core_ext/string/multibyte.rb +2 -2
- data/lib/active_support/core_ext/string/output_safety.rb +10 -10
- data/lib/active_support/core_ext/string/starts_ends_with.rb +2 -2
- data/lib/active_support/core_ext/symbol.rb +3 -0
- data/lib/active_support/core_ext/symbol/starts_ends_with.rb +14 -0
- data/lib/active_support/core_ext/time/calculations.rb +27 -3
- data/lib/active_support/core_ext/time/conversions.rb +2 -0
- data/lib/active_support/core_ext/uri.rb +5 -1
- data/lib/active_support/current_attributes.rb +7 -2
- data/lib/active_support/current_attributes/test_helper.rb +13 -0
- data/lib/active_support/dependencies.rb +43 -19
- data/lib/active_support/deprecation.rb +6 -1
- data/lib/active_support/deprecation/behaviors.rb +15 -2
- data/lib/active_support/deprecation/disallowed.rb +56 -0
- data/lib/active_support/deprecation/instance_delegator.rb +0 -1
- data/lib/active_support/deprecation/method_wrappers.rb +3 -2
- data/lib/active_support/deprecation/proxy_wrappers.rb +3 -3
- data/lib/active_support/deprecation/reporting.rb +50 -7
- data/lib/active_support/descendants_tracker.rb +6 -2
- data/lib/active_support/duration.rb +71 -22
- data/lib/active_support/duration/iso8601_serializer.rb +15 -9
- data/lib/active_support/encrypted_file.rb +19 -2
- data/lib/active_support/environment_inquirer.rb +20 -0
- data/lib/active_support/evented_file_update_checker.rb +69 -133
- data/lib/active_support/fork_tracker.rb +62 -0
- data/lib/active_support/gem_version.rb +2 -2
- data/lib/active_support/hash_with_indifferent_access.rb +43 -24
- data/lib/active_support/i18n_railtie.rb +14 -19
- data/lib/active_support/inflector/inflections.rb +1 -2
- data/lib/active_support/inflector/methods.rb +35 -31
- data/lib/active_support/inflector/transliterate.rb +4 -4
- data/lib/active_support/json/decoding.rb +4 -4
- data/lib/active_support/json/encoding.rb +5 -1
- data/lib/active_support/key_generator.rb +1 -1
- data/lib/active_support/locale/en.yml +7 -3
- data/lib/active_support/log_subscriber.rb +8 -0
- data/lib/active_support/logger.rb +1 -1
- data/lib/active_support/logger_silence.rb +2 -26
- data/lib/active_support/logger_thread_safe_level.rb +34 -12
- data/lib/active_support/message_encryptor.rb +4 -7
- data/lib/active_support/message_verifier.rb +5 -5
- data/lib/active_support/messages/metadata.rb +9 -1
- data/lib/active_support/messages/rotation_configuration.rb +2 -1
- data/lib/active_support/messages/rotator.rb +6 -5
- data/lib/active_support/multibyte/chars.rb +4 -42
- data/lib/active_support/multibyte/unicode.rb +9 -83
- data/lib/active_support/notifications.rb +32 -5
- data/lib/active_support/notifications/fanout.rb +23 -8
- data/lib/active_support/notifications/instrumenter.rb +6 -15
- data/lib/active_support/number_helper.rb +29 -14
- data/lib/active_support/number_helper/number_converter.rb +1 -1
- data/lib/active_support/number_helper/number_to_currency_converter.rb +3 -7
- data/lib/active_support/number_helper/number_to_human_converter.rb +1 -1
- data/lib/active_support/number_helper/number_to_human_size_converter.rb +1 -1
- data/lib/active_support/number_helper/number_to_rounded_converter.rb +3 -3
- data/lib/active_support/number_helper/rounding_helper.rb +12 -28
- data/lib/active_support/option_merger.rb +3 -2
- data/lib/active_support/ordered_options.rb +8 -2
- data/lib/active_support/parameter_filter.rb +16 -11
- data/lib/active_support/per_thread_registry.rb +1 -1
- data/lib/active_support/rails.rb +1 -4
- data/lib/active_support/railtie.rb +23 -1
- data/lib/active_support/rescuable.rb +4 -4
- data/lib/active_support/secure_compare_rotator.rb +51 -0
- data/lib/active_support/security_utils.rb +19 -12
- data/lib/active_support/string_inquirer.rb +4 -2
- data/lib/active_support/subscriber.rb +12 -7
- data/lib/active_support/tagged_logging.rb +29 -4
- data/lib/active_support/testing/assertions.rb +18 -11
- data/lib/active_support/testing/parallelization.rb +12 -95
- data/lib/active_support/testing/parallelization/server.rb +78 -0
- data/lib/active_support/testing/parallelization/worker.rb +100 -0
- data/lib/active_support/testing/time_helpers.rb +40 -3
- data/lib/active_support/time_with_zone.rb +67 -43
- data/lib/active_support/values/time_zone.rb +20 -10
- data/lib/active_support/xml_mini/rexml.rb +8 -1
- metadata +34 -36
- data/lib/active_support/core_ext/array/prepend_and_append.rb +0 -5
- data/lib/active_support/core_ext/hash/compact.rb +0 -5
- data/lib/active_support/core_ext/hash/transform_values.rb +0 -5
- data/lib/active_support/core_ext/module/reachable.rb +0 -6
- data/lib/active_support/core_ext/numeric/inquiry.rb +0 -5
- data/lib/active_support/core_ext/range/include_range.rb +0 -9
@@ -19,7 +19,7 @@ module ActiveSupport
|
|
19
19
|
# By using <tt>ActiveSupport::Concern</tt> the above module could instead be
|
20
20
|
# written as:
|
21
21
|
#
|
22
|
-
# require
|
22
|
+
# require "active_support/concern"
|
23
23
|
#
|
24
24
|
# module M
|
25
25
|
# extend ActiveSupport::Concern
|
@@ -76,7 +76,7 @@ module ActiveSupport
|
|
76
76
|
# is the +Bar+ module, not the +Host+ class. With <tt>ActiveSupport::Concern</tt>,
|
77
77
|
# module dependencies are properly resolved:
|
78
78
|
#
|
79
|
-
# require
|
79
|
+
# require "active_support/concern"
|
80
80
|
#
|
81
81
|
# module Foo
|
82
82
|
# extend ActiveSupport::Concern
|
@@ -99,6 +99,14 @@ module ActiveSupport
|
|
99
99
|
# class Host
|
100
100
|
# include Bar # It works, now Bar takes care of its dependencies
|
101
101
|
# end
|
102
|
+
#
|
103
|
+
# === Prepending concerns
|
104
|
+
#
|
105
|
+
# Just like <tt>include</tt>, concerns also support <tt>prepend</tt> with a corresponding
|
106
|
+
# <tt>prepended do</tt> callback. <tt>module ClassMethods</tt> or <tt>class_methods do</tt> are
|
107
|
+
# prepended as well.
|
108
|
+
#
|
109
|
+
# <tt>prepend</tt> is also used for any dependencies.
|
102
110
|
module Concern
|
103
111
|
class MultipleIncludedBlocks < StandardError #:nodoc:
|
104
112
|
def initialize
|
@@ -106,6 +114,12 @@ module ActiveSupport
|
|
106
114
|
end
|
107
115
|
end
|
108
116
|
|
117
|
+
class MultiplePrependBlocks < StandardError #:nodoc:
|
118
|
+
def initialize
|
119
|
+
super "Cannot define multiple 'prepended' blocks for a Concern"
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
109
123
|
def self.extended(base) #:nodoc:
|
110
124
|
base.instance_variable_set(:@_dependencies, [])
|
111
125
|
end
|
@@ -123,6 +137,19 @@ module ActiveSupport
|
|
123
137
|
end
|
124
138
|
end
|
125
139
|
|
140
|
+
def prepend_features(base) #:nodoc:
|
141
|
+
if base.instance_variable_defined?(:@_dependencies)
|
142
|
+
base.instance_variable_get(:@_dependencies).unshift self
|
143
|
+
false
|
144
|
+
else
|
145
|
+
return false if base < self
|
146
|
+
@_dependencies.each { |dep| base.prepend(dep) }
|
147
|
+
super
|
148
|
+
base.singleton_class.prepend const_get(:ClassMethods) if const_defined?(:ClassMethods)
|
149
|
+
base.class_eval(&@_prepended_block) if instance_variable_defined?(:@_prepended_block)
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
126
153
|
# Evaluate given block in context of base class,
|
127
154
|
# so that you can write class macros here.
|
128
155
|
# When you define more than one +included+ block, it raises an exception.
|
@@ -140,6 +167,23 @@ module ActiveSupport
|
|
140
167
|
end
|
141
168
|
end
|
142
169
|
|
170
|
+
# Evaluate given block in context of base class,
|
171
|
+
# so that you can write class macros here.
|
172
|
+
# When you define more than one +prepended+ block, it raises an exception.
|
173
|
+
def prepended(base = nil, &block)
|
174
|
+
if base.nil?
|
175
|
+
if instance_variable_defined?(:@_prepended_block)
|
176
|
+
if @_prepended_block.source_location != block.source_location
|
177
|
+
raise MultiplePrependBlocks
|
178
|
+
end
|
179
|
+
else
|
180
|
+
@_prepended_block = block
|
181
|
+
end
|
182
|
+
else
|
183
|
+
super
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
143
187
|
# Define class methods from given block.
|
144
188
|
# You can define private class methods as well.
|
145
189
|
#
|
@@ -5,7 +5,7 @@ require "active_support/ordered_options"
|
|
5
5
|
|
6
6
|
module ActiveSupport
|
7
7
|
# Configurable provides a <tt>config</tt> method to store and retrieve
|
8
|
-
# configuration options as an <tt>
|
8
|
+
# configuration options as an <tt>OrderedOptions</tt>.
|
9
9
|
module Configurable
|
10
10
|
extend ActiveSupport::Concern
|
11
11
|
|
@@ -124,9 +124,9 @@ module ActiveSupport
|
|
124
124
|
private :config_accessor
|
125
125
|
end
|
126
126
|
|
127
|
-
# Reads and writes attributes from a configuration <tt>
|
127
|
+
# Reads and writes attributes from a configuration <tt>OrderedOptions</tt>.
|
128
128
|
#
|
129
|
-
# require
|
129
|
+
# require "active_support/configurable"
|
130
130
|
#
|
131
131
|
# class User
|
132
132
|
# include ActiveSupport::Configurable
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveSupport
|
4
|
+
# Reads a YAML configuration file, evaluating any ERB, then
|
5
|
+
# parsing the resulting YAML.
|
6
|
+
#
|
7
|
+
# Warns in case of YAML confusing characters, like invisible
|
8
|
+
# non-breaking spaces.
|
9
|
+
class ConfigurationFile # :nodoc:
|
10
|
+
class FormatError < StandardError; end
|
11
|
+
|
12
|
+
def initialize(content_path)
|
13
|
+
@content_path = content_path.to_s
|
14
|
+
@content = read content_path
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.parse(content_path, **options)
|
18
|
+
new(content_path).parse(**options)
|
19
|
+
end
|
20
|
+
|
21
|
+
def parse(context: nil, **options)
|
22
|
+
YAML.load(render(context), **options) || {}
|
23
|
+
rescue Psych::SyntaxError => error
|
24
|
+
raise "YAML syntax error occurred while parsing #{@content_path}. " \
|
25
|
+
"Please note that YAML must be consistently indented using spaces. Tabs are not allowed. " \
|
26
|
+
"Error: #{error.message}"
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
def read(content_path)
|
31
|
+
require "yaml"
|
32
|
+
require "erb"
|
33
|
+
|
34
|
+
File.read(content_path).tap do |content|
|
35
|
+
if content.include?("\u00A0")
|
36
|
+
warn "File contains invisible non-breaking spaces, you may want to remove those"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def render(context)
|
42
|
+
erb = ERB.new(@content).tap { |e| e.filename = @content_path }
|
43
|
+
context ? erb.result(context) : erb.result
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -1,8 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "active_support/core_ext/kernel/singleton_class"
|
4
3
|
require "active_support/core_ext/module/redefine_method"
|
5
|
-
require "active_support/core_ext/array/extract_options"
|
6
4
|
|
7
5
|
class Class
|
8
6
|
# Declare a class-level attribute whose value is inheritable by subclasses.
|
@@ -84,58 +82,50 @@ class Class
|
|
84
82
|
# To set a default value for the attribute, pass <tt>default:</tt>, like so:
|
85
83
|
#
|
86
84
|
# class_attribute :settings, default: {}
|
87
|
-
def class_attribute(
|
88
|
-
|
89
|
-
instance_accessor: true,
|
90
|
-
instance_reader: instance_accessor,
|
91
|
-
instance_writer: instance_accessor,
|
92
|
-
instance_predicate: true,
|
93
|
-
default: nil
|
94
|
-
)
|
95
|
-
attrs.each do |name|
|
96
|
-
singleton_class.silence_redefinition_of_method(name)
|
97
|
-
define_singleton_method(name) { default }
|
98
|
-
|
99
|
-
singleton_class.silence_redefinition_of_method("#{name}?")
|
100
|
-
define_singleton_method("#{name}?") { !!public_send(name) } if instance_predicate
|
85
|
+
def class_attribute(*attrs, instance_accessor: true,
|
86
|
+
instance_reader: instance_accessor, instance_writer: instance_accessor, instance_predicate: true, default: nil)
|
101
87
|
|
102
|
-
|
88
|
+
class_methods, methods = [], []
|
89
|
+
attrs.each do |name|
|
90
|
+
unless name.is_a?(Symbol) || name.is_a?(String)
|
91
|
+
raise TypeError, "#{name.inspect} is not a symbol nor a string"
|
92
|
+
end
|
103
93
|
|
104
|
-
|
105
|
-
|
106
|
-
|
94
|
+
class_methods << <<~RUBY # In case the method exists and is not public
|
95
|
+
silence_redefinition_of_method def #{name}
|
96
|
+
end
|
97
|
+
RUBY
|
107
98
|
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
if instance_variable_defined? ivar
|
112
|
-
instance_variable_get ivar
|
113
|
-
else
|
114
|
-
singleton_class.send name
|
115
|
-
end
|
116
|
-
end
|
117
|
-
end
|
99
|
+
methods << <<~RUBY if instance_reader
|
100
|
+
silence_redefinition_of_method def #{name}
|
101
|
+
defined?(@#{name}) ? @#{name} : self.class.#{name}
|
118
102
|
end
|
119
|
-
|
120
|
-
end
|
103
|
+
RUBY
|
121
104
|
|
122
|
-
|
123
|
-
|
124
|
-
if
|
125
|
-
|
126
|
-
|
127
|
-
self.class.public_send name
|
128
|
-
end
|
105
|
+
class_methods << <<~RUBY
|
106
|
+
silence_redefinition_of_method def #{name}=(value)
|
107
|
+
redefine_method(:#{name}) { value } if singleton_class?
|
108
|
+
redefine_singleton_method(:#{name}) { value }
|
109
|
+
value
|
129
110
|
end
|
111
|
+
RUBY
|
130
112
|
|
131
|
-
|
132
|
-
|
113
|
+
methods << <<~RUBY if instance_writer
|
114
|
+
silence_redefinition_of_method(:#{name}=)
|
115
|
+
attr_writer :#{name}
|
116
|
+
RUBY
|
133
117
|
|
134
|
-
if
|
135
|
-
|
136
|
-
|
118
|
+
if instance_predicate
|
119
|
+
class_methods << "silence_redefinition_of_method def #{name}?; !!self.#{name}; end"
|
120
|
+
if instance_reader
|
121
|
+
methods << "silence_redefinition_of_method def #{name}?; !!self.#{name}; end"
|
137
122
|
end
|
138
123
|
end
|
139
124
|
end
|
125
|
+
|
126
|
+
location = caller_locations(1, 1).first
|
127
|
+
class_eval(["class << self", *class_methods, "end", *methods].join(";").tr("\n", ";"), location.path, location.lineno)
|
128
|
+
|
129
|
+
attrs.each { |name| public_send("#{name}=", default) }
|
140
130
|
end
|
141
131
|
end
|
@@ -1,39 +1,22 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
class Class
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
# C.descendants # => [B, A, D]
|
21
|
-
def descendants
|
22
|
-
descendants = []
|
23
|
-
ObjectSpace.each_object(singleton_class) do |k|
|
24
|
-
next if k.singleton_class?
|
25
|
-
descendants.unshift k unless k == self
|
26
|
-
end
|
27
|
-
descendants
|
28
|
-
end
|
29
|
-
rescue StandardError # JRuby 9.0.4.0 and earlier
|
30
|
-
def descendants
|
31
|
-
descendants = []
|
32
|
-
ObjectSpace.each_object(Class) do |k|
|
33
|
-
descendants.unshift k if k < self
|
34
|
-
end
|
35
|
-
descendants.uniq!
|
36
|
-
descendants
|
4
|
+
# Returns an array with all classes that are < than its receiver.
|
5
|
+
#
|
6
|
+
# class C; end
|
7
|
+
# C.descendants # => []
|
8
|
+
#
|
9
|
+
# class B < C; end
|
10
|
+
# C.descendants # => [B]
|
11
|
+
#
|
12
|
+
# class A < B; end
|
13
|
+
# C.descendants # => [B, A]
|
14
|
+
#
|
15
|
+
# class D < C; end
|
16
|
+
# C.descendants # => [B, A, D]
|
17
|
+
def descendants
|
18
|
+
ObjectSpace.each_object(singleton_class).reject do |k|
|
19
|
+
k.singleton_class? || k == self
|
37
20
|
end
|
38
21
|
end
|
39
22
|
|
@@ -45,10 +28,6 @@ class Class
|
|
45
28
|
#
|
46
29
|
# Foo.subclasses # => [Bar]
|
47
30
|
def subclasses
|
48
|
-
|
49
|
-
chain.each do |k|
|
50
|
-
subclasses << k unless chain.any? { |c| c > k }
|
51
|
-
end
|
52
|
-
subclasses
|
31
|
+
descendants.select { |descendant| descendant.superclass == self }
|
53
32
|
end
|
54
33
|
end
|
@@ -10,6 +10,7 @@ class Date
|
|
10
10
|
short: "%d %b",
|
11
11
|
long: "%B %d, %Y",
|
12
12
|
db: "%Y-%m-%d",
|
13
|
+
inspect: "%Y-%m-%d",
|
13
14
|
number: "%Y%m%d",
|
14
15
|
long_ordinal: lambda { |date|
|
15
16
|
day_format = ActiveSupport::Inflector.ordinalize(date.day)
|
@@ -80,7 +81,7 @@ class Date
|
|
80
81
|
# If the *application's* timezone is needed, then use +in_time_zone+ instead.
|
81
82
|
def to_time(form = :local)
|
82
83
|
raise ArgumentError, "Expected :local or :utc, got #{form.inspect}." unless [:local, :utc].include?(form)
|
83
|
-
::Time.
|
84
|
+
::Time.public_send(form, year, month, day)
|
84
85
|
end
|
85
86
|
|
86
87
|
silence_redefinition_of_method :xmlschema
|
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "active_support/core_ext/object/try"
|
4
|
+
require "active_support/core_ext/date_time/conversions"
|
4
5
|
|
5
6
|
module DateAndTime
|
6
7
|
module Calculations
|
@@ -30,6 +31,18 @@ module DateAndTime
|
|
30
31
|
to_date == ::Date.current
|
31
32
|
end
|
32
33
|
|
34
|
+
# Returns true if the date/time is tomorrow.
|
35
|
+
def tomorrow?
|
36
|
+
to_date == ::Date.current.tomorrow
|
37
|
+
end
|
38
|
+
alias :next_day? :tomorrow?
|
39
|
+
|
40
|
+
# Returns true if the date/time is yesterday.
|
41
|
+
def yesterday?
|
42
|
+
to_date == ::Date.current.yesterday
|
43
|
+
end
|
44
|
+
alias :prev_day? :yesterday?
|
45
|
+
|
33
46
|
# Returns true if the date/time is in the past.
|
34
47
|
def past?
|
35
48
|
self < self.class.current
|
@@ -12,5 +12,20 @@ module DateAndTime
|
|
12
12
|
# this behavior, but new apps will have an initializer that sets
|
13
13
|
# this to true, because the new behavior is preferred.
|
14
14
|
mattr_accessor :preserve_timezone, instance_writer: false, default: false
|
15
|
+
|
16
|
+
# Change the output of <tt>ActiveSupport::TimeZone.utc_to_local</tt>.
|
17
|
+
#
|
18
|
+
# When `true`, it returns local times with an UTC offset, with `false` local
|
19
|
+
# times are returned as UTC.
|
20
|
+
#
|
21
|
+
# # Given this zone:
|
22
|
+
# zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"]
|
23
|
+
#
|
24
|
+
# # With `utc_to_local_returns_utc_offset_times = false`, local time is converted to UTC:
|
25
|
+
# zone.utc_to_local(Time.utc(2000, 1)) # => 1999-12-31 19:00:00 UTC
|
26
|
+
#
|
27
|
+
# # With `utc_to_local_returns_utc_offset_times = true`, local time is returned with UTC offset:
|
28
|
+
# zone.utc_to_local(Time.utc(2000, 1)) # => 1999-12-31 19:00:00 -0500
|
29
|
+
mattr_accessor :utc_to_local_returns_utc_offset_times, instance_writer: false, default: false
|
15
30
|
end
|
16
31
|
end
|
@@ -44,7 +44,8 @@ module Enumerable
|
|
44
44
|
end
|
45
45
|
end
|
46
46
|
|
47
|
-
# Convert an enumerable to a hash
|
47
|
+
# Convert an enumerable to a hash, using the block result as the key and the
|
48
|
+
# element as the value.
|
48
49
|
#
|
49
50
|
# people.index_by(&:login)
|
50
51
|
# # => { "nextangle" => <Person ...>, "chade-" => <Person ...>, ...}
|
@@ -61,12 +62,19 @@ module Enumerable
|
|
61
62
|
end
|
62
63
|
end
|
63
64
|
|
64
|
-
# Convert an enumerable to a hash
|
65
|
+
# Convert an enumerable to a hash, using the element as the key and the block
|
66
|
+
# result as the value.
|
65
67
|
#
|
66
68
|
# post = Post.new(title: "hey there", body: "what's up?")
|
67
69
|
#
|
68
70
|
# %i( title body ).index_with { |attr_name| post.public_send(attr_name) }
|
69
71
|
# # => { title: "hey there", body: "what's up?" }
|
72
|
+
#
|
73
|
+
# If an argument is passed instead of a block, it will be used as the value
|
74
|
+
# for all elements:
|
75
|
+
#
|
76
|
+
# %i( created_at updated_at ).index_with(Time.now)
|
77
|
+
# # => { created_at: 2020-03-09 22:31:47, updated_at: 2020-03-09 22:31:47 }
|
70
78
|
def index_with(default = INDEX_WITH_DEFAULT)
|
71
79
|
if block_given?
|
72
80
|
result = {}
|
@@ -134,7 +142,7 @@ module Enumerable
|
|
134
142
|
excluding(*elements)
|
135
143
|
end
|
136
144
|
|
137
|
-
#
|
145
|
+
# Extract the given key from each element in the enumerable.
|
138
146
|
#
|
139
147
|
# [{ name: "David" }, { name: "Rafael" }, { name: "Aaron" }].pluck(:name)
|
140
148
|
# # => ["David", "Rafael", "Aaron"]
|
@@ -145,9 +153,62 @@ module Enumerable
|
|
145
153
|
if keys.many?
|
146
154
|
map { |element| keys.map { |key| element[key] } }
|
147
155
|
else
|
148
|
-
|
156
|
+
key = keys.first
|
157
|
+
map { |element| element[key] }
|
149
158
|
end
|
150
159
|
end
|
160
|
+
|
161
|
+
# Extract the given key from the first element in the enumerable.
|
162
|
+
#
|
163
|
+
# [{ name: "David" }, { name: "Rafael" }, { name: "Aaron" }].pick(:name)
|
164
|
+
# # => "David"
|
165
|
+
#
|
166
|
+
# [{ id: 1, name: "David" }, { id: 2, name: "Rafael" }].pick(:id, :name)
|
167
|
+
# # => [1, "David"]
|
168
|
+
def pick(*keys)
|
169
|
+
return if none?
|
170
|
+
|
171
|
+
if keys.many?
|
172
|
+
keys.map { |key| first[key] }
|
173
|
+
else
|
174
|
+
first[keys.first]
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
# Returns a new +Array+ without the blank items.
|
179
|
+
# Uses Object#blank? for determining if an item is blank.
|
180
|
+
#
|
181
|
+
# [1, "", nil, 2, " ", [], {}, false, true].compact_blank
|
182
|
+
# # => [1, 2, true]
|
183
|
+
#
|
184
|
+
# Set.new([nil, "", 1, 2])
|
185
|
+
# # => [2, 1] (or [1, 2])
|
186
|
+
#
|
187
|
+
# When called on a +Hash+, returns a new +Hash+ without the blank values.
|
188
|
+
#
|
189
|
+
# { a: "", b: 1, c: nil, d: [], e: false, f: true }.compact_blank
|
190
|
+
# #=> { b: 1, f: true }
|
191
|
+
def compact_blank
|
192
|
+
reject(&:blank?)
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
class Hash
|
197
|
+
# Hash#reject has its own definition, so this needs one too.
|
198
|
+
def compact_blank #:nodoc:
|
199
|
+
reject { |_k, v| v.blank? }
|
200
|
+
end
|
201
|
+
|
202
|
+
# Removes all blank values from the +Hash+ in place and returns self.
|
203
|
+
# Uses Object#blank? for determining if a value is blank.
|
204
|
+
#
|
205
|
+
# h = { a: "", b: 1, c: nil, d: [], e: false, f: true }
|
206
|
+
# h.compact_blank!
|
207
|
+
# # => { b: 1, f: true }
|
208
|
+
def compact_blank!
|
209
|
+
# use delete_if rather than reject! because it always returns self even if nothing changed
|
210
|
+
delete_if { |_k, v| v.blank? }
|
211
|
+
end
|
151
212
|
end
|
152
213
|
|
153
214
|
class Range #:nodoc:
|
@@ -185,4 +246,15 @@ class Array #:nodoc:
|
|
185
246
|
super
|
186
247
|
end
|
187
248
|
end
|
249
|
+
|
250
|
+
# Removes all blank elements from the +Array+ in place and returns self.
|
251
|
+
# Uses Object#blank? for determining if an item is blank.
|
252
|
+
#
|
253
|
+
# a = [1, "", nil, 2, " ", [], {}, false, true]
|
254
|
+
# a.compact_blank!
|
255
|
+
# # => [1, 2, true]
|
256
|
+
def compact_blank!
|
257
|
+
# use delete_if rather than reject! because it always returns self even if nothing changed
|
258
|
+
delete_if(&:blank?)
|
259
|
+
end
|
188
260
|
end
|