仕事のコードで,子クラスがたくさんいる難しいクラスがいて,継承関係を整理したいけど,どこがどうなってるのか一見すると分からなかったので,静的解析してクラス図をレンダリングするやつを作った.
- 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::Shotgun
PPIでソースコードを解析して,メソッド名が_から始まったら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には上げてない.意外と使えるとか分かったら上げるかも.