activesupport 5.2.4.4 → 6.1.1

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.

Files changed (187) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +353 -435
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +4 -3
  5. data/lib/active_support.rb +14 -1
  6. data/lib/active_support/actionable_error.rb +48 -0
  7. data/lib/active_support/array_inquirer.rb +4 -2
  8. data/lib/active_support/backtrace_cleaner.rb +29 -3
  9. data/lib/active_support/benchmarkable.rb +1 -1
  10. data/lib/active_support/cache.rb +142 -78
  11. data/lib/active_support/cache/file_store.rb +33 -33
  12. data/lib/active_support/cache/mem_cache_store.rb +32 -20
  13. data/lib/active_support/cache/memory_store.rb +59 -33
  14. data/lib/active_support/cache/null_store.rb +8 -3
  15. data/lib/active_support/cache/redis_cache_store.rb +70 -43
  16. data/lib/active_support/cache/strategy/local_cache.rb +41 -26
  17. data/lib/active_support/callbacks.rb +81 -64
  18. data/lib/active_support/concern.rb +70 -3
  19. data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +18 -0
  20. data/lib/active_support/concurrency/share_lock.rb +0 -1
  21. data/lib/active_support/configurable.rb +10 -14
  22. data/lib/active_support/configuration_file.rb +46 -0
  23. data/lib/active_support/core_ext.rb +1 -1
  24. data/lib/active_support/core_ext/array.rb +1 -1
  25. data/lib/active_support/core_ext/array/access.rb +18 -6
  26. data/lib/active_support/core_ext/array/conversions.rb +5 -5
  27. data/lib/active_support/core_ext/array/extract.rb +21 -0
  28. data/lib/active_support/core_ext/benchmark.rb +2 -2
  29. data/lib/active_support/core_ext/class/attribute.rb +32 -47
  30. data/lib/active_support/core_ext/class/subclasses.rb +17 -38
  31. data/lib/active_support/core_ext/date/calculations.rb +6 -5
  32. data/lib/active_support/core_ext/date/conversions.rb +2 -1
  33. data/lib/active_support/core_ext/date_and_time/calculations.rb +37 -47
  34. data/lib/active_support/core_ext/date_and_time/compatibility.rb +15 -0
  35. data/lib/active_support/core_ext/date_and_time/zones.rb +0 -1
  36. data/lib/active_support/core_ext/date_time/calculations.rb +1 -1
  37. data/lib/active_support/core_ext/date_time/conversions.rb +0 -1
  38. data/lib/active_support/core_ext/enumerable.rb +171 -75
  39. data/lib/active_support/core_ext/hash.rb +1 -2
  40. data/lib/active_support/core_ext/hash/conversions.rb +3 -3
  41. data/lib/active_support/core_ext/hash/deep_transform_values.rb +46 -0
  42. data/lib/active_support/core_ext/hash/except.rb +2 -2
  43. data/lib/active_support/core_ext/hash/keys.rb +1 -30
  44. data/lib/active_support/core_ext/hash/slice.rb +6 -27
  45. data/lib/active_support/core_ext/integer/multiple.rb +1 -1
  46. data/lib/active_support/core_ext/kernel.rb +0 -1
  47. data/lib/active_support/core_ext/load_error.rb +1 -1
  48. data/lib/active_support/core_ext/marshal.rb +2 -0
  49. data/lib/active_support/core_ext/module.rb +0 -1
  50. data/lib/active_support/core_ext/module/attr_internal.rb +2 -2
  51. data/lib/active_support/core_ext/module/attribute_accessors.rb +30 -39
  52. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +17 -19
  53. data/lib/active_support/core_ext/module/concerning.rb +8 -2
  54. data/lib/active_support/core_ext/module/delegation.rb +76 -33
  55. data/lib/active_support/core_ext/module/introspection.rb +16 -15
  56. data/lib/active_support/core_ext/module/redefine_method.rb +8 -17
  57. data/lib/active_support/core_ext/name_error.rb +29 -2
  58. data/lib/active_support/core_ext/numeric.rb +0 -1
  59. data/lib/active_support/core_ext/numeric/conversions.rb +129 -129
  60. data/lib/active_support/core_ext/object/blank.rb +1 -2
  61. data/lib/active_support/core_ext/object/deep_dup.rb +1 -1
  62. data/lib/active_support/core_ext/object/duplicable.rb +7 -114
  63. data/lib/active_support/core_ext/object/json.rb +14 -2
  64. data/lib/active_support/core_ext/object/try.rb +17 -7
  65. data/lib/active_support/core_ext/object/with_options.rb +1 -1
  66. data/lib/active_support/core_ext/range/compare_range.rb +34 -13
  67. data/lib/active_support/core_ext/range/conversions.rb +31 -29
  68. data/lib/active_support/core_ext/range/each.rb +0 -1
  69. data/lib/active_support/core_ext/range/include_time_with_zone.rb +8 -3
  70. data/lib/active_support/core_ext/regexp.rb +8 -5
  71. data/lib/active_support/core_ext/securerandom.rb +23 -3
  72. data/lib/active_support/core_ext/string/access.rb +5 -16
  73. data/lib/active_support/core_ext/string/conversions.rb +1 -0
  74. data/lib/active_support/core_ext/string/filters.rb +42 -1
  75. data/lib/active_support/core_ext/string/inflections.rb +45 -6
  76. data/lib/active_support/core_ext/string/inquiry.rb +1 -0
  77. data/lib/active_support/core_ext/string/multibyte.rb +6 -5
  78. data/lib/active_support/core_ext/string/output_safety.rb +70 -13
  79. data/lib/active_support/core_ext/string/starts_ends_with.rb +2 -2
  80. data/lib/active_support/core_ext/string/strip.rb +3 -1
  81. data/lib/active_support/core_ext/symbol.rb +3 -0
  82. data/lib/active_support/core_ext/symbol/starts_ends_with.rb +14 -0
  83. data/lib/active_support/core_ext/time/calculations.rb +50 -3
  84. data/lib/active_support/core_ext/time/conversions.rb +2 -0
  85. data/lib/active_support/core_ext/uri.rb +6 -1
  86. data/lib/active_support/current_attributes.rb +15 -2
  87. data/lib/active_support/current_attributes/test_helper.rb +13 -0
  88. data/lib/active_support/dependencies.rb +109 -34
  89. data/lib/active_support/dependencies/zeitwerk_integration.rb +117 -0
  90. data/lib/active_support/deprecation.rb +6 -1
  91. data/lib/active_support/deprecation/behaviors.rb +16 -3
  92. data/lib/active_support/deprecation/disallowed.rb +56 -0
  93. data/lib/active_support/deprecation/instance_delegator.rb +0 -1
  94. data/lib/active_support/deprecation/method_wrappers.rb +18 -23
  95. data/lib/active_support/deprecation/proxy_wrappers.rb +29 -6
  96. data/lib/active_support/deprecation/reporting.rb +50 -7
  97. data/lib/active_support/descendants_tracker.rb +59 -9
  98. data/lib/active_support/duration.rb +90 -38
  99. data/lib/active_support/duration/iso8601_parser.rb +2 -4
  100. data/lib/active_support/duration/iso8601_serializer.rb +18 -14
  101. data/lib/active_support/encrypted_configuration.rb +0 -4
  102. data/lib/active_support/encrypted_file.rb +22 -4
  103. data/lib/active_support/environment_inquirer.rb +20 -0
  104. data/lib/active_support/evented_file_update_checker.rb +82 -117
  105. data/lib/active_support/execution_wrapper.rb +1 -0
  106. data/lib/active_support/file_update_checker.rb +0 -1
  107. data/lib/active_support/fork_tracker.rb +62 -0
  108. data/lib/active_support/gem_version.rb +4 -4
  109. data/lib/active_support/hash_with_indifferent_access.rb +64 -41
  110. data/lib/active_support/i18n.rb +1 -0
  111. data/lib/active_support/i18n_railtie.rb +15 -8
  112. data/lib/active_support/inflector/inflections.rb +2 -7
  113. data/lib/active_support/inflector/methods.rb +49 -58
  114. data/lib/active_support/inflector/transliterate.rb +47 -18
  115. data/lib/active_support/json/decoding.rb +25 -26
  116. data/lib/active_support/json/encoding.rb +11 -3
  117. data/lib/active_support/key_generator.rb +1 -33
  118. data/lib/active_support/lazy_load_hooks.rb +5 -2
  119. data/lib/active_support/locale/en.rb +33 -0
  120. data/lib/active_support/locale/en.yml +7 -3
  121. data/lib/active_support/log_subscriber.rb +39 -9
  122. data/lib/active_support/logger.rb +2 -17
  123. data/lib/active_support/logger_silence.rb +11 -19
  124. data/lib/active_support/logger_thread_safe_level.rb +50 -6
  125. data/lib/active_support/message_encryptor.rb +8 -13
  126. data/lib/active_support/message_verifier.rb +10 -10
  127. data/lib/active_support/messages/metadata.rb +11 -2
  128. data/lib/active_support/messages/rotation_configuration.rb +2 -1
  129. data/lib/active_support/messages/rotator.rb +10 -9
  130. data/lib/active_support/multibyte/chars.rb +10 -68
  131. data/lib/active_support/multibyte/unicode.rb +15 -327
  132. data/lib/active_support/notifications.rb +72 -8
  133. data/lib/active_support/notifications/fanout.rb +116 -16
  134. data/lib/active_support/notifications/instrumenter.rb +71 -9
  135. data/lib/active_support/number_helper.rb +38 -12
  136. data/lib/active_support/number_helper/number_converter.rb +5 -6
  137. data/lib/active_support/number_helper/number_to_currency_converter.rb +4 -9
  138. data/lib/active_support/number_helper/number_to_delimited_converter.rb +3 -2
  139. data/lib/active_support/number_helper/number_to_human_converter.rb +4 -3
  140. data/lib/active_support/number_helper/number_to_human_size_converter.rb +4 -3
  141. data/lib/active_support/number_helper/number_to_percentage_converter.rb +3 -1
  142. data/lib/active_support/number_helper/number_to_phone_converter.rb +2 -1
  143. data/lib/active_support/number_helper/number_to_rounded_converter.rb +8 -7
  144. data/lib/active_support/number_helper/rounding_helper.rb +12 -28
  145. data/lib/active_support/option_merger.rb +22 -3
  146. data/lib/active_support/ordered_hash.rb +1 -1
  147. data/lib/active_support/ordered_options.rb +13 -3
  148. data/lib/active_support/parameter_filter.rb +133 -0
  149. data/lib/active_support/per_thread_registry.rb +1 -1
  150. data/lib/active_support/rails.rb +1 -10
  151. data/lib/active_support/railtie.rb +23 -1
  152. data/lib/active_support/reloader.rb +4 -5
  153. data/lib/active_support/rescuable.rb +4 -4
  154. data/lib/active_support/secure_compare_rotator.rb +51 -0
  155. data/lib/active_support/security_utils.rb +19 -12
  156. data/lib/active_support/string_inquirer.rb +4 -3
  157. data/lib/active_support/subscriber.rb +72 -28
  158. data/lib/active_support/tagged_logging.rb +42 -8
  159. data/lib/active_support/test_case.rb +91 -0
  160. data/lib/active_support/testing/assertions.rb +30 -9
  161. data/lib/active_support/testing/deprecation.rb +0 -1
  162. data/lib/active_support/testing/file_fixtures.rb +2 -0
  163. data/lib/active_support/testing/isolation.rb +2 -2
  164. data/lib/active_support/testing/method_call_assertions.rb +28 -1
  165. data/lib/active_support/testing/parallelization.rb +51 -0
  166. data/lib/active_support/testing/parallelization/server.rb +78 -0
  167. data/lib/active_support/testing/parallelization/worker.rb +100 -0
  168. data/lib/active_support/testing/stream.rb +1 -2
  169. data/lib/active_support/testing/time_helpers.rb +47 -12
  170. data/lib/active_support/time_with_zone.rb +81 -47
  171. data/lib/active_support/values/time_zone.rb +32 -17
  172. data/lib/active_support/xml_mini.rb +2 -10
  173. data/lib/active_support/xml_mini/jdom.rb +2 -3
  174. data/lib/active_support/xml_mini/libxml.rb +2 -2
  175. data/lib/active_support/xml_mini/libxmlsax.rb +4 -4
  176. data/lib/active_support/xml_mini/nokogiri.rb +2 -2
  177. data/lib/active_support/xml_mini/nokogirisax.rb +3 -3
  178. data/lib/active_support/xml_mini/rexml.rb +10 -3
  179. metadata +58 -32
  180. data/lib/active_support/core_ext/array/prepend_and_append.rb +0 -9
  181. data/lib/active_support/core_ext/hash/compact.rb +0 -29
  182. data/lib/active_support/core_ext/hash/transform_values.rb +0 -32
  183. data/lib/active_support/core_ext/kernel/agnostics.rb +0 -13
  184. data/lib/active_support/core_ext/module/reachable.rb +0 -11
  185. data/lib/active_support/core_ext/numeric/inquiry.rb +0 -28
  186. data/lib/active_support/core_ext/range/include_range.rb +0 -3
  187. data/lib/active_support/values/unicode_tables.dat +0 -0
@@ -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 'active_support/concern'
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 'active_support/concern'
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,11 +114,17 @@ 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
112
126
 
113
- def append_features(base)
127
+ def append_features(base) #:nodoc:
114
128
  if base.instance_variable_defined?(:@_dependencies)
115
129
  base.instance_variable_get(:@_dependencies) << self
116
130
  false
@@ -123,6 +137,22 @@ 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
+
153
+ # Evaluate given block in context of base class,
154
+ # so that you can write class macros here.
155
+ # When you define more than one +included+ block, it raises an exception.
126
156
  def included(base = nil, &block)
127
157
  if base.nil?
128
158
  if instance_variable_defined?(:@_included_block)
@@ -137,6 +167,43 @@ module ActiveSupport
137
167
  end
138
168
  end
139
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
+
187
+ # Define class methods from given block.
188
+ # You can define private class methods as well.
189
+ #
190
+ # module Example
191
+ # extend ActiveSupport::Concern
192
+ #
193
+ # class_methods do
194
+ # def foo; puts 'foo'; end
195
+ #
196
+ # private
197
+ # def bar; puts 'bar'; end
198
+ # end
199
+ # end
200
+ #
201
+ # class Buzz
202
+ # include Example
203
+ # end
204
+ #
205
+ # Buzz.foo # => "foo"
206
+ # Buzz.bar # => private method 'bar' called for Buzz:Class(NoMethodError)
140
207
  def class_methods(&class_methods_module_definition)
141
208
  mod = const_defined?(:ClassMethods, false) ?
142
209
  const_get(:ClassMethods) :
@@ -7,11 +7,29 @@ module ActiveSupport
7
7
  # A monitor that will permit dependency loading while blocked waiting for
8
8
  # the lock.
9
9
  class LoadInterlockAwareMonitor < Monitor
10
+ EXCEPTION_NEVER = { Exception => :never }.freeze
11
+ EXCEPTION_IMMEDIATE = { Exception => :immediate }.freeze
12
+ private_constant :EXCEPTION_NEVER, :EXCEPTION_IMMEDIATE
13
+
10
14
  # Enters an exclusive section, but allows dependency loading while blocked
11
15
  def mon_enter
12
16
  mon_try_enter ||
13
17
  ActiveSupport::Dependencies.interlock.permit_concurrent_loads { super }
14
18
  end
19
+
20
+ def synchronize
21
+ Thread.handle_interrupt(EXCEPTION_NEVER) do
22
+ mon_enter
23
+
24
+ begin
25
+ Thread.handle_interrupt(EXCEPTION_IMMEDIATE) do
26
+ yield
27
+ end
28
+ ensure
29
+ mon_exit
30
+ end
31
+ end
32
+ end
15
33
  end
16
34
  end
17
35
  end
@@ -200,7 +200,6 @@ module ActiveSupport
200
200
  end
201
201
 
202
202
  private
203
-
204
203
  # Must be called within synchronize
205
204
  def busy_for_exclusive?(purpose)
206
205
  busy_for_sharing?(purpose) ||
@@ -2,12 +2,10 @@
2
2
 
3
3
  require "active_support/concern"
4
4
  require "active_support/ordered_options"
5
- require "active_support/core_ext/array/extract_options"
6
- require "active_support/core_ext/regexp"
7
5
 
8
6
  module ActiveSupport
9
7
  # Configurable provides a <tt>config</tt> method to store and retrieve
10
- # configuration options as an <tt>OrderedHash</tt>.
8
+ # configuration options as an <tt>OrderedOptions</tt>.
11
9
  module Configurable
12
10
  extend ActiveSupport::Concern
13
11
 
@@ -69,8 +67,8 @@ module ActiveSupport
69
67
  # end
70
68
  # # => NameError: invalid config attribute name
71
69
  #
72
- # To opt out of the instance writer method, pass <tt>instance_writer: false</tt>.
73
- # To opt out of the instance reader method, pass <tt>instance_reader: false</tt>.
70
+ # To omit the instance writer method, pass <tt>instance_writer: false</tt>.
71
+ # To omit the instance reader method, pass <tt>instance_reader: false</tt>.
74
72
  #
75
73
  # class User
76
74
  # include ActiveSupport::Configurable
@@ -83,7 +81,7 @@ module ActiveSupport
83
81
  # User.new.allowed_access = true # => NoMethodError
84
82
  # User.new.allowed_access # => NoMethodError
85
83
  #
86
- # Or pass <tt>instance_accessor: false</tt>, to opt out both instance methods.
84
+ # Or pass <tt>instance_accessor: false</tt>, to omit both instance methods.
87
85
  #
88
86
  # class User
89
87
  # include ActiveSupport::Configurable
@@ -106,9 +104,7 @@ module ActiveSupport
106
104
  # end
107
105
  #
108
106
  # User.hair_colors # => [:brown, :black, :blonde, :red]
109
- def config_accessor(*names)
110
- options = names.extract_options!
111
-
107
+ def config_accessor(*names, instance_reader: true, instance_writer: true, instance_accessor: true) # :doc:
112
108
  names.each do |name|
113
109
  raise NameError.new("invalid config attribute name") unless /\A[_A-Za-z]\w*\z/.match?(name)
114
110
 
@@ -118,9 +114,9 @@ module ActiveSupport
118
114
  singleton_class.class_eval reader, __FILE__, reader_line
119
115
  singleton_class.class_eval writer, __FILE__, writer_line
120
116
 
121
- unless options[:instance_accessor] == false
122
- class_eval reader, __FILE__, reader_line unless options[:instance_reader] == false
123
- class_eval writer, __FILE__, writer_line unless options[:instance_writer] == false
117
+ if instance_accessor
118
+ class_eval reader, __FILE__, reader_line if instance_reader
119
+ class_eval writer, __FILE__, writer_line if instance_writer
124
120
  end
125
121
  send("#{name}=", yield) if block_given?
126
122
  end
@@ -128,9 +124,9 @@ module ActiveSupport
128
124
  private :config_accessor
129
125
  end
130
126
 
131
- # Reads and writes attributes from a configuration <tt>OrderedHash</tt>.
127
+ # Reads and writes attributes from a configuration <tt>OrderedOptions</tt>.
132
128
  #
133
- # require 'active_support/configurable'
129
+ # require "active_support/configurable"
134
130
  #
135
131
  # class User
136
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,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- Dir.glob(File.expand_path("core_ext/*.rb", __dir__)).each do |path|
3
+ Dir.glob(File.expand_path("core_ext/*.rb", __dir__)).sort.each do |path|
4
4
  require path
5
5
  end
@@ -3,7 +3,7 @@
3
3
  require "active_support/core_ext/array/wrap"
4
4
  require "active_support/core_ext/array/access"
5
5
  require "active_support/core_ext/array/conversions"
6
+ require "active_support/core_ext/array/extract"
6
7
  require "active_support/core_ext/array/extract_options"
7
8
  require "active_support/core_ext/array/grouping"
8
- require "active_support/core_ext/array/prepend_and_append"
9
9
  require "active_support/core_ext/array/inquiry"
@@ -29,16 +29,28 @@ class Array
29
29
  end
30
30
  end
31
31
 
32
- # Returns a copy of the Array without the specified elements.
32
+ # Returns a new array that includes the passed elements.
33
33
  #
34
- # people = ["David", "Rafael", "Aaron", "Todd"]
35
- # people.without "Aaron", "Todd"
36
- # # => ["David", "Rafael"]
34
+ # [ 1, 2, 3 ].including(4, 5) # => [ 1, 2, 3, 4, 5 ]
35
+ # [ [ 0, 1 ] ].including([ [ 1, 0 ] ]) # => [ [ 0, 1 ], [ 1, 0 ] ]
36
+ def including(*elements)
37
+ self + elements.flatten(1)
38
+ end
39
+
40
+ # Returns a copy of the Array excluding the specified elements.
41
+ #
42
+ # ["David", "Rafael", "Aaron", "Todd"].excluding("Aaron", "Todd") # => ["David", "Rafael"]
43
+ # [ [ 0, 1 ], [ 1, 0 ] ].excluding([ [ 1, 0 ] ]) # => [ [ 0, 1 ] ]
37
44
  #
38
- # Note: This is an optimization of <tt>Enumerable#without</tt> that uses <tt>Array#-</tt>
45
+ # Note: This is an optimization of <tt>Enumerable#excluding</tt> that uses <tt>Array#-</tt>
39
46
  # instead of <tt>Array#reject</tt> for performance reasons.
47
+ def excluding(*elements)
48
+ self - elements.flatten(1)
49
+ end
50
+
51
+ # Alias for #excluding.
40
52
  def without(*elements)
41
- self - elements
53
+ excluding(*elements)
42
54
  end
43
55
 
44
56
  # Equal to <tt>self[1]</tt>.
@@ -74,13 +74,13 @@ class Array
74
74
 
75
75
  case length
76
76
  when 0
77
- ""
77
+ +""
78
78
  when 1
79
- "#{self[0]}"
79
+ +"#{self[0]}"
80
80
  when 2
81
- "#{self[0]}#{options[:two_words_connector]}#{self[1]}"
81
+ +"#{self[0]}#{options[:two_words_connector]}#{self[1]}"
82
82
  else
83
- "#{self[0...-1].join(options[:words_connector])}#{options[:last_word_connector]}#{self[-1]}"
83
+ +"#{self[0...-1].join(options[:words_connector])}#{options[:last_word_connector]}#{self[-1]}"
84
84
  end
85
85
  end
86
86
 
@@ -181,7 +181,7 @@ class Array
181
181
  # </messages>
182
182
  #
183
183
  def to_xml(options = {})
184
- require "active_support/builder" unless defined?(Builder)
184
+ require "active_support/builder" unless defined?(Builder::XmlMarkup)
185
185
 
186
186
  options = options.dup
187
187
  options[:indent] ||= 2
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Array
4
+ # Removes and returns the elements for which the block returns a true value.
5
+ # If no block is given, an Enumerator is returned instead.
6
+ #
7
+ # numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
8
+ # odd_numbers = numbers.extract! { |number| number.odd? } # => [1, 3, 5, 7, 9]
9
+ # numbers # => [0, 2, 4, 6, 8]
10
+ def extract!
11
+ return to_enum(:extract!) { size } unless block_given?
12
+
13
+ extracted_elements = []
14
+
15
+ reject! do |element|
16
+ extracted_elements << element if yield(element)
17
+ end
18
+
19
+ extracted_elements
20
+ end
21
+ end
@@ -10,7 +10,7 @@ class << Benchmark
10
10
  #
11
11
  # Benchmark.ms { User.all }
12
12
  # # => 0.074
13
- def ms
14
- 1000 * realtime { yield }
13
+ def ms(&block)
14
+ 1000 * realtime(&block)
15
15
  end
16
16
  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,63 +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(*attrs)
88
- options = attrs.extract_options!
89
- instance_reader = options.fetch(:instance_accessor, true) && options.fetch(:instance_reader, true)
90
- instance_writer = options.fetch(:instance_accessor, true) && options.fetch(:instance_writer, true)
91
- instance_predicate = options.fetch(:instance_predicate, true)
92
- default_value = options.fetch(:default, nil)
85
+ def class_attribute(*attrs, instance_accessor: true,
86
+ instance_reader: instance_accessor, instance_writer: instance_accessor, instance_predicate: true, default: nil)
93
87
 
88
+ class_methods, methods = [], []
94
89
  attrs.each do |name|
95
- singleton_class.silence_redefinition_of_method(name)
96
- define_singleton_method(name) { nil }
97
-
98
- singleton_class.silence_redefinition_of_method("#{name}?")
99
- define_singleton_method("#{name}?") { !!public_send(name) } if instance_predicate
100
-
101
- ivar = "@#{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
102
93
 
103
- singleton_class.silence_redefinition_of_method("#{name}=")
104
- define_singleton_method("#{name}=") do |val|
105
- singleton_class.class_eval do
106
- redefine_method(name) { val }
94
+ class_methods << <<~RUBY # In case the method exists and is not public
95
+ silence_redefinition_of_method def #{name}
107
96
  end
97
+ RUBY
108
98
 
109
- if singleton_class?
110
- class_eval do
111
- redefine_method(name) do
112
- if instance_variable_defined? ivar
113
- instance_variable_get ivar
114
- else
115
- singleton_class.send name
116
- end
117
- end
118
- end
99
+ methods << <<~RUBY if instance_reader
100
+ silence_redefinition_of_method def #{name}
101
+ defined?(@#{name}) ? @#{name} : self.class.#{name}
119
102
  end
120
- val
121
- end
103
+ RUBY
122
104
 
123
- if instance_reader
124
- redefine_method(name) do
125
- if instance_variable_defined?(ivar)
126
- instance_variable_get ivar
127
- else
128
- self.class.public_send name
129
- 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
130
110
  end
111
+ RUBY
131
112
 
132
- redefine_method("#{name}?") { !!public_send(name) } if instance_predicate
133
- end
113
+ methods << <<~RUBY if instance_writer
114
+ silence_redefinition_of_method(:#{name}=)
115
+ attr_writer :#{name}
116
+ RUBY
134
117
 
135
- if instance_writer
136
- redefine_method("#{name}=") do |val|
137
- instance_variable_set ivar, val
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"
138
122
  end
139
123
  end
140
-
141
- unless default_value.nil?
142
- self.send("#{name}=", default_value)
143
- end
144
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) }
145
130
  end
146
131
  end