diff --git a/lib/sof/members.rb b/lib/sof/members.rb index cfbd310..7e1b5f9 100644 --- a/lib/sof/members.rb +++ b/lib/sof/members.rb @@ -16,74 +16,87 @@ module Sof @root = root @counter = 1 @objects = {} - add(root , 0) + add_object( root , 0) + collect_level(0 , [root]) end attr_reader :objects , :root private - # recursively add reachable objects from this object - # this is called from the initialize and is private - def add object , level - # not storing simple (value) objects - return if is_value?(object) - + # add object (as occurence) if it doesn't exist + # return object or nil + def add_object object , level # see if we we came accross this before if( occurence = @objects[object.object_id] ) - puts "reset level #{level} at #{occurence.level}" if occurence.referenced == 19 + #puts "reset level #{level} at #{occurence.level}" if occurence.referenced #== 19 if occurence.level > level #always store the most shallow level occurence.level = level end # and only one Occurence for each object, create a reference for the second occurence unless occurence.referenced - puts "referencing #{@counter} #{occurence.object.name}, at level #{level}/#{occurence.level} " if @counter == 14 - puts "referencing #{@counter} #{occurence.object.name}, at level #{level}/#{occurence.level} " if @counter == 19 + puts "referencing #{@counter} #{occurence.object.name}, at level #{level}/#{occurence.level} " if @counter == 23 +# puts "referencing #{@counter} #{occurence.object.name}, at level #{level}/#{occurence.level} " if @counter == 19 occurence.set_reference(@counter) @counter = @counter + 1 end - return + return nil end - # if first time see, create and store Occurence - o = Occurence.new( object , level ) - @objects[object.object_id] = o + @objects[object.object_id] = Occurence.new( object , level ) + return object + end - case object.class.name - when "Array" , "Parfait::List" - add_array object , level - when "Hash" , "Parfait::Dictionary" - add_hash object , level - else - # and recursively add attributes - attributes = attributes_for(object) - attributes.each do |a| - val = get_value( object , a) - add(val , level + 1) - end - #TODO get all superclsses here, but this covers 99% so . . moving on - superclasses = [object.class.superclass.name] - if superclasses.include?( "Array") or superclasses.include?( "List") - add_array object , level - end - if superclasses.include?( "Hash") or superclasses.include?( "Dictionary") - add_hash object , level + # recursively find reachable objects from this level of objects + # this is called from the initialize and is private + # we go through the tree in breadth first (which is a little more effort) to catch lowest + # references. + def collect_level level , objects + next_level = Array.new + #puts "collect level #{level} #{objects.length}" + objects.each do |object| + #puts "collect level #{level} #{object.object_id}" + # not storing simple (value) objects + next if is_value?(object) + case object.class.name + when "Array" , "Parfait::List" + collect_array object , next_level + when "Hash" , "Parfait::Dictionary" + collect_hash object, next_level + else + # and recursively add attributes + attributes = attributes_for(object) + attributes.each do |a| + val = get_value( object , a) + next_level << val + end + #TODO get all superclsses here, but this covers 99% so . . moving on + superclasses = [object.class.superclass.name] + if superclasses.include?( "Array") or superclasses.include?( "List") + collect_array object, next_level + end + if superclasses.include?( "Hash") or superclasses.include?( "Dictionary") + collect_hash object, next_level + end end end + new_objects = next_level.collect { |o| add_object(o , level + 1) } + new_objects.compact! + # recurse , but break off if hit bottom + collect_level( level + 1 , new_objects) unless new_objects.empty? end + # and hash keys/values - def add_hash hash ,level + def collect_hash hash , next_level hash.each do |a,b| - add(a , level + 1) - add(b , level + 1) + next_level << a + next_level << b end end # and array values - def add_array array , level + def collect_array array , next_level array.each do |a| - add(a , level + 1) + next_level << a end end end - # TODO, since this class only has one function, and one instance - # it could be merged as class functions to Occurence end diff --git a/lib/sof/simple_node.rb b/lib/sof/simple_node.rb index e59d25b..4389140 100644 --- a/lib/sof/simple_node.rb +++ b/lib/sof/simple_node.rb @@ -9,8 +9,8 @@ module Sof class SimpleNode < Node # data is a string that is written out in "out" function - def initialize data , ref = nil - super(ref) + def initialize data + super(nil) # simple nodes can not be referenced, always value @data = data end diff --git a/test/test_refs.rb b/test/test_refs.rb index 50fa0d1..a46d137 100644 --- a/test/test_refs.rb +++ b/test/test_refs.rb @@ -36,7 +36,7 @@ class TestRefs < MiniTest::Test object2 = ObjectWithAttributes.new object.extra = [object2] @out = [ {:one => object} , object2 ] - check "- - :one => ObjectWithAttributes(:name => 'some name', :number => 1234, :extra => [->1])\n- &1 ObjectWithAttributes(:name => 'some name', :number => 1234)" + check "- - :one => ObjectWithAttributes(:name => 'some name', :number => 1234, :extra => [->2])\n- &2 ObjectWithAttributes(:name => 'some name', :number => 1234)" end end