2010-03-04 3 views
9

Perl 스크립트에서 다음과 같은 반 패턴이 반복되는 것을 발견했습니다.이 스크립트에는 스크립트의 상수로 인라인으로 저장하는 일부 기계/설정 관련 설정이 포함되어 있습니다. 스크립트는 자연에서 일반적이다 :Perl 스크립트에서 구성 데이터와 스크립트 논리 분리하기

#!/usr/bin/perl 

use strict; 
use warnings; 

# machine specific settings at the start of the script. 
my $SETTING_1 = "foo"; 
my @SETTING_2 = ("123", "456"); 
my $SETTING_3 = "something"; 

# general part of script follows. 
... 

하나의 시스템에서 실행 때이 패턴은 어느 정도 괜찮지 만, 내가하지 않도록 내가 추적해야하기 때문에 최대한 빨리 여러 컴퓨터에 스크립트를 배포 할로 문제가 시작 설정 부분을 일반 부분의 새 업데이트로 덮어 씁니다.

올바른 솔루션은 하나 개의 일반 스크립트 파일이 있고이 스크립트에서 실행되는 환경에 특정한 설정 파일을 읽게 분명히

내 질문은 다음과 같습니다. 당신이 추천 할 것입니다 무엇 CPAN 모듈 이 문제를 해결 하시겠습니까? 왜?

답변

4

내 즐겨 찾기는 Config::Std입니다. 나는 multi-linemulti-part 구성 값을 처리하는 방식을 좋아합니다.

변수가 일 때 복수 값이 될 수 있습니다. 다중 값 : 구성 파일에 단일 값이 있으면 값을 스칼라로 저장합니다. 여러 값이있는 경우 배열 참조를 얻습니다.

운영 환경을 설명하는 값 (라이브러리 등을 찾는 위치)과 사용자가 수정할 수있는 동작을 나타내는 값을위한 두 개의 구성 파일이있는 것이 편리하다는 것을 알았습니다.

나는 또한 주위에 래퍼를 쓰고 싶다. 예를 들어 (자동 생성 읽기 전용 접근을 포함하도록 업데이트) :

#!/usr/bin/perl 

package My::Config; 
use strict; use warnings; 

use Config::Std; 
use FindBin qw($Bin); 
use File::Spec::Functions qw(catfile); 

sub new { 
    my $class = shift; 
    my ($config_file) = @_; 

    $config_file = catfile($Bin, 'config.ini'); 
    read_config $config_file => my %config; 

    my $object = bless \%config => $class; 

    $object->gen_accessors(
     single => { 
      install => [ qw(root) ], 
     }, 
     multi => { 
      template => [ qw(dir) ], 
     }, 
    ); 

    return $object; 
} 

sub gen_accessors { 
    my $config = shift; 
    my %args = @_; 

    my $class = ref $config; 

    { 
     no strict 'refs'; 
     for my $section (keys %{ $args{single} }) { 
      my @vars = @{ $args{single}->{$section} }; 
      for my $var (@vars) { 
       *{ "${class}::${section}_${var}" } = sub { 
        $config->{$section}{$var}; 
       }; 
      } 
     } 

     for my $section (keys %{ $args{multi} }) { 
      my @vars = @{ $args{multi}->{$section} }; 
      for my $var (@vars) { 
       *{ "${class}::${section}_${var}" } = sub { 
        my $val = $config->{$section}{$var}; 
        return [ $val ] unless 'ARRAY' eq ref $val; 
        return $val; 
       } 
      } 
     } 
    } 

    return; 
} 

package main; 

use strict; use warnings; 

my $config = My::Config->new; 

use Data::Dumper; 
print Dumper($config->install_root, $config->template_dir); 
C:\Temp> cat config.ini 
[install] 
root = c:\opt 

[template] 
dir = C:\opt\app\tmpl 
dir = C:\opt\common\tmpl

출력 : 클래스에서 웃었되는 위험에서

C:\Temp> g.pl 
$VAR1 = 'c:\\opt'; 
$VAR2 = [ 
      'C:\\opt\\app\\tmpl', 
      'C:\\opt\\common\\tmpl' 
     ];
+0

+1 매우 도움이 됨 - 감사합니다. 우리에게'template_dirs'와 같은 메소드를 생성하는 모듈이 있어야하는 것처럼 보입니다. 'Config :: General', 특히'-ExtendedAccess' 옵션을 우연히 발견했습니다. 사용하지 않았지만 재미있어 보입니다. – FMc

+0

@FM'Config :: General'에 대해 알지 못했습니다. 흥미로워 보이지만 때로는 일반적인 솔루션이 너무 일반적 일 수 있습니다. 물론 스칼라 값 옵션과 잠재적으로 다중 값 옵션을위한 접근자를 자동으로 생성 할 수 있습니다. –

1

일반적으로 최첨단 방법은 구성 파일 do EXPR입니다. 이걸 들여다 봤니?

+5

이것은 오류를 전혀 검사하지 않으며 임의의 코드를 실행할 수 있습니다. 표현식이나 파일의 내용을 단순히 변수로 읽어 들일 수 있으면 평가하지 마십시오. – Ether

+1

@eother'do' 메소드는 내장되어 있고, 쉽고, 일반적으로 사용됩니다. 많은 크고 인기있는 패키지는 여전히 더 안전하지만보다 복잡한 구성 체계를 위해이를 사용합니다 (예 : http://gna.org/projects/savane/ 및 http://packages.debian.org/sbuild 및 Net :: Config Perl 배포판에 포함됨). 구성 파일을 만드는 사용자를 신뢰하는 한 완벽하게 좋습니다. – ephemient

2

구성 데이터의 경우 YAMLYAML::XS을 선호합니다. 간단하고 읽기 쉽고 거의 모든 프로그래밍 언어에 대한 바인딩이 있습니다. 또 다른 인기있는 선택은 Config::General입니다.

7

구성 파일의 경우 YAML을 사용하고 싶습니다. 사람이 읽을 수있는 간단한 플랫폼 간 구성으로 실수로 실제 프로그램으로 변형 될 위험이 없습니다.

+3

필자는 YAML :: Tiny를 가볍고 순수한 Perl로 선호합니다 (필요한 경우 번들링하기가 쉽습니다). –

+0

인간이 쓸 수 있습니까? – mob

+2

@mobrule : 인간이 편집 할 수 있다고 말하고 싶습니다. 기존 값을 변경하는 것은 간단합니다. 처음부터 수동으로 YAML 파일을 만드는 것은 약간 어렵습니다. –

1

는, 하나 개의 솔루션에 설정을 저장하는 것입니다 XML (또는 모험심 많은 JSON). 인간이 소모 할 수 있고 상호 운용 가능한 Perl은 로컬 PC에 존재할 필요가 없습니다 (XML과 JSON은 모두 "config URL"로 요청할 수 있습니다). 그리고 표준 모듈 (XML :: Simple은 일반적으로 config XML 파일)가 CPAN에 있습니다.

0

자신을 형식에 묶지 마십시오. Config::Any을 사용하거나 좀 더 많은 whizbang DWIM 요소 인 Config::JFDI (Config :: Any를 래핑합니다)을 사용하십시오. 그들과 함께 INI, YAML, XML, Apache-style config 등을 지원할 수있는 능력을 구입하십시오.

Config :: JFDI는 Catalyst의 config loader의 마법을 포착하려고 시도합니다. 즉, app-wide config, 환경 변수 지원, 제한된 매크로 기능으로 인스턴스 로컬 설정 병합 (__path_to(foo/bar)__이 유용합니다 놀랍게도 종종.)

1

이 간단한 구성의 경우, 특히이 데이터가 실제 세계에서 변경 될 것으로 예상하지 않는 사소한 일들에 대해서는 종종 YAML을 사용합니다. 단순함은 이길 수 없습니다 :

먼저 구성을 포함하는 Perl 데이터 구조를 작성하십시오.

use YAML; 

my $SETTINGS = { 
    '1' => "foo", 
    '2' => ["123", "456"], 
    '3' => "something", 
}; 

그런 다음 YAML :: DumpFile();

YAML::DumpFile("~/.$appname.yaml", $SETTINGS); 

는 데이터 구조를 삭제하고

my $SETTINGS = YAML::LoadFile("~/.$appname.yaml"); 

로 교체 그리고 잊어. 비록 당신이 YAML 문법을 알지 못하거나 배우고 싶다 할지라도, config에 대한 작은 변경은 수동으로 할 수 있고 더 많은 주요 변경은 Perl에서 수행 된 다음 YAML로 다시 덤프 될 수 있습니다.

관련 문제