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

View File

@ -21,15 +21,15 @@ class BasicSof < MiniTest::Test
end
def test_array_array
@out = [true, 1 , [true , 12 ]]
check "- true\n- 1\n- [true, 12]"
check "[true, 1, [true, 12]]"
end
def test_array_array_reverse
@out = [ [true , 12 ], true, 1]
check "- [true, 12]\n- true\n- 1"
check "[[true, 12], true, 1]"
end
def test_array_array_array
@out = [true, 1 , [true , 12 , [true , 123 ]]]
check "- true\n- 1\n- - true\n - 12\n - [true, 123]"
check "[true, 1, [true, 12, [true, 123]]]"
end
def test_simple_hash
@out = { :one => 1 , :tru => true }
@ -37,7 +37,7 @@ class BasicSof < MiniTest::Test
end
def test_array_hash
@out = [true, 1 , { :one => 1 , :tru => true }]
check "- true\n- 1\n- {:one => 1, :tru => true}"
check "[true, 1, {:one => 1, :tru => true}]"
end
def test_array_recursive
ar = [true, 1 ]

View File

@ -11,7 +11,7 @@ class ObjectSof < MiniTest::Test
object = ObjectWithAttributes.new
object.extra = [:sym , 123]
@out = object
check "#{OBJECT_STRING}\n :extra [:sym, 123]"
check "ObjectWithAttributes(:name => 'some name', :number => 1234, :extra => [:sym, 123])"
end
def test_array_object
@out = [true, 1234 , ObjectWithAttributes.new]

View File

@ -14,30 +14,29 @@ class TestRefs < MiniTest::Test
def test_one_empty
@out = @array << @hash
check "- {}"
check "[{}]"
end
def test_two_empty
@out = @array << @hash
@out << @hash
check "- &1 {}
- ->1"
check "[&1 {}, ->1]"
end
def test_bigger
@out = [ { :one => @array , :two => [{ :three => @array}] } ]
check "- - :one => &1 []\n - :two => - {:three => ->1}"
check "[{:one => &1 [], :two => [{:three => ->1}]}]"
end
def test_object_ref
object = ObjectWithAttributes.new
object.extra = [object]
@out = [ {:one => object} , object ]
check "- {:one => ->1}\n- &1 #{OBJECT_STRING}\n :extra [->1]"
check "- {:one => ->1}\n- &1 ObjectWithAttributes(:name => 'some name', :number => 1234, :extra => [->1])"
end
def test_object_ref2
object = ObjectWithAttributes.new
object2 = ObjectWithAttributes.new
object.extra = [object2]
@out = [ {:one => object} , object2 ]
check "- - :one => #{OBJECT_STRING}\n :extra [->1]\n- &1 #{OBJECT_STRING}"
check "- - :one => ObjectWithAttributes(:name => 'some name', :number => 1234, :extra => [->1])\n- &1 ObjectWithAttributes(:name => 'some name', :number => 1234)"
end
end