module Hashie::Extensions::Mash::PermissiveRespondTo

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

Public Class Methods

included(base) click to toggle source

The Ruby hook for behavior when including the module

@api private @private @return void

# File lib/hashie/extensions/mash/permissive_respond_to.rb, line 34
def self.included(base)
  base.instance_variable_set :@_method_cache, base.instance_methods
  base.define_singleton_method(:method_cache) { @_method_cache }
end

Public Instance Methods

respond_to_missing?(_method_name, _include_private = false) click to toggle source

The Ruby hook for determining what messages a class might respond to

@api private @private

# File lib/hashie/extensions/mash/permissive_respond_to.rb, line 43
def respond_to_missing?(_method_name, _include_private = false)
  true
end

Private Instance Methods

log_collision?(method_key) click to toggle source

Override the Mash logging behavior to account for permissiveness

@api private @private

# File lib/hashie/extensions/mash/permissive_respond_to.rb, line 53
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