ソフトウェア/pukiwiki/uml.inc.php のバックアップ(No.7)

更新


公開メモ

UML を貼るためのプラグインです

このように書くと、

&uml(
[*] -> コマンド待ち
コマンド待ち: rready = 1
コマンド待ち: rvalid = 0
コマンド待ち --> 読み出し: arvalid & \narready
読み出し: rready = 0
読み出し: rvalid = 0
読み出し-right--> 結果送信: 読み出し終了
結果送信: rready = 0
結果送信: rvalid = 1
結果送信 --> コマンド待ち : rready
);

こう表示されます。

&uml( [*] -> コマンド待ち コマンド待ち: rready = 1 コマンド待ち: rvalid = 0 コマンド待ち --> 読み出し: arvalid & \narready 読み出し: rready = 0 読み出し: rvalid = 0 読み出し-right--> 結果送信: 読み出し終了 結果送信: rready = 0 結果送信: rvalid = 1 結果送信 --> コマンド待ち : rready );

先頭に "skinparam handwritten true" という行を加えると、 手書き風にもできます。

&uml( skinparam handwritten true

[*] -> コマンド待ち コマンド待ち: rready = 1 コマンド待ち: rvalid = 0 コマンド待ち --> 読み出し: arvalid & \narready 読み出し: rready = 0 読み出し: rvalid = 0 読み出し-right--> 結果送信: 読み出し終了 結果送信: rready = 0 結果送信: rvalid = 1 結果送信 --> コマンド待ち : rready );

謝辞

図の作成には PlantUML を利用させていただきました

http://ja.plantuml.com/

/usr/local/bin に plantuml.jar を置いて使っています。

表示には、

ダーツフォント
http://www.p-darts.jp/font/dartsfont/

を使わせていただきました。

cdn.rawgit.com で公開されているようでしたので、そちらを参照するようにしています。

ソースファイル

cache/uml_svg/ というフォルダの下に .svg ファイルをキャッシュします。

plugin/uml.inc.php

LANG:php
<?php

$plugin_uml_initialized = false;

function plantuml($source)
{
    $tmp = tempnam("/tmp", "plantuml");

    if (preg_match('/skinparam\s+handwritten\s+true/', $source)) {
      $source = <<<"EOS"
@startuml
skinparam defaultFontName dartsfont
skinparam defaultFontStyle bold
skinparam monochrome true
skinparam shadowing false
$source
@enduml
EOS;
    } else {
      $source = <<<"EOS"
@startuml
skinparam defaultFontName umldefault
$source
@enduml
EOS;
    }

    $handle = fopen($tmp, "w");
    fwrite($handle, preg_replace("/\\r?\\n/","\r\n",$source));
    fclose($handle);
    system("/usr/bin/java -Dfile.encoding=utf-8 -jar /usr/local/bin/plantuml.jar ".$tmp." -tsvg");
    unlink($tmp);

    $svg = file_get_contents($tmp.".svg");
    unlink($tmp.".svg");

    return preg_replace('/^<\\?xml.*?>/', '', $svg);
}

function plantuml_convert($source)
{
    $image_base = sha1($source);
    $image_dir = "cache/uml_svg/{$image_base[0]}/{$image_base[1]}";
    $image_svg = "{$image_dir}/{$image_base}.svg";

    if(!file_exists($image_svg)) {
        $svg = plantuml($source);
        
        if (mb_substr($svg,0,4)=="<svg") {
            if(!file_exists($image_dir)){
                mkdir($image_dir, 0770, true);
            }
            $fh = fopen($image_svg, "w");
            fwrite($fh, $svg);
            fclose($fh);
        }
    } else {
        $svg = file_get_contents($image_svg);
    }

    return $svg;
}

function plugin_uml_header()
{
    $style = '';
    global $plugin_uml_initialized;
    if (!$plugin_uml_initialized) {
      $style = <<<'EOS'
<style type="text/css">
@font-face {
  font-family: "dartsfont";
  src: url("http://dora.bk.tsukuba.ac.jp/~takeuchi/skin/font/dartsfont.eot?#iefix") format('eot'),
       url("http://dora.bk.tsukuba.ac.jp/~takeuchi/skin/font/dartsfont.woff") format('woff');
}

svg text[font-family="dartsfont"] {
  font-family: "dartsfont";
}

svg text[font-family="umldefault"] {
  font-family:Arial,Helvetica,'ヒラギノ角ゴ Pro W3','Hiragino Kaku Gothic Pro','メイリオ',Meiryo,'MS Pゴシック',sans-serif;
}
</style>
EOS;
      $plugin_uml_initialized = true;
    }
    return $style;
}

function plugin_uml_inline()
{
    $aryargs = func_get_args();
    $source = join(",", $aryargs);
    $source = rtrim($source, ",");  //remove extra comma at the end.
    $source = str_replace("<br>", "\n",$source);

    $style = plugin_uml_header();
    return $style . plantuml_convert($source);
}

?>

pukiwiki.php の改造

複数行のパラメータを渡せるように、次のように改造しました。

LANG:php
//      $body  = convert_html(get_source($base));

        $lines = get_source($base); 

        for($i=0;$i<count($lines);$i++)
            if (preg_match('/\&uml\(/', $lines[$i]) && $lines[$i][0]!=' ') 
                while(!preg_match('/\&uml\(.*?\)\;/', $lines[$i]) && ($i+1<count($lines)))
                    array_splice($lines, $i, 2, chop($lines[$i]) . '<br>' . $lines[$i+1] );

        $body  = convert_html($lines);

plantuml のソースコードを簡単に書くには

こちらが参考になりそうです。

Qiita - AtomとPlantUMLで爆速UMLモデリング
http://qiita.com/nakahashi/items/3d88655f055ca6a2617c

Windows7 64bit 上でリアルタイムに図を確認できました。

atom-plugim-plantuml.png

以下では Sublime 3 でも似たようなことができると書かれているのですが、

http://qiita.com/ogomr/items/0b5c4de7f38fd1482a48

まだうまくいってません。

使用例

http://ja.plantuml.com/ の例をいくつか。

skinparam handwritten true

actor Foo1
boundary Foo2
control Foo3
entity Foo4
database Foo5
Foo1 -> Foo2 : To boundary
Foo1 -> Foo3 : To control
Foo1 -> Foo4 : To entity
Foo1 -> Foo5 : To database

&uml( skinparam handwritten true

actor Foo1 boundary Foo2 control Foo3 entity Foo4 database Foo5 Foo1 -> Foo2 : To boundary Foo1 -> Foo3 : To control Foo1 -> Foo4 : To entity Foo1 -> Foo5 : To database );

handwritten true が無ければ次のようになります。

&uml( actor Foo1 boundary Foo2 control Foo3 entity Foo4 database Foo5 Foo1 -> Foo2 : To boundary Foo1 -> Foo3 : To control Foo1 -> Foo4 : To entity Foo1 -> Foo5 : To database );

skinparam handwritten true

:Main Admin: as Admin
 (Use the application) as (Use)

User -> (Start)
User --> (Use)

Admin ---> (Use)

note right of Admin : This is an example.

note right of (Use)
  A note can also
  be on several lines
end note

note "This note is connected\nto several objects." as N2
(Start) .. N2
N2 .. (Use)

&uml( skinparam handwritten true

:Main Admin: as Admin (Use the application) as (Use)

User -> (Start) User --> (Use)

Admin ---> (Use)

note right of Admin : This is an example.

note right of (Use)

 A note can also
 be on several lines

end note

note "This note is connected\nto several objects." as N2 (Start) .. N2 N2 .. (Use) );

package "Classic Collections" #DDDDDD {
abstract class AbstractList
abstract AbstractCollection
interface List
interface Collection
}

List <|-- AbstractList
Collection <|-- AbstractCollection

Collection <|- List
AbstractCollection <|- AbstractList

AbstractList <|-- ArrayList

class ArrayList {
  Object[] elementData
  size()
}

enum TimeUnit {
  DAYS
  HOURS
  MINUTES
}

annotation SuppressWarnings

&uml( package "Classic Collections" #DDDDDD { abstract class AbstractList abstract AbstractCollection interface List interface Collection }

List <|-- AbstractList Collection <|-- AbstractCollection

Collection <|- List AbstractCollection <|- AbstractList

AbstractList <|-- ArrayList

class ArrayList {

 Object[] elementData
 size()

}

enum TimeUnit {

 DAYS
 HOURS
 MINUTES

}

annotation SuppressWarnings );

start
:ClickServlet.handleRequest() ;
:new page;
if (Page.onSecurityCheck) then (true)
  :Page.onInit() ;
  if (isForward?) then (no)
    :Process controls;
    if (continue processing?) then (no)
      stop
    endif
    
    if (isPost?) then (yes)
      :Page.onPost() ;
    else (no)
      :Page.onGet() ;
    endif
    :Page.onRender() ;
  endif
else (false)
endif

if (do redirect?) then (yes)
  :redirect process;
else
  if (do forward?) then (yes)
    :Forward request;
  else (no)
    :Render page template;
  endif
endif

stop

&uml( start :ClickServlet.handleRequest() ; :new page; if (Page.onSecurityCheck) then (true)

 :Page.onInit() ;
 if (isForward?) then (no)
   :Process controls;
   if (continue processing?) then (no)
     stop
   endif
   
   if (isPost?) then (yes)
     :Page.onPost() ;
   else (no)
     :Page.onGet() ;
   endif
   :Page.onRender() ;
 endif

else (false) endif

if (do redirect?) then (yes)

 :redirect process;

else

 if (do forward?) then (yes)
   :Forward request;
 else (no)
   :Render page template;
 endif

endif

stop );

質問・コメント




pukiwikiの改造について

()

便利に使わせてもらっています。

 lib/pukiwiki.phpですが、こちらの環境では$lines = get_source($base);
を追加したら動くようになりました。(1.5.1)

ご参考まで。

  • ご指摘ありがとうございます。本当ですね、一行抜けていました。本文を修正いたしました。 -- 武内 (管理人)?

Counter: 5952 (from 2010/06/03), today: 2, yesterday: 0