qmuntal / stateless

Go library for creating finite state machines
BSD 2-Clause "Simplified" License
942 stars 49 forks source link

rewrite ToGraph with gographviz #22

Closed okhowang closed 2 years ago

okhowang commented 3 years ago

close #21 I use gographviz to refactor ToGraph function features:

example code

package main

import (
    "context"
    "fmt"

    "github.com/qmuntal/stateless"
)

func main() {
    sm := stateless.NewStateMachine("a")
    sm.Configure("a").Permit("toB", "b").OnEntry(func(ctx context.Context, i ...interface{}) error {
        return nil
    })
    sm.Configure("b").InitialTransition("b_1").OnExit(func(ctx context.Context, i ...interface{}) error {
        return nil
    }).Permit("toC", "c")
    sm.Configure("b_1").SubstateOf("b").InitialTransition("b_1_1").Permit("toB2", "b_2")
    sm.Configure("b_2").SubstateOf("b")
    sm.Configure("b_1_1").SubstateOf("b_1")
    fmt.Println(sm.ToGraph())
}

exmaple output

digraph stateless {
    compound=true;
    rankdir=LR;
    "cluster_b_1-init"->b_1_1;
    "cluster_b-init"->"cluster_b_1-init"[ lhead=cluster_b_1 ];
    a->b_1_1[ label=toB, lhead=cluster_b ];
    b_1_1->c[ label=toC, ltail=cluster_b ];
    b_1_1->b_2[ label=toB2, ltail=cluster_b_1 ];
    "stateless-init"->a;
    subgraph cluster_b {
    label="b
----------
exit / func2";
    "cluster_b-init" [ label=init, shape=point ];
    b_2 [ label=b_2, shape=Mrecord ];
    subgraph cluster_b_1 {
    label=b_1;
    "cluster_b_1-init" [ label=init, shape=point ];
    b_1_1 [ label=b_1_1, shape=Mrecord ];

}
;

}
;
    "stateless-init" [ label=init, shape=point ];
    a [ label="a|entry / func1", shape=Mrecord ];
    c;

}

image

qmuntal commented 3 years ago

Thanks for take a stab on this issue @okhowang, but I would rather keep the graph generator with the current design. It currently just has 138 lines of code and the logic is quite simple, so adding an external dependency will increase the complexity with few added value.

Do you see an easy way to fix #21 without using gographviz?

okhowang commented 3 years ago

Escape in graphviz is a little complex logic which is about 100 line in gographviz. ToGraph remain bug if we don't add Escape to it. gographviz is used only in ToGraph. it do not effect core code in stateless. PS: gographviz is a pure go project.

jairobjunior commented 2 years ago

@qmuntal After @okhowang's comment, do you have any feedback on this issue?

@qmuntal is the complexity you're talking about that much higher that justifies having a buggy feature?

qmuntal commented 2 years ago

@qmuntal After @okhowang's comment, do you have any feedback on this issue?

@qmuntal is the complexity you're talking about that much higher that justifies having a buggy feature?

@jairobjunior I plan to fix the graph export functionality soon without importing gographviz. I almost have it done.

qmuntal commented 2 years ago

Fixed in d97731633b8155699d8c14872789ba1702ac1376:

digraph {
    compound=true;
    node [shape=Mrecord];
    rankdir=LR;

    a [label="a|entry / func1"];
    subgraph cluster_b {
        label="b\n----------\nexit / func2";
        "cluster_b-init" [label="", shape=point];
        subgraph cluster_b_1 {
            label="b_1";
            "cluster_b_1-init" [label="", shape=point];
            b_1_1 [label="b_1_1"];
        }
        b_2 [label="b_2"];
    }
    "cluster_b-init" -> b_1_1 [label="", lhead="cluster_b_1"];
    "cluster_b_1-init" -> b_1_1 [label=""];
    b_1_1 -> b_2 [label="toB2", ltail="cluster_b_1"];
    b_1_1 -> c [label="toC", ltail="cluster_b_1"];
    a -> b_1_1 [label="toB", lhead="cluster_b"];
    init [label="", shape=point];
    init -> a
}

image