MTエンジニアブログ

プラグインはどのクラスで new すべきか

ぴろり上西 2011年03月18日

 小粋空間さんの記事で、プラグイン オブジェクトを生成するバリエーションがいろいろと紹介されています。いずれの方法でも、プラグインとして登録でき動作するのですが、今回、その違いでハマったことがあったので情報展開しておきます。

 まず、new メソッドによるオブジェクト インスタンスの生成についてですが、これは以下の二つの記述は同じ動作と考えて差し支えありません。ですので、new の位置は今回は特に気にしないことにします。実際、間接オブジェクト形式での記述では動作に違いがあるのですが、ここでは割愛します。

package MT::Plugin::MyPlugin;
my $instance1 = new MT::Plugin::MyPlugin ({...});
my $instance2 = MT::Plugin::MyPlugin->new ({...});

 次に以下の二つのプラグインのソースコードです。どちらもやっていることはほぼ同じです。

  1. package で名前空間を宣言
  2. MT::Plugins のサブクラスとして宣言
  3. プラグインのインスタンスを生成
  4. MT にプラグインを追加
  5. MT::Plugin::init_app をオーバーライド

 するだけの単純なプラグインになります。違いは、new で指定しているクラス名ですが、これらのプラグインを MT に登録すると、確かにプラグイン一覧に表示されますし、特にエラーも発生しません。何が違うのでしょうか?

### src.1
package MT::Plugin::MyPlugin;
use base qw( MT::Plugin );
my $plugin = MT::Plugin::MyPlugin->new ({...});
MT->add_plugin ($plugin);

sub init_app {
    # override MT::Plugin::init_app
}
### src.2
package MT::Plugin::MyPlugin;
use base qw( MT::Plugin );
my $plugin = MT::Plugin->new ({...});
MT->add_plugin ($plugin);

sub init_app {
    # override MT::Plugin::init_app
}

 src.2 の方では、$plugin は MT::Plugin クラスのインスタンスであって、init_app は MT::Plugin::MyPlugin 名前空間に属します。そのため、一見正しく動作しているようですが、MT にしてみれば MT::Plugin::MyPlugin なんていうクラスは知らない訳ですから、init_app がコールバックされません。これに気がつくまで 1 時間浪費しました orz 普通にテンプレートタグを拡張するようなプラグインでは問題になりませんが、少し複雑なことをやろうとして MT::Plugin のメソッドをオーバーライドするような時に問題になります。反対に、package で宣言した名前で new しておけば、どんな場合でも問題は発生しません。
 以上を踏まえてプラグインの初期化コードを書くと以下のようになるでしょうか。

### src.3
package MT::Plugin::SKR::MyPlugin;
use base qw( MT::Plugin );
my $plugin = __PACKAGE__->new ({...});
MT->add_plugin ($plugin);
  1. package で宣言する名前空間には会社名や自分の名前を入れる。他社製の同じ名前のプラグインがあっても名前空間が衝突しにくい。
  2. new に指定するクラス名は、特殊リテラル __PACKAGE__ を利用する。package 名を変更した時の変更忘れを防げる。DRY。
投稿者 ぴろり上西 : 03/18

RedmineでWikiやカテゴリ抽出結果に一発ジャンプできるGreasemonkeyスクリプト

ぴろり上西 2011年03月14日

 弊社スカイアークシステムでは、プロジェクト管理ソフトウェアとして Redmine を利用しています。特に、大量のプラグイン コンポーネントから構成されている MTCMS の開発でその威力を発揮しています。
 具体的には、プラグインの名称ごとにカテゴリを設定してチケットを管理し、プラグインの仕様や使い方に関する情報を全て、カテゴリをページ名とする Wiki ページにまとめるようにしています。この方法であれば、チケットをカテゴリでフィルタすることで、プラグインごとにどれくらいの作業タスクやバグが残っているのか一目瞭然です。また、仕様や使い方が判らなくなれば、その Wiki ページを見れば良い、というフローが確立しています。
 ただ、ここで Redmine にもちょっとした不便があります。チケットから、そのチケットに設定されたカテゴリ名の Wiki ページや、カテゴリ名でフィルタしたチケット一覧に瞬時に飛べないのです。そこで、Greasemonkey スクリプトを書いてみました。この Greasemonkey を導入することで以下が可能になります。

  • チケットのカテゴリが「HogeHoge」に設定されている場合
    • カテゴリ名と同じ Wiki ページ「http://your.domain.net/projects/name/wiki/HogeHoge」へのリンクが追加されます
    • そのカテゴリでフィルタされたチケット一覧へのリンクが追加されます

Category2Wiki.user.js のダウンロード

  • Mozilla Firefox + Greasemonkey Add-on 専用です
  • インストール前に @include の URL をお使いの Redmine の環境に合わせてください
  • このプラグインはブログウェアです。無償でご利用頂けますが、感想、要望などをあなたのブログで記事として紹介頂けると幸いです。
  • 個人利用または商用利用に関わらず無償でご利用いただけます
  • 無保証ですので、十分にテストしてから運用してください
投稿者 ぴろり上西 : 03/14

Greasemonkey ユーザースクリプトの作成でハマったところ

ぴろり上西 2011年03月09日

 先日、Redmine 用の Greasemokey スクリプトを公開したのですが、まぁ、久々に JavaScript を書いたこともあって、幾つかハマりました。これといった検索結果にもヒットしなかったので、自分用まとめとしてメモしておきます。

form エレメントの submit イベントをフックしたい

 フォームの送信前に、フォームの入力データをチェックするとします。普通なら、getElementById か何かで目的の form エレメントを取得して、onsubmit に任意の関数を設定すればOKな感じですよね。これが動きません。エレメントは取得できているのですが、onsubmit に設定した関数が呼ばれません。issue_form1 は、 [object XPCNativeWrapper [object HTMLFormElement]] とかいうオブジェクトになっていて、安全のために、オブジェクトの要素に直にアクセスできないようになっているようです(´・ω・`)

// 入力値のチェックをしたい form エレメントを取得
var issue_form1 = document.getElementById ('issue-form');
// submit 時のハンドラを上書きする
issue_form1.onsubmit = function () {...};

form エレメントの submit イベントをフックしたい その2

 検索してみると、イベントをフックするには addEventListener を使うようです。書換えます。

// 入力値のチェックをしたい form エレメントを取得
var issue_form1 = document.getElementById ('issue-form');
// submit イベントにハンドラを追加
issue_form1.addEventListener ('submit', function () {
    alert ('飛び込んできたよ');
    // フォームは送信しない
    return false;
}, false);

 フォームを送信しようとするとアラートが出るようになりました。これで送信前に任意の処理を追加できるようになりました。しかし、false を返してもフォームが常に送信されてしまいます。条件によってフォームの送信を実行/禁止できません(´・ω・`)

submit する/しないようにする

 フォーム内に submit タイプのボタンが設置されているので、これを何とかしてみます。

// 送信ボタンを取得
var commit = document.getElementById ('commit');
// type="submit" を type="button" に置き換える
commit.setAttribute ('type', 'button');
// ボタンが押された時のハンドラを登録する
commit.addEventListener ('click', function () {
    // もし入力値のチェックがOKなら
    if (checking_condition)
        // フォームを送信する
        issue_form.submit();
}, false);

 これでようやく期待した動作になりました(・∀・) 何か変なことやってるなーと思われた方、こういう経過があったのです...

投稿者 ぴろり上西 : 03/09

札幌C++勉強会 #1 に行ってきました

logo2.gif やまかわ 2011年03月07日

こんにちはこんにちはやまかわです。
だいぶ遅くなりましたが
先日札幌C++勉強会#1というのに行ってきました。

今回は東京で開催されたBoost勉強会のUSTを見るというイベントだったため、久々に何もスピーカーやらないイベントでした。

紹介された話の中ではやはりBoost.ProtoのExpression Templateは地獄のようにコンパイルが重い、と言う話が大変印象的でした。コンパイル時のテンプレートメタプログラミングもほどほどにということでしょうかねえ。同じようなものとしてはC#のExpression Treeの方が解決はスマートですね。

あと、C++でもタプルを使えるようにするBoost::Tupleは使用した事が無かったのですが、大変使いでが良さそうでした。計算機でいうtupleというのは、型が異なっても良いデータのシークエンス(というか組)を言います。図にすると以下のような感じでしょうか。

array tuple record
データ長 変動 固定 固定
データ要素の型 全て同じ 変動 変動
要素へのアクセス 順序数 順序数 名前

Pythonや関数型言語ではtupleが標準で利用できるようになっています(例えば一般に、関数の引数やDBMS内のデータの各列はtupleとして表す事ができます)。構造体を起こすまでもない構造化データの受け渡しに便利そうですね。

実際のところ一番印象的だったのはcpp_akiraさんのいけめん具合でしたが!


ところで今C++使ってる人ってどこらへんかなーというところをそこらへんにいた人に聞いてみたのですが、だいたい以下のような感じになるようです。

  • 数値計算屋さん
  • ゲーム屋さん
  • 携帯屋さん

東京だともう少し色々居るみたいですが、札幌だとこの辺でしょうか。

だんだん業務アプリもC#等で書く事がほとんどになっており、C++の使用される場面というのは減ってきておりますがそれでも特にメモリ資源がそれなりに余裕が無い場合などは、C++の利用価値が十分高いところです。
PerlもそうですがC++も標準ライブラリは割と貧弱ですので、Boostとかつかわんとしんどいわけですが、リハビリしないと忘れてしまいますので次回も参加したいと思います。

投稿者 やまかわ : 03/07

Redmineチケットの項目の変更忘れを注意してくれるGreasemonkeyスクリプト

ぴろり上西 2011年03月03日

 弊社スカイアークシステムでは、プロジェクト管理ソフトウェアとして Redmine を利用しています。以前は、社内に Remine のサーバーを自前で建てていたのですが、今では Redmine for SaaS 上で運用しています。ダウンタイムもほとんど無く、バックアップやソフトウェアのバージョンアップの心配や手間も不要でオススメなのです(≧∇≦)

 さてさて、ここからが本題。上西はおっちょこちょいなので、Redmine でチケットを更新する時に、ステータス欄や担当者欄を変更するのを頻繁に忘れます。

  1. よし、バグ直った!
  2. CVS にもコミットしたぞ!
  3. チケットを更新「○○を修正しました!」
  4. チケットを送信
  5. この忌まわしい(?)バグチケットともこれでおさらばだぜ! HAHAHAHA(・∀・)
  6. 担当者欄が上西のまま
  7. orz
  8. 担当者欄をリーダーに変更してもう一度チケット送信

 ということが何度もありまして。その度にチケットの更新通知メールが社員全員に飛んだりするわけですよ。
 そこで、チケットを送信する時に、重要なオプションが変更されていなかった場合に、警告を表示する Greasemonkey スクリプトを書いてみました。送信ボタンを押すと、「担当者欄が変更されていないが大丈夫か?」と確認ダイアログを表示してくれるようになるので「おっと危ないところだった。一番いいやつを頼む」と、おっちょこちょいな上西にはピッタリなのです。
 でも、同僚二人に聞いてみたらあんまり評判は良くなかったんですがね... いいじゃん。便利じゃん!

RedmineSubmitConfirm.user.js のダウンロード

  • Mozilla Firefox + Greasemonkey Add-on 専用です
  • インストール前に @include の URL をお使いの Redmine の環境に合わせてください
  • 警告対象のオプションは、スクリプト中にちょっと追記するだけで簡単にカスタマイズできるようになっています。checks 配列を参照してみてください。
  • このプラグインはブログウェアです。無償でご利用頂けますが、感想、要望などをあなたのブログで記事として紹介頂けると幸いです。
  • 個人利用または商用利用に関わらず無償でご利用いただけます
  • 無保証ですので、十分にテストしてから運用してください
投稿者 ぴろり上西 : 03/03
お問い合わせはこちらから お電話でのお問い合わせ03-5475-5101

MTエンジニアブログ

MTCMS Smartキャンペーン!
承認フロー付きCMS「MTCMS Smart(98,000円)」をお買い上げの方、MTライセンス1本がタダに!

配布プラグイン一覧

MultiFileUploader
複数ファイルを一括でアップロードできるMovable Typeプラグイン
ParentalInclude
MT5でウェブサイトとブログのテンプレート連携を便利にするプラグイン
DuplicateEntry
ブログ記事を複製または移動するMovableTypeプラグイン
NotifyAnythingChanged
何かが起きたらメールで通知するMovableTypeプラグイン
rssEntry
取込んだRSSをエントリとして書き出すMovableTypeプラグイン
AutoTagging
面倒な記事のタグ付けを自動化する
FutureRebuild
日時を指定してページを再構築する
EntryImExporter
エントリをCSVに書出したり、CSVから一括登録するMovableTypeプラグイン
MailPack
Movable Typeで簡単携帯投稿!メール投稿プラグイン
DirectoryUtility
カテゴリ・フォルダの階層を表示したり、親フォルダを表示したり、何かと便利なプラグイン
CSVList
CSVデータを整形して表示する
PageBute
静的ページ用ページ分割プラグイン

注目記事

RSS

ページの先頭へ戻る