60 lines
1.9 KiB
Ruby
60 lines
1.9 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
require 'set'
|
|
|
|
module DumpHelper
|
|
class << self
|
|
def find_dump_error(val, key = "<toplevel>", prefix = "", __visited_dump_vars = Set.new)
|
|
return if __visited_dump_vars.include?(val)
|
|
__visited_dump_vars << val
|
|
|
|
Marshal.dump(val)
|
|
rescue TypeError
|
|
|
|
if $!.message == "singleton can't be dumped" && !val.singleton_methods.empty?
|
|
raise TypeError, "Unable to dump #{prefix}#{key} (#<#{val.class}>): #{$!}"
|
|
end
|
|
|
|
# see if anything inside val can't be dumped...
|
|
sub_prefix = " #{prefix}#{key} (#<#{val.class}>) => "
|
|
|
|
if val.respond_to?(:marshal_dump, true)
|
|
return find_dump_error(val.marshal_dump, "marshal_dump", sub_prefix, __visited_dump_vars)
|
|
elsif val.respond_to?(:_dump, true)
|
|
stringval = val._dump(-1)
|
|
unless stringvals.instance_variables.empty?
|
|
dump_ivars(stringval, "#{sub_prefix}_dump => ", __visited_dump_vars)
|
|
else
|
|
dump_ivars(val, sub_prefix, __visited_dump_vars)
|
|
end
|
|
return
|
|
else
|
|
dump_ivars(val, sub_prefix, __visited_dump_vars)
|
|
|
|
if val.is_a?(Hash) || val.is_a?(Struct)
|
|
val.each_pair do |k, v|
|
|
find_dump_error(k, "hash key #{k}", sub_prefix, __visited_dump_vars)
|
|
find_dump_error(v, "[#{k.inspect}]", sub_prefix, __visited_dump_vars)
|
|
end
|
|
elsif val.is_a?(Array)
|
|
val.each_with_index do |v, i|
|
|
find_dump_error(v, "[#{i}]", sub_prefix, __visited_dump_vars)
|
|
end if val.is_a?(Array)
|
|
else
|
|
# guess it's val proper
|
|
raise TypeError.new("Unable to dump #{prefix}#{key} (#<#{val.class}>): #{$!}")
|
|
end
|
|
end
|
|
end
|
|
|
|
private
|
|
|
|
def dump_ivars(val, sub_prefix, __visited_dump_vars)
|
|
val.instance_variables.map do |k|
|
|
v = val.instance_variable_get(k)
|
|
find_dump_error(v, k, sub_prefix, __visited_dump_vars)
|
|
end
|
|
end
|
|
end
|
|
end
|