activesupport 6.0.0.beta2 → 6.0.2.rc1
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.
Potentially problematic release.
This version of activesupport might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +287 -3
- data/README.rdoc +2 -1
- data/lib/active_support.rb +1 -0
- data/lib/active_support/actionable_error.rb +48 -0
- data/lib/active_support/backtrace_cleaner.rb +5 -1
- data/lib/active_support/cache.rb +5 -5
- data/lib/active_support/cache/memory_store.rb +2 -0
- data/lib/active_support/cache/redis_cache_store.rb +9 -6
- data/lib/active_support/concern.rb +24 -1
- data/lib/active_support/configurable.rb +3 -3
- data/lib/active_support/core_ext/array/access.rb +18 -6
- data/lib/active_support/core_ext/class/attribute.rb +10 -15
- data/lib/active_support/core_ext/date_and_time/calculations.rb +0 -30
- data/lib/active_support/core_ext/digest.rb +3 -0
- data/lib/active_support/core_ext/enumerable.rb +24 -4
- data/lib/active_support/core_ext/hash/deep_transform_values.rb +2 -2
- data/lib/active_support/core_ext/hash/except.rb +1 -1
- data/lib/active_support/core_ext/module/attribute_accessors.rb +5 -5
- data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +5 -5
- data/lib/active_support/core_ext/module/delegation.rb +6 -0
- data/lib/active_support/core_ext/object/duplicable.rb +7 -117
- data/lib/active_support/core_ext/range/compare_range.rb +27 -12
- data/lib/active_support/core_ext/range/include_time_with_zone.rb +2 -2
- data/lib/active_support/core_ext/string/filters.rb +1 -1
- data/lib/active_support/core_ext/string/inflections.rb +7 -2
- data/lib/active_support/core_ext/string/output_safety.rb +51 -4
- data/lib/active_support/core_ext/time/calculations.rb +31 -2
- data/lib/active_support/dependencies.rb +41 -5
- data/lib/active_support/dependencies/zeitwerk_integration.rb +44 -21
- data/lib/active_support/deprecation/method_wrappers.rb +7 -18
- data/lib/active_support/deprecation/proxy_wrappers.rb +24 -3
- data/lib/active_support/descendants_tracker.rb +52 -6
- data/lib/active_support/duration.rb +2 -3
- data/lib/active_support/evented_file_update_checker.rb +14 -2
- data/lib/active_support/gem_version.rb +2 -2
- data/lib/active_support/hash_with_indifferent_access.rb +6 -3
- data/lib/active_support/i18n_railtie.rb +6 -1
- data/lib/active_support/inflector/transliterate.rb +43 -14
- data/lib/active_support/logger_thread_safe_level.rb +2 -1
- data/lib/active_support/notifications/fanout.rb +2 -2
- data/lib/active_support/notifications/instrumenter.rb +12 -11
- data/lib/active_support/ordered_hash.rb +1 -1
- data/lib/active_support/ordered_options.rb +1 -1
- data/lib/active_support/parameter_filter.rb +6 -1
- data/lib/active_support/security_utils.rb +1 -1
- data/lib/active_support/subscriber.rb +55 -6
- data/lib/active_support/testing/parallelization.rb +21 -2
- metadata +13 -14
| @@ -152,12 +152,14 @@ module ActiveSupport | |
| 152 152 |  | 
| 153 153 | 
             
                  # Creates a new Redis cache store.
         | 
| 154 154 | 
             
                  #
         | 
| 155 | 
            -
                  # Handles  | 
| 156 | 
            -
                  #  | 
| 155 | 
            +
                  # Handles four options: :redis block, :redis instance, single :url
         | 
| 156 | 
            +
                  # string, and multiple :url strings.
         | 
| 157 157 | 
             
                  #
         | 
| 158 | 
            -
                  #    | 
| 159 | 
            -
                  #   : | 
| 160 | 
            -
                  #   : | 
| 158 | 
            +
                  #   Option  Class       Result
         | 
| 159 | 
            +
                  #   :redis  Proc    ->  options[:redis].call
         | 
| 160 | 
            +
                  #   :redis  Object  ->  options[:redis]
         | 
| 161 | 
            +
                  #   :url    String  ->  Redis.new(url: …)
         | 
| 162 | 
            +
                  #   :url    Array   ->  Redis::Distributed.new([{ url: … }, { url: … }, …])
         | 
| 161 163 | 
             
                  #
         | 
| 162 164 | 
             
                  # No namespace is set by default. Provide one if the Redis cache
         | 
| 163 165 | 
             
                  # server is shared with other apps: <tt>namespace: 'myapp-cache'</tt>.
         | 
| @@ -361,6 +363,7 @@ module ActiveSupport | |
| 361 363 | 
             
                    def read_multi_mget(*names)
         | 
| 362 364 | 
             
                      options = names.extract_options!
         | 
| 363 365 | 
             
                      options = merged_options(options)
         | 
| 366 | 
            +
                      return {} if names == []
         | 
| 364 367 |  | 
| 365 368 | 
             
                      keys = names.map { |name| normalize_key(name, options) }
         | 
| 366 369 |  | 
| @@ -468,7 +471,7 @@ module ActiveSupport | |
| 468 471 |  | 
| 469 472 | 
             
                    def failsafe(method, returning: nil)
         | 
| 470 473 | 
             
                      yield
         | 
| 471 | 
            -
                    rescue ::Redis:: | 
| 474 | 
            +
                    rescue ::Redis::BaseError => e
         | 
| 472 475 | 
             
                      handle_exception exception: e, method: method, returning: returning
         | 
| 473 476 | 
             
                      returning
         | 
| 474 477 | 
             
                    end
         | 
| @@ -110,7 +110,7 @@ module ActiveSupport | |
| 110 110 | 
             
                  base.instance_variable_set(:@_dependencies, [])
         | 
| 111 111 | 
             
                end
         | 
| 112 112 |  | 
| 113 | 
            -
                def append_features(base)
         | 
| 113 | 
            +
                def append_features(base) #:nodoc:
         | 
| 114 114 | 
             
                  if base.instance_variable_defined?(:@_dependencies)
         | 
| 115 115 | 
             
                    base.instance_variable_get(:@_dependencies) << self
         | 
| 116 116 | 
             
                    false
         | 
| @@ -123,6 +123,9 @@ module ActiveSupport | |
| 123 123 | 
             
                  end
         | 
| 124 124 | 
             
                end
         | 
| 125 125 |  | 
| 126 | 
            +
                # Evaluate given block in context of base class,
         | 
| 127 | 
            +
                # so that you can write class macros here.
         | 
| 128 | 
            +
                # When you define more than one +included+ block, it raises an exception.
         | 
| 126 129 | 
             
                def included(base = nil, &block)
         | 
| 127 130 | 
             
                  if base.nil?
         | 
| 128 131 | 
             
                    if instance_variable_defined?(:@_included_block)
         | 
| @@ -137,6 +140,26 @@ module ActiveSupport | |
| 137 140 | 
             
                  end
         | 
| 138 141 | 
             
                end
         | 
| 139 142 |  | 
| 143 | 
            +
                # Define class methods from given block.
         | 
| 144 | 
            +
                # You can define private class methods as well.
         | 
| 145 | 
            +
                #
         | 
| 146 | 
            +
                #   module Example
         | 
| 147 | 
            +
                #     extend ActiveSupport::Concern
         | 
| 148 | 
            +
                #
         | 
| 149 | 
            +
                #     class_methods do
         | 
| 150 | 
            +
                #       def foo; puts 'foo'; end
         | 
| 151 | 
            +
                #
         | 
| 152 | 
            +
                #       private
         | 
| 153 | 
            +
                #         def bar; puts 'bar'; end
         | 
| 154 | 
            +
                #     end
         | 
| 155 | 
            +
                #   end
         | 
| 156 | 
            +
                #
         | 
| 157 | 
            +
                #   class Buzz
         | 
| 158 | 
            +
                #     include Example
         | 
| 159 | 
            +
                #   end
         | 
| 160 | 
            +
                #
         | 
| 161 | 
            +
                #   Buzz.foo # => "foo"
         | 
| 162 | 
            +
                #   Buzz.bar # => private method 'bar' called for Buzz:Class(NoMethodError)
         | 
| 140 163 | 
             
                def class_methods(&class_methods_module_definition)
         | 
| 141 164 | 
             
                  mod = const_defined?(:ClassMethods, false) ?
         | 
| 142 165 | 
             
                    const_get(:ClassMethods) :
         | 
| @@ -67,8 +67,8 @@ module ActiveSupport | |
| 67 67 | 
             
                  #   end
         | 
| 68 68 | 
             
                  #   # => NameError: invalid config attribute name
         | 
| 69 69 | 
             
                  #
         | 
| 70 | 
            -
                  # To  | 
| 71 | 
            -
                  # To  | 
| 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>.
         | 
| 72 72 | 
             
                  #
         | 
| 73 73 | 
             
                  #   class User
         | 
| 74 74 | 
             
                  #     include ActiveSupport::Configurable
         | 
| @@ -81,7 +81,7 @@ module ActiveSupport | |
| 81 81 | 
             
                  #   User.new.allowed_access = true # => NoMethodError
         | 
| 82 82 | 
             
                  #   User.new.allowed_access        # => NoMethodError
         | 
| 83 83 | 
             
                  #
         | 
| 84 | 
            -
                  # Or pass <tt>instance_accessor: false</tt>, to  | 
| 84 | 
            +
                  # Or pass <tt>instance_accessor: false</tt>, to omit both instance methods.
         | 
| 85 85 | 
             
                  #
         | 
| 86 86 | 
             
                  #   class User
         | 
| 87 87 | 
             
                  #     include ActiveSupport::Configurable
         | 
| @@ -29,16 +29,28 @@ class Array | |
| 29 29 | 
             
                end
         | 
| 30 30 | 
             
              end
         | 
| 31 31 |  | 
| 32 | 
            -
              # Returns a  | 
| 32 | 
            +
              # Returns a new array that includes the passed elements.
         | 
| 33 33 | 
             
              #
         | 
| 34 | 
            -
              #    | 
| 35 | 
            -
              #    | 
| 36 | 
            -
               | 
| 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# | 
| 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 | 
            -
                 | 
| 53 | 
            +
                excluding(*elements)
         | 
| 42 54 | 
             
              end
         | 
| 43 55 |  | 
| 44 56 | 
             
              # Equal to <tt>self[1]</tt>.
         | 
| @@ -84,16 +84,17 @@ class Class | |
| 84 84 | 
             
              # To set a default value for the attribute, pass <tt>default:</tt>, like so:
         | 
| 85 85 | 
             
              #
         | 
| 86 86 | 
             
              #   class_attribute :settings, default: {}
         | 
| 87 | 
            -
              def class_attribute( | 
| 88 | 
            -
                 | 
| 89 | 
            -
                 | 
| 90 | 
            -
                 | 
| 91 | 
            -
                 | 
| 92 | 
            -
                 | 
| 93 | 
            -
             | 
| 87 | 
            +
              def class_attribute(
         | 
| 88 | 
            +
                *attrs,
         | 
| 89 | 
            +
                instance_accessor: true,
         | 
| 90 | 
            +
                instance_reader: instance_accessor,
         | 
| 91 | 
            +
                instance_writer: instance_accessor,
         | 
| 92 | 
            +
                instance_predicate: true,
         | 
| 93 | 
            +
                default: nil
         | 
| 94 | 
            +
              )
         | 
| 94 95 | 
             
                attrs.each do |name|
         | 
| 95 96 | 
             
                  singleton_class.silence_redefinition_of_method(name)
         | 
| 96 | 
            -
                  define_singleton_method(name) {  | 
| 97 | 
            +
                  define_singleton_method(name) { default }
         | 
| 97 98 |  | 
| 98 99 | 
             
                  singleton_class.silence_redefinition_of_method("#{name}?")
         | 
| 99 100 | 
             
                  define_singleton_method("#{name}?") { !!public_send(name) } if instance_predicate
         | 
| @@ -102,9 +103,7 @@ class Class | |
| 102 103 |  | 
| 103 104 | 
             
                  singleton_class.silence_redefinition_of_method("#{name}=")
         | 
| 104 105 | 
             
                  define_singleton_method("#{name}=") do |val|
         | 
| 105 | 
            -
                     | 
| 106 | 
            -
                      redefine_method(name) { val }
         | 
| 107 | 
            -
                    end
         | 
| 106 | 
            +
                    redefine_singleton_method(name) { val }
         | 
| 108 107 |  | 
| 109 108 | 
             
                    if singleton_class?
         | 
| 110 109 | 
             
                      class_eval do
         | 
| @@ -137,10 +136,6 @@ class Class | |
| 137 136 | 
             
                      instance_variable_set ivar, val
         | 
| 138 137 | 
             
                    end
         | 
| 139 138 | 
             
                  end
         | 
| 140 | 
            -
             | 
| 141 | 
            -
                  unless default_value.nil?
         | 
| 142 | 
            -
                    self.send("#{name}=", default_value)
         | 
| 143 | 
            -
                  end
         | 
| 144 139 | 
             
                end
         | 
| 145 140 | 
             
              end
         | 
| 146 141 | 
             
            end
         | 
| @@ -20,21 +20,11 @@ module DateAndTime | |
| 20 20 | 
             
                  advance(days: -1)
         | 
| 21 21 | 
             
                end
         | 
| 22 22 |  | 
| 23 | 
            -
                # Returns a new date/time the specified number of days ago.
         | 
| 24 | 
            -
                def prev_day(days = 1)
         | 
| 25 | 
            -
                  advance(days: -days)
         | 
| 26 | 
            -
                end
         | 
| 27 | 
            -
             | 
| 28 23 | 
             
                # Returns a new date/time representing tomorrow.
         | 
| 29 24 | 
             
                def tomorrow
         | 
| 30 25 | 
             
                  advance(days: 1)
         | 
| 31 26 | 
             
                end
         | 
| 32 27 |  | 
| 33 | 
            -
                # Returns a new date/time the specified number of days in the future.
         | 
| 34 | 
            -
                def next_day(days = 1)
         | 
| 35 | 
            -
                  advance(days: days)
         | 
| 36 | 
            -
                end
         | 
| 37 | 
            -
             | 
| 38 28 | 
             
                # Returns true if the date/time is today.
         | 
| 39 29 | 
             
                def today?
         | 
| 40 30 | 
             
                  to_date == ::Date.current
         | 
| @@ -198,21 +188,11 @@ module DateAndTime | |
| 198 188 | 
             
                  end
         | 
| 199 189 | 
             
                end
         | 
| 200 190 |  | 
| 201 | 
            -
                # Returns a new date/time the specified number of months in the future.
         | 
| 202 | 
            -
                def next_month(months = 1)
         | 
| 203 | 
            -
                  advance(months: months)
         | 
| 204 | 
            -
                end
         | 
| 205 | 
            -
             | 
| 206 191 | 
             
                # Short-hand for months_since(3)
         | 
| 207 192 | 
             
                def next_quarter
         | 
| 208 193 | 
             
                  months_since(3)
         | 
| 209 194 | 
             
                end
         | 
| 210 195 |  | 
| 211 | 
            -
                # Returns a new date/time the specified number of years in the future.
         | 
| 212 | 
            -
                def next_year(years = 1)
         | 
| 213 | 
            -
                  advance(years: years)
         | 
| 214 | 
            -
                end
         | 
| 215 | 
            -
             | 
| 216 196 | 
             
                # Returns a new date/time representing the given day in the previous week.
         | 
| 217 197 | 
             
                # Week is assumed to start on +start_day+, default is
         | 
| 218 198 | 
             
                # +Date.beginning_of_week+ or +config.beginning_of_week+ when set.
         | 
| @@ -233,11 +213,6 @@ module DateAndTime | |
| 233 213 | 
             
                end
         | 
| 234 214 | 
             
                alias_method :last_weekday, :prev_weekday
         | 
| 235 215 |  | 
| 236 | 
            -
                # Returns a new date/time the specified number of months ago.
         | 
| 237 | 
            -
                def prev_month(months = 1)
         | 
| 238 | 
            -
                  advance(months: -months)
         | 
| 239 | 
            -
                end
         | 
| 240 | 
            -
             | 
| 241 216 | 
             
                # Short-hand for months_ago(1).
         | 
| 242 217 | 
             
                def last_month
         | 
| 243 218 | 
             
                  months_ago(1)
         | 
| @@ -249,11 +224,6 @@ module DateAndTime | |
| 249 224 | 
             
                end
         | 
| 250 225 | 
             
                alias_method :last_quarter, :prev_quarter
         | 
| 251 226 |  | 
| 252 | 
            -
                # Returns a new date/time the specified number of years ago.
         | 
| 253 | 
            -
                def prev_year(years = 1)
         | 
| 254 | 
            -
                  advance(years: -years)
         | 
| 255 | 
            -
                end
         | 
| 256 | 
            -
             | 
| 257 227 | 
             
                # Short-hand for years_ago(1).
         | 
| 258 228 | 
             
                def last_year
         | 
| 259 229 | 
             
                  years_ago(1)
         | 
| @@ -97,23 +97,43 @@ module Enumerable | |
| 97 97 | 
             
                end
         | 
| 98 98 | 
             
              end
         | 
| 99 99 |  | 
| 100 | 
            +
              # Returns a new array that includes the passed elements.
         | 
| 101 | 
            +
              #
         | 
| 102 | 
            +
              #   [ 1, 2, 3 ].including(4, 5)
         | 
| 103 | 
            +
              #   # => [ 1, 2, 3, 4, 5 ]
         | 
| 104 | 
            +
              #
         | 
| 105 | 
            +
              #   ["David", "Rafael"].including %w[ Aaron Todd ]
         | 
| 106 | 
            +
              #   # => ["David", "Rafael", "Aaron", "Todd"]
         | 
| 107 | 
            +
              def including(*elements)
         | 
| 108 | 
            +
                to_a.including(*elements)
         | 
| 109 | 
            +
              end
         | 
| 110 | 
            +
             | 
| 100 111 | 
             
              # The negative of the <tt>Enumerable#include?</tt>. Returns +true+ if the
         | 
| 101 112 | 
             
              # collection does not include the object.
         | 
| 102 113 | 
             
              def exclude?(object)
         | 
| 103 114 | 
             
                !include?(object)
         | 
| 104 115 | 
             
              end
         | 
| 105 116 |  | 
| 106 | 
            -
              # Returns a copy of the enumerable  | 
| 117 | 
            +
              # Returns a copy of the enumerable excluding the specified elements.
         | 
| 118 | 
            +
              #
         | 
| 119 | 
            +
              #   ["David", "Rafael", "Aaron", "Todd"].excluding "Aaron", "Todd"
         | 
| 120 | 
            +
              #   # => ["David", "Rafael"]
         | 
| 107 121 | 
             
              #
         | 
| 108 | 
            -
              #   ["David", "Rafael", "Aaron", "Todd"]. | 
| 122 | 
            +
              #   ["David", "Rafael", "Aaron", "Todd"].excluding %w[ Aaron Todd ]
         | 
| 109 123 | 
             
              #   # => ["David", "Rafael"]
         | 
| 110 124 | 
             
              #
         | 
| 111 | 
            -
              #   {foo: 1, bar: 2, baz: 3}. | 
| 125 | 
            +
              #   {foo: 1, bar: 2, baz: 3}.excluding :bar
         | 
| 112 126 | 
             
              #   # => {foo: 1, baz: 3}
         | 
| 113 | 
            -
              def  | 
| 127 | 
            +
              def excluding(*elements)
         | 
| 128 | 
            +
                elements.flatten!(1)
         | 
| 114 129 | 
             
                reject { |element| elements.include?(element) }
         | 
| 115 130 | 
             
              end
         | 
| 116 131 |  | 
| 132 | 
            +
              # Alias for #excluding.
         | 
| 133 | 
            +
              def without(*elements)
         | 
| 134 | 
            +
                excluding(*elements)
         | 
| 135 | 
            +
              end
         | 
| 136 | 
            +
             | 
| 117 137 | 
             
              # Convert an enumerable to an array based on the given key.
         | 
| 118 138 | 
             
              #
         | 
| 119 139 | 
             
              #   [{ name: "David" }, { name: "Rafael" }, { name: "Aaron" }].pluck(:name)
         | 
| @@ -1,8 +1,8 @@ | |
| 1 1 | 
             
            # frozen_string_literal: true
         | 
| 2 2 |  | 
| 3 3 | 
             
            class Hash
         | 
| 4 | 
            -
              # Returns a new hash with all  | 
| 5 | 
            -
              # This includes the  | 
| 4 | 
            +
              # Returns a new hash with all values converted by the block operation.
         | 
| 5 | 
            +
              # This includes the values from the root hash and from all
         | 
| 6 6 | 
             
              # nested hashes and arrays.
         | 
| 7 7 | 
             
              #
         | 
| 8 8 | 
             
              #  hash = { person: { name: 'Rob', age: '28' } }
         | 
| @@ -10,7 +10,7 @@ class Hash | |
| 10 10 | 
             
              # This is useful for limiting a set of parameters to everything but a few known toggles:
         | 
| 11 11 | 
             
              #   @person.update(params[:person].except(:admin))
         | 
| 12 12 | 
             
              def except(*keys)
         | 
| 13 | 
            -
                 | 
| 13 | 
            +
                slice(*self.keys - keys)
         | 
| 14 14 | 
             
              end
         | 
| 15 15 |  | 
| 16 16 | 
             
              # Removes the given keys from hash and returns it.
         | 
| @@ -24,7 +24,7 @@ class Module | |
| 24 24 | 
             
              #   end
         | 
| 25 25 | 
             
              #   # => NameError: invalid attribute name: 1_Badname
         | 
| 26 26 | 
             
              #
         | 
| 27 | 
            -
              #  | 
| 27 | 
            +
              # To omit the instance reader method, pass
         | 
| 28 28 | 
             
              # <tt>instance_reader: false</tt> or <tt>instance_accessor: false</tt>.
         | 
| 29 29 | 
             
              #
         | 
| 30 30 | 
             
              #   module HairColors
         | 
| @@ -91,7 +91,7 @@ class Module | |
| 91 91 | 
             
              #   Person.new.hair_colors = [:blonde, :red]
         | 
| 92 92 | 
             
              #   HairColors.class_variable_get("@@hair_colors") # => [:blonde, :red]
         | 
| 93 93 | 
             
              #
         | 
| 94 | 
            -
              #  | 
| 94 | 
            +
              # To omit the instance writer method, pass
         | 
| 95 95 | 
             
              # <tt>instance_writer: false</tt> or <tt>instance_accessor: false</tt>.
         | 
| 96 96 | 
             
              #
         | 
| 97 97 | 
             
              #   module HairColors
         | 
| @@ -166,8 +166,8 @@ class Module | |
| 166 166 | 
             
              #   Citizen.new.hair_colors << :blue
         | 
| 167 167 | 
             
              #   Person.new.hair_colors # => [:brown, :black, :blonde, :red, :blue]
         | 
| 168 168 | 
             
              #
         | 
| 169 | 
            -
              # To  | 
| 170 | 
            -
              # To  | 
| 169 | 
            +
              # To omit the instance writer method, pass <tt>instance_writer: false</tt>.
         | 
| 170 | 
            +
              # To omit the instance reader method, pass <tt>instance_reader: false</tt>.
         | 
| 171 171 | 
             
              #
         | 
| 172 172 | 
             
              #   module HairColors
         | 
| 173 173 | 
             
              #     mattr_accessor :hair_colors, instance_writer: false, instance_reader: false
         | 
| @@ -180,7 +180,7 @@ class Module | |
| 180 180 | 
             
              #   Person.new.hair_colors = [:brown]  # => NoMethodError
         | 
| 181 181 | 
             
              #   Person.new.hair_colors             # => NoMethodError
         | 
| 182 182 | 
             
              #
         | 
| 183 | 
            -
              # Or pass <tt>instance_accessor: false</tt>, to  | 
| 183 | 
            +
              # Or pass <tt>instance_accessor: false</tt>, to omit both instance methods.
         | 
| 184 184 | 
             
              #
         | 
| 185 185 | 
             
              #   module HairColors
         | 
| 186 186 | 
             
              #     mattr_accessor :hair_colors, instance_accessor: false
         | 
| @@ -25,7 +25,7 @@ class Module | |
| 25 25 | 
             
              #   end
         | 
| 26 26 | 
             
              #   # => NameError: invalid attribute name: 1_Badname
         | 
| 27 27 | 
             
              #
         | 
| 28 | 
            -
              #  | 
| 28 | 
            +
              # To omit the instance reader method, pass
         | 
| 29 29 | 
             
              # <tt>instance_reader: false</tt> or <tt>instance_accessor: false</tt>.
         | 
| 30 30 | 
             
              #
         | 
| 31 31 | 
             
              #   class Current
         | 
| @@ -66,7 +66,7 @@ class Module | |
| 66 66 | 
             
              #   Current.user = "DHH"
         | 
| 67 67 | 
             
              #   Thread.current[:attr_Current_user] # => "DHH"
         | 
| 68 68 | 
             
              #
         | 
| 69 | 
            -
              #  | 
| 69 | 
            +
              # To omit the instance writer method, pass
         | 
| 70 70 | 
             
              # <tt>instance_writer: false</tt> or <tt>instance_accessor: false</tt>.
         | 
| 71 71 | 
             
              #
         | 
| 72 72 | 
             
              #   class Current
         | 
| @@ -118,8 +118,8 @@ class Module | |
| 118 118 | 
             
              #   Customer.user # => "Rafael"
         | 
| 119 119 | 
             
              #   Account.user  # => "DHH"
         | 
| 120 120 | 
             
              #
         | 
| 121 | 
            -
              # To  | 
| 122 | 
            -
              # To  | 
| 121 | 
            +
              # To omit the instance writer method, pass <tt>instance_writer: false</tt>.
         | 
| 122 | 
            +
              # To omit the instance reader method, pass <tt>instance_reader: false</tt>.
         | 
| 123 123 | 
             
              #
         | 
| 124 124 | 
             
              #   class Current
         | 
| 125 125 | 
             
              #     thread_mattr_accessor :user, instance_writer: false, instance_reader: false
         | 
| @@ -128,7 +128,7 @@ class Module | |
| 128 128 | 
             
              #   Current.new.user = "DHH"  # => NoMethodError
         | 
| 129 129 | 
             
              #   Current.new.user          # => NoMethodError
         | 
| 130 130 | 
             
              #
         | 
| 131 | 
            -
              # Or pass <tt>instance_accessor: false</tt>, to  | 
| 131 | 
            +
              # Or pass <tt>instance_accessor: false</tt>, to omit both instance methods.
         | 
| 132 132 | 
             
              #
         | 
| 133 133 | 
             
              #   class Current
         | 
| 134 134 | 
             
              #     thread_mattr_accessor :user, instance_accessor: false
         | 
| @@ -275,6 +275,11 @@ class Module | |
| 275 275 | 
             
              #
         | 
| 276 276 | 
             
              # The delegated method must be public on the target, otherwise it will
         | 
| 277 277 | 
             
              # raise +NoMethodError+.
         | 
| 278 | 
            +
              #
         | 
| 279 | 
            +
              # The <tt>marshal_dump</tt> and <tt>_dump</tt> methods are exempt from
         | 
| 280 | 
            +
              # delegation due to possible interference when calling
         | 
| 281 | 
            +
              # <tt>Marshal.dump(object)</tt>, should the delegation target method
         | 
| 282 | 
            +
              # of <tt>object</tt> add or remove instance variables.
         | 
| 278 283 | 
             
              def delegate_missing_to(target)
         | 
| 279 284 | 
             
                target = target.to_s
         | 
| 280 285 | 
             
                target = "self.#{target}" if DELEGATION_RESERVED_METHOD_NAMES.include?(target)
         | 
| @@ -284,6 +289,7 @@ class Module | |
| 284 289 | 
             
                    # It may look like an oversight, but we deliberately do not pass
         | 
| 285 290 | 
             
                    # +include_private+, because they do not get delegated.
         | 
| 286 291 |  | 
| 292 | 
            +
                    return false if name == :marshal_dump || name == :_dump
         | 
| 287 293 | 
             
                    #{target}.respond_to?(name) || super
         | 
| 288 294 | 
             
                  end
         | 
| 289 295 |  | 
| @@ -28,96 +28,6 @@ class Object | |
| 28 28 | 
             
              end
         | 
| 29 29 | 
             
            end
         | 
| 30 30 |  | 
| 31 | 
            -
            class NilClass
         | 
| 32 | 
            -
              begin
         | 
| 33 | 
            -
                nil.dup
         | 
| 34 | 
            -
              rescue TypeError
         | 
| 35 | 
            -
             | 
| 36 | 
            -
                # +nil+ is not duplicable:
         | 
| 37 | 
            -
                #
         | 
| 38 | 
            -
                #   nil.duplicable? # => false
         | 
| 39 | 
            -
                #   nil.dup         # => TypeError: can't dup NilClass
         | 
| 40 | 
            -
                def duplicable?
         | 
| 41 | 
            -
                  false
         | 
| 42 | 
            -
                end
         | 
| 43 | 
            -
              end
         | 
| 44 | 
            -
            end
         | 
| 45 | 
            -
             | 
| 46 | 
            -
            class FalseClass
         | 
| 47 | 
            -
              begin
         | 
| 48 | 
            -
                false.dup
         | 
| 49 | 
            -
              rescue TypeError
         | 
| 50 | 
            -
             | 
| 51 | 
            -
                # +false+ is not duplicable:
         | 
| 52 | 
            -
                #
         | 
| 53 | 
            -
                #   false.duplicable? # => false
         | 
| 54 | 
            -
                #   false.dup         # => TypeError: can't dup FalseClass
         | 
| 55 | 
            -
                def duplicable?
         | 
| 56 | 
            -
                  false
         | 
| 57 | 
            -
                end
         | 
| 58 | 
            -
              end
         | 
| 59 | 
            -
            end
         | 
| 60 | 
            -
             | 
| 61 | 
            -
            class TrueClass
         | 
| 62 | 
            -
              begin
         | 
| 63 | 
            -
                true.dup
         | 
| 64 | 
            -
              rescue TypeError
         | 
| 65 | 
            -
             | 
| 66 | 
            -
                # +true+ is not duplicable:
         | 
| 67 | 
            -
                #
         | 
| 68 | 
            -
                #   true.duplicable? # => false
         | 
| 69 | 
            -
                #   true.dup         # => TypeError: can't dup TrueClass
         | 
| 70 | 
            -
                def duplicable?
         | 
| 71 | 
            -
                  false
         | 
| 72 | 
            -
                end
         | 
| 73 | 
            -
              end
         | 
| 74 | 
            -
            end
         | 
| 75 | 
            -
             | 
| 76 | 
            -
            class Symbol
         | 
| 77 | 
            -
              begin
         | 
| 78 | 
            -
                :symbol.dup
         | 
| 79 | 
            -
             | 
| 80 | 
            -
                # Some symbols couldn't be duped in Ruby 2.4.0 only, due to a bug.
         | 
| 81 | 
            -
                # This feature check catches any regression.
         | 
| 82 | 
            -
                "symbol_from_string".to_sym.dup
         | 
| 83 | 
            -
              rescue TypeError
         | 
| 84 | 
            -
             | 
| 85 | 
            -
                # Symbols are not duplicable:
         | 
| 86 | 
            -
                #
         | 
| 87 | 
            -
                #   :my_symbol.duplicable? # => false
         | 
| 88 | 
            -
                #   :my_symbol.dup         # => TypeError: can't dup Symbol
         | 
| 89 | 
            -
                def duplicable?
         | 
| 90 | 
            -
                  false
         | 
| 91 | 
            -
                end
         | 
| 92 | 
            -
              end
         | 
| 93 | 
            -
            end
         | 
| 94 | 
            -
             | 
| 95 | 
            -
            class Numeric
         | 
| 96 | 
            -
              begin
         | 
| 97 | 
            -
                1.dup
         | 
| 98 | 
            -
              rescue TypeError
         | 
| 99 | 
            -
             | 
| 100 | 
            -
                # Numbers are not duplicable:
         | 
| 101 | 
            -
                #
         | 
| 102 | 
            -
                #  3.duplicable? # => false
         | 
| 103 | 
            -
                #  3.dup         # => TypeError: can't dup Integer
         | 
| 104 | 
            -
                def duplicable?
         | 
| 105 | 
            -
                  false
         | 
| 106 | 
            -
                end
         | 
| 107 | 
            -
              end
         | 
| 108 | 
            -
            end
         | 
| 109 | 
            -
             | 
| 110 | 
            -
            require "bigdecimal"
         | 
| 111 | 
            -
            class BigDecimal
         | 
| 112 | 
            -
              # BigDecimals are duplicable:
         | 
| 113 | 
            -
              #
         | 
| 114 | 
            -
              #   BigDecimal("1.2").duplicable? # => true
         | 
| 115 | 
            -
              #   BigDecimal("1.2").dup         # => #<BigDecimal:...,'0.12E1',18(18)>
         | 
| 116 | 
            -
              def duplicable?
         | 
| 117 | 
            -
                true
         | 
| 118 | 
            -
              end
         | 
| 119 | 
            -
            end
         | 
| 120 | 
            -
             | 
| 121 31 | 
             
            class Method
         | 
| 122 32 | 
             
              # Methods are not duplicable:
         | 
| 123 33 | 
             
              #
         | 
| @@ -128,32 +38,12 @@ class Method | |
| 128 38 | 
             
              end
         | 
| 129 39 | 
             
            end
         | 
| 130 40 |  | 
| 131 | 
            -
            class  | 
| 132 | 
            -
               | 
| 133 | 
            -
             | 
| 134 | 
            -
               | 
| 135 | 
            -
             | 
| 136 | 
            -
             | 
| 137 | 
            -
                 | 
| 138 | 
            -
                #   Complex(1).duplicable? # => false
         | 
| 139 | 
            -
                #   Complex(1).dup         # => TypeError: can't copy Complex
         | 
| 140 | 
            -
                def duplicable?
         | 
| 141 | 
            -
                  false
         | 
| 142 | 
            -
                end
         | 
| 143 | 
            -
              end
         | 
| 144 | 
            -
            end
         | 
| 145 | 
            -
             | 
| 146 | 
            -
            class Rational
         | 
| 147 | 
            -
              begin
         | 
| 148 | 
            -
                Rational(1).dup
         | 
| 149 | 
            -
              rescue TypeError
         | 
| 150 | 
            -
             | 
| 151 | 
            -
                # Rationals are not duplicable:
         | 
| 152 | 
            -
                #
         | 
| 153 | 
            -
                #   Rational(1).duplicable? # => false
         | 
| 154 | 
            -
                #   Rational(1).dup         # => TypeError: can't copy Rational
         | 
| 155 | 
            -
                def duplicable?
         | 
| 156 | 
            -
                  false
         | 
| 157 | 
            -
                end
         | 
| 41 | 
            +
            class UnboundMethod
         | 
| 42 | 
            +
              # Unbound methods are not duplicable:
         | 
| 43 | 
            +
              #
         | 
| 44 | 
            +
              #  method(:puts).unbind.duplicable? # => false
         | 
| 45 | 
            +
              #  method(:puts).unbind.dup         # => TypeError: allocator undefined for UnboundMethod
         | 
| 46 | 
            +
              def duplicable?
         | 
| 47 | 
            +
                false
         | 
| 158 48 | 
             
              end
         | 
| 159 49 | 
             
            end
         |