@nqounetです。

最近、なにかとjQuery(Mobile)を使うことが多くなってきて、イベント駆動型のプログラミングにはなんとなく期待を持っています。

そこで、Mojoliciousに含まれているイベント駆動型クラスのMojo::EventEmitterを使って何かできないかなと試してみました。

とりあえずSYNOPSISを試してみます。

SYNOPSIS
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package Cat;
use Mojo::Base 'Mojo::EventEmitter';

# Emit events
sub poke {
my $self = shift;
$self->emit(roar => 3);
}

package main;

# Subscribe to events
my $tiger = Cat->new;
$tiger->on(roar => sub {
my ($tiger, $times) = @_;
say 'RAWR!' for 1 .. $times;
});
$tiger->poke;

結果としては、RAWR!と3回鳴く(画面に表示される)わけです。

しかし、package mainの中でtigerを定義しているあたりで、EventEmitterの醍醐味がよくわからない…。

なんかモヤモヤする。

JavaScriptだとどうなの

JavaScriptで考えると、例えばボタンにonclickを書いておくと、そのボタンをクリックした時にonclickで定義した関数が実行される。

JavaScriptで最初に試すのはこんな感じだと思う。

1
<a href="#" onclick="alert('こんにちは')">クリックして!</a>

クリックして!をクリックすると、画面にアラートで「こんにちは」と表示されるプログラムだ。

GUIだとわかりやすいような気がする。

 イベント駆動の考え方は,ユーザーの操作と実行プログラムを密接に関連付けたもので,マウスとアイコンを組み合わせたGUI(グラフィカル・ユーザー・インタフェース)と相性が良い。これまで手続き型の文化に慣れ親しんできた技術者もイベント駆動型で開発しなければならない場面が増えてきた。

ユーザーが操作した行動を、イベントとして、そのイベントに対応したプログラムが実行される。

操作しないイベント駆動

ところで、先ほどのonclickというのは、jQuery風に言い方を変えると、ボタンがクリックされた時にclickイベントが発行される、という感じになる。

プログラムの立場から考えると、ボタンをクリックした、ではなく、clickイベントが発生した、となる。

最近のjQueryでは、onという命令で、このイベントを仕掛けることができるようになっている。(昔は、clickという命令で同じことができた)

たとえばこんな風に。

1
2
3
$('#run-button').on('click', function(e){
/* id="run-button"がクリックされると、プログラムのこの部分が実行される */
});

そして、そのclickイベントはプログラムからも発生させることができる。

jQueryの場合だとtriggerという命令だ。

1
$('#run-button').trigger('click');

こちらが実行されると、先にonで定義したプログラムが実行される。

Mojo::EventEmitterだとどうなの

Mojo::EventEmittertriggerに相当するのがemitで、onに相当するのは、jQueryと同じくonだ。

synopsisを見てみると、イベントを発生させる’’emit’’がCatクラスに入っているのが、JavaScriptと大きく違うところだと思う。

Catクラスは、メソッドのpokeを実行すると、roarイベントが発生する、というクラス。

なので、$tigerを定義するときに、pokeを実行する前にroarイベントが発行された時のプログラムを用意している。

普通のOOPだと、Catクラスを継承したTigerクラスを作っていくところを、直接mainで定義しているのがわかりにくかった気がする。

普通の(?)OOPだとこんな感じですかね。よくわかりませんが。

oop-synopsis
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package Cat;
use Mojo::Base -base;

has roar => "MEOW";
has times => 2;

sub poke {
my $self = shift;
say $self->roar for 1 .. $self->times;
}

package Tiger;
use Mojo::Base 'Cat';
has roar => "RAWR!";
has times => 3;

package main;

my $tiger = Tiger->new;
$tiger->poke;

上を書いてみてから、synopsisと同じようにTigerを定義せずに書くとどうなるのか試してみました。

oop-synopsis-2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package Cat;
use Mojo::Base -base;

has roar => "MEOW";
has times => 2;

sub poke {
my $self = shift;
say $self->roar for 1 .. $self->times;
}

package main;

my $tiger = Cat->new;
$tiger->roar('RAWR!')->times(3);
$tiger->poke;

うーむ。

Tigerを定義してあるほうがしっくりきます。

SYNOPSISに書いてあるとはいえ、この例だとわかりにくいというか、イベント駆動型プログラミングとしての特徴が活かされていない気がします。