class CleanHash def initialize data, mode=nil @data = data @mode = mode case mode when :safe @is_safe = true else @is_strict = true if mode end end # for debug def to_json JSON.pretty_generate @data end # for puts def to_ary [@data] end def [] key __value_for key.to_s end def []= key, value __error_set if @is_strict && !key?(key) @data[key.to_sym] = value end def key? name __value_for name true rescue NoMethodError false end def keys @data.keys end def values @data.values end def to_h @data end def method_missing name, *args m = name.to_s if m.end_with?('=') m = m.sub('=', '') __error_set if @is_strict && !key?(m) value = args.first if @is_safe value = value.to_s if value.is_a?(Symbol) unless value.nil? || value.is_a?(Hash) || value.is_a?(Numeric) || value.is_a?(String) raise ArgumentError.new('Unsupported safe type: %s' % value.class) end end m = m.to_sym if @data[m].nil? @data[m] = value elsif m.end_with?('?') begin !__value_for(m.sub('?', '')).nil? rescue NoMethodError false end else __value_for m end end private def __value_for name data = @data[name.to_s] data = @data[name.to_sym] if data.nil? if data.nil? if @is_strict && !keys.include?(name.to_sym) raise NoMethodError, 'Clean hash: key "%s" not found' % name else nil end elsif data.is_a?(Hash) CleanHash.new data, @mode else data end end def __error_set raise NoMethodError, 'Clean hash: setting a key value is not allowedß' end end