summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorBobby McDonald <BobbyMcWho@users.noreply.github.com>2019-11-18 17:04:37 -0500
committerGitHub <noreply@github.com>2019-11-18 17:04:37 -0500
commitd5f253963731f7b2ef96ba415ecad22c89e22d28 (patch)
treef2a772ddfe026f34262d3339f8efa6c351c626d8 /lib
parent4f014e7fedad93fa2070166051947070cc8ac01c (diff)
parent15ea67ef0667546627f9a3cd4fef4457512f5880 (diff)
downloadhashie-d5f253963731f7b2ef96ba415ecad22c89e22d28.tar.gz
Merge pull request #499 from michaelherold/permissive-respond-to
Add a PermissiveRespondTo extension for Mashes
Diffstat (limited to 'lib')
-rw-r--r--lib/hashie.rb1
-rw-r--r--lib/hashie/extensions/mash/permissive_respond_to.rb61
2 files changed, 62 insertions, 0 deletions
diff --git a/lib/hashie.rb b/lib/hashie.rb
index a3fc11c..7f88ed4 100644
--- a/lib/hashie.rb
+++ b/lib/hashie.rb
@@ -45,6 +45,7 @@ module Hashie
module Mash
autoload :KeepOriginalKeys, 'hashie/extensions/mash/keep_original_keys'
+ autoload :PermissiveRespondTo, 'hashie/extensions/mash/permissive_respond_to'
autoload :SafeAssignment, 'hashie/extensions/mash/safe_assignment'
autoload :SymbolizeKeys, 'hashie/extensions/mash/symbolize_keys'
autoload :DefineAccessors, 'hashie/extensions/mash/define_accessors'
diff --git a/lib/hashie/extensions/mash/permissive_respond_to.rb b/lib/hashie/extensions/mash/permissive_respond_to.rb
new file mode 100644
index 0000000..5f8c231
--- /dev/null
+++ b/lib/hashie/extensions/mash/permissive_respond_to.rb
@@ -0,0 +1,61 @@
+module Hashie
+ module Extensions
+ module Mash
+ # Allow a Mash to properly respond to everything
+ #
+ # By default, Mashes only say they respond to methods for keys that exist
+ # in their key set or any of the affix methods (e.g. setter, underbang,
+ # etc.). This causes issues when you try to use them within a
+ # SimpleDelegator or bind to a method for a key that is unset.
+ #
+ # This extension allows a Mash to properly respond to `respond_to?` and
+ # `method` for keys that have not yet been set. This enables full
+ # compatibility with SimpleDelegator and thunk-oriented programming.
+ #
+ # There is a trade-off with this extension: it will run slower than a
+ # regular Mash; insertions and initializations with keys run approximately
+ # 20% slower and cost approximately 19KB of memory per class that you
+ # make permissive.
+ #
+ # @api public
+ # @example Make a new, permissively responding Mash subclass
+ # class PermissiveMash < Hashie::Mash
+ # include Hashie::Extensions::Mash::PermissiveRespondTo
+ # end
+ #
+ # mash = PermissiveMash.new(a: 1)
+ # mash.respond_to? :b #=> true
+ module PermissiveRespondTo
+ # The Ruby hook for behavior when including the module
+ #
+ # @api private
+ # @private
+ # @return void
+ def self.included(base)
+ base.instance_variable_set :@_method_cache, base.instance_methods
+ base.define_singleton_method(:method_cache) { @_method_cache }
+ end
+
+ # The Ruby hook for determining what messages a class might respond to
+ #
+ # @api private
+ # @private
+ def respond_to_missing?(_method_name, _include_private = false)
+ true
+ end
+
+ private
+
+ # Override the Mash logging behavior to account for permissiveness
+ #
+ # @api private
+ # @private
+ def log_collision?(method_key)
+ self.class.method_cache.include?(method_key) &&
+ !self.class.disable_warnings?(method_key) &&
+ !(regular_key?(method_key) || regular_key?(method_key.to_s))
+ end
+ end
+ end
+ end
+end