module SnakyHash::Snake::SnakyModulizer

def self.to_mod(key_type)

def self.to_mod(key_type)
  Module.new do
    # Converts a key to a symbol, or a string, depending on key_type,
    #   but only if it is able to be converted to a symbol,
    #   and after underscoring it.
    #
    # @api private
    # @param [<K>] key the key to attempt convert to a symbol
    # @return [Symbol, K]
    case key_type
    when :string then
      define_method(:convert_key) { |key| key.respond_to?(:to_sym) ? underscore_string(key.to_s) : key }
    when :symbol then
      define_method(:convert_key) { |key| key.respond_to?(:to_sym) ? underscore_string(key.to_s).to_sym : key }
    else
      raise ArgumentError, "SnakyHash: Unhandled key_type: #{key_type}"
    end
    # Unlike its parent Mash, a SnakyHash::Snake will convert other
    #   Hashie::Hash values to a SnakyHash::Snake when assigning
    #   instead of respecting the existing subclass
    define_method :convert_value do |val, duping = false| #:nodoc:
      case val
      when self.class
        val.dup
      when ::Hash
        val = val.dup if duping
        self.class.new(val)
      when ::Array
        val.collect { |e| convert_value(e) }
      else
        val
      end
    end
    # converts a camel_cased string to a underscore string
    # subs spaces with underscores, strips whitespace
    # Same way ActiveSupport does string.underscore
    define_method :underscore_string do |str|
      str.to_s.strip
         .tr(" ", "_")
         .gsub(/::/, "/")
         .gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
         .gsub(/([a-z\d])([A-Z])/, '\1_\2')
         .tr("-", "_")
         .squeeze("_")
         .downcase
    end
  end
end