push more responsibility down to node

expose simple attribute
write long or short
many test got more compact, good
This commit is contained in:
Torsten Ruger
2015-06-17 21:16:39 +03:00
parent 72fa26b00e
commit 78f0108166
10 changed files with 100 additions and 71 deletions

View File

@ -26,35 +26,29 @@ module Sof
super(ref)
@children = []
end
attr_reader :children
def add c
@children << c
end
# The output of a Array can be a long or a short format
# The short is used for 7 or less SimpleNodes
def out io , level
super
def is_simple?
return false if(@children.length > 7 )
short = true
children.each do |c|
short = false unless c.is_a?(SimpleNode)
end
if(short and children.length < 7 )
short_out(io , level)
else
long_out(io , level)
@children.each do |c|
short = false unless c.is_simple?
end
short
end
private
# This defines the short output which is basically what you would write in ruby
# ie [ value1 , value2 , ...]
# The short is used for 7 or less SimpleNodes
def short_out(io,level)
io.write("[")
@children.each_with_index do |child , i|
child.out(io , level + 1 )
io.write ", " unless (i+1) == children.length
io.write ", " unless (i+1) == @children.length
end
io.write("]")
end

View File

@ -28,39 +28,32 @@ module Sof
super(ref)
@children = []
end
attr_reader :children
def add key , val
@children << [key,val]
end
# The output of a Hash can be a long or a short format
# The short is used for 7 or less SimpleNodes
def out io , level
super
short = true
children.each do |k,v|
short = false unless k.is_a?(SimpleNode)
short = false unless v.is_a?(SimpleNode)
end
if(short and children.length < 7 )
short_out(io,level)
else
long_out(io , level)
def is_simple?
return false if(@children.length > 7 )
@children.each do |k,v|
return false unless k.is_simple?
return false unless v.is_simple?
end
true
end
private
# This defines the short output which is basically what you would write in ruby
# ie { key1 => value1 , ... }
# The short is used for 7 or less SimpleNodes
def short_out(io,level)
io.write("{")
children.each_with_index do |child , i|
@children.each_with_index do |child , i|
key , val = child
key.out(io , level + 1)
io.write " => "
val.out(io , level + 1)
io.write ", " unless (i+1) == children.length
io.write ", " unless (i+1) == @children.length
end
io.write("}")
end
@ -70,7 +63,7 @@ module Sof
# and each line has the association key => value, same as used for the {} syntax
def long_out io , level
indent = " " * level
children.each_with_index do |child , i|
@children.each_with_index do |child , i|
key , val = child
io.write "\n#{indent}" unless i == 0
io.write "- "

View File

@ -29,14 +29,15 @@ module Sof
# see if we we came accross this before
if( occurence = @objects[object.object_id] )
#puts "reset level #{level} at #{occurence.level}"
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} , at level #{level}/#{occurence.level} "
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
occurence.set_reference(@counter)
@counter = @counter + 1
end

View File

@ -7,7 +7,13 @@ module Sof
#
# There are only two subclasses, SimpleNode and ObejctNode, for simple or not
# The base class only holds the referenced flag
# Also nodes must implement the out function
# Node implements the out function which just checks wether a node is_simple?
# and either calls short_out or long_out
#
# Notice that different instances of the same clas may be simple or not
# So deriving classes must implement is_simple? and accordingly long/and or short_out
class Node
include Util
@ -20,10 +26,23 @@ module Sof
end
attr_reader :referenced
# must be able to output to a stream
# This function must be called as super as it handles possible reference marker "& num"
# This ochastrates the output of derived classes to the stream
# It writes any possible reference and sees if the noe is_simple? (see there)
# and calls long / or short_out respectively
def out io ,level
io.write "&#{@referenced} " if @referenced
if( is_simple? )
short_out(io,level)
else
long_out(io,level)
end
end
# Determine wether node is simple, meaning short, in the 30 char region
# The point of hoisting this property into the public api is that
# other nodes may ask of their children and output accordingly
def is_simple?
raise "abstact function is_simple called for #{self}"
end
# helper function to return the output as a string
@ -33,5 +52,14 @@ module Sof
out(io,level)
io.string
end
private
def short_out io , level
raise "abstact function short_out called for #{self}"
end
def long_out io , level
raise "abstact function long_out called for #{self}"
end
end
end

View File

@ -8,31 +8,48 @@ module Sof
# init with a string, much like a simple node
# structure is added after construction and kept in a children array
def initialize data , ref
def initialize name , ref
super(ref)
@data = data
@children = []
@name = name
@simple = {}
@complex = {}
end
attr_reader :children , :data
# children array hold key value pairs
# attributes hold key value pairs
def add k , v
@children << [k,v]
raise "Key should be symbol not #{k}" unless k.is_a? Symbol
if( v.is_simple?)
@simple[k] = v
else
@complex[k] = v
end
end
def is_simple?
true if( @referenced.nil? and @complex.empty? and head.length < 30 )
end
# write out at the given level
# level determines the indentation (level * space)
# write out the data and then the children (always key value on one line)
def out io , level
super
io.write(@data)
def long_out io , level
io.write(head)
indent = " " * (level + 1)
@children.each do |k,v|
@complex.each do |k,v|
io.write "\n#{indent}"
k.out(io , level + 1)
io.write ":#{k}"
io.write " "
v.out(io , level + 1)
end
end
def short_out io , level
io.write head
end
def head
body = @simple.collect {|a,val| ":#{a} => #{val.as_string(1)}"}.join(", ")
"#{@name}(#{body})"
end
end
end

View File

@ -13,12 +13,17 @@ module Sof
super(ref)
@data = data
end
attr_reader :data
# A SimpleNode is always simple (aha).
# accordingly there is no long_out
def is_simple?
true
end
private
# just write the data given in construcor. simple. hence the name.
def out io , level
super(io,level)
io.write(data)
def short_out io , level
io.write(@data)
end
end

View File

@ -66,19 +66,11 @@ module Sof
# small means only simple attributes and only 30 chars of them
# object nodes are basically arrays (see there)
def object_sof_node( object , level , ref)
head = object.class.name + "("
atts = {}
node = ObjectNode.new(object.class.name , ref)
attributes_for(object).each() do |a|
val = get_value(object , a)
next if val.nil?
atts[a] = to_sof_node(val , level + 1)
end
immediate , extended = atts.partition {|a,val| val.is_a?(SimpleNode) }
head += immediate.collect {|a,val| "#{a.to_sof()} => #{val.as_string(level + 1)}"}.join(", ") + ")"
return SimpleNode.new(head) if( ref.nil? and extended.empty? and head.length < 30 )
node = ObjectNode.new(head , ref)
extended.each do |a , val|
node.add( to_sof_node(a,level + 1) , val )
node.add( a , to_sof_node( val , level + 1) )
end
node
end