Skip to content

Commit 9470d31

Browse files
authored
Fanin fanout (#20)
* [WIP] Fanout * 中間ノードでFanout funcの呼び出しは不可 * Fanin * modify checklist * update
1 parent a09158c commit 9470d31

File tree

9 files changed

+231
-4
lines changed

9 files changed

+231
-4
lines changed

README.md

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,53 @@ func main() {
301301
- [x] finish
302302

303303
## Miscellaneous
304+
305+
### FanIn/FanOut
306+
> **Warning**<br>
307+
> Continued calls to Fanin/Fanout func will result in panic.<br>
308+
> e.g. ❌t.Fanout(n1).Fanout(n2) / ❌Fanin(t.Fanout(n1))
309+
310+
1. Fanin/Fanout func usage
311+
```go
312+
package main
313+
314+
import (
315+
"fmt"
316+
"os"
317+
318+
g "github.com/ddddddO/gdag"
319+
)
320+
321+
func main() {
322+
dag := g.DAG("Fanin/Fanout")
323+
task1 := g.Task("task1")
324+
task2 := g.Task("task2")
325+
task3 := g.Task("task3")
326+
task4 := g.Task("task4")
327+
328+
// block1
329+
dag.Fanout(task1, task2, task3).Con(task4)
330+
task5 := task4.Con(g.Task("task5"))
331+
task6 := task4.Con(g.Task("task6"))
332+
task7 := task4.Con(g.Task("task7"))
333+
g.Fanin(task5, task6, task7).Con(g.Task("end"))
334+
335+
// block2
336+
// dag.Fanout(task1, task2, task3).Con(task4).Fanout(g.Task("task5"), g.Task("task6"), g.Task("task7")).Con(g.Task("end"))
337+
338+
uml, err := dag.UML()
339+
if err != nil {
340+
fmt.Fprintln(os.Stderr, err)
341+
os.Exit(1)
342+
}
343+
fmt.Println(uml)
344+
}
345+
```
346+
- `block1` and `block2` are same result.
347+
348+
2. Result
349+
![](./_example/fanin_fanout/uml.svg)
350+
304351
### short name methods
305352

306353
```go

_example/fanin_fanout/main.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
"os"
6+
7+
g "github.com/ddddddO/gdag"
8+
)
9+
10+
func main() {
11+
dag := g.DAG("Fanin/Fanout")
12+
task1 := g.Task("task1")
13+
task2 := g.Task("task2")
14+
task3 := g.Task("task3")
15+
task4 := g.Task("task4")
16+
17+
// block1
18+
dag.Fanout(task1, task2, task3).Con(task4)
19+
task5 := task4.Con(g.Task("task5"))
20+
task6 := task4.Con(g.Task("task6"))
21+
task7 := task4.Con(g.Task("task7"))
22+
g.Fanin(task5, task6, task7).Con(g.Task("end"))
23+
24+
// block2
25+
// dag.Fanout(task1, task2, task3).Con(task4).Fanout(g.Task("task5"), g.Task("task6"), g.Task("task7")).Con(g.Task("end"))
26+
27+
uml, err := dag.UML()
28+
if err != nil {
29+
fmt.Fprintln(os.Stderr, err)
30+
os.Exit(1)
31+
}
32+
fmt.Println(uml)
33+
}

_example/fanin_fanout/uml.pu

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
@startuml
2+
rectangle "Fanin/Fanout" as 1
3+
usecase "task1" as 2
4+
usecase "task4" as 5
5+
usecase "task5" as 7
6+
usecase "end" as 11
7+
usecase "task6" as 8
8+
usecase "task7" as 9
9+
usecase "task2" as 3
10+
usecase "task3" as 4
11+
12+
1 --> 2
13+
2 --> 5
14+
5 --> 7
15+
7 --> 11
16+
5 --> 8
17+
8 --> 11
18+
5 --> 9
19+
9 --> 11
20+
1 --> 3
21+
3 --> 5
22+
1 --> 4
23+
4 --> 5
24+
25+
@enduml

_example/fanin_fanout/uml.svg

Lines changed: 48 additions & 0 deletions
Loading

_example/system_failure_response/main.go

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,12 @@ func main() {
2020
end := g.Task("終了")
2121

2222
flow.Con(checkEvent).Con(checkMatter)
23-
checkMatter.Con(checkBusinessImpact).Con(recoveryResponse)
24-
checkMatter.Con(checkCause).Con(recoveryResponse)
23+
24+
checkMatter.Fanout(checkBusinessImpact, checkCause).Con(recoveryResponse)
25+
// Fanout method is same below.
26+
// checkMatter.Con(checkBusinessImpact).Con(recoveryResponse)
27+
// checkMatter.Con(checkCause).Con(recoveryResponse)
28+
2529
recoveryResponse.Con(permanentResponse)
2630
permanentResponse.Con(faultAnalysis)
2731
permanentResponse.Con(recurrencePreventionMeasures)
@@ -34,4 +38,11 @@ func main() {
3438
os.Exit(1)
3539
}
3640
fmt.Println(uml)
41+
42+
// mermaid, err := flow.Mermaid()
43+
// if err != nil {
44+
// fmt.Fprintln(os.Stderr, err)
45+
// os.Exit(1)
46+
// }
47+
// fmt.Println(mermaid)
3748
}

checklist.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,9 @@ func (*checkListGenerator) renderRow(node *Node) string {
6363
if node.isDone() {
6464
return fmt.Sprintf("- [x] %s\n", node.text)
6565
} else {
66+
if node.nodeType == intermediate {
67+
return ""
68+
}
6669
return fmt.Sprintf("- [ ] %s\n", node.text)
6770
}
6871
}

mermaid.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@ func (*mermaidGenerator) renderComponent(node *Node) string {
4848
ret := ""
4949
// TODO: mermaid用に修正するかどうか。リファクタは必要
5050
switch node.nodeType {
51+
case intermediate:
52+
break
5153
case rectangle:
5254
s := fmt.Sprintf("%d(\"%s\")", node.index, node.text)
5355
if len(node.colorMermaid) != 0 {
@@ -76,8 +78,17 @@ func (mg *mermaidGenerator) generateRelations(start *Node) string {
7678

7779
func (mg *mermaidGenerator) generateRelation(node *Node, out string) string {
7880
edge := fmt.Sprintf("%d --> ", node.index)
81+
if node.nodeType == intermediate {
82+
edge = fmt.Sprintf("%d --> ", node.parent.index)
83+
}
84+
7985
ret := out
8086
for _, d := range node.downstream {
87+
if d.nodeType == intermediate {
88+
ret += mg.generateRelation(d, "")
89+
continue
90+
}
91+
8192
key := fmt.Sprintf("%d-%d", node.index, d.index)
8293
if _, ok := mg.uniqueRelations[key]; ok {
8394
continue

node.go

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,16 @@ type Node struct {
88
color string // done: #DarkGray
99
colorMermaid string // done: doneColor
1010

11+
parent *Node // TODO: 現状、中間ノードのためにおいてる
1112
downstream []*Node
1213
}
1314

1415
type nodeType string
1516

1617
const (
17-
rectangle = nodeType("rectangle")
18-
usecase = nodeType("usecase")
18+
intermediate = nodeType("intermediate node")
19+
rectangle = nodeType("rectangle")
20+
usecase = nodeType("usecase")
1921
)
2022

2123
func DAG(text string) *Node {
@@ -51,6 +53,13 @@ func Done(nodes ...*Node) {
5153
}
5254

5355
func (upstream *Node) Con(current *Node) *Node {
56+
if upstream.nodeType == intermediate {
57+
for i := range upstream.downstream {
58+
upstream.downstream[i].downstream = append(upstream.downstream[i].downstream, current)
59+
}
60+
return current
61+
}
62+
5463
for _, d := range upstream.downstream {
5564
if current.index == d.index {
5665
return d
@@ -61,6 +70,35 @@ func (upstream *Node) Con(current *Node) *Node {
6170
return current
6271
}
6372

73+
func Fanin(nodes ...*Node) *Node {
74+
for i := range nodes {
75+
nodes[i].invalid()
76+
}
77+
78+
intermediateNode := newNode(intermediate, "not output")
79+
intermediateNode.downstream = nodes
80+
return intermediateNode
81+
}
82+
83+
func (upstream *Node) Fanout(nodes ...*Node) *Node {
84+
upstream.invalid()
85+
86+
intermediateNode := newNode(intermediate, "not output")
87+
intermediateNode.downstream = nodes
88+
89+
intermediateNode.parent = upstream
90+
upstream.downstream = append(upstream.downstream, intermediateNode)
91+
return intermediateNode
92+
}
93+
94+
// TODO: refactor
95+
func (n *Node) invalid() {
96+
if n.nodeType == intermediate {
97+
// TODO: 後ほど、Fanout(n1, n2).Fanout(n3, n4)みたいに、中間ノードでもチェイン出来るようにしたい
98+
panic("Fanin/Fanout calls are not supported for intermediate node.")
99+
}
100+
}
101+
64102
func (current *Node) Note(note string) *Node {
65103
current.note = note
66104
return current

plantuml.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ func (ug *umlGenerator) generateComponent(node *Node) string {
4747
func (*umlGenerator) renderComponent(node *Node) string {
4848
ret := ""
4949
switch node.nodeType {
50+
case intermediate:
51+
break
5052
case rectangle, usecase:
5153
s := fmt.Sprintf("%s \"%s\" as %d", node.nodeType, node.text, node.index)
5254
if len(node.color) != 0 {
@@ -67,8 +69,17 @@ func (ug *umlGenerator) generateRelations(start *Node) string {
6769

6870
func (ug *umlGenerator) generateRelation(node *Node, out string) string {
6971
edge := fmt.Sprintf("%d --> ", node.index)
72+
if node.nodeType == intermediate {
73+
edge = fmt.Sprintf("%d --> ", node.parent.index)
74+
}
75+
7076
ret := out
7177
for _, d := range node.downstream {
78+
if d.nodeType == intermediate {
79+
ret += ug.generateRelation(d, "")
80+
continue
81+
}
82+
7283
key := fmt.Sprintf("%d-%d", node.index, d.index)
7384
if _, ok := ug.uniqueRelations[key]; ok {
7485
continue

0 commit comments

Comments
 (0)