読者です 読者をやめる 読者になる 読者になる

hitode909の日記

趣味はマリンスポーツですの日記です

Perlのモジュールを静的解析してPlantUMLでクラス図をレンダリングするやつ

仕事のコードで,子クラスがたくさんいる難しいクラスがいて,継承関係を整理したいけど,どこがどうなってるのか一見すると分からなかったので,静的解析してクラス図をレンダリングするやつを作った.

github.com

  1. package2plantumlclassdiagramっていうコマンド(長い)に,このファイルたちをレンダリングしてくれ,って渡して,PlantUML形式のファイルを作る
  2. PlantUMLでPNGとかに変換

という手順で使う.

% package2plantumlclassdiagram ~/Plack/lib/**/**.pm > plack.plantuml
% GRAPHVIZ_DOT=$(which dot) plantuml -charset UTF-8 -tpng plack.plantuml


Plackのソースコード全体をレンダリングするとこんなかんじで,継承してると,これ継承してますよ,とか出てくる.実際にはアプリケーション全部やらずに,一部のネームスペースだけやったほうが便利.

f:id:hitode909:20151012184050p:plain

オリジナルサイズの画像はこちら(でかい)

このコマンド自体は,こういうテキストを生成しているだけで,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には上げてない.意外と使えるとか分かったら上げるかも.