Evaluatorプラグインを作る

Daisukeh 2009/02/24 14:13 初稿
Daisukeh 2009/02/24 21:33 校正
Daisukeh 2009/02/25 13:35 更新
Daisukeh 2009/08/06 15:09 移設

記事一覧

DokuWikiは素晴らしい

 DokuWiki:pluginsには400を超えるプラグインが存在しています。その分類を簡単に説明すると、DokuWikiの文法を拡張するSyntax、他のプラグインの補助をするHelperDokuWikiの管理を行うAdminWiki システムのイベントを拡張するAction、そして Wiki 文法からブラウザで閲覧できる HTMLCSS といったウェブ・コンテキストを作成するRenderがあります。一般的にはSyntaxに属するプラグインが多く存在していて、その中には「Chart2プラグインを使う」や「DivAlignプラグインを改造する」で紹介したような、便利で有用なプラグインがあります。

 一方でDokuWikiは、<php>や<html>というタグを使えば、 Wiki システムであるにもかかわらず、動的なコンテンツをページ内に内包することができます。この機能を標準搭載しているという点は、数ある Wiki システムの中でも少ないでしょう。もちろん他のシステムでもプラグインなどによって拡張は可能だと思いますし、自作のプラグインをコンテンツとして表示したり、 CMS と連携させることで同様の機能を持たせることも可能です。DokuWikiはそういう点で、遠回りする必要がなく、自然な形で Wiki ページを動的なコンテンツに変貌させることができる非常に強力な Wiki システムのひとつと言えるでしょう。たとえば、

<php> echo date('c'); </php>

と書けば、

2019-02-23T05:22:18+09:00

と表示されます。当たり前ですが、その当たり前が手軽にできてしまうのです。素晴らしいとは思いませんか?

一歩進んだ動的なページ

 ところで、PHPを使って動的なページを作成することは上記のサンプルが示すとおり、直接 Wiki にコードを書けばよいので、データベースでもファイルでも外部のネットワークでも、データが取得できるなら何でもPHPで作ればいいのですが、表示するデータそのものを Wiki 文法で表現したい場合はどうすればいいのでしょうか?たとえば、クライアントの種類に応じて表示を変更したり、時刻やシステムの状態に応じてコンテンツのデータだけでなく構成も変更したい場合などです。たとえばplugin:noteでは、<php>タグを内包できるので、内容を変更することは可能ですが、表示の有無やパラメータ(tipとかwarningなど)を変更することができるでしょうか?

「現在時刻は 2019-02-23T05:22:18+09:00 です。」
というように、内部で<php>タグを使うことはできます。

 これを可能にしようと試みたのが、ここで紹介する「Evaluatorプラグイン」です。他のプラグインを見よう見まねで作りましたが、何とか動いてくれました。LOL まずは「論より証拠」ということで、簡単なサンプルを下に示します。これは、現在時刻の秒が偶数か奇数かを判定して、plugin:noteのパラメータとメッセージを変更しています。

偶数でした。

plugin:evaluatorのサンプル

<eval>
<php>
  if((time() % 2) == 0) echo '<note>偶数でした。</note>';
  else                  echo '<note tip>奇数でした。</note>';
</php>
</eval>

ソースコード

 特に難しくないし短いコードなので、掲載してみました。関係ないけど、<code>タグでPHPのソースコードを表示させると、標準関数に自動的にリンクが張られているんですね!昨日まで知りませんでした。すごいね、DokuWiki

/lib/plugins/evaluator/syntax.php

<?php
 
/*
 * Evaluator Plugin : Evalute context as DokuWiki syntax (version 1.01)
 *
 * Usage :
 *    1. <eval> (re-evaluating context) </eval>
 *    2. <eval align="right|center|left">...</eval>
 *    3. <eval style="(inline CSS code)">...</eval>
 *    4. <eval type="text/css" src="(external CSS url)">...</eval>
 *    5. <eval type="text/javascript" src="(external Javascript url)">...</eval>
 *    6. <eval id="(ID)">...</eval>
 *    7. <eval class="(CLASS)">...</eval>
 *
 * Notes:
 *   1. Re-evaluate the context of internal capsule
 *   2. Specify position (right,center,left) of the context
 *   3. Apply stylesheet to the context
 *   4.  Specify an external style sheet
 *   5. Specify an external Javascript (or else languages)
 *   6. Apply tag ID to the context
 *   7. Apply tag class to the context
 *
 * @author       Daisukeh <cqn04630@nifty.com> (http://daisukeh.ddo.jp/)
 * @license      GPL2 (http://www.gnu.org/licenses/gpl.html)
 * 
 */
 
if(!defined('DOKU_INC')) define('DOKU_INC',realpath(dirname(__FILE__).'/../../').'/');
if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/');
require_once(DOKU_PLUGIN.'syntax.php');
 
class syntax_plugin_evaluator extends DokuWiki_Syntax_Plugin
{
  function getInfo()
  {
    return array(
      'author' => 'Daisukeh',
      'email'  => 'cqn04630@nifty.com',
      'date'   => '2009-02-24',
      'name'   => 'Evaluator Plugin',
      'desc'   => 'Evalute context as DokuWiki syntax '.
                  '(usage: <eval {options}> {context} </eval>)',
      'url'    => 'http://daisukeh.ddo.jp/',
    );
  }
 
  function getType()
  {
    return 'protected';
  }
 
  function connectTo($mode)
  {
    $this->Lexer->addEntryPattern('<eval.*?>(?=.*?</eval>)', $mode, 'plugin_evaluator');
  }
 
  function postConnect()
  {
    $this->Lexer->addExitPattern('</eval>', 'plugin_evaluator');
  }
 
  function handle($match, $state, $pos, &$handler)
  {
    switch($state)
    {
    case DOKU_LEXER_ENTER :
      $param = array();
      if(preg_match('/id="([^"]+)"/i',    $match, $pmch)) $param['id'   ] = $pmch[1];
      if(preg_match('/class="([^"]+)"/i', $match, $pmch)) $param['class'] = $pmch[1];
      if(preg_match('/align="([^"]+)"/i', $match, $pmch)) $param['align'] = $pmch[1];
      if(preg_match('/style="([^"]+)"/i', $match, $pmch)) $param['style'] = $pmch[1];
      if(preg_match('/type="([^"]+)" +src="([^"]+)"/i', $match, $pmch))
      {
        $param['type'] = $pmch[1];
        $param['src' ] = $pmch[2];
      }
    return array($state, $param);
    case DOKU_LEXER_UNMATCHED : return array($state, $match);
    case DOKU_LEXER_EXIT :      return array($state, '');
    }
    return array();
  }
 
  function render($mode, &$renderer, $data)
  {
    if($mode != 'xhtml') return false;
    list($state, $match) = $data;
    switch($state)
    {
    case DOKU_LEXER_ENTER :
      $div = '<div';
      if(array_key_exists('id',    $match)) $div .= ' id="'.$match['id'].'"';
      if(array_key_exists('class', $match)) $div .= ' class="'.$match['class'].'"';
      if(array_key_exists('align', $match)) $div .= ' align="'.$match['align'].'"';
      if(array_key_exists('style', $match)) $div .= ' style="'.$match['style'].'"';
      $div .= '>';
      if(array_key_exists('type',  $match)
      && array_key_exists('src',   $match))
      {
        $type = $match['type'];
        $src  = $match['src' ];
        if($type == 'text/css')
           $div = '<link rel="stylesheet" type="'.$type.'" href="'.$src.'">'.$div;
        else $div = '<script type="'.$type.'" src="'.$src.'"></script>'.$div;
      }
      $renderer->doc .= $div;
      break;
    case DOKU_LEXER_UNMATCHED :
      global $conf;
      $renderdoc = $match;
      $renderdoc = preg_replace('/http:\/\/(localhost|127\.0\.0\.1)/i', $conf['baseurl'], $renderdoc);
      $renderdoc = $renderer->render($renderer->render($renderdoc));
      $renderdoc = preg_replace('/&lt;\/?p&gt;/i', '', $renderdoc);
      $renderer->doc .= $renderdoc;
      break;
    case DOKU_LEXER_EXIT :
      $renderer->doc .= '</div>';
      break;
    }
    return true;
  }
}
 
?>

ダウンロードdokuwiki-plugin-evaluator-090225.zip

 DokuWikiSyntax系のプラグインは、handle()で事前に設定しておいた字句解析結果を取得して、必要なデータを抽出してシステムに返送し、再びrender()が呼び出されて、そのプラグインに必要なレンダリング処理を行ってから、上位のレンダラーに結果を追加して返すという仕組みのようですね。なかなか単純でわかりやすいシステムだと思います。ところで、このプラグインでは他のプラグインとちょっと違うことをしています。それは、

  $renderdoc = $renderer->render($renderer->render($renderdoc));

と書かれている部分で、対象となるコンテキストをレンダリングして、その結果を再度レンダリングします。そうすることで、<php>タグなどで生成した Wiki データを Wiki テキストとしてレンダリングすることが可能になります。このコードの上の行はドメインの書き換えで、あると便利な人には便利な機能でしょう。:-D 下の行は二重レンダリングの弊害なのか、 HTML エンティティが表示されてしまうので、正規表現で除去しています。

使い方

 このEvaluatorプラグインには「おまけ機能」があって、いくつかのオプションがあります。

  • align=”…“
    “right”、”center”、”left”を指定することで、<div align="...">タグを生成して、出力 HTML の配置指定を行うことができます。
  • style=”…“
    CSS のインラインコードを指定することで、<div style="...">タグを生成して、出力 HTML の体裁指定を行うことができます。
  • type=“text/css” src=”…“
    外部スタイルシートを指定することができます。
    具体的には、<link rel="stylesheet" type="text/css" href="...">タグを<div>タグの前に生成します。
  • type=“text/javascript” src=”…“
    外部 Javascript プログラムを指定することができます。
    具体的には、<script type="text/javascript" src="..."></script>タグを<div>タグの前に生成します。
    実際にはtypeには別の言語を指定してもかまいません。

 DokuWikiWiki システムとしてではなく、 CMS として利用している自分のような人には、このプラグインはちょっと便利な機能だとおもう。スイスアーミーナイフにはなれないけれど、さらに一歩 PHP スクリプトとの親和性がよくなるプラグインだと思います。次は、DokuWikiCodeIgniterかな … 。

バグフィックスとパラメータ追加

Daisukeh 2009/02/25 13:35

 先日のコードをよく見ていたら、 CSS や Javascript のタグを出力する部分で<div>タグを破壊していることが判明したので修正しました。ついでに、<div>のIDとクラスを定義できるように、パラメータを追加しました。

  • id=”…“
    <div>のID( CSS や Javascript などで使う識別子)を定義することができます。
  • class=”…“
    <div>のクラス( CSS や Javascript などで使う識別子)を定義することができます。

これで外部の CSS や Javascript を読み込んで、<div>の体裁を整えたり、スクリプトで操作することが容易になったと思います。

掲示板

, 2012/01/25 05:32
Boy that rlelay helps me the heck out.
時計,バッグ,財布,ルイヴィトンコピー,エルメスコピー
弊店に主要な販売する商品は時計,バッグ,財布,ルイヴィトンコピー,エルメスコピー,
シャネルコピー,グッチコピー,プラダコピー,ロレックスコピー,カルティエコピー,オメガコピー,
ウブロ コピーなどの世界にプランド商品です。
2006年に弊社が設立された、
弊社は自社製品を世界中に販売して、高品質な製品と優れたアフターサービスで、
, 2019/01/18 14:29
Hello there,

My name is Aly and I would like to know if you would have any interest to have your website here at dooo.jp promoted as a resource on our blog alychidesign.com ?

We are in the midst of updating our broken link resources to include current and up to date resources for our readers. Our resource links are manually approved allowing us to mark a link as a do-follow link as well
.
If you may be interested please in being included as a resource on our blog, please let me know.

Thanks,
Aly
Enter your comment
 
 
programming/dokuwiki/evaluatorプラグインを作る.txt · 最終更新: 2009/08/06 15:11 by daisukeh
 

Recent changes RSS feed Donate Powered by PHP Valid XHTML 1.0 Valid CSS
Driven by DokuWiki Powered by Google do yourself a favour and use a real browser - get firefox ! GIMP is the GNU Image Manipulation Program. Adobe Flex smarty : Template Engine