activesupport 7.1.3.4 → 8.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +74 -1136
- data/lib/active_support/array_inquirer.rb +1 -1
- data/lib/active_support/backtrace_cleaner.rb +15 -3
- data/lib/active_support/benchmark.rb +21 -0
- data/lib/active_support/benchmarkable.rb +3 -2
- data/lib/active_support/broadcast_logger.rb +19 -18
- data/lib/active_support/cache/file_store.rb +27 -12
- data/lib/active_support/cache/mem_cache_store.rb +16 -74
- data/lib/active_support/cache/memory_store.rb +8 -3
- data/lib/active_support/cache/redis_cache_store.rb +21 -15
- data/lib/active_support/cache/serializer_with_fallback.rb +0 -23
- data/lib/active_support/cache.rb +76 -78
- data/lib/active_support/callbacks.rb +79 -116
- data/lib/active_support/class_attribute.rb +33 -0
- data/lib/active_support/code_generator.rb +24 -10
- data/lib/active_support/concurrency/share_lock.rb +0 -1
- data/lib/active_support/configuration_file.rb +15 -6
- data/lib/active_support/core_ext/array/conversions.rb +3 -5
- data/lib/active_support/core_ext/benchmark.rb +6 -9
- data/lib/active_support/core_ext/class/attribute.rb +24 -20
- data/lib/active_support/core_ext/class/subclasses.rb +15 -35
- 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_and_time/compatibility.rb +28 -1
- data/lib/active_support/core_ext/date_time/blank.rb +4 -0
- data/lib/active_support/core_ext/date_time/conversions.rb +0 -4
- data/lib/active_support/core_ext/digest/uuid.rb +6 -0
- data/lib/active_support/core_ext/enumerable.rb +8 -3
- data/lib/active_support/core_ext/erb/util.rb +7 -2
- 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/module/attr_internal.rb +16 -6
- data/lib/active_support/core_ext/module/delegation.rb +20 -148
- data/lib/active_support/core_ext/module/deprecation.rb +1 -4
- data/lib/active_support/core_ext/numeric/conversions.rb +3 -3
- data/lib/active_support/core_ext/object/blank.rb +45 -1
- data/lib/active_support/core_ext/object/duplicable.rb +24 -15
- data/lib/active_support/core_ext/object/instance_variables.rb +11 -19
- data/lib/active_support/core_ext/object/json.rb +21 -13
- data/lib/active_support/core_ext/object/with.rb +5 -3
- data/lib/active_support/core_ext/pathname/blank.rb +4 -0
- data/lib/active_support/core_ext/range/overlap.rb +1 -1
- 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 +1 -1
- data/lib/active_support/core_ext/string/multibyte.rb +1 -1
- data/lib/active_support/core_ext/string/output_safety.rb +0 -7
- data/lib/active_support/core_ext/thread/backtrace/location.rb +2 -7
- data/lib/active_support/core_ext/time/calculations.rb +32 -30
- data/lib/active_support/core_ext/time/compatibility.rb +24 -0
- 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.rb +0 -1
- data/lib/active_support/current_attributes.rb +38 -40
- data/lib/active_support/delegation.rb +200 -0
- data/lib/active_support/dependencies/autoload.rb +0 -12
- data/lib/active_support/dependencies.rb +0 -1
- 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 +3 -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/encrypted_configuration.rb +20 -2
- data/lib/active_support/encrypted_file.rb +1 -1
- data/lib/active_support/error_reporter.rb +65 -3
- data/lib/active_support/evented_file_update_checker.rb +0 -2
- data/lib/active_support/execution_wrapper.rb +0 -1
- data/lib/active_support/file_update_checker.rb +1 -1
- data/lib/active_support/fork_tracker.rb +2 -38
- data/lib/active_support/gem_version.rb +4 -4
- data/lib/active_support/hash_with_indifferent_access.rb +21 -23
- data/lib/active_support/html_safe_translation.rb +7 -4
- data/lib/active_support/i18n_railtie.rb +19 -11
- data/lib/active_support/isolated_execution_state.rb +0 -2
- data/lib/active_support/json/encoding.rb +3 -3
- data/lib/active_support/log_subscriber.rb +1 -12
- data/lib/active_support/logger.rb +15 -2
- data/lib/active_support/logger_thread_safe_level.rb +0 -8
- data/lib/active_support/message_pack/extensions.rb +15 -2
- data/lib/active_support/message_verifier.rb +12 -0
- data/lib/active_support/messages/codec.rb +1 -1
- data/lib/active_support/multibyte/chars.rb +2 -2
- data/lib/active_support/notifications/fanout.rb +4 -8
- data/lib/active_support/notifications/instrumenter.rb +32 -21
- 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 +8 -11
- data/lib/active_support/string_inquirer.rb +1 -1
- data/lib/active_support/subscriber.rb +1 -0
- data/lib/active_support/syntax_error_proxy.rb +1 -11
- data/lib/active_support/tagged_logging.rb +9 -1
- data/lib/active_support/test_case.rb +3 -1
- data/lib/active_support/testing/assertions.rb +79 -21
- data/lib/active_support/testing/constant_stubbing.rb +30 -8
- data/lib/active_support/testing/deprecation.rb +5 -12
- 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/parallelization/server.rb +3 -0
- data/lib/active_support/testing/setup_and_teardown.rb +2 -0
- data/lib/active_support/testing/strict_warnings.rb +8 -4
- data/lib/active_support/testing/tests_without_assertions.rb +19 -0
- data/lib/active_support/testing/time_helpers.rb +4 -3
- data/lib/active_support/time_with_zone.rb +30 -17
- data/lib/active_support/values/time_zone.rb +25 -14
- data/lib/active_support/xml_mini.rb +11 -2
- data/lib/active_support.rb +12 -4
- metadata +68 -19
- 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
@@ -9,16 +9,19 @@ module ActiveSupport
|
|
9
9
|
@cache = METHOD_CACHES[namespace]
|
10
10
|
@sources = []
|
11
11
|
@methods = {}
|
12
|
+
@canonical_methods = {}
|
12
13
|
end
|
13
14
|
|
14
|
-
def define_cached_method(
|
15
|
-
|
16
|
-
as = as.to_sym
|
17
|
-
|
18
|
-
|
15
|
+
def define_cached_method(canonical_name, as: nil)
|
16
|
+
canonical_name = canonical_name.to_sym
|
17
|
+
as = (as || canonical_name).to_sym
|
18
|
+
|
19
|
+
@methods.fetch(as) do
|
20
|
+
unless @cache.method_defined?(canonical_name) || @canonical_methods[canonical_name]
|
19
21
|
yield @sources
|
20
22
|
end
|
21
|
-
@
|
23
|
+
@canonical_methods[canonical_name] = true
|
24
|
+
@methods[as] = canonical_name
|
22
25
|
end
|
23
26
|
end
|
24
27
|
|
@@ -26,8 +29,10 @@ module ActiveSupport
|
|
26
29
|
unless @sources.empty?
|
27
30
|
@cache.module_eval("# frozen_string_literal: true\n" + @sources.join(";"), path, line)
|
28
31
|
end
|
29
|
-
@
|
30
|
-
|
32
|
+
@canonical_methods.clear
|
33
|
+
|
34
|
+
@methods.each do |as, canonical_name|
|
35
|
+
owner.define_method(as, @cache.instance_method(canonical_name))
|
31
36
|
end
|
32
37
|
end
|
33
38
|
end
|
@@ -50,16 +55,25 @@ module ActiveSupport
|
|
50
55
|
@path = path
|
51
56
|
@line = line
|
52
57
|
@namespaces = Hash.new { |h, k| h[k] = MethodSet.new(k) }
|
58
|
+
@sources = []
|
59
|
+
end
|
60
|
+
|
61
|
+
def class_eval
|
62
|
+
yield @sources
|
53
63
|
end
|
54
64
|
|
55
|
-
def define_cached_method(
|
56
|
-
@namespaces[namespace].define_cached_method(
|
65
|
+
def define_cached_method(canonical_name, namespace:, as: nil, &block)
|
66
|
+
@namespaces[namespace].define_cached_method(canonical_name, as: as, &block)
|
57
67
|
end
|
58
68
|
|
59
69
|
def execute
|
60
70
|
@namespaces.each_value do |method_set|
|
61
71
|
method_set.apply(@owner, @path, @line - 1)
|
62
72
|
end
|
73
|
+
|
74
|
+
unless @sources.empty?
|
75
|
+
@owner.class_eval("# frozen_string_literal: true\n" + @sources.join(";"), @path, @line - 1)
|
76
|
+
end
|
63
77
|
end
|
64
78
|
end
|
65
79
|
end
|
@@ -19,11 +19,20 @@ module ActiveSupport
|
|
19
19
|
end
|
20
20
|
|
21
21
|
def parse(context: nil, **options)
|
22
|
-
source = render(context)
|
23
|
-
|
24
|
-
|
22
|
+
source = @content.include?("<%") ? render(context) : @content
|
23
|
+
|
24
|
+
if source == @content
|
25
|
+
if YAML.respond_to?(:unsafe_load)
|
26
|
+
YAML.unsafe_load_file(@content_path, **options) || {}
|
27
|
+
else
|
28
|
+
YAML.load_file(@content_path, **options) || {}
|
29
|
+
end
|
25
30
|
else
|
26
|
-
YAML.
|
31
|
+
if YAML.respond_to?(:unsafe_load)
|
32
|
+
YAML.unsafe_load(source, **options) || {}
|
33
|
+
else
|
34
|
+
YAML.load(source, **options) || {}
|
35
|
+
end
|
27
36
|
end
|
28
37
|
rescue Psych::SyntaxError => error
|
29
38
|
raise "YAML syntax error occurred while parsing #{@content_path}. " \
|
@@ -33,8 +42,7 @@ module ActiveSupport
|
|
33
42
|
|
34
43
|
private
|
35
44
|
def read(content_path)
|
36
|
-
require "yaml"
|
37
|
-
require "erb"
|
45
|
+
require "yaml" unless defined?(YAML)
|
38
46
|
|
39
47
|
File.read(content_path).tap do |content|
|
40
48
|
if content.include?("\u00A0")
|
@@ -44,6 +52,7 @@ module ActiveSupport
|
|
44
52
|
end
|
45
53
|
|
46
54
|
def render(context)
|
55
|
+
require "erb" unless defined?(ERB)
|
47
56
|
erb = ERB.new(@content).tap { |e| e.filename = @content_path }
|
48
57
|
context ? erb.result(context) : erb.result
|
49
58
|
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
|
@@ -3,14 +3,11 @@
|
|
3
3
|
require "benchmark"
|
4
4
|
|
5
5
|
class << Benchmark
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
# # => 0.074
|
13
|
-
def ms(&block)
|
14
|
-
1000 * realtime(&block)
|
6
|
+
def ms(&block) # :nodoc
|
7
|
+
# NOTE: Please also remove the Active Support `benchmark` dependency when removing this
|
8
|
+
ActiveSupport.deprecator.warn <<~TEXT
|
9
|
+
`Benchmark.ms` is deprecated and will be removed in Rails 8.1 without replacement.
|
10
|
+
TEXT
|
11
|
+
ActiveSupport::Benchmark.realtime(:float_millisecond, &block)
|
15
12
|
end
|
16
13
|
end
|
@@ -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,32 +84,37 @@ 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
|
-
|
87
|
+
instance_reader: instance_accessor, instance_writer: instance_accessor, instance_predicate: true, default: nil
|
88
|
+
)
|
88
89
|
class_methods, methods = [], []
|
89
90
|
attrs.each do |name|
|
90
91
|
unless name.is_a?(Symbol) || name.is_a?(String)
|
91
92
|
raise TypeError, "#{name.inspect} is not a symbol nor a string"
|
92
93
|
end
|
93
94
|
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
RUBY
|
95
|
+
name = name.to_sym
|
96
|
+
namespaced_name = :"__class_attr_#{name}"
|
97
|
+
::ActiveSupport::ClassAttribute.redefine(self, name, namespaced_name, default)
|
98
98
|
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
RUBY
|
99
|
+
delegators = [
|
100
|
+
"def #{name}; #{namespaced_name}; end",
|
101
|
+
"def #{name}=(value); self.#{namespaced_name} = value; end",
|
102
|
+
]
|
104
103
|
|
105
|
-
class_methods
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
104
|
+
class_methods.concat(delegators)
|
105
|
+
if singleton_class?
|
106
|
+
methods.concat(delegators)
|
107
|
+
else
|
108
|
+
methods << <<~RUBY if instance_reader
|
109
|
+
silence_redefinition_of_method def #{name}
|
110
|
+
if defined?(@#{name})
|
111
|
+
@#{name}
|
112
|
+
else
|
113
|
+
self.class.#{name}
|
114
|
+
end
|
115
|
+
end
|
116
|
+
RUBY
|
117
|
+
end
|
112
118
|
|
113
119
|
methods << <<~RUBY if instance_writer
|
114
120
|
silence_redefinition_of_method(:#{name}=)
|
@@ -125,7 +131,5 @@ class Class
|
|
125
131
|
|
126
132
|
location = caller_locations(1, 1).first
|
127
133
|
class_eval(["class << self", *class_methods, "end", *methods].join(";").tr("\n", ";"), location.path, location.lineno)
|
128
|
-
|
129
|
-
attrs.each { |name| public_send("#{name}=", default) }
|
130
134
|
end
|
131
135
|
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,6 +1,7 @@
|
|
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
|
@@ -11,7 +12,33 @@ module DateAndTime
|
|
11
12
|
# of the receiver. For backwards compatibility we're overriding
|
12
13
|
# this behavior, but new apps will have an initializer that sets
|
13
14
|
# this to true, because the new behavior is preferred.
|
14
|
-
mattr_accessor :preserve_timezone,
|
15
|
+
mattr_accessor :preserve_timezone, instance_accessor: false, default: nil
|
16
|
+
|
17
|
+
singleton_class.silence_redefinition_of_method :preserve_timezone
|
18
|
+
|
19
|
+
#--
|
20
|
+
# This re-implements the behaviour of the mattr_reader, instead
|
21
|
+
# of prepending on to it, to avoid overcomplicating a module that
|
22
|
+
# is in turn included in several places. This will all go away in
|
23
|
+
# Rails 8.0 anyway.
|
24
|
+
def self.preserve_timezone # :nodoc:
|
25
|
+
if @@preserve_timezone.nil?
|
26
|
+
# Only warn once, the first time the value is used (which should
|
27
|
+
# be the first time #to_time is called).
|
28
|
+
ActiveSupport.deprecator.warn(
|
29
|
+
"`to_time` will always preserve the receiver timezone rather than system local time in Rails 8.1." \
|
30
|
+
"To opt in to the new behavior, set `config.active_support.to_time_preserves_timezone = :zone`."
|
31
|
+
)
|
32
|
+
|
33
|
+
@@preserve_timezone = false
|
34
|
+
end
|
35
|
+
|
36
|
+
@@preserve_timezone
|
37
|
+
end
|
38
|
+
|
39
|
+
def preserve_timezone # :nodoc:
|
40
|
+
Compatibility.preserve_timezone
|
41
|
+
end
|
15
42
|
|
16
43
|
# Change the output of <tt>ActiveSupport::TimeZone.utc_to_local</tt>.
|
17
44
|
#
|
@@ -40,10 +40,6 @@ class DateTime
|
|
40
40
|
end
|
41
41
|
end
|
42
42
|
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
43
|
|
48
44
|
|
49
45
|
# Returns a formatted string of the offset from UTC, or an alternative
|
@@ -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,9 +192,14 @@ 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
|
@@ -174,7 +174,7 @@ class ERB
|
|
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 }
|
@@ -8,13 +8,13 @@ class Hash
|
|
8
8
|
# hash.stringify_keys
|
9
9
|
# # => {"name"=>"Rob", "age"=>"28"}
|
10
10
|
def stringify_keys
|
11
|
-
transform_keys
|
11
|
+
transform_keys { |k| Symbol === k ? k.name : k.to_s }
|
12
12
|
end
|
13
13
|
|
14
14
|
# Destructively converts all keys to strings. Same as
|
15
15
|
# +stringify_keys+, but modifies +self+.
|
16
16
|
def stringify_keys!
|
17
|
-
transform_keys!
|
17
|
+
transform_keys! { |k| Symbol === k ? k.name : k.to_s }
|
18
18
|
end
|
19
19
|
|
20
20
|
# Returns a new hash with all keys converted to symbols, as long as
|
@@ -82,14 +82,14 @@ class Hash
|
|
82
82
|
# hash.deep_stringify_keys
|
83
83
|
# # => {"person"=>{"name"=>"Rob", "age"=>"28"}}
|
84
84
|
def deep_stringify_keys
|
85
|
-
deep_transform_keys
|
85
|
+
deep_transform_keys { |k| Symbol === k ? k.name : k.to_s }
|
86
86
|
end
|
87
87
|
|
88
88
|
# Destructively converts all keys to strings.
|
89
89
|
# This includes the keys from the root hash and from all
|
90
90
|
# nested hashes and arrays.
|
91
91
|
def deep_stringify_keys!
|
92
|
-
deep_transform_keys!
|
92
|
+
deep_transform_keys! { |k| Symbol === k ? k.name : k.to_s }
|
93
93
|
end
|
94
94
|
|
95
95
|
# Returns a new hash with all keys converted to symbols, as long as
|
@@ -19,16 +19,26 @@ class Module
|
|
19
19
|
end
|
20
20
|
alias_method :attr_internal, :attr_internal_accessor
|
21
21
|
|
22
|
-
class << self
|
23
|
-
|
22
|
+
class << self
|
23
|
+
attr_reader :attr_internal_naming_format
|
24
24
|
|
25
|
-
|
26
|
-
|
27
|
-
|
25
|
+
def attr_internal_naming_format=(format)
|
26
|
+
if format.start_with?("@")
|
27
|
+
raise ArgumentError, <<~MESSAGE.squish
|
28
|
+
Setting `attr_internal_naming_format` with a `@` prefix is not supported.
|
29
|
+
|
30
|
+
You can simply replace #{format.inspect} by #{format.delete_prefix("@").inspect}.
|
31
|
+
MESSAGE
|
32
|
+
end
|
33
|
+
|
34
|
+
@attr_internal_naming_format = format
|
28
35
|
end
|
36
|
+
end
|
37
|
+
self.attr_internal_naming_format = "_%s"
|
29
38
|
|
39
|
+
private
|
30
40
|
def attr_internal_define(attr_name, type)
|
31
|
-
internal_name =
|
41
|
+
internal_name = Module.attr_internal_naming_format % attr_name
|
32
42
|
# use native attr_* methods as they are faster on some Ruby implementations
|
33
43
|
public_send("attr_#{type}", internal_name)
|
34
44
|
attr_name, internal_name = "#{attr_name}=", "#{internal_name}=" if type == :writer
|