activesupport 7.1.6 → 8.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +256 -1133
- data/README.rdoc +1 -1
- data/lib/active_support/array_inquirer.rb +1 -1
- data/lib/active_support/backtrace_cleaner.rb +81 -3
- data/lib/active_support/benchmark.rb +21 -0
- data/lib/active_support/benchmarkable.rb +3 -2
- data/lib/active_support/broadcast_logger.rb +65 -78
- data/lib/active_support/cache/file_store.rb +29 -14
- data/lib/active_support/cache/mem_cache_store.rb +42 -102
- data/lib/active_support/cache/memory_store.rb +11 -6
- data/lib/active_support/cache/null_store.rb +2 -2
- data/lib/active_support/cache/redis_cache_store.rb +58 -46
- data/lib/active_support/cache/serializer_with_fallback.rb +0 -23
- data/lib/active_support/cache/strategy/local_cache.rb +72 -27
- data/lib/active_support/cache/strategy/local_cache_middleware.rb +7 -7
- data/lib/active_support/cache.rb +146 -86
- data/lib/active_support/callbacks.rb +102 -126
- data/lib/active_support/class_attribute.rb +33 -0
- data/lib/active_support/code_generator.rb +9 -0
- data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +8 -62
- data/lib/active_support/concurrency/share_lock.rb +0 -1
- data/lib/active_support/concurrency/thread_monitor.rb +55 -0
- data/lib/active_support/configurable.rb +34 -0
- data/lib/active_support/configuration_file.rb +15 -6
- data/lib/active_support/continuous_integration.rb +145 -0
- data/lib/active_support/core_ext/array/conversions.rb +3 -5
- data/lib/active_support/core_ext/array.rb +7 -7
- data/lib/active_support/core_ext/benchmark.rb +4 -14
- data/lib/active_support/core_ext/big_decimal.rb +1 -1
- data/lib/active_support/core_ext/class/attribute.rb +26 -19
- data/lib/active_support/core_ext/class/subclasses.rb +15 -35
- data/lib/active_support/core_ext/class.rb +2 -2
- data/lib/active_support/core_ext/date/blank.rb +4 -0
- data/lib/active_support/core_ext/date/conversions.rb +2 -2
- data/lib/active_support/core_ext/date.rb +5 -5
- data/lib/active_support/core_ext/date_and_time/compatibility.rb +1 -9
- data/lib/active_support/core_ext/date_time/blank.rb +4 -0
- data/lib/active_support/core_ext/date_time/compatibility.rb +3 -5
- data/lib/active_support/core_ext/date_time/conversions.rb +4 -6
- data/lib/active_support/core_ext/date_time.rb +5 -5
- data/lib/active_support/core_ext/digest/uuid.rb +6 -0
- data/lib/active_support/core_ext/digest.rb +1 -1
- data/lib/active_support/core_ext/enumerable.rb +25 -8
- data/lib/active_support/core_ext/erb/util.rb +10 -5
- data/lib/active_support/core_ext/file.rb +1 -1
- data/lib/active_support/core_ext/hash/deep_merge.rb +1 -0
- data/lib/active_support/core_ext/hash/except.rb +0 -12
- data/lib/active_support/core_ext/hash/keys.rb +4 -4
- data/lib/active_support/core_ext/hash.rb +8 -8
- data/lib/active_support/core_ext/integer.rb +3 -3
- data/lib/active_support/core_ext/kernel.rb +3 -3
- data/lib/active_support/core_ext/module/attr_internal.rb +16 -6
- data/lib/active_support/core_ext/module/delegation.rb +20 -163
- data/lib/active_support/core_ext/module/deprecation.rb +1 -4
- data/lib/active_support/core_ext/module/introspection.rb +3 -0
- data/lib/active_support/core_ext/module.rb +11 -11
- data/lib/active_support/core_ext/numeric/conversions.rb +3 -3
- data/lib/active_support/core_ext/numeric.rb +3 -3
- data/lib/active_support/core_ext/object/blank.rb +45 -1
- data/lib/active_support/core_ext/object/instance_variables.rb +11 -19
- data/lib/active_support/core_ext/object/json.rb +24 -11
- data/lib/active_support/core_ext/object/to_query.rb +7 -1
- data/lib/active_support/core_ext/object/try.rb +2 -2
- data/lib/active_support/core_ext/object/with.rb +5 -3
- data/lib/active_support/core_ext/object.rb +13 -13
- data/lib/active_support/core_ext/pathname/blank.rb +4 -0
- data/lib/active_support/core_ext/pathname.rb +2 -2
- data/lib/active_support/core_ext/range/overlap.rb +4 -4
- data/lib/active_support/core_ext/range/sole.rb +17 -0
- data/lib/active_support/core_ext/range.rb +4 -4
- data/lib/active_support/core_ext/securerandom.rb +4 -4
- data/lib/active_support/core_ext/string/conversions.rb +1 -1
- data/lib/active_support/core_ext/string/filters.rb +4 -4
- data/lib/active_support/core_ext/string/multibyte.rb +13 -4
- data/lib/active_support/core_ext/string/output_safety.rb +19 -19
- data/lib/active_support/core_ext/string.rb +13 -13
- data/lib/active_support/core_ext/symbol.rb +1 -1
- data/lib/active_support/core_ext/thread/backtrace/location.rb +2 -7
- data/lib/active_support/core_ext/time/calculations.rb +25 -30
- data/lib/active_support/core_ext/time/compatibility.rb +2 -3
- data/lib/active_support/core_ext/time/conversions.rb +2 -2
- data/lib/active_support/core_ext/time/zones.rb +1 -1
- data/lib/active_support/core_ext/time.rb +5 -5
- data/lib/active_support/core_ext.rb +1 -2
- data/lib/active_support/current_attributes/test_helper.rb +2 -2
- data/lib/active_support/current_attributes.rb +58 -50
- data/lib/active_support/delegation.rb +200 -0
- data/lib/active_support/dependencies/autoload.rb +0 -12
- data/lib/active_support/dependencies/interlock.rb +11 -5
- data/lib/active_support/dependencies.rb +6 -2
- data/lib/active_support/deprecation/constant_accessor.rb +47 -26
- data/lib/active_support/deprecation/proxy_wrappers.rb +9 -12
- data/lib/active_support/deprecation/reporting.rb +5 -17
- data/lib/active_support/deprecation.rb +8 -5
- data/lib/active_support/descendants_tracker.rb +9 -87
- data/lib/active_support/duration/iso8601_parser.rb +2 -2
- data/lib/active_support/duration/iso8601_serializer.rb +1 -2
- data/lib/active_support/duration.rb +25 -16
- data/lib/active_support/editor.rb +70 -0
- data/lib/active_support/encrypted_configuration.rb +20 -2
- data/lib/active_support/encrypted_file.rb +1 -1
- data/lib/active_support/error_reporter.rb +121 -6
- data/lib/active_support/event_reporter/test_helper.rb +32 -0
- data/lib/active_support/event_reporter.rb +592 -0
- data/lib/active_support/evented_file_update_checker.rb +5 -3
- data/lib/active_support/execution_context.rb +64 -7
- data/lib/active_support/execution_wrapper.rb +1 -2
- data/lib/active_support/file_update_checker.rb +9 -7
- data/lib/active_support/fork_tracker.rb +2 -38
- data/lib/active_support/gem_version.rb +2 -2
- data/lib/active_support/gzip.rb +1 -0
- data/lib/active_support/hash_with_indifferent_access.rb +66 -45
- data/lib/active_support/html_safe_translation.rb +3 -0
- data/lib/active_support/i18n_railtie.rb +19 -11
- data/lib/active_support/inflector/inflections.rb +31 -15
- data/lib/active_support/inflector/transliterate.rb +6 -8
- data/lib/active_support/isolated_execution_state.rb +12 -17
- data/lib/active_support/json/decoding.rb +6 -4
- data/lib/active_support/json/encoding.rb +157 -21
- data/lib/active_support/lazy_load_hooks.rb +1 -1
- data/lib/active_support/log_subscriber.rb +2 -18
- data/lib/active_support/logger.rb +15 -2
- data/lib/active_support/logger_thread_safe_level.rb +4 -9
- data/lib/active_support/message_encryptors.rb +54 -2
- data/lib/active_support/message_pack/extensions.rb +20 -2
- data/lib/active_support/message_verifier.rb +21 -0
- data/lib/active_support/message_verifiers.rb +57 -3
- data/lib/active_support/messages/rotation_coordinator.rb +9 -0
- data/lib/active_support/messages/rotator.rb +10 -0
- data/lib/active_support/multibyte/chars.rb +14 -4
- data/lib/active_support/multibyte.rb +4 -0
- data/lib/active_support/notifications/fanout.rb +68 -50
- data/lib/active_support/notifications/instrumenter.rb +22 -19
- data/lib/active_support/notifications.rb +28 -27
- data/lib/active_support/number_helper/number_converter.rb +2 -2
- data/lib/active_support/number_helper.rb +22 -0
- data/lib/active_support/option_merger.rb +2 -2
- data/lib/active_support/ordered_options.rb +53 -15
- data/lib/active_support/railtie.rb +36 -20
- data/lib/active_support/string_inquirer.rb +1 -1
- data/lib/active_support/structured_event_subscriber.rb +99 -0
- data/lib/active_support/subscriber.rb +1 -5
- data/lib/active_support/syntax_error_proxy.rb +3 -0
- data/lib/active_support/tagged_logging.rb +5 -1
- data/lib/active_support/test_case.rb +63 -6
- data/lib/active_support/testing/assertions.rb +113 -27
- data/lib/active_support/testing/constant_stubbing.rb +30 -8
- data/lib/active_support/testing/deprecation.rb +5 -12
- data/lib/active_support/testing/error_reporter_assertions.rb +18 -1
- data/lib/active_support/testing/event_reporter_assertions.rb +227 -0
- data/lib/active_support/testing/isolation.rb +19 -9
- data/lib/active_support/testing/method_call_assertions.rb +2 -16
- data/lib/active_support/testing/notification_assertions.rb +92 -0
- data/lib/active_support/testing/parallelization/server.rb +18 -2
- data/lib/active_support/testing/parallelization/worker.rb +4 -2
- data/lib/active_support/testing/parallelization.rb +25 -1
- data/lib/active_support/testing/tests_without_assertions.rb +19 -0
- data/lib/active_support/testing/time_helpers.rb +11 -6
- data/lib/active_support/time_with_zone.rb +39 -26
- data/lib/active_support/values/time_zone.rb +26 -17
- data/lib/active_support/xml_mini.rb +14 -4
- data/lib/active_support.rb +22 -9
- metadata +31 -17
- data/lib/active_support/core_ext/range/each.rb +0 -24
- data/lib/active_support/deprecation/instance_delegator.rb +0 -65
- data/lib/active_support/proxy_object.rb +0 -17
- data/lib/active_support/ruby_features.rb +0 -7
- data/lib/active_support/testing/strict_warnings.rb +0 -39
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ActiveSupport
|
|
4
|
+
# Provides a DSL for declaring a continuous integration workflow that can be run either locally or in the cloud.
|
|
5
|
+
# Each step is timed, reports success/error, and is aggregated into a collective report that reports total runtime,
|
|
6
|
+
# as well as whether the entire run was successful or not.
|
|
7
|
+
#
|
|
8
|
+
# Example:
|
|
9
|
+
#
|
|
10
|
+
# ActiveSupport::ContinuousIntegration.run do
|
|
11
|
+
# step "Setup", "bin/setup --skip-server"
|
|
12
|
+
# step "Style: Ruby", "bin/rubocop"
|
|
13
|
+
# step "Security: Gem audit", "bin/bundler-audit"
|
|
14
|
+
# step "Tests: Rails", "bin/rails test test:system"
|
|
15
|
+
#
|
|
16
|
+
# if success?
|
|
17
|
+
# step "Signoff: Ready for merge and deploy", "gh signoff"
|
|
18
|
+
# else
|
|
19
|
+
# failure "Skipping signoff; CI failed.", "Fix the issues and try again."
|
|
20
|
+
# end
|
|
21
|
+
# end
|
|
22
|
+
#
|
|
23
|
+
# Starting with Rails 8.1, a default `bin/ci` and `config/ci.rb` file are created to provide out-of-the-box CI.
|
|
24
|
+
class ContinuousIntegration
|
|
25
|
+
COLORS = {
|
|
26
|
+
banner: "\033[1;32m", # Green
|
|
27
|
+
title: "\033[1;35m", # Purple
|
|
28
|
+
subtitle: "\033[1;90m", # Medium Gray
|
|
29
|
+
error: "\033[1;31m", # Red
|
|
30
|
+
success: "\033[1;32m" # Green
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
attr_reader :results
|
|
34
|
+
|
|
35
|
+
# Perform a CI run. Execute each step, show their results and runtime, and exit with a non-zero status if there are any failures.
|
|
36
|
+
#
|
|
37
|
+
# Pass an optional title, subtitle, and a block that declares the steps to be executed.
|
|
38
|
+
#
|
|
39
|
+
# Sets the CI environment variable to "true" to allow for conditional behavior in the app, like enabling eager loading and disabling logging.
|
|
40
|
+
#
|
|
41
|
+
# Example:
|
|
42
|
+
#
|
|
43
|
+
# ActiveSupport::ContinuousIntegration.run do
|
|
44
|
+
# step "Setup", "bin/setup --skip-server"
|
|
45
|
+
# step "Style: Ruby", "bin/rubocop"
|
|
46
|
+
# step "Security: Gem audit", "bin/bundler-audit"
|
|
47
|
+
# step "Tests: Rails", "bin/rails test test:system"
|
|
48
|
+
#
|
|
49
|
+
# if success?
|
|
50
|
+
# step "Signoff: Ready for merge and deploy", "gh signoff"
|
|
51
|
+
# else
|
|
52
|
+
# failure "Skipping signoff; CI failed.", "Fix the issues and try again."
|
|
53
|
+
# end
|
|
54
|
+
# end
|
|
55
|
+
def self.run(title = "Continuous Integration", subtitle = "Running tests, style checks, and security audits", &block)
|
|
56
|
+
new.tap do |ci|
|
|
57
|
+
ENV["CI"] = "true"
|
|
58
|
+
ci.heading title, subtitle, padding: false
|
|
59
|
+
ci.report(title, &block)
|
|
60
|
+
abort unless ci.success?
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def initialize
|
|
65
|
+
@results = []
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# Declare a step with a title and a command. The command can either be given as a single string or as multiple
|
|
69
|
+
# strings that will be passed to `system` as individual arguments (and therefore correctly escaped for paths etc).
|
|
70
|
+
#
|
|
71
|
+
# Examples:
|
|
72
|
+
#
|
|
73
|
+
# step "Setup", "bin/setup"
|
|
74
|
+
# step "Single test", "bin/rails", "test", "--name", "test_that_is_one"
|
|
75
|
+
def step(title, *command)
|
|
76
|
+
heading title, command.join(" "), type: :title
|
|
77
|
+
report(title) { results << system(*command) }
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# Returns true if all steps were successful.
|
|
81
|
+
def success?
|
|
82
|
+
results.all?
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# Display an error heading with the title and optional subtitle to reflect that the run failed.
|
|
86
|
+
def failure(title, subtitle = nil)
|
|
87
|
+
heading title, subtitle, type: :error
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# Display a colorized heading followed by an optional subtitle.
|
|
91
|
+
#
|
|
92
|
+
# Examples:
|
|
93
|
+
#
|
|
94
|
+
# heading "Smoke Testing", "End-to-end tests verifying key functionality", padding: false
|
|
95
|
+
# heading "Skipping video encoding tests", "Install FFmpeg to run these tests", type: :error
|
|
96
|
+
#
|
|
97
|
+
# See ActiveSupport::ContinuousIntegration::COLORS for a complete list of options.
|
|
98
|
+
def heading(heading, subtitle = nil, type: :banner, padding: true)
|
|
99
|
+
echo "#{padding ? "\n\n" : ""}#{heading}", type: type
|
|
100
|
+
echo "#{subtitle}#{padding ? "\n" : ""}", type: :subtitle if subtitle
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
# Echo text to the terminal in the color corresponding to the type of the text.
|
|
104
|
+
#
|
|
105
|
+
# Examples:
|
|
106
|
+
#
|
|
107
|
+
# echo "This is going to be green!", type: :success
|
|
108
|
+
# echo "This is going to be red!", type: :error
|
|
109
|
+
#
|
|
110
|
+
# See ActiveSupport::ContinuousIntegration::COLORS for a complete list of options.
|
|
111
|
+
def echo(text, type:)
|
|
112
|
+
puts colorize(text, type)
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
# :nodoc:
|
|
116
|
+
def report(title, &block)
|
|
117
|
+
Signal.trap("INT") { abort colorize(:error, "\n❌ #{title} interrupted") }
|
|
118
|
+
|
|
119
|
+
ci = self.class.new
|
|
120
|
+
elapsed = timing { ci.instance_eval(&block) }
|
|
121
|
+
|
|
122
|
+
if ci.success?
|
|
123
|
+
echo "\n✅ #{title} passed in #{elapsed}", type: :success
|
|
124
|
+
else
|
|
125
|
+
echo "\n❌ #{title} failed in #{elapsed}", type: :error
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
results.concat ci.results
|
|
129
|
+
ensure
|
|
130
|
+
Signal.trap("INT", "-")
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
private
|
|
134
|
+
def timing
|
|
135
|
+
started_at = Time.now.to_f
|
|
136
|
+
yield
|
|
137
|
+
min, sec = (Time.now.to_f - started_at).divmod(60)
|
|
138
|
+
"#{"#{min}m" if min > 0}%.2fs" % sec
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def colorize(text, type)
|
|
142
|
+
"#{COLORS.fetch(type)}#{text}\033[0m"
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
end
|
|
@@ -16,11 +16,11 @@ class Array
|
|
|
16
16
|
# ==== Options
|
|
17
17
|
#
|
|
18
18
|
# * <tt>:words_connector</tt> - The sign or word used to join all but the last
|
|
19
|
-
# element in arrays with three or more elements (default: ", ").
|
|
19
|
+
# element in arrays with three or more elements (default: <tt>", "</tt>).
|
|
20
20
|
# * <tt>:last_word_connector</tt> - The sign or word used to join the last element
|
|
21
|
-
# in arrays with three or more elements (default: ", and ").
|
|
21
|
+
# in arrays with three or more elements (default: <tt>", and "</tt>).
|
|
22
22
|
# * <tt>:two_words_connector</tt> - The sign or word used to join the elements
|
|
23
|
-
# in arrays with two elements (default: " and ").
|
|
23
|
+
# in arrays with two elements (default: <tt>" and "</tt>).
|
|
24
24
|
# * <tt>:locale</tt> - If +i18n+ is available, you can set a locale and use
|
|
25
25
|
# the connector options defined on the 'support.array' namespace in the
|
|
26
26
|
# corresponding dictionary file.
|
|
@@ -104,8 +104,6 @@ class Array
|
|
|
104
104
|
end
|
|
105
105
|
end
|
|
106
106
|
alias_method :to_formatted_s, :to_fs
|
|
107
|
-
alias_method :to_default_s, :to_s
|
|
108
|
-
deprecate to_default_s: :to_s, deprecator: ActiveSupport.deprecator
|
|
109
107
|
|
|
110
108
|
# Returns a string that represents the array in XML by invoking +to_xml+
|
|
111
109
|
# on each element. Active Record collections delegate their representation
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
3
|
+
require_relative "array/wrap"
|
|
4
|
+
require_relative "array/access"
|
|
5
|
+
require_relative "array/conversions"
|
|
6
|
+
require_relative "array/extract"
|
|
7
|
+
require_relative "array/extract_options"
|
|
8
|
+
require_relative "array/grouping"
|
|
9
|
+
require_relative "array/inquiry"
|
|
@@ -1,16 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
#
|
|
8
|
-
# Benchmark.realtime { User.all }
|
|
9
|
-
# # => 8.0e-05
|
|
10
|
-
#
|
|
11
|
-
# Benchmark.ms { User.all }
|
|
12
|
-
# # => 0.074
|
|
13
|
-
def ms(&block)
|
|
14
|
-
1000 * realtime(&block)
|
|
15
|
-
end
|
|
16
|
-
end
|
|
3
|
+
# Remove this file from activesupport/lib/active_support/core_ext.rb when deleting the deprecation.
|
|
4
|
+
ActiveSupport.deprecator.warn <<~TEXT
|
|
5
|
+
active_support/core_ext/benchmark.rb is deprecated and will be removed in Rails 8.2 without replacement.
|
|
6
|
+
TEXT
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "active_support/core_ext/module/redefine_method"
|
|
4
|
+
require "active_support/class_attribute"
|
|
4
5
|
|
|
5
6
|
class Class
|
|
6
7
|
# Declare a class-level attribute whose value is inheritable by subclasses.
|
|
@@ -83,31 +84,39 @@ class Class
|
|
|
83
84
|
#
|
|
84
85
|
# class_attribute :settings, default: {}
|
|
85
86
|
def class_attribute(*attrs, instance_accessor: true,
|
|
86
|
-
instance_reader: instance_accessor, instance_writer: instance_accessor, instance_predicate: true, default: nil
|
|
87
|
+
instance_reader: instance_accessor, instance_writer: instance_accessor, instance_predicate: true, default: nil
|
|
88
|
+
)
|
|
87
89
|
class_methods, methods = [], []
|
|
88
90
|
attrs.each do |name|
|
|
89
91
|
unless name.is_a?(Symbol) || name.is_a?(String)
|
|
90
92
|
raise TypeError, "#{name.inspect} is not a symbol nor a string"
|
|
91
93
|
end
|
|
92
94
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
RUBY
|
|
95
|
+
name = name.to_sym
|
|
96
|
+
namespaced_name = :"__class_attr_#{name}"
|
|
97
|
+
::ActiveSupport::ClassAttribute.redefine(self, name, namespaced_name, default)
|
|
97
98
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
defined?(@#{name}) ? @#{name} : self.class.#{name}
|
|
101
|
-
end
|
|
102
|
-
RUBY
|
|
99
|
+
class_methods << "def #{name}; #{namespaced_name}; end"
|
|
100
|
+
class_methods << "def #{name}=(value); self.#{namespaced_name} = value; end"
|
|
103
101
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
102
|
+
if singleton_class?
|
|
103
|
+
methods << <<~RUBY if instance_reader
|
|
104
|
+
silence_redefinition_of_method(:#{name})
|
|
105
|
+
def #{name}
|
|
106
|
+
self.singleton_class.#{name}
|
|
107
|
+
end
|
|
108
|
+
RUBY
|
|
109
|
+
else
|
|
110
|
+
methods << <<~RUBY if instance_reader
|
|
111
|
+
silence_redefinition_of_method def #{name}
|
|
112
|
+
if defined?(@#{name})
|
|
113
|
+
@#{name}
|
|
114
|
+
else
|
|
115
|
+
self.class.#{name}
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
RUBY
|
|
119
|
+
end
|
|
111
120
|
|
|
112
121
|
methods << <<~RUBY if instance_writer
|
|
113
122
|
silence_redefinition_of_method(:#{name}=)
|
|
@@ -124,7 +133,5 @@ class Class
|
|
|
124
133
|
|
|
125
134
|
location = caller_locations(1, 1).first
|
|
126
135
|
class_eval(["class << self", *class_methods, "end", *methods].join(";").tr("\n", ";"), location.path, location.lineno)
|
|
127
|
-
|
|
128
|
-
attrs.each { |name| public_send("#{name}=", default) }
|
|
129
136
|
end
|
|
130
137
|
end
|
|
@@ -1,43 +1,23 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "active_support/ruby_features"
|
|
4
3
|
require "active_support/descendants_tracker"
|
|
5
4
|
|
|
6
5
|
class Class
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
subclasses.concat(subclasses.flat_map(&:descendants))
|
|
23
|
-
end
|
|
24
|
-
else
|
|
25
|
-
def descendants
|
|
26
|
-
ObjectSpace.each_object(singleton_class).reject do |k|
|
|
27
|
-
k.singleton_class? || k == self
|
|
28
|
-
end
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
# Returns an array with the direct children of +self+.
|
|
32
|
-
#
|
|
33
|
-
# class Foo; end
|
|
34
|
-
# class Bar < Foo; end
|
|
35
|
-
# class Baz < Bar; end
|
|
36
|
-
#
|
|
37
|
-
# Foo.subclasses # => [Bar]
|
|
38
|
-
def subclasses
|
|
39
|
-
descendants.select { |descendant| descendant.superclass == self }
|
|
40
|
-
end
|
|
6
|
+
# Returns an array with all classes that are < than its receiver.
|
|
7
|
+
#
|
|
8
|
+
# class C; end
|
|
9
|
+
# C.descendants # => []
|
|
10
|
+
#
|
|
11
|
+
# class B < C; end
|
|
12
|
+
# C.descendants # => [B]
|
|
13
|
+
#
|
|
14
|
+
# class A < B; end
|
|
15
|
+
# C.descendants # => [B, A]
|
|
16
|
+
#
|
|
17
|
+
# class D < C; end
|
|
18
|
+
# C.descendants # => [B, A, D]
|
|
19
|
+
def descendants
|
|
20
|
+
subclasses.concat(subclasses.flat_map(&:descendants))
|
|
41
21
|
end
|
|
42
22
|
|
|
43
23
|
prepend ActiveSupport::DescendantsTracker::ReloadedClassesFiltering
|
|
@@ -17,6 +17,7 @@ class Date
|
|
|
17
17
|
date.strftime("%B #{day_format}, %Y") # => "April 25th, 2007"
|
|
18
18
|
},
|
|
19
19
|
rfc822: "%d %b %Y",
|
|
20
|
+
rfc2822: "%d %b %Y",
|
|
20
21
|
iso8601: lambda { |date| date.iso8601 }
|
|
21
22
|
}
|
|
22
23
|
|
|
@@ -34,6 +35,7 @@ class Date
|
|
|
34
35
|
# date.to_fs(:long) # => "November 10, 2007"
|
|
35
36
|
# date.to_fs(:long_ordinal) # => "November 10th, 2007"
|
|
36
37
|
# date.to_fs(:rfc822) # => "10 Nov 2007"
|
|
38
|
+
# date.to_fs(:rfc2822) # => "10 Nov 2007"
|
|
37
39
|
# date.to_fs(:iso8601) # => "2007-11-10"
|
|
38
40
|
#
|
|
39
41
|
# == Adding your own date formats to to_fs
|
|
@@ -56,8 +58,6 @@ class Date
|
|
|
56
58
|
end
|
|
57
59
|
end
|
|
58
60
|
alias_method :to_formatted_s, :to_fs
|
|
59
|
-
alias_method :to_default_s, :to_s
|
|
60
|
-
deprecate to_default_s: :to_s, deprecator: ActiveSupport.deprecator
|
|
61
61
|
|
|
62
62
|
# Overrides the default inspect method with a human readable one, e.g., "Mon, 21 Feb 2005"
|
|
63
63
|
def readable_inspect
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
3
|
+
require_relative "date/acts_like"
|
|
4
|
+
require_relative "date/blank"
|
|
5
|
+
require_relative "date/calculations"
|
|
6
|
+
require_relative "date/conversions"
|
|
7
|
+
require_relative "date/zones"
|
|
@@ -1,18 +1,10 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "active_support/core_ext/module/attribute_accessors"
|
|
4
|
+
require "active_support/core_ext/module/redefine_method"
|
|
4
5
|
|
|
5
6
|
module DateAndTime
|
|
6
7
|
module Compatibility
|
|
7
|
-
# If true, +to_time+ preserves the timezone offset of receiver.
|
|
8
|
-
#
|
|
9
|
-
# NOTE: With Ruby 2.4+ the default for +to_time+ changed from
|
|
10
|
-
# converting to the local system time, to preserving the offset
|
|
11
|
-
# of the receiver. For backwards compatibility we're overriding
|
|
12
|
-
# this behavior, but new apps will have an initializer that sets
|
|
13
|
-
# this to true, because the new behavior is preferred.
|
|
14
|
-
mattr_accessor :preserve_timezone, instance_writer: false, default: false
|
|
15
|
-
|
|
16
8
|
# Change the output of <tt>ActiveSupport::TimeZone.utc_to_local</tt>.
|
|
17
9
|
#
|
|
18
10
|
# When +true+, it returns local times with a UTC offset, with +false+ local
|
|
@@ -8,11 +8,9 @@ class DateTime
|
|
|
8
8
|
|
|
9
9
|
silence_redefinition_of_method :to_time
|
|
10
10
|
|
|
11
|
-
#
|
|
12
|
-
# as +self
|
|
13
|
-
# in the local system timezone depending on the setting of
|
|
14
|
-
# on the setting of +ActiveSupport.to_time_preserves_timezone+.
|
|
11
|
+
# Return an instance of +Time+ with the same UTC offset
|
|
12
|
+
# as +self+.
|
|
15
13
|
def to_time
|
|
16
|
-
|
|
14
|
+
getlocal(utc_offset)
|
|
17
15
|
end
|
|
18
16
|
end
|
|
@@ -11,7 +11,8 @@ class DateTime
|
|
|
11
11
|
#
|
|
12
12
|
# This method is aliased to <tt>to_formatted_s</tt>.
|
|
13
13
|
#
|
|
14
|
-
#
|
|
14
|
+
# ==== Examples
|
|
15
|
+
#
|
|
15
16
|
# datetime = DateTime.civil(2007, 12, 4, 0, 0, 0, 0) # => Tue, 04 Dec 2007 00:00:00 +0000
|
|
16
17
|
#
|
|
17
18
|
# datetime.to_fs(:db) # => "2007-12-04 00:00:00"
|
|
@@ -23,7 +24,8 @@ class DateTime
|
|
|
23
24
|
# datetime.to_fs(:rfc822) # => "Tue, 04 Dec 2007 00:00:00 +0000"
|
|
24
25
|
# datetime.to_fs(:iso8601) # => "2007-12-04T00:00:00+00:00"
|
|
25
26
|
#
|
|
26
|
-
#
|
|
27
|
+
# ==== Adding your own datetime formats to +to_fs+
|
|
28
|
+
#
|
|
27
29
|
# DateTime formats are shared with Time. You can add your own to the
|
|
28
30
|
# Time::DATE_FORMATS hash. Use the format name as the hash key and
|
|
29
31
|
# either a strftime string or Proc instance that takes a time or
|
|
@@ -40,10 +42,6 @@ class DateTime
|
|
|
40
42
|
end
|
|
41
43
|
end
|
|
42
44
|
alias_method :to_formatted_s, :to_fs
|
|
43
|
-
if instance_methods(false).include?(:to_s)
|
|
44
|
-
alias_method :to_default_s, :to_s
|
|
45
|
-
deprecate to_default_s: :to_s, deprecator: ActiveSupport.deprecator
|
|
46
|
-
end
|
|
47
45
|
|
|
48
46
|
|
|
49
47
|
# Returns a formatted string of the offset from UTC, or an alternative
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
3
|
+
require_relative "date_time/acts_like"
|
|
4
|
+
require_relative "date_time/blank"
|
|
5
|
+
require_relative "date_time/calculations"
|
|
6
|
+
require_relative "date_time/compatibility"
|
|
7
|
+
require_relative "date_time/conversions"
|
|
@@ -53,6 +53,12 @@ module Digest
|
|
|
53
53
|
SecureRandom.uuid
|
|
54
54
|
end
|
|
55
55
|
|
|
56
|
+
# Returns the nil UUID. This is a special form of UUID that is specified to
|
|
57
|
+
# have all 128 bits set to zero.
|
|
58
|
+
def self.nil_uuid
|
|
59
|
+
"00000000-0000-0000-0000-000000000000"
|
|
60
|
+
end
|
|
61
|
+
|
|
56
62
|
def self.pack_uuid_namespace(namespace)
|
|
57
63
|
if [DNS_NAMESPACE, OID_NAMESPACE, URL_NAMESPACE, X500_NAMESPACE].include?(namespace)
|
|
58
64
|
namespace
|
|
@@ -192,22 +192,39 @@ module Enumerable
|
|
|
192
192
|
# # => [ Person.find(1), Person.find(5), Person.find(3) ]
|
|
193
193
|
#
|
|
194
194
|
# If the +series+ include keys that have no corresponding element in the Enumerable, these are ignored.
|
|
195
|
-
# If the Enumerable has additional elements that aren't named in the +series+, these are not included in the result
|
|
196
|
-
|
|
197
|
-
|
|
195
|
+
# If the Enumerable has additional elements that aren't named in the +series+, these are not included in the result, unless
|
|
196
|
+
# the +filter+ option is set to +false+.
|
|
197
|
+
def in_order_of(key, series, filter: true)
|
|
198
|
+
if filter
|
|
199
|
+
group_by(&key).values_at(*series).flatten(1).compact
|
|
200
|
+
else
|
|
201
|
+
sort_by { |v| series.index(v.public_send(key)) || series.size }.compact
|
|
202
|
+
end
|
|
198
203
|
end
|
|
199
204
|
|
|
200
205
|
# Returns the sole item in the enumerable. If there are no items, or more
|
|
201
|
-
# than one item, raises
|
|
206
|
+
# than one item, raises Enumerable::SoleItemExpectedError.
|
|
202
207
|
#
|
|
203
208
|
# ["x"].sole # => "x"
|
|
204
209
|
# Set.new.sole # => Enumerable::SoleItemExpectedError: no item found
|
|
205
210
|
# { a: 1, b: 2 }.sole # => Enumerable::SoleItemExpectedError: multiple items found
|
|
206
211
|
def sole
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
212
|
+
result = nil
|
|
213
|
+
found = false
|
|
214
|
+
|
|
215
|
+
each do |*element|
|
|
216
|
+
if found
|
|
217
|
+
raise SoleItemExpectedError, "multiple items found"
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
result = element.size == 1 ? element[0] : element
|
|
221
|
+
found = true
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
if found
|
|
225
|
+
result
|
|
226
|
+
else
|
|
227
|
+
raise SoleItemExpectedError, "no item found"
|
|
211
228
|
end
|
|
212
229
|
end
|
|
213
230
|
end
|
|
@@ -12,7 +12,7 @@ module ActiveSupport
|
|
|
12
12
|
if s.html_safe?
|
|
13
13
|
s
|
|
14
14
|
else
|
|
15
|
-
super(
|
|
15
|
+
super(s)
|
|
16
16
|
end
|
|
17
17
|
end
|
|
18
18
|
alias :unwrapped_html_escape :html_escape # :nodoc:
|
|
@@ -61,7 +61,7 @@ class ERB
|
|
|
61
61
|
# html_escape_once('<< Accept & Checkout')
|
|
62
62
|
# # => "<< Accept & Checkout"
|
|
63
63
|
def html_escape_once(s)
|
|
64
|
-
|
|
64
|
+
s.to_s.gsub(HTML_ESCAPE_ONCE_REGEXP, HTML_ESCAPE).html_safe
|
|
65
65
|
end
|
|
66
66
|
|
|
67
67
|
module_function :html_escape_once
|
|
@@ -169,12 +169,12 @@ class ERB
|
|
|
169
169
|
while !source.eos?
|
|
170
170
|
pos = source.pos
|
|
171
171
|
source.scan_until(/(?:#{start_re}|#{finish_re})/)
|
|
172
|
-
|
|
172
|
+
return [[:PLAIN, source.string]] unless source.matched?
|
|
173
173
|
len = source.pos - source.matched.bytesize - pos
|
|
174
174
|
|
|
175
175
|
case source.matched
|
|
176
176
|
when start_re
|
|
177
|
-
tokens << [:TEXT, source.string
|
|
177
|
+
tokens << [:TEXT, source.string.byteslice(pos, len)] if len > 0
|
|
178
178
|
tokens << [:OPEN, source.matched]
|
|
179
179
|
if source.scan(/(.*?)(?=#{finish_re}|\z)/m)
|
|
180
180
|
tokens << [:CODE, source.matched] unless source.matched.empty?
|
|
@@ -183,11 +183,16 @@ class ERB
|
|
|
183
183
|
raise NotImplementedError
|
|
184
184
|
end
|
|
185
185
|
when finish_re
|
|
186
|
-
tokens << [:CODE, source.string
|
|
186
|
+
tokens << [:CODE, source.string.byteslice(pos, len)] if len > 0
|
|
187
187
|
tokens << [:CLOSE, source.matched]
|
|
188
188
|
else
|
|
189
189
|
raise NotImplementedError, source.matched
|
|
190
190
|
end
|
|
191
|
+
|
|
192
|
+
unless source.eos? || source.exist?(start_re) || source.exist?(finish_re)
|
|
193
|
+
tokens << [:TEXT, source.rest]
|
|
194
|
+
source.terminate
|
|
195
|
+
end
|
|
191
196
|
end
|
|
192
197
|
|
|
193
198
|
tokens
|
|
@@ -1,18 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
class Hash
|
|
4
|
-
# Returns a hash that includes everything except given keys.
|
|
5
|
-
# hash = { a: true, b: false, c: nil }
|
|
6
|
-
# hash.except(:c) # => { a: true, b: false }
|
|
7
|
-
# hash.except(:a, :b) # => { c: nil }
|
|
8
|
-
# hash # => { a: true, b: false, c: nil }
|
|
9
|
-
#
|
|
10
|
-
# This is useful for limiting a set of parameters to everything but a few known toggles:
|
|
11
|
-
# @person.update(params[:person].except(:admin))
|
|
12
|
-
def except(*keys)
|
|
13
|
-
slice(*self.keys - keys)
|
|
14
|
-
end unless method_defined?(:except)
|
|
15
|
-
|
|
16
4
|
# Removes the given keys from hash and returns it.
|
|
17
5
|
# hash = { a: true, b: false, c: nil }
|
|
18
6
|
# hash.except!(:c) # => { a: true, b: false }
|