6

構成ファイルの多くの定義済み定数を含むこの Perl スクリプトがあります。例えば:

use constant  {
LOG_DIR                             => "/var/log/",
LOG_FILENAME                        => "/var/log/file1.log",
LOG4PERL_CONF_FILE                  => "/etc/app1/log4perl.conf",
CONF_FILE1                          => "/etc/app1/config1.xml",
CONF_FILE2                          => "/etc/app1/config2.xml",
CONF_FILE3                          => "/etc/app1/config3.xml",
CONF_FILE4                          => "/etc/app1/config4.xml",
CONF_FILE5                          => "/etc/app1/config5.xml",
};

「/etc/app1」と「/var/log」の重複を減らしたいのですが、変数を使用してもうまくいきません。また、以前に定義された定数の使用は、同じ「定数ブロックの使用」では機能しません。例えば:

use constant {
LOG_DIR                             => "/var/log/",
FILE_FILENAME                       => LOG_DIR . "file1.log" 
};

動作しません。

別の「use constant」ブロックを使用すると、この問題を回避できますが、多くの不要なコードが追加されます。

これを行う正しい方法は何ですか?

ありがとうございました。

4

5 に答える 5

8

別の「use constant」ブロックを使用すると、この問題を回避できますが、多くの不要なコードが追加されます。

本当にそうですか?

use constant BASE_PATH => "/etc/app1";

use constant  {
    LOG4PERL_CONF_FILE                  => BASE_PATH . "/log4perl.conf",
    CONF_FILE1                          => BASE_PATH . "/config1.xml",
    CONF_FILE2                          => BASE_PATH . "/config2.xml",
    CONF_FILE3                          => BASE_PATH . "/config3.xml",
    CONF_FILE4                          => BASE_PATH . "/config4.xml",
    CONF_FILE5                          => BASE_PATH . "/config5.xml",
};

これには多くの問題は見られません。基本パスを 1 点のみで指定したため、DRY 原則が尊重されます。環境変数で BASE_PATH を割り当てる場合:

use constant BASE_PATH => $ENV{MY_BASE_PATH} || "/etc/app1";

...コードを編集せずに定数を再構成する安価な方法があります。これについて何が気に入らないのですか?

反復的な "BASE_PATH ." 連結を本当に削減したい場合は、定数を自分でインストールしてそれを取り除くための機械を少し追加できます。

use strict;
use warnings;

use constant BASE_PATH => $ENV{MY_PATH} || '/etc/apps';

BEGIN {
    my %conf = (
        FILE1 => "/config1.xml",
        FILE2 => "/config2.xml",
    );

    for my $constant (keys %conf) {
        no strict 'refs';
        *{__PACKAGE__ . "::CONF_$constant"}
            = sub () {BASE_PATH . "$conf{$constant}"};
    }
}

print "Config is ", CONF_FILE1, ".\n";

しかし、この時点で、バランスが正しいものから厄介なものに変わったと思います:)まず、CONF_FILE1をgrepして、それが定義されている場所を確認することはできなくなりました。

于 2008-10-23T12:36:24.457 に答える
7

私はおそらくそれを次のように書くでしょう:

use Readonly;

Readonly my $LOG_DIR            => "/var/log";
Readonly my $LOG_FILENAME       => "$LOG_DIR/file1.log";
Readonly my $ETC                => '/etc/app1';
Readonly my $LOG4PERL_CONF_FILE => "$ETC/log4perl.con";

# hash because we don't have an index '0'
Readonly my %CONF_FILES => map { $_ => "$ETC/config$_.xml" } 1 .. 5;

しかし、それはまだ多くのコードですが、それは重複を取り除き、それは勝利です。

ログファイルが数値であるのはなぜですか?0で始まる場合は、ハッシュよりも配列の方が適しています。名前が付けられている場合は、よりわかりやすくなります。

于 2008-10-23T09:14:12.773 に答える
4
use constant +{
    map { sprintf $_, '/var/log' } (
        LOG_DIR            => "%s/",
        LOG_FILENAME       => "%s/file1.log",
    ),
    map { sprintf $_, '/etc/app1' } (
        LOG4PERL_CONF_FILE => "%s/log4perl.conf",
        CONF_FILE1         => "%s/config1.xml",
        CONF_FILE2         => "%s/config2.xml",
        CONF_FILE3         => "%s/config3.xml",
        CONF_FILE4         => "%s/config4.xml",
        CONF_FILE5         => "%s/config5.xml",
    ),
};
于 2008-10-23T14:54:12.773 に答える
3

残念ながら、それはうまくいきません。これは、定義される前に関数 (「定数」) を使用しているためです。を呼び出す前にそれらを評価しますconstant->import

use ステートメントはコンパイル時に評価されるため、変数の使用は機能しません。変数への割り当ては実行時にのみ行われるため、まだ定義されていません。

私ができる唯一の解決策は、それを複数のuse constantステートメントに分割することです。この場合、2 つのステートメントで十分です (1 つはLOG_DIRCONF_DIR、もう 1 つは残りの部分です)。

于 2008-10-23T08:47:40.113 に答える
0

何をしているかによっては、定数がまったく必要ない場合があります。ほとんどの場合、私は他の人が自分の仕事を成し遂げるために使用するものを書いているので、他のプログラマーに柔軟性を与える方法でこの問題を解決しています。私はこれらのものをメソッドにします:

 sub base_log_dir { '...' }

 sub get_log_file
      {
      my( $self, $number ) = @_;

      my $log_file = catfile( 
        $self->base_log_dir, 
        sprintf "foo%03d", $number
        );
      }

このようにすることで、物事を簡単に拡張またはオーバーライドできます。

ただし、これを行うと一定の折りたたみの価値が失われるため、それが自分にとってどれほど重要かを考える必要があります。

于 2008-10-27T20:36:29.813 に答える