仕事のコードで,子クラスがたくさんいる難しいクラスがいて,継承関係を整理したいけど,どこがどうなってるのか一見すると分からなかったので,静的解析してクラス図をレンダリングするやつを作った.
- package2plantumlclassdiagramっていうコマンド(長い)に,このファイルたちをレンダリングしてくれ,って渡して,PlantUML形式のファイルを作る
- PlantUMLでPNGとかに変換
という手順で使う.
% package2plantumlclassdiagram ~/Plack/lib/**/**.pm > plack.plantuml % GRAPHVIZ_DOT=$(which dot) plantuml -charset UTF-8 -tpng plack.plantuml
Plackのソースコード全体をレンダリングするとこんなかんじで,継承してると,これ継承してますよ,とか出てくる.実際にはアプリケーション全部やらずに,一部のネームスペースだけやったほうが便利.
このコマンド自体は,こういうテキストを生成しているだけで,PlantUMLがこれを見ていいかんじの図にしてくれる.
@startuml
class HTTP::Message::PSGI {
{static} new($content, $chunked)
+ req_to_psgi()
+ res_from_psgi($psgi_res)
+ HTTP::Request::to_psgi()
+ HTTP::Response::from_psgi()
+ read()
+ close()
- _res_from_psgi($status, $headers, $body)
}
class HTTP::Server::PSGI {
{static} new(%args)
+ BEGIN()
+ run($app)
+ prepare_socket_class($args)
+ setup_listener()
+ accept_loop($app)
+ handle_connection($env, $conn, $app)
+ do_timeout($cb, $timeout)
+ read_timeout($sock, $buf, $len, $off, $timeout)
+ write_timeout($sock, $buf, $len, $off, $timeout)
+ write_all($sock, $buf, $timeout)
- _handle_response($res, $conn)
- _encode()
}
...
Plack::Loader <|-- Plack::Loader::Delayed
Plack::Loader <|-- Plack::Loader::Restarter
Plack::Loader <|-- Plack::Loader::ShotgunPPIでソースコードを解析して,メソッド名が_から始まったらprivateとか,$classで受けてたらstaticにするとか,ややヒューリスティックな感じ.継承ツリーはuse parentかuse baseだったら,という感じで,PRTでやってたのと同様.
クラスの内容を省いて,継承関係をプロットするには,grepというコマンドを使います.
package2plantumlclassdiagram ~/Plack/lib/**/**.pm | ggrep -P '^(@startuml|@enduml)|(<|--)' > plack.plantuml
PerlのクラスのUMLを書くやつ,UML::Class::Simpleっていうのを前に使ってたけど,レンダリング対象のコードを実際にロードする必要があって,ちょっと使いにくかった.PRTを作ったときと同じ方法で,たんにファイルを開いて中身を見ていく方法でなんとかした.metacpan.org
PlantUMLについては前に日記に書いてた.テキストからUMLをレンダリングしてくれるやつで,テキストなのでリポジトリにつっこんでバージョン管理などしやすくて便利.hitode909.hatenablog.com
ヒューリスティックすぎるのでさすがにどうかと思ってCPANには上げてない.意外と使えるとか分かったら上げるかも.