<!-- -*- mode:text coding:euc-jp -*-
   $FML: hook.sgml,v 1.8 2008/08/18 20:52:59 fukachan Exp $
-->


<chapter id="hook">
	<title>
	HOOK(フック)
	</title>

<para>
HOOK とは、&fml8; の内部にあらかじめ用意されている
「小さな perl のプログラムを実行する」
機能です(専門用語でいえば HOOK を eval() するということです)。
</para>

<para>
HOOK は要所要所に用意されています。
</para>

<para>
もちろん、HOOK は、そのコンテキストの中で実行されます。 
その意味で本質的に危険な機能です。
ある程度、&fml8; の中身について理解していないと
HOOK を書くことはできません。
</para>

<para>
その一方、
HOOK をうまく使うことで、
少しの手間で複雑な動作を実現することが可能になります。
</para>

<para>
ものは使い用です。
</para>


<sect1 id="hook.problems">
	<title>
	概要もしくは HOOK における諸問題
	</title>

<para>
HOOK は微妙な修正、もしくは複雑なカスタマイズのために是非必要な機能ですが、
実装においては、いくつかの問題があります。
</para>

<para>
まず、&fml4; の $START_HOOK のような曖昧なものでは、
プログラムごとに異なる動作をさせることが難しい。
たとえば $START_HOOK を設定すると、
配送システムとコマンドメールシステムで同じ $START_HOOK を実行します。
それが便利な場合もあるのですが、プログラムの役割ごとに異なる動作をさせ
ようとすると面倒で分かりにくい設定になります。
</para>

<para>
そのため HOOK の名前に一定の基準が必要でしょう。
&fml8; では、ある関数の最初と最後に HOOK を用意する場合、
次のようなスタイルの HOOK 名称としています。
<screen>
$役割_関数_start_hook
$役割_関数_end_hook
</screen>
</para>

<para>
これにより配送システムとコマンドメールシステムで共通の HOOK などという
ものはなくなり、別々の HOOK をしかけることができるようになります。逆に、
共通のものをしかけようとするなら、一杯書いて下さい;)ということです。まぁ
コピーすればいいだけだから、さして難しくないですよね？(と思いたい)
<screen>
$distribute_XXX_start_hook = q{ ... };
$YYY_XXX_start_hook = $distribute_XXX_start_hook;
</screen>
</para>

<para>
また、HOOK の書き方が少々良くなくても動かないと困るでしょう。
というのは「少しだけ修整する」というケースでは、
Perl の素人さんが行なうことも多いからです。
</para>

<para>
現場では、欲しい機能を実現したい場合、美しいコードを書くことよりも、少
しでも早く実現することが求められます。そこは「美しさ」にこだわるべきで
はない点と考えます。
</para>

<para>
というわけで、通常、各モジュールでは
<screen>
use strict;
</screen>
になっていますが、
HOOK を評価する lexical scope では無視するようにしてあります。
実際には、HOOK を評価する際に、つねに
<screen>
no strict;
HOOK の内容
</screen>
という構文に変換した上で eval() しています。
</para>

<para>
&fml4; と &fml8; の大きな違いのひとつは変数・関数のスコープです。
注意して下さい。
&fml4; の関数は全てグローバル関数なので、どんな関数でも使えますが、
&fml8; では、そうはいきません。
とはいえ、まったく手がかりがないのも困るので、HOOK が利用できる環境では
$curproc オブジェクトだけは常にアクセス可能であることを保証しています。
</para>

<para>
つまり HOOK を書く際には、
$curproc オブジェクトのアクセスメソッドだけを使って書くようにして下さい。
</para>

</sect1>


<sect1 id="hook.naming.convention">
	<title>
	HOOK の命名規則
	</title>

<para>
HOOK 名前の標準的な形式については
<screen>
役割名_メソッド名_start_hook
役割名_メソッド名_end_hook
</screen>
などとすることにしました。ここで役割名は「use_XXX_function」(例:
use_article_post_function)の XXX 部分です。
もっと粒度の細かい HOOK については、この形式でないものもあります。
</para>

<para>
たとえば、fmlconf コマンドのメインメソッド run() の HOOK の名前は
<screen>
fmlconf_run_start_hook
fmlconf_run_end_hook
</screen>
となり、run() の中での hook 呼び出しは次のようなコードになります。
<screen>
sub run
{
    my ($curproc, $args) = @_;
    my $config  = $curproc-&gt;{ config };

    my $eval = $config-&gt;get_hook( 'fmlconf_run_start_hook' );
    if ($eval) {
	eval qq{ $eval; };
	print STDERR $@ if $@;
    }

    $curproc-&gt;_fmlconf($args);

    $eval = $config-&gt;get_hook( 'fmlconf_run_end_hook' );
    if ($eval) {
	eval qq{ $eval; };
	print STDERR $@ if $@;
    }
}
</screen>
</para>

<!--
<para>
現実にはもっといろいろな場所に HOOK がないと不便でしょうが、
その名前は上述の HOOK 以外に設定します。
単純に hook2 でいいのかもしれないし、
可能であればもう少し理解しやすい名前にするべきでしょう。
</para>
-->

</sect1>


<sect1 id="hook.recipes">
	<title>
	レシピ’s
	</title>

<qandaset>
&sect.hook.recipes;
</qandaset>

</sect1>


</chapter>
