Practice of Programming

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

Util::Any 0.17 リリース

先日、といっても、一週間ほど前になってしまいましたが、Util::Anyの0.17をリリースしました。細かくバグってて、あーもーと思って、0.15のコードを見直したら、なんだこりゃって状態だったので、整理しました。リリースするレベルじゃなかったです。ごめんなさいm(__)m


で、0.16でOKと思ってたのですが、プロダクション環境で使ってくれている人からバグレポートがあり。調べたところ原因はtypo...という。テストも追加してるんですが、整理した方が良いな...。
で、直したよって言って、Changesをコピペしたメールを投げたら,Changesも2箇所typoしてて,"try less coffee Kato. :-)"って言われました orz


というわけで...最近付いた機能です。

  • プラグイン
  • Sub::Exporter的関数ジェネレータまわりの改善

プラグイン

プラグインは最初どうかなと思ってたのですが、つけました。Util::Allの方で大きめのモジュールを集めてたら、-all時のロードが遅くなっちゃってたので。{plugin => 0} と最後にオプションを与えてやると、ロードしないようにしました。なお、Util::Any には、pluginは作れません。自分のユーティリティモジュール作る際に使います。

 package Util::Yours;
 use Util::Any -Base, -Pluggable;

のように、-Pluggableを指定します。プラグインは下記のように書きます。

  package Util::Yours::Plugin::Net;
  
  sub utils {
    return {
        -net => [
                  [
                   'Net::Amazon', '',
                   {
                    amazon => sub {
                      my ($pkg, $class, $func, $args) = @_;
                      my $amazon = Net::Amazon->new(token => $args->{token});
                      sub { $amazon }
                    },
                   }
                  ]
                ]
       };
  }
  
  1;

Sub::Exporter的関数ジェネレータ

結構便利でUtil::Allで、使ってます。下記の、now、years、months、hourは、この関数ジェネレータを使ってます。

use Util::All -datetime;
my $dt = now + years 5 + months 10 + hour; # 今から5年10ヶ月と1時間後のDateTimeオブジェクト

ところで、DateTime::Duration には、end_of_month ていう、微妙なオプションがあります(デフォルトが微妙なので、Util::Allではデフォルトがlimitです)。こいつをまとめて指定することが出来ます。

use Util::All -datetime => {-args => {end_of_month => "preserve"}};

のようにします。これで、years、months ほか、定義されているモジュールに初期値としてこれが渡ります。

実際、上で書かれている関数はどのように定義されているかというと(※自動生成しているコードなんで、若干変なところがあります)。

  '-datetime' => [
    [
      'DateTime', '',
      {
        'now' => sub {
            sub () { 'DateTime'->now(@_) }
        },
        # 略
      }
    ],
    [
      'DateTime::Duration', '',
       # 略
       {
        'month' => sub {
            my($pkg, $class, $func, $args, $kind_args) = @_;
            sub () {
                'DateTime::Duration'->new('months', 1, 'end_of_month',
                     $$kind_args{'end_of_month'} || $$args{'end_of_month'} || 'limit');
            }
        },
        'years' => sub {
            my($pkg, $class, $func, $args, $kind_args) = @_;
            sub ($) {
                'DateTime::Duration'->new('years', shift @_, 'end_of_month',
                     $$kind_args{'end_of_month'} || $$args{'end_of_month'} || 'limit');
            }
        },
        # 略
      }
    ],

最初のuseの引数の{ -args => {end_of_month => "preserve"}} の部分は、$kind_args で取れます。
$args は、個別に渡されている引数です。これは、下記のようにして渡します。

use Util::All -datetime => [years => {end_of_month => "preserve"}]

のようにすると、years の$argsに渡ります。datetimeの場合は、一括で渡すケースが多いと思いますが。


個別に渡す場合というのは、例えば下記のような場合でしょうか。

  '-basecalc' => [
    [
      'Math::BaseCalc', '',
      {
        'to_base' => sub {
            my($pkg, $class, $func, $args, $kind_args) = @_;
            sub {
                'Math::BaseCalc'->new('digits', $$kind_args{'digits'} ||
                                                $$args{'digits'})->to_base(shift @_);
            }
            ;
        },
        'from_base' => sub {
            my($pkg, $class, $func, $args, $kind_args) = @_;
            sub {
                'Math::BaseCalc'->new('digits', $$kind_args{'digits'} || 
                                                $$args{'digits'})->from_base(shift @_);
            }
        }
      }
    ]
  ],

で、

  use Util::Yours -basecalc => [
                                 to_base   => {-as => "to_base16"  , digit => [0..9, "a" .. "f"]},
                                 from_base => {-as => "from_base16", digit => [0..9, "a" .. "f"]},
                                 to_base   => {-as => "to_base2"  , digit => [0, 1]},
                                 from_base => {-as => "from_base2", digit => [0, 1]},
                               ]

みたいにして、-as で独自の関数名を渡してやれば、その名前で関数がExportされます。

print from_base16(to_base16(255));
print from_base2(to_base2(8));

みたいなことが出来たります。他の実例は、Util::Allに結構あります。


このへんはSub::Exporterを見て、便利だなぁと思ってつけた機能なんで、興味のある方は、Sub::Exporterも見てみるといいんではないでしょうか。


もう、だいたいやること終わった感があるのですが、次やるとしたら、種類ごとの初期化か、関数から種類、モジュールの逆マッピングかなと思っています。

Util::Allについて

ここで、例をいろいろ出したものの、まだ、結構定義を変えてますので、使わない方がいいと思います。
テストも何も書いてませんしね。
Util::Allは、定義もドキュメントも全部YAMLファイルに書いてます。そのうちテストもYAML内に書けるようにする予定です。