MTエンジニアブログ
ぴろり上西
2011年03月18日
小粋空間さんの記事で、プラグイン オブジェクトを生成するバリエーションがいろいろと紹介されています。いずれの方法でも、プラグインとして登録でき動作するのですが、今回、その違いでハマったことがあったので情報展開しておきます。
まず、new メソッドによるオブジェクト インスタンスの生成についてですが、これは以下の二つの記述は同じ動作と考えて差し支えありません。ですので、new の位置は今回は特に気にしないことにします。実際、間接オブジェクト形式での記述では動作に違いがあるのですが、ここでは割愛します。
package MT::Plugin::MyPlugin;
my $instance1 = new MT::Plugin::MyPlugin ({...});
my $instance2 = MT::Plugin::MyPlugin->new ({...});
次に以下の二つのプラグインのソースコードです。どちらもやっていることはほぼ同じです。
- package で名前空間を宣言
- MT::Plugins のサブクラスとして宣言
- プラグインのインスタンスを生成
- MT にプラグインを追加
- 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);
- package で宣言する名前空間には会社名や自分の名前を入れる。他社製の同じ名前のプラグインがあっても名前空間が衝突しにくい。
- new に指定するクラス名は、特殊リテラル __PACKAGE__ を利用する。package 名を変更した時の変更忘れを防げる。DRY。
ぴろり上西
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 の環境に合わせてください
- このプラグインはブログウェアです。無償でご利用頂けますが、感想、要望などをあなたのブログで記事として紹介頂けると幸いです。
- 個人利用または商用利用に関わらず無償でご利用いただけます
- 無保証ですので、十分にテストしてから運用してください
ぴろり上西
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);
これでようやく期待した動作になりました(・∀・) 何か変なことやってるなーと思われた方、こういう経過があったのです...
やまかわ
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とかつかわんとしんどいわけですが、リハビリしないと忘れてしまいますので次回も参加したいと思います。
ぴろり上西
2011年03月03日
弊社スカイアークシステムでは、プロジェクト管理ソフトウェアとして Redmine を利用しています。以前は、社内に Remine のサーバーを自前で建てていたのですが、今では Redmine for SaaS 上で運用しています。ダウンタイムもほとんど無く、バックアップやソフトウェアのバージョンアップの心配や手間も不要でオススメなのです(≧∇≦)
さてさて、ここからが本題。上西はおっちょこちょいなので、Redmine でチケットを更新する時に、ステータス欄や担当者欄を変更するのを頻繁に忘れます。
- よし、バグ直った!
- CVS にもコミットしたぞ!
- チケットを更新「○○を修正しました!」
- チケットを送信
- この忌まわしい(?)バグチケットともこれでおさらばだぜ! HAHAHAHA(・∀・)
- 担当者欄が上西のまま
- orz
- 担当者欄をリーダーに変更してもう一度チケット送信
ということが何度もありまして。その度にチケットの更新通知メールが社員全員に飛んだりするわけですよ。
そこで、チケットを送信する時に、重要なオプションが変更されていなかった場合に、警告を表示する Greasemonkey スクリプトを書いてみました。送信ボタンを押すと、「担当者欄が変更されていないが大丈夫か?」と確認ダイアログを表示してくれるようになるので「おっと危ないところだった。一番いいやつを頼む」と、おっちょこちょいな上西にはピッタリなのです。
でも、同僚二人に聞いてみたらあんまり評判は良くなかったんですがね... いいじゃん。便利じゃん!
RedmineSubmitConfirm.user.js のダウンロード
- Mozilla Firefox + Greasemonkey Add-on 専用です
- インストール前に @include の URL をお使いの Redmine の環境に合わせてください
- 警告対象のオプションは、スクリプト中にちょっと追記するだけで簡単にカスタマイズできるようになっています。checks 配列を参照してみてください。
- このプラグインはブログウェアです。無償でご利用頂けますが、感想、要望などをあなたのブログで記事として紹介頂けると幸いです。
- 個人利用または商用利用に関わらず無償でご利用いただけます
- 無保証ですので、十分にテストしてから運用してください