Devel::REPLのプラグイン(1)
めも。
Devel::REPLの、プラグインの呼び出しには(たぶん)2種類あって、
1つめがDevel::PERLに定義されてるメソッドをhookする(before,after,aroundする)。
こっちのタイプは単純にMoose::Roleを使ってる。
Plugin::Colorsとかだと、
package Devel::REPL::Plugin::Colors; use Moose::Role; ... around print => sub { my $orig = shift; my $self = shift; print {$self->out_fh} color($self->normal_color); $orig->($self, @_); print {$self->out_fh} color('reset'); };
みたいな感じでDevel::REPL->print()にhookしてる。
このaroundとかが、どこでDevel::REPL->print()に設定されるかというと、
MooseX::Object::Pluggable->_load_and_apply_role()の中の、$role->meta->apply($self)の部分。
package MooseX::Object::Pluggable; ... sub _load_and_apply_role{ my ($self, $role) = @_; die("You must provide a role name") unless $role; eval { Class::MOP::load_class($role) }; confess("Failed to load role: ${role} $@") if $@; carp("Using 'override' is strongly discouraged and may not behave ". "as you expect it to. Please use 'around'") if scalar keys %{ $role->meta->get_override_method_modifiers_map }; $role->meta->apply( $self ); return 1; }
$roleには"Devel::Plugin::Colors"とか、プラグインクラス名が入ってて、
$role->metaはMoose::Meta::Role。たぶんuse Moose::Roleするとexportしてくれるのかな。んでapply()する。
Moose::Meta::Role->apply()は既存のインスタンスとかクラスとかにMixin(?)するメソッドで、
定義されてるメソッドだけじゃなくてaroundとかbeforeとかも一緒にやってくれる。
わすれないようにサンプル。
use strict; use warnings; package Foo; sub new { bless {}, shift } sub hello { print "hello\n" } package Foo::Plugin::Hello; use Moose::Role; before 'hello' => sub { print "before hello\n"; }; sub buy { print "buy\n" } package main; my $foo = Foo->new; Foo::Plugin::Hello->meta->apply($foo); $foo->hello(); $foo->buy(); #結果 before hello hello buy
まあこんな感じでDevel::REPLのメソッドが呼ばれるたびに、Pluginのaroundやらbeforeやらが呼ばれるみたい。
古いentryからDedupedしつつ1件ずつPublishするyaml
「サンプルコードによるPerl入門」を、最初の記事から順にメールで読みたいなあと思って書いてみた。
昨日のPlugin::Expressionを使ってます。
global: ... plugins: - module: Subscription::Config config: feed: http://d.hatena.ne.jp/taraburo/rss2 - module: Expression config: hooks: hook: update.feed.fixup expression: | my ($self, $context, $args) = @_; my $dedup = Plagger::Rule->new({ module => 'Deduped', path => '/path/to/deduped.db', }); my @entries = grep { $dedup->{deduper}->is_new($_); } $args->{feed}->entries; my $last_entry; if (@entries) { $last_entry = pop @entries; $dedup->{deduper}->add($last_entry); $context->log(debug => "deduper add entry: " . $last_entry->title); } $args->{feed}->{entries} = $last_entry ? [ $last_entry ] : []; - module: Publish::Gmail config: ...
こんなんしなくてもPluginとRule組み合わせればもっとスマートにいけるような気がするけど気にしない。
最初はFilter::ReverseとFilter::Ruleでいけるかと思ったんだけどなあ。
- module: Filter::Reverse - module: Filter::Rule rule: - module: RecentN count: 1 - module: Deduped
RecentNで1件に削ってそれをDedupedしてくれるわけじゃないんですね。
Plagger::Plugin::Expression
既存のPluginじゃ上手く処理できないんだけど、新しくPlugin書くほどでもないよなーって時に。
package Plagger::Plugin::Expression; use strict; use base qw( Plagger::Plugin ); sub init { my $self = shift; $self->SUPER::init(@_); $self->rule_hook($self->conf->{rule_hook}); my $hooks = $self->conf->{hooks} or return; $hooks = [ $hooks ] unless ref $hooks eq 'ARRAY'; for my $hook (@$hooks) { my $callback = sub { eval $hook->{expression}; Plagger->context->error($@) if ($@); }; push @{$self->{hooks}}, $hook->{hook}, $callback; } } sub register { my ($self, $context) = @_; $context->register_hook( $self, @{$self->{hooks}}, ); } 1; __END__ =head1 SYNOPSIS - module: Expression config: rule_hook: smartfeed.entry hooks: - hook: smartfeed.init expression: Plagger->context->log(debug => 'smartfeed.init') - hook: smartfeed.entry expression: my ($self, $context, $args) = @_; $context->log(debug => $args->{entry}->title) - module: Expression config: hooks: hook: update.feed.fixup expression: Plagger->context->log(debug => 'update.feed.fixup') =cut
QIQ試してみた
前々から気になってたQIQを試してみました。
とりあえずPlaggerのrun_hookっぽい感じで。
<?php class Pluggable { function loadPlugin($plugin, $to) { new $plugin($this, $to); } function registerHook() { foreach (func_get_args() as $hooks) { foreach ($hooks as $hook => $closure) { $this->hooks[$hook][] = $closure; } } } function runHook($hook) { foreach ($this->hooks[$hook] as $closure) { $closure(); } } } // Pluginぽいの class Pluggable_Plugin_Hello { function __construct($p, $to) { $this->to = $to; $self = $this; // $this は static $this で取り込めないようなので $p->registerHook( array( 'hello_hook' => function() { echo "hello\n"; } ), array( 'buy_hook' => static function() { static $self; $self->buy(); } ) ); } function buy() { echo "buy {$this->to}\n"; } }
んで実行してみる。
<?php $p = new Pluggable; $p->loadPlugin('Pluggable_Plugin_Hello', 'id:taraburo'); $p->runHook('hello_hook'); $p->runHook('buy_hook');
hello buy id:taraburo
PHPでも変態になれそう。。。
str_transliterate()
Matzにっき(2008-03-15)で知ったのだけれど、
PHP6の新しい関数str_transliterate()がおもろい。
$php -r "echo str_transliterate('taraburo', 'Latin', 'Hiragana');"
で
たらぶろ
うへー。
次の5.3でも名前空間や新しいsyntax追加だというし、最近はPHPも動きが活発になってきたなあ。
PHP5.3や6は下記でダウンロードできる。メモ。
http://snaps.php.net/
$php -r "echo str_transliterate('PHP6 ha sugoiyo!', 'Latin', 'Hiragana');"
ぷへぷ6 は すごいよ !
(´・ω・`)
PHP6のunicodeのpdf見つけた。あとで読む。
http://www.gravitonic.com/downloads/talks/fosdem-2008/php-unicode-i18n.pdf
Zend Debugger
PDT、PHP5.2.3(win)、ローカルのApacheで動かすまで。
なんかどのサイトみても設定とかばらばらではまった。。。
http://downloads.zend.com/pdt/server-debugger/から、
ZendDebugger-5.2.10-cygwin_nt-i386.tar.gzをダウンロード。
(ZendDebugger-5.2.12-cygwin_nt-i386.zipはなんでか動かなかった)
アーカイブを解凍したら、
5_2_x_comp\ZendDebugger.dllを
C:\PHP5\ext\ZendDebugger.dllとかにコピー(コピーする場所はどこでもOK)
php.iniに設定書く
zend_extension_ts="C:\PHP5\ext\ZendDebugger.dll" // コピーしたdllのパス zend_debugger.allow_hosts=127.0.0.1 zend_debugger.expose_remotely=always
Apache再起動
require require require...
うはw こんなんできるんか。
return1.php
<?php return 'return2.php';
return2.php
<?php return 'return3.php';
return3.php
<?php return 'end.php';
end.php
<?php return 'Hello World!';
start.php
<?php echo require require require require 'return1.php';
結果
$php start.php Hello World!
ほかに思いつくのは
<?php echo print print print print print `echo`;
とかでしょうか。