push more responsibility down to node
expose simple attribute write long or short many test got more compact, good
This commit is contained in:
parent
72fa26b00e
commit
78f0108166
@ -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
|
||||
|
@ -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 "- "
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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 ]
|
||||
|
@ -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]
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user