hashie/lib/hashie/extensions/mash/permissive_respond_to.rb

62 lines
2.2 KiB
Ruby

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