hashie 3.6.0 → 4.1.0

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.
Files changed (78) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +228 -174
  3. data/CONTRIBUTING.md +13 -6
  4. data/README.md +127 -15
  5. data/UPGRADING.md +83 -7
  6. data/hashie.gemspec +13 -7
  7. data/lib/hashie.rb +21 -19
  8. data/lib/hashie/dash.rb +2 -1
  9. data/lib/hashie/extensions/active_support/core_ext/hash.rb +14 -0
  10. data/lib/hashie/extensions/coercion.rb +23 -16
  11. data/lib/hashie/extensions/dash/indifferent_access.rb +20 -1
  12. data/lib/hashie/extensions/dash/property_translation.rb +6 -3
  13. data/lib/hashie/extensions/deep_fetch.rb +4 -2
  14. data/lib/hashie/extensions/deep_find.rb +12 -3
  15. data/lib/hashie/extensions/deep_locate.rb +22 -7
  16. data/lib/hashie/extensions/deep_merge.rb +18 -1
  17. data/lib/hashie/extensions/indifferent_access.rb +1 -3
  18. data/lib/hashie/extensions/key_conflict_warning.rb +55 -0
  19. data/lib/hashie/extensions/mash/define_accessors.rb +90 -0
  20. data/lib/hashie/extensions/mash/keep_original_keys.rb +2 -1
  21. data/lib/hashie/extensions/mash/permissive_respond_to.rb +61 -0
  22. data/lib/hashie/extensions/mash/safe_assignment.rb +3 -1
  23. data/lib/hashie/extensions/method_access.rb +5 -2
  24. data/lib/hashie/extensions/parsers/yaml_erb_parser.rb +26 -4
  25. data/lib/hashie/extensions/ruby_version_check.rb +5 -1
  26. data/lib/hashie/extensions/strict_key_access.rb +8 -4
  27. data/lib/hashie/hash.rb +16 -9
  28. data/lib/hashie/mash.rb +114 -53
  29. data/lib/hashie/railtie.rb +7 -0
  30. data/lib/hashie/rash.rb +1 -1
  31. data/lib/hashie/utils.rb +28 -0
  32. data/lib/hashie/version.rb +1 -1
  33. metadata +19 -130
  34. data/spec/hashie/array_spec.rb +0 -29
  35. data/spec/hashie/clash_spec.rb +0 -70
  36. data/spec/hashie/dash_spec.rb +0 -598
  37. data/spec/hashie/extensions/autoload_spec.rb +0 -24
  38. data/spec/hashie/extensions/coercion_spec.rb +0 -639
  39. data/spec/hashie/extensions/dash/coercion_spec.rb +0 -13
  40. data/spec/hashie/extensions/dash/indifferent_access_spec.rb +0 -84
  41. data/spec/hashie/extensions/deep_fetch_spec.rb +0 -97
  42. data/spec/hashie/extensions/deep_find_spec.rb +0 -138
  43. data/spec/hashie/extensions/deep_locate_spec.rb +0 -137
  44. data/spec/hashie/extensions/deep_merge_spec.rb +0 -70
  45. data/spec/hashie/extensions/ignore_undeclared_spec.rb +0 -47
  46. data/spec/hashie/extensions/indifferent_access_spec.rb +0 -295
  47. data/spec/hashie/extensions/indifferent_access_with_rails_hwia_spec.rb +0 -208
  48. data/spec/hashie/extensions/key_conversion_spec.rb +0 -12
  49. data/spec/hashie/extensions/mash/keep_original_keys_spec.rb +0 -46
  50. data/spec/hashie/extensions/mash/safe_assignment_spec.rb +0 -50
  51. data/spec/hashie/extensions/mash/symbolize_keys_spec.rb +0 -39
  52. data/spec/hashie/extensions/merge_initializer_spec.rb +0 -23
  53. data/spec/hashie/extensions/method_access_spec.rb +0 -226
  54. data/spec/hashie/extensions/strict_key_access_spec.rb +0 -110
  55. data/spec/hashie/extensions/stringify_keys_spec.rb +0 -124
  56. data/spec/hashie/extensions/symbolize_keys_spec.rb +0 -129
  57. data/spec/hashie/hash_spec.rb +0 -84
  58. data/spec/hashie/mash_spec.rb +0 -771
  59. data/spec/hashie/parsers/yaml_erb_parser_spec.rb +0 -46
  60. data/spec/hashie/rash_spec.rb +0 -83
  61. data/spec/hashie/trash_spec.rb +0 -328
  62. data/spec/hashie/utils_spec.rb +0 -25
  63. data/spec/hashie/version_spec.rb +0 -7
  64. data/spec/hashie_spec.rb +0 -13
  65. data/spec/integration/elasticsearch/integration_spec.rb +0 -40
  66. data/spec/integration/omniauth-oauth2/app.rb +0 -52
  67. data/spec/integration/omniauth-oauth2/integration_spec.rb +0 -26
  68. data/spec/integration/omniauth-oauth2/some_site.rb +0 -38
  69. data/spec/integration/omniauth/app.rb +0 -11
  70. data/spec/integration/omniauth/integration_spec.rb +0 -38
  71. data/spec/integration/rails-without-dependency/integration_spec.rb +0 -15
  72. data/spec/integration/rails/app.rb +0 -47
  73. data/spec/integration/rails/integration_spec.rb +0 -26
  74. data/spec/spec_helper.rb +0 -23
  75. data/spec/support/integration_specs.rb +0 -36
  76. data/spec/support/logger.rb +0 -24
  77. data/spec/support/module_context.rb +0 -11
  78. data/spec/support/ruby_version_check.rb +0 -6
@@ -15,7 +15,8 @@ module Hashie
15
15
  # mash[:symbol_key] == mash['symbol_key'] #=> true
16
16
  module KeepOriginalKeys
17
17
  def self.included(descendant)
18
- raise ArgumentError, "#{descendant} is not a kind of Hashie::Mash" unless descendant <= Hashie::Mash
18
+ error_message = "#{descendant} is not a kind of Hashie::Mash"
19
+ raise ArgumentError, error_message unless descendant <= Hashie::Mash
19
20
  end
20
21
 
21
22
  private
@@ -0,0 +1,61 @@
1
+ module Hashie
2
+ module Extensions
3
+ module Mash
4
+ # Allow a Mash to properly respond to everything
5
+ #
6
+ # By default, Mashes only say they respond to methods for keys that exist
7
+ # in their key set or any of the affix methods (e.g. setter, underbang,
8
+ # etc.). This causes issues when you try to use them within a
9
+ # SimpleDelegator or bind to a method for a key that is unset.
10
+ #
11
+ # This extension allows a Mash to properly respond to `respond_to?` and
12
+ # `method` for keys that have not yet been set. This enables full
13
+ # compatibility with SimpleDelegator and thunk-oriented programming.
14
+ #
15
+ # There is a trade-off with this extension: it will run slower than a
16
+ # regular Mash; insertions and initializations with keys run approximately
17
+ # 20% slower and cost approximately 19KB of memory per class that you
18
+ # make permissive.
19
+ #
20
+ # @api public
21
+ # @example Make a new, permissively responding Mash subclass
22
+ # class PermissiveMash < Hashie::Mash
23
+ # include Hashie::Extensions::Mash::PermissiveRespondTo
24
+ # end
25
+ #
26
+ # mash = PermissiveMash.new(a: 1)
27
+ # mash.respond_to? :b #=> true
28
+ module PermissiveRespondTo
29
+ # The Ruby hook for behavior when including the module
30
+ #
31
+ # @api private
32
+ # @private
33
+ # @return void
34
+ def self.included(base)
35
+ base.instance_variable_set :@_method_cache, base.instance_methods
36
+ base.define_singleton_method(:method_cache) { @_method_cache }
37
+ end
38
+
39
+ # The Ruby hook for determining what messages a class might respond to
40
+ #
41
+ # @api private
42
+ # @private
43
+ def respond_to_missing?(_method_name, _include_private = false)
44
+ true
45
+ end
46
+
47
+ private
48
+
49
+ # Override the Mash logging behavior to account for permissiveness
50
+ #
51
+ # @api private
52
+ # @private
53
+ def log_collision?(method_key)
54
+ self.class.method_cache.include?(method_key) &&
55
+ !self.class.disable_warnings?(method_key) &&
56
+ !(regular_key?(method_key) || regular_key?(method_key.to_s))
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
@@ -3,7 +3,9 @@ module Hashie
3
3
  module Mash
4
4
  module SafeAssignment
5
5
  def custom_writer(key, *args) #:nodoc:
6
- raise ArgumentError, "The property #{key} clashes with an existing method." if !key?(key) && respond_to?(key, true)
6
+ if !key?(key) && respond_to?(key, true)
7
+ raise ArgumentError, "The property #{key} clashes with an existing method."
8
+ end
7
9
  super
8
10
  end
9
11
 
@@ -73,7 +73,9 @@ module Hashie
73
73
  end
74
74
 
75
75
  def method_missing(name, *args)
76
- return self[convert_key(Regexp.last_match[1])] = args.first if args.size == 1 && name.to_s =~ /(.*)=$/
76
+ if args.size == 1 && name.to_s =~ /(.*)=$/
77
+ return self[convert_key(Regexp.last_match[1])] = args.first
78
+ end
77
79
 
78
80
  super
79
81
  end
@@ -231,7 +233,8 @@ module Hashie
231
233
  # underscores.
232
234
  module MethodAccessWithOverride
233
235
  def self.included(base)
234
- [MethodReader, MethodOverridingWriter, MethodQuery, MethodOverridingInitializer].each do |mod|
236
+ [MethodReader, MethodOverridingWriter,
237
+ MethodQuery, MethodOverridingInitializer].each do |mod|
235
238
  base.send :include, mod
236
239
  end
237
240
  end
@@ -6,19 +6,41 @@ module Hashie
6
6
  module Extensions
7
7
  module Parsers
8
8
  class YamlErbParser
9
- def initialize(file_path)
9
+ def initialize(file_path, options = {})
10
10
  @content = File.read(file_path)
11
11
  @file_path = file_path.is_a?(Pathname) ? file_path.to_s : file_path
12
+ @options = options
12
13
  end
13
14
 
14
15
  def perform
15
16
  template = ERB.new(@content)
16
17
  template.filename = @file_path
17
- YAML.safe_load template.result
18
+ permitted_classes = @options.fetch(:permitted_classes) { [] }
19
+ permitted_symbols = @options.fetch(:permitted_symbols) { [] }
20
+ aliases = @options.fetch(:aliases) { true }
21
+
22
+ yaml_safe_load(template, permitted_classes, permitted_symbols, aliases)
23
+ end
24
+
25
+ def self.perform(file_path, options = {})
26
+ new(file_path, options).perform
18
27
  end
19
28
 
20
- def self.perform(file_path)
21
- new(file_path).perform
29
+ private
30
+
31
+ if Gem::Version.new(Psych::VERSION) >= Gem::Version.new('3.1.0') # Ruby 2.6+
32
+ def yaml_safe_load(template, permitted_classes, permitted_symbols, aliases)
33
+ YAML.safe_load(
34
+ template.result,
35
+ permitted_classes: permitted_classes,
36
+ permitted_symbols: permitted_symbols,
37
+ aliases: aliases
38
+ )
39
+ end
40
+ else
41
+ def yaml_safe_load(template, permitted_classes, permitted_symbols, aliases)
42
+ YAML.safe_load(template.result, permitted_classes, permitted_symbols, aliases)
43
+ end
22
44
  end
23
45
  end
24
46
  end
@@ -9,7 +9,11 @@ module Hashie
9
9
 
10
10
  module ClassMethods
11
11
  def with_minimum_ruby(version)
12
- yield if RubyVersion.new(RUBY_VERSION) >= RubyVersion.new(version)
12
+ yield if with_minimum_ruby?(version)
13
+ end
14
+
15
+ def with_minimum_ruby?(version)
16
+ RubyVersion.new(RUBY_VERSION) >= RubyVersion.new(version)
13
17
  end
14
18
  end
15
19
  end
@@ -1,6 +1,7 @@
1
1
  module Hashie
2
2
  module Extensions
3
- # SRP: This extension will fail an error whenever a key is accessed that does not exist in the hash.
3
+ # SRP: This extension will fail an error whenever a key is accessed
4
+ # that does not exist in the hash.
4
5
  #
5
6
  # EXAMPLE:
6
7
  #
@@ -15,12 +16,15 @@ module Hashie
15
16
  # >> hash[:cow]
16
17
  # KeyError: key not found: :cow
17
18
  #
18
- # NOTE: For googlers coming from Python to Ruby, this extension makes a Hash behave more like a "Dictionary".
19
+ # NOTE: For googlers coming from Python to Ruby, this extension makes a Hash
20
+ # behave more like a "Dictionary".
19
21
  #
20
22
  module StrictKeyAccess
21
23
  class DefaultError < StandardError
22
- def initialize(msg = 'Setting or using a default with Hashie::Extensions::StrictKeyAccess does not make sense', *args)
23
- super
24
+ def initialize
25
+ super('Setting or using a default with Hashie::Extensions::StrictKeyAccess'\
26
+ ' does not make sense'
27
+ )
24
28
  end
25
29
  end
26
30
 
data/lib/hashie/hash.rb CHANGED
@@ -18,20 +18,21 @@ module Hashie
18
18
  def to_hash(options = {})
19
19
  out = {}
20
20
  each_key do |k|
21
- assignment_key = if options[:stringify_keys]
22
- k.to_s
23
- elsif options[:symbolize_keys]
24
- k.to_s.to_sym
25
- else
26
- k
27
- end
21
+ assignment_key =
22
+ if options[:stringify_keys]
23
+ k.to_s
24
+ elsif options[:symbolize_keys]
25
+ k.to_s.to_sym
26
+ else
27
+ k
28
+ end
28
29
  if self[k].is_a?(Array)
29
30
  out[assignment_key] ||= []
30
31
  self[k].each do |array_object|
31
- out[assignment_key] << (array_object.is_a?(Hash) ? flexibly_convert_to_hash(array_object, options) : array_object)
32
+ out[assignment_key] << maybe_convert_to_hash(array_object, options)
32
33
  end
33
34
  else
34
- out[assignment_key] = self[k].is_a?(Hash) || self[k].respond_to?(:to_hash) ? flexibly_convert_to_hash(self[k], options) : self[k]
35
+ out[assignment_key] = maybe_convert_to_hash(self[k], options)
35
36
  end
36
37
  end
37
38
  out
@@ -44,6 +45,12 @@ module Hashie
44
45
 
45
46
  private
46
47
 
48
+ def maybe_convert_to_hash(object, options)
49
+ return object unless object.is_a?(Hash) || object.respond_to?(:to_hash)
50
+
51
+ flexibly_convert_to_hash(object, options)
52
+ end
53
+
47
54
  def flexibly_convert_to_hash(object, options = {})
48
55
  if object.method(:to_hash).arity.zero?
49
56
  object.to_hash
data/lib/hashie/mash.rb CHANGED
@@ -2,6 +2,7 @@ require 'hashie/hash'
2
2
  require 'hashie/array'
3
3
  require 'hashie/utils'
4
4
  require 'hashie/logger'
5
+ require 'hashie/extensions/key_conflict_warning'
5
6
 
6
7
  module Hashie
7
8
  # Mash allows you to create pseudo-objects that have method-like
@@ -15,9 +16,12 @@ module Hashie
15
16
  #
16
17
  # * No punctuation: Returns the value of the hash for that key, or nil if none exists.
17
18
  # * Assignment (<tt>=</tt>): Sets the attribute of the given method name.
18
- # * Existence (<tt>?</tt>): Returns true or false depending on whether that key has been set.
19
- # * Bang (<tt>!</tt>): Forces the existence of this key, used for deep Mashes. Think of it as "touch" for mashes.
20
- # * Under Bang (<tt>_</tt>): Like Bang, but returns a new Mash rather than creating a key. Used to test existance in deep Mashes.
19
+ # * Truthiness (<tt>?</tt>): Returns true or false depending on the truthiness of
20
+ # the attribute, or false if the key is not set.
21
+ # * Bang (<tt>!</tt>): Forces the existence of this key, used for deep Mashes. Think of it
22
+ # as "touch" for mashes.
23
+ # * Under Bang (<tt>_</tt>): Like Bang, but returns a new Mash rather than creating a key.
24
+ # Used to test existance in deep Mashes.
21
25
  #
22
26
  # == Basic Example
23
27
  #
@@ -60,49 +64,19 @@ module Hashie
60
64
  class Mash < Hash
61
65
  include Hashie::Extensions::PrettyInspect
62
66
  include Hashie::Extensions::RubyVersionCheck
67
+ extend Hashie::Extensions::KeyConflictWarning
63
68
 
64
69
  ALLOWED_SUFFIXES = %w[? ! = _].freeze
65
70
 
66
- class CannotDisableMashWarnings < StandardError
67
- def initialize(message = 'You cannot disable warnings on the base Mash class. Please subclass the Mash and disable it in the subclass.')
68
- super(message)
69
- end
70
- end
71
-
72
- # Disable the logging of warnings based on keys conflicting keys/methods
73
- #
74
- # @api semipublic
75
- # @return [void]
76
- def self.disable_warnings
77
- raise CannotDisableMashWarnings if self == Hashie::Mash
78
- @disable_warnings = true
79
- end
80
-
81
- # Checks whether this class disables warnings for conflicting keys/methods
82
- #
83
- # @api semipublic
84
- # @return [Boolean]
85
- def self.disable_warnings?
86
- @disable_warnings ||= false
87
- end
88
-
89
- # Inheritance hook that sets class configuration when inherited.
90
- #
91
- # @api semipublic
92
- # @return [void]
93
- def self.inherited(subclass)
94
- super
95
- subclass.disable_warnings if disable_warnings?
96
- end
97
-
98
71
  def self.load(path, options = {})
99
72
  @_mashes ||= new
100
73
 
101
74
  return @_mashes[path] if @_mashes.key?(path)
102
75
  raise ArgumentError, "The following file doesn't exist: #{path}" unless File.file?(path)
103
76
 
104
- parser = options.fetch(:parser) { Hashie::Extensions::Parsers::YamlErbParser }
105
- @_mashes[path] = new(parser.perform(path)).freeze
77
+ options = options.dup
78
+ parser = options.delete(:parser) { Hashie::Extensions::Parsers::YamlErbParser }
79
+ @_mashes[path] = new(parser.perform(path, options)).freeze
106
80
  end
107
81
 
108
82
  def to_module(mash_method_name = :settings)
@@ -114,6 +88,10 @@ module Hashie
114
88
  end
115
89
  end
116
90
 
91
+ def with_accessors!
92
+ extend Hashie::Extensions::Mash::DefineAccessors
93
+ end
94
+
117
95
  alias to_s inspect
118
96
 
119
97
  # If you pass in an existing hash, it will
@@ -125,6 +103,19 @@ module Hashie
125
103
  default ? super(default) : super(&blk)
126
104
  end
127
105
 
106
+ # Creates a new anonymous subclass with key conflict
107
+ # warnings disabled. You may pass an array of method
108
+ # symbols to restrict the disabled warnings to.
109
+ # Hashie::Mash.quiet.new(hash) all warnings disabled.
110
+ # Hashie::Mash.quiet(:zip).new(hash) only zip warning
111
+ # is disabled.
112
+ def self.quiet(*method_keys)
113
+ @memoized_classes ||= {}
114
+ @memoized_classes[method_keys] ||= Class.new(self) do
115
+ disable_warnings(*method_keys)
116
+ end
117
+ end
118
+
128
119
  class << self; alias [] new; end
129
120
 
130
121
  alias regular_reader []
@@ -183,6 +174,25 @@ module Hashie
183
174
  super(*keys.map { |key| convert_key(key) })
184
175
  end
185
176
 
177
+ # Returns a new instance of the class it was called on, using its keys as
178
+ # values, and its values as keys. The new values and keys will always be
179
+ # strings.
180
+ def invert
181
+ self.class.new(super)
182
+ end
183
+
184
+ # Returns a new instance of the class it was called on, containing elements
185
+ # for which the given block returns false.
186
+ def reject(&blk)
187
+ self.class.new(super(&blk))
188
+ end
189
+
190
+ # Returns a new instance of the class it was called on, containing elements
191
+ # for which the given block returns true.
192
+ def select(&blk)
193
+ self.class.new(super(&blk))
194
+ end
195
+
186
196
  alias regular_dup dup
187
197
  # Duplicates the current mash as a new mash.
188
198
  def dup
@@ -197,19 +207,47 @@ module Hashie
197
207
  alias include? key?
198
208
  alias member? key?
199
209
 
200
- # Performs a deep_update on a duplicate of the
201
- # current mash.
202
- def deep_merge(other_hash, &blk)
203
- dup.deep_update(other_hash, &blk)
210
+ if with_minimum_ruby?('2.6.0')
211
+ # Performs a deep_update on a duplicate of the
212
+ # current mash.
213
+ def deep_merge(*other_hashes, &blk)
214
+ dup.deep_update(*other_hashes, &blk)
215
+ end
216
+
217
+ # Recursively merges this mash with the passed
218
+ # in hash, merging each hash in the hierarchy.
219
+ def deep_update(*other_hashes, &blk)
220
+ other_hashes.each do |other_hash|
221
+ _deep_update(other_hash, &blk)
222
+ end
223
+ self
224
+ end
225
+ else
226
+ # Performs a deep_update on a duplicate of the
227
+ # current mash.
228
+ def deep_merge(other_hash, &blk)
229
+ dup.deep_update(other_hash, &blk)
230
+ end
231
+
232
+ # Recursively merges this mash with the passed
233
+ # in hash, merging each hash in the hierarchy.
234
+ def deep_update(other_hash, &blk)
235
+ _deep_update(other_hash, &blk)
236
+ self
237
+ end
204
238
  end
239
+
240
+ # Alias these lexically so they get the correctly defined
241
+ # #deep_merge and #deep_update based on ruby version.
205
242
  alias merge deep_merge
243
+ alias deep_merge! deep_update
244
+ alias update deep_update
245
+ alias merge! update
206
246
 
207
- # Recursively merges this mash with the passed
208
- # in hash, merging each hash in the hierarchy.
209
- def deep_update(other_hash, &blk)
247
+ def _deep_update(other_hash, &blk)
210
248
  other_hash.each_pair do |k, v|
211
249
  key = convert_key(k)
212
- if regular_reader(key).is_a?(Mash) && v.is_a?(::Hash)
250
+ if v.is_a?(::Hash) && key?(key) && regular_reader(key).is_a?(Mash)
213
251
  custom_reader(key).deep_update(v, &blk)
214
252
  else
215
253
  value = convert_value(v, true)
@@ -217,11 +255,8 @@ module Hashie
217
255
  custom_writer(key, value, false)
218
256
  end
219
257
  end
220
- self
221
258
  end
222
- alias deep_merge! deep_update
223
- alias update deep_update
224
- alias merge! update
259
+ private :_deep_update
225
260
 
226
261
  # Assigns a value to a key
227
262
  def assign_property(name, value)
@@ -296,6 +331,29 @@ module Hashie
296
331
  end
297
332
  end
298
333
 
334
+ with_minimum_ruby('2.4.0') do
335
+ def transform_values(&blk)
336
+ self.class.new(super(&blk))
337
+ end
338
+
339
+ # Returns a new instance of the class it was called on, with nil values
340
+ # removed.
341
+ def compact
342
+ self.class.new(super)
343
+ end
344
+ end
345
+
346
+ with_minimum_ruby('2.5.0') do
347
+ def slice(*keys)
348
+ string_keys = keys.map { |key| convert_key(key) }
349
+ self.class.new(super(*string_keys))
350
+ end
351
+
352
+ def transform_keys(&blk)
353
+ self.class.new(super(&blk))
354
+ end
355
+ end
356
+
299
357
  protected
300
358
 
301
359
  def method_name_and_suffix(method_name)
@@ -325,8 +383,6 @@ module Hashie
325
383
  when ::Hash
326
384
  val = val.dup if duping
327
385
  self.class.new(val)
328
- when Array
329
- val.map { |e| convert_value(e) }
330
386
  when ::Array
331
387
  Array.new(val.map { |e| convert_value(e) })
332
388
  else
@@ -337,7 +393,7 @@ module Hashie
337
393
  private
338
394
 
339
395
  def log_built_in_message(method_key)
340
- return if self.class.disable_warnings?
396
+ return if self.class.disable_warnings?(method_key)
341
397
 
342
398
  method_information = Hashie::Utils.method_information(method(method_key))
343
399
 
@@ -350,7 +406,12 @@ module Hashie
350
406
  end
351
407
 
352
408
  def log_collision?(method_key)
353
- respond_to?(method_key) && !self.class.disable_warnings? &&
409
+ return unless respond_to?(method_key)
410
+
411
+ _, suffix = method_name_and_suffix(method_key)
412
+
413
+ (!suffix || suffix == '='.freeze) &&
414
+ !self.class.disable_warnings?(method_key) &&
354
415
  !(regular_key?(method_key) || regular_key?(method_key.to_s))
355
416
  end
356
417
  end