Practice of Programming

プログラム とか Linuxとかの話題

attributes

てきとーなんで信用しないでください。アトリビュートについて、調べてみました。
暇ができたら、perldoc attributesでも訳します。

アトリビュートというのは、

sub index : Private{
   ...
}

というように、サブルーチンの横にくっついている、: の横のもの、
上の例では、Privateになります。


Catalystでよく使われているのですが、Catalystでは、Private とか、Global とか、Regexとか色々あります。
何もしない状態だと、組み込みのアトリビュート以外のものを使うと、エラーになってしまいます。

組み込みのアトリビュートというのは、lvalue、method、locked などなど。


で、どうやったら、Catalystみたいなのできるのかなぁ、と調べてみました。
ちなみに、ここに書いているのは、package-specifiedなアトリビュートな話であって、他のは知らない。

package Hoge

sub hoge :XXX{
  
}

とするためには、このサブルーチンの前にMODIFY_CODE_ATTRIBUTEというサブルーチンを定義します。
このサブルーチンは、サブルーチンの宣言中に処理されるそうです。

my %Attribute;

sub MODIFY_CODE_ATTRIBUTES {
  my($class, $code_ref, @attribute) = @_;
  $Attribute{$code_ref} = \@attribute;
  return;
}

上のとおり、クラス名、サブルーチンのコードリファレンス、アトリビュートが引数
として渡ってきます。上の例だと、"Hoge", \&Hoge::hoge, "XXX"ですね。
で、この中では、%Attributeハッシュ内に、コードリファレンスに対するアトリビュートを保存しています。


このアトリビュートを取り出すために、FETCH_CODE_ATTRIBUTESというサブルーチンを定義します。

sub FETCH_CODE_ATTRIBUTES {
  my($class, $code_ref) = @_;
  return @{$Attribute{$code_ref} || []};
}

こちらは、クラス名、コードリファレンスが引数になり、
%Attributeにそのコードリファレンスを渡して、その値(さっき、MODIFY_CODE_ATTRIBUTESで保存したやつ)を返します。


このサブルーチンは、attributes::get が呼ばれたときに使われます(組み込みのアトリビュートは別)。
attributes::get は、コードリファレンスを引数にとり、それについてる、アトリビュートを返します。


下記、サンプルスクリプト

#!/usr/bin/perl

package Hoge;

use attributes;
use strict;

my %Attribute;

sub MODIFY_CODE_ATTRIBUTES {
  my($class, $code_ref, @attribute) = @_;
  $Attribute{$code_ref} = \@attribute;
  return;
}

sub FETCH_CODE_ATTRIBUTES {
  my($class, $code_ref) = @_;
  return @{$Attribute{$code_ref} || []};
}

sub hoge : xxxx {
  my $self = shift;
  print "\nget:", attributes::get(\&Hoge::hoge);
}

sub hogehoge : locked{
  my $self = shift;
  print "\nget:", attributes::get(\&Hoge::hogehoge);
}

Hoge->hoge();
Hoge->hogehoge();
print "\n\n";

実行結果。

get:xxxx
get:locked

hogehoge の方は、組み込みのアトリビュートlockedなので、
FETCH_CODE_ATTRIBUTESを定義しなくても、取り出せます。
hogeの方は、FETCH_CODE_ATTRIBUTESを定義しないと取り出せません。

そんな感じ。