Skip to content

Commit

Permalink
Merge pull request #73 from jfeliu007/issue-58
Browse files Browse the repository at this point in the history
Enhancement: Additional CLI options to control rendered output -label-edges
  • Loading branch information
jfeliu007 authored Oct 26, 2019
2 parents 625bce6 + d8f1722 commit 8f7983f
Show file tree
Hide file tree
Showing 7 changed files with 232 additions and 101 deletions.
15 changes: 10 additions & 5 deletions ClassDiagram.puml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ namespace parser {
- handleFuncDecl(decl *ast.FuncDecl)
- handleGenDecl(decl *ast.GenDecl)
- renderStructures(pack string, structures <font color=blue>map</font>[string]*Struct, str *LineStringBuilder)
- renderAliases(str *LineStringBuilder)
- renderStructure(structure *Struct, pack string, name string, str *LineStringBuilder, composition *LineStringBuilder, extends *LineStringBuilder, aggregations *LineStringBuilder)
- renderCompositions(structure *Struct, name string, composition *LineStringBuilder)
- renderAggregations(structure *Struct, name string, aggregations *LineStringBuilder)
Expand All @@ -33,7 +34,7 @@ namespace parser {
- getStruct(structName string) *Struct

+ Render() string
+ SetRenderingOptions(ro *RenderingOptions)
+ SetRenderingOptions(ro <font color=blue>map</font>[RenderingOption]bool) error

}
class Field << (S,Aquamarine) >> {
Expand Down Expand Up @@ -63,6 +64,7 @@ namespace parser {
+ Compositions bool
+ Implementations bool
+ Aliases bool
+ ConnectionLabels bool

}
class Struct << (S,Aquamarine) >> {
Expand All @@ -82,12 +84,15 @@ namespace parser {
+ AddMethod(method *ast.Field, aliases <font color=blue>map</font>[string]string)

}
class parser.RenderingOption << (T, #FF7700) >> {
}
}
"strings.Builder" *-- "parser.LineStringBuilder"
"strings.Builder" *-- "extends""parser.LineStringBuilder"


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

"__builtin__.int" #.. "alias of""parser.RenderingOption"
@enduml
20 changes: 11 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,23 +34,25 @@ goplantuml [-recursive] path/to/gofiles path/to/gofiles2 > diagram_file_name.pum
```
Usage of goplantuml:
-hide-connections
hides all connections in the diagram
hides all connections in the diagram
-hide-fields
hides fields
hides fields
-hide-methods
hides methods
hides methods
-ignore string
comma separated list of folders to ignore
comma separated list of folders to ignore
-recursive
walk all directories recursively
walk all directories recursively
-show-aggregations
renders public aggregations
renders public aggregations even when -hide-connections is used (do not render by default)
-show-aliases
Shows aliases even when -hide-connections is used (default true)
Shows aliases even when -hide-connections is used
-show-compositions
Shows compositions even when -hide-connections is used (default true)
Shows compositions even when -hide-connections is used
-show-connection-labels
Shows labels in the connections to identify the connections types (e.g. extends, implements, aggregates, alias of
-show-implementations
Shows implementations even when -hide-connections is used (default true)
Shows implementations even when -hide-connections is used
```

#### Example
Expand Down
30 changes: 18 additions & 12 deletions cmd/goplantuml/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,14 @@ import (
func main() {
recursive := flag.Bool("recursive", false, "walk all directories recursively")
ignore := flag.String("ignore", "", "comma separated list of folders to ignore")
showAggregations := flag.Bool("show-aggregations", false, "renders public aggregations")
showAggregations := flag.Bool("show-aggregations", false, "renders public aggregations even when -hide-connections is used (do not render by default)")
hideFields := flag.Bool("hide-fields", false, "hides fields")
hideMethods := flag.Bool("hide-methods", false, "hides methods")
hideConnections := flag.Bool("hide-connections", false, "hides all connections in the diagram")
showCompositions := flag.Bool("show-compositions", true, "Shows compositions even when -hide-connections is used")
showImplementations := flag.Bool("show-implementations", true, "Shows implementations even when -hide-connections is used")
showAliases := flag.Bool("show-aliases", true, "Shows aliases even when -hide-connections is used")
showCompositions := flag.Bool("show-compositions", false, "Shows compositions even when -hide-connections is used")
showImplementations := flag.Bool("show-implementations", false, "Shows implementations even when -hide-connections is used")
showAliases := flag.Bool("show-aliases", false, "Shows aliases even when -hide-connections is used")
showConnectionLabels := flag.Bool("show-connection-labels", false, "Shows labels in the connections to identify the connections types (e.g. extends, implements, aggregates, alias of")

flag.Parse()
dirs, err := getDirectories()
Expand All @@ -37,16 +38,21 @@ func main() {
fmt.Println(err.Error())
os.Exit(1)
}
renderingOptions := map[goplantuml.RenderingOption]bool{
goplantuml.RenderConnectionLabels: *showConnectionLabels,
goplantuml.RenderFields: !*hideFields,
goplantuml.RenderMethods: !*hideMethods,
goplantuml.RenderAggregations: *showAggregations,
}
if *hideConnections {
renderingOptions[goplantuml.RenderAliases] = *showAliases
renderingOptions[goplantuml.RenderCompositions] = *showCompositions
renderingOptions[goplantuml.RenderImplementations] = *showImplementations

}

result, err := goplantuml.NewClassDiagram(dirs, ignoredDirectories, *recursive)
result.SetRenderingOptions(&goplantuml.RenderingOptions{
Aggregations: *showAggregations && !*hideConnections,
Fields: !*hideFields,
Methods: !*hideMethods,
Compositions: *showCompositions && !*hideConnections,
Implementations: *showImplementations && !*hideConnections,
Aliases: *showAliases && !*hideConnections,
})
result.SetRenderingOptions(renderingOptions)
if err != nil {
fmt.Println(err.Error())
os.Exit(1)
Expand Down
2 changes: 1 addition & 1 deletion generate_diagram
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
#!/bin/bash
go install ./... && goplantuml -show-aggregations -recursive -ignore="./testingsupport/" ./parser > ClassDiagram.puml
go install ./... && goplantuml -show-connection-labels -show-aggregations -recursive -ignore="./testingsupport/" ./parser > ClassDiagram.puml
124 changes: 95 additions & 29 deletions parser/class_parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ type LineStringBuilder struct {

const tab = " "
const builtinPackageName = "__builtin__"
const implements = `"implements"`
const extends = `"extends"`
const aggregates = `"uses"`
const aliasOf = `"alias of"`

//WriteLineWithDepth will write the given text with added tabs at the beginning into the string builder.
func (lsb *LineStringBuilder) WriteLineWithDepth(depth int, str string) {
Expand All @@ -44,14 +48,39 @@ func (lsb *LineStringBuilder) WriteLineWithDepth(depth int, str string) {

//RenderingOptions will allow the class parser to optionally enebale or disable the things to render.
type RenderingOptions struct {
Aggregations bool
Fields bool
Methods bool
Compositions bool
Implementations bool
Aliases bool
Aggregations bool
Fields bool
Methods bool
Compositions bool
Implementations bool
Aliases bool
ConnectionLabels bool
}

//RenderAggregations is to be used in the SetRenderingOptions argument as the key to the map, when value is true, it will set the parser to render aggregations
const RenderAggregations = 0

//RenderCompositions is to be used in the SetRenderingOptions argument as the key to the map, when value is true, it will set the parser to render compositions
const RenderCompositions = 1

//RenderImplementations is to be used in the SetRenderingOptions argument as the key to the map, when value is true, it will set the parser to render implementations
const RenderImplementations = 2

//RenderAliases is to be used in the SetRenderingOptions argument as the key to the map, when value is true, it will set the parser to render aliases
const RenderAliases = 3

//RenderFields is to be used in the SetRenderingOptions argument as the key to the map, when value is true, it will set the parser to render fields
const RenderFields = 4

//RenderMethods is to be used in the SetRenderingOptions argument as the key to the map, when value is true, it will set the parser to render methods
const RenderMethods = 5

//RenderConnectionLabels is to be used in the SetRenderingOptions argument as the key to the map, when value is true, it will set the parser to render the connection labels
const RenderConnectionLabels = 6

//RenderingOption is an alias for an it so it is easier to use it as options in a map (see SetRenderingOptions(map[RenderingOption]bool) error)
type RenderingOption int

//ClassParser contains the structure of the parsed files. The structure is a map of package_names that contains
//a map of structure_names -> Structs
type ClassParser struct {
Expand All @@ -69,12 +98,13 @@ type ClassParser struct {
func NewClassDiagram(directoryPaths []string, ignoreDirectories []string, recursive bool) (*ClassParser, error) {
classParser := &ClassParser{
renderingOptions: &RenderingOptions{
Aggregations: false,
Fields: true,
Methods: true,
Compositions: true,
Implementations: true,
Aliases: true,
Aggregations: false,
Fields: true,
Methods: true,
Compositions: true,
Implementations: true,
Aliases: true,
ConnectionLabels: false,
},
structure: make(map[string]map[string]*Struct),
allInterfaces: make(map[string]struct{}),
Expand Down Expand Up @@ -310,16 +340,7 @@ func (p *ClassParser) Render() string {

}
if p.renderingOptions.Aliases {

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)
}
p.renderAliases(str)
}
if !p.renderingOptions.Fields {
str.WriteLineWithDepth(0, "hide fields")
Expand Down Expand Up @@ -362,8 +383,20 @@ func (p *ClassParser) renderStructures(pack string, structures map[string]*Struc
}
}

func renderAlias(alias *Alias, str *LineStringBuilder) {
str.WriteLineWithDepth(0, fmt.Sprintf(`"%s" #.. "%s"`, alias.Name, alias.AliasOf))
func (p *ClassParser) renderAliases(str *LineStringBuilder) {

aliasString := ""
if p.renderingOptions.ConnectionLabels {
aliasString = aliasOf
}
orderedAliases := []string{}
for name := range p.allAliases {
orderedAliases = append(orderedAliases, name)
}
for _, name := range orderedAliases {
alias := p.allAliases[name]
str.WriteLineWithDepth(0, fmt.Sprintf(`"%s" #.. %s"%s"`, alias.Name, aliasString, alias.AliasOf))
}
}

func (p *ClassParser) renderStructure(structure *Struct, pack string, name string, str *LineStringBuilder, composition *LineStringBuilder, extends *LineStringBuilder, aggregations *LineStringBuilder) {
Expand Down Expand Up @@ -414,7 +447,11 @@ func (p *ClassParser) renderCompositions(structure *Struct, name string, composi
if !strings.Contains(c, ".") {
c = fmt.Sprintf("%s.%s", p.getPackageName(c, structure), c)
}
composition.WriteLineWithDepth(0, fmt.Sprintf(`"%s" *-- "%s.%s"`, c, structure.PackageName, name))
composedString := ""
if p.renderingOptions.ConnectionLabels {
composedString = extends
}
composition.WriteLineWithDepth(0, fmt.Sprintf(`"%s" *-- %s"%s.%s"`, c, composedString, structure.PackageName, name))
}
}

Expand All @@ -432,8 +469,12 @@ func (p *ClassParser) renderAggregations(structure *Struct, name string, aggrega
if !strings.Contains(a, ".") {
a = fmt.Sprintf("%s.%s", p.getPackageName(a, structure), a)
}
aggregationString := ""
if p.renderingOptions.ConnectionLabels {
aggregationString = aggregates
}
if p.getPackageName(a, structure) != builtinPackageName {
aggregations.WriteLineWithDepth(0, fmt.Sprintf(`"%s.%s" o-- "%s"`, structure.PackageName, name, a))
aggregations.WriteLineWithDepth(0, fmt.Sprintf(`"%s.%s"%s o-- "%s"`, structure.PackageName, name, aggregationString, a))
}
}
}
Expand All @@ -457,7 +498,11 @@ func (p *ClassParser) renderExtends(structure *Struct, name string, extends *Lin
if !strings.Contains(c, ".") {
c = fmt.Sprintf("%s.%s", structure.PackageName, c)
}
extends.WriteLineWithDepth(0, fmt.Sprintf(`"%s" <|-- "%s.%s"`, c, structure.PackageName, name))
implementString := ""
if p.renderingOptions.ConnectionLabels {
implementString = implements
}
extends.WriteLineWithDepth(0, fmt.Sprintf(`"%s" <|-- %s"%s.%s"`, c, implementString, structure.PackageName, name))
}
}

Expand Down Expand Up @@ -531,6 +576,27 @@ func (p *ClassParser) getStruct(structName string) *Struct {
}

//SetRenderingOptions Sets the rendering options for the Render() Function
func (p *ClassParser) SetRenderingOptions(ro *RenderingOptions) {
p.renderingOptions = ro
func (p *ClassParser) SetRenderingOptions(ro map[RenderingOption]bool) error {
for option, val := range ro {
switch option {
case RenderAggregations:
p.renderingOptions.Aggregations = val
case RenderAliases:
p.renderingOptions.Aliases = val
case RenderCompositions:
p.renderingOptions.Compositions = val
case RenderFields:
p.renderingOptions.Fields = val
case RenderImplementations:
p.renderingOptions.Implementations = val
case RenderMethods:
p.renderingOptions.Methods = val
case RenderConnectionLabels:
p.renderingOptions.ConnectionLabels = val
default:
return fmt.Errorf("Invalid Rendering option %v", option)
}

}
return nil
}
Loading

0 comments on commit 8f7983f

Please sign in to comment.