Skip to content

Commit

Permalink
Repeatable output (idempotent output)
Browse files Browse the repository at this point in the history
Fixes #61
Make sure we iterate over ordered keys when iterating maps. This allows for a more consisten rendering. Thanks @Justin-W for this tip.
This update also remove now unnecessary testing supporting files that were checking different variants of the same rendering.
  • Loading branch information
Javier Feliu committed Oct 26, 2019
1 parent 03dcc67 commit e0ac4f6
Show file tree
Hide file tree
Showing 7 changed files with 106 additions and 93 deletions.
91 changes: 48 additions & 43 deletions ClassDiagram.puml
Original file line number Diff line number Diff line change
@@ -1,51 1,10 @@
@startuml
namespace parser {
class Struct << (S,Aquamarine) >> {
PackageName string
Functions []*Function
Fields []*Field
Type string
Composition <font color=blue>map</font>[string]<font color=blue>struct</font>{}
Extends <font color=blue>map</font>[string]<font color=blue>struct</font>{}
Aggregations <font color=blue>map</font>[string]<font color=blue>struct</font>{}

ImplementsInterface(inter *Struct) bool
AddToComposition(fType string)
AddToExtends(fType string)
AddToAggregation(fType string)
AddField(field *ast.Field, aliases <font color=blue>map</font>[string]string)
AddMethod(method *ast.Field, aliases <font color=blue>map</font>[string]string)

}
class Function << (S,Aquamarine) >> {
Name string
Parameters []*Field
ReturnValues []string
PackageName string
FullNameReturnValues []string

SignturesAreEqual(function *Function) bool

}
class Alias << (S,Aquamarine) >> {
Name string
PackageName string
AliasOf string

}
class Field << (S,Aquamarine) >> {
Name string
Type string
FullType string

}
class LineStringBuilder << (S,Aquamarine) >> {
WriteLineWithDepth(depth int, str string)

}
class RenderingOptions << (S,Aquamarine) >> {
Aggregation bool

}
class ClassParser << (S,Aquamarine) >> {
- renderingOptions *RenderingOptions
Expand Down Expand Up @@ -77,12 36,58 @@ namespace parser {
SetRenderingOptions(ro *RenderingOptions)

}
class Field << (S,Aquamarine) >> {
Name string
Type string
FullType string

}
class Function << (S,Aquamarine) >> {
Name string
Parameters []*Field
ReturnValues []string
PackageName string
FullNameReturnValues []string

SignturesAreEqual(function *Function) bool

}
class LineStringBuilder << (S,Aquamarine) >> {
WriteLineWithDepth(depth int, str string)

}
class RenderingOptions << (S,Aquamarine) >> {
Aggregations bool
Fields bool
Methods bool
Compositions bool
Implementations bool
Aliases bool

}
class Struct << (S,Aquamarine) >> {
PackageName string
Functions []*Function
Fields []*Field
Type string
Composition <font color=blue>map</font>[string]<font color=blue>struct</font>{}
Extends <font color=blue>map</font>[string]<font color=blue>struct</font>{}
Aggregations <font color=blue>map</font>[string]<font color=blue>struct</font>{}

ImplementsInterface(inter *Struct) bool
AddToComposition(fType string)
AddToExtends(fType string)
AddToAggregation(fType string)
AddField(field *ast.Field, aliases <font color=blue>map</font>[string]string)
AddMethod(method *ast.Field, aliases <font color=blue>map</font>[string]string)

}
}
"strings.Builder" *-- "parser.LineStringBuilder"


"parser.Struct" o-- "parser.Function"
"parser.Struct" o-- "parser.Field"
"parser.Function" o-- "parser.Field"
"parser.Struct" o-- "parser.Field"
"parser.Struct" o-- "parser.Function"

@enduml
2 changes: 2 additions & 0 deletions generate_diagram
Original file line number Diff line number Diff line change
@@ -0,0 1,2 @@
#!/bin/bash
go install ./... && goplantuml -show-aggregations -recursive -ignore="./testingsupport/" ./parser > ClassDiagram.puml
52 changes: 47 additions & 5 deletions parser/class_parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 21,7 @@ import (
"go/token"
"os"
"path/filepath"
"sort"
"strings"
"unicode"
)
Expand Down Expand Up @@ -297,13 298,27 @@ func getBasicType(theType ast.Expr) ast.Expr {
func (p *ClassParser) Render() string {
str := &LineStringBuilder{}
str.WriteLineWithDepth(0, "@startuml")
for pack, structures := range p.structure {

var packages []string
for pack := range p.structure {
packages = append(packages, pack)
}
sort.Strings(packages)
for _, pack := range packages {
structures := p.structure[pack]
p.renderStructures(pack, structures, str)

}
if p.renderingOptions.Aliases {
for name, alias := range p.allAliases {
renderAlias(name, alias, str)

var aliases []string
for a := range p.allAliases {
aliases = append(aliases, a)
}
sort.Strings(aliases)
for _, a := range aliases {
alias := p.allAliases[a]
renderAlias(alias, str)
}
}
if !p.renderingOptions.Fields {
Expand All @@ -322,7 337,16 @@ func (p *ClassParser) renderStructures(pack string, structures map[string]*Struc
extends := &LineStringBuilder{}
aggregations := &LineStringBuilder{}
str.WriteLineWithDepth(0, fmt.Sprintf(`namespace %s {`, pack))
for name, structure := range structures {

names := []string{}
for name := range structures {
names = append(names, name)
}

sort.Strings(names)

for _, name := range names {
structure := structures[name]
p.renderStructure(structure, pack, name, str, composition, extends, aggregations)
}
str.WriteLineWithDepth(0, fmt.Sprintf(`}`))
Expand All @@ -338,7 362,7 @@ func (p *ClassParser) renderStructures(pack string, structures map[string]*Struc
}
}

func renderAlias(name string, alias *Alias, str *LineStringBuilder) {
func renderAlias(alias *Alias, str *LineStringBuilder) {
str.WriteLineWithDepth(0, fmt.Sprintf(`"%s" #.. "%s"`, alias.Name, alias.AliasOf))
}

Expand Down Expand Up @@ -380,8 404,13 @@ func (p *ClassParser) renderStructure(structure *Struct, pack string, name strin
}

func (p *ClassParser) renderCompositions(structure *Struct, name string, composition *LineStringBuilder) {
orderedCompositions := []string{}

for c := range structure.Composition {
orderedCompositions = append(orderedCompositions, c)
}
sort.Strings(orderedCompositions)
for _, c := range orderedCompositions {
if !strings.Contains(c, ".") {
c = fmt.Sprintf("%s.%s", p.getPackageName(c, structure), c)
}
Expand All @@ -391,7 420,15 @@ func (p *ClassParser) renderCompositions(structure *Struct, name string, composi

func (p *ClassParser) renderAggregations(structure *Struct, name string, aggregations *LineStringBuilder) {

orderedAggregations := []string{}

for a := range structure.Aggregations {
orderedAggregations = append(orderedAggregations, a)
}

sort.Strings(orderedAggregations)

for _, a := range orderedAggregations {
if !strings.Contains(a, ".") {
a = fmt.Sprintf("%s.%s", p.getPackageName(a, structure), a)
}
Expand All @@ -411,7 448,12 @@ func (p *ClassParser) getPackageName(t string, st *Struct) string {
}
func (p *ClassParser) renderExtends(structure *Struct, name string, extends *LineStringBuilder) {

orderedExtends := []string{}
for c := range structure.Extends {
orderedExtends = append(orderedExtends, c)
}
sort.Strings(orderedExtends)
for _, c := range orderedExtends {
if !strings.Contains(c, ".") {
c = fmt.Sprintf("%s.%s", structure.PackageName, c)
}
Expand Down
10 changes: 4 additions & 6 deletions parser/class_parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -549,9 549,8 @@ func TestRender(t *testing.T) {
if err != nil {
t.Errorf("TestRender: expected no errors reading testing file, got %s", err.Error())
}
resultAlt, err := ioutil.ReadFile("../testingsupport/testingsupport alt.puml")
if string(result) != resultRender && string(resultAlt) != resultRender {
t.Errorf("TestRender: Expected renders to be the same as %s or %s, but got %s", result, resultAlt, resultRender)
if string(result) != resultRender {
t.Errorf("TestRender: Expected renders to be the same as %s , but got %s", result, resultRender)
}
}

Expand Down Expand Up @@ -579,9 578,8 @@ func TestMultipleFolders(t *testing.T) {
if err != nil {
t.Errorf("TestMultipleFolders: expected no errors reading testing file, got %s", err.Error())
}
resultAlt, err := ioutil.ReadFile("../testingsupport/subfolder1-2alt.puml")
if string(result) != resultRender && string(resultAlt) != resultRender {
t.Errorf("TestMultipleFolders: Expected renders to be the same as %s or %s, but got %s", result, resultAlt, resultRender)
if string(result) != resultRender {
t.Errorf("TestMultipleFolders: Expected renders to be the same as %s , but got %s", result, resultRender)
}
}

Expand Down
10 changes: 5 additions & 5 deletions testingsupport/subfolder1-2.puml
Original file line number Diff line number Diff line change
@@ -1,19 1,19 @@
@startuml
namespace subfolder3 {
interface SubfolderInterface {
namespace subfolder2 {
class Subfolder2 << (S,Aquamarine) >> {
SubfolderFunction() bool

}
}

"subfolder3.SubfolderInterface" <|-- "subfolder2.Subfolder2"

namespace subfolder2 {
class Subfolder2 << (S,Aquamarine) >> {
namespace subfolder3 {
interface SubfolderInterface {
SubfolderFunction() bool

}
}

"subfolder3.SubfolderInterface" <|-- "subfolder2.Subfolder2"

@enduml
19 changes: 0 additions & 19 deletions testingsupport/subfolder1-2alt.puml

This file was deleted.

15 changes: 0 additions & 15 deletions testingsupport/testingsupport alt.puml

This file was deleted.

0 comments on commit e0ac4f6

Please sign in to comment.