hashie 3.6.0 → 4.1.0

Sign up to get free protection for your applications and to get access to all the features.
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