I like recursion.
Here's a decent way, iterating through everything and saving a hash of the objects you saw (for quick searching)
class Object def is_recursive?(known = {}) false end end module Enumerable def is_recursive?(known = {}) return true if known.include?(self) known[self] = true begin any? do |*args| args.any?{|item| item.is_recursive?(known)} end ensure known[self] = false end end end x = []; x << x p x.is_recursive? # => true p ({x => 42}).is_recursive? # => true p [{foo: x}].is_recursive? # => true p [[[[[[:foo], {bar: [42]}]]]]].is_recursive? # => false
Remember that this is a little rude and you may run into trouble. For example, will you have endless loops with [1..Float::INFINITY].is_recursive? although this is easily possible with
class Range def is_recursive?(known = {}) false # optimization end end
source share