[첫화면으로]Perl/모듈

마지막으로 [b]

1. 다른 파일을 include 하기
1.1. do
1.2. require
1.3. use
2. perldoc use 번역
2.1. 참고: 'use VERSION'의 사이드 이펙트
3. @INC 변경하기
3.1. 환경변수로 모듈 디렉토리 추가
3.2. 명령행 인자 -I
4. import, Exporter
4.1. %EXPORT_TAGS
4.2. 객체 지향 모듈의 경우
4.3. import 직접 구현하기
5. 패키지
5.1. package 의 스코프
5.2. __PACKAGE__ 상수
6. 기타
7. Comments

1. 다른 파일을 include 하기

1.1. do

@INC에 나열된 경로에서 파일을 찾아서, do가 있는 자리에서 파일의 내용을 실행. 메인 프로그램의 블록 안에 있는 것처럼 동작하나, 메인 프로그램에 있는 렉시컬 변수들은 접근하지 못한다.1

리턴값2

config 파일을 읽는 예3

                   # read in config files: system first, then user
                   for $file ("/share/prog/defaults.rc",
                              "$ENV{HOME}/.someprogrc")
                  {
                       unless ($return = do $file) {
                           warn "couldn't parse $file: $@" if $@;
                           warn "couldn't do $file: $!"    unless defined $return;
                           warn "couldn't run $file"       unless $return;
                       }
                   }

1.2. require

do와 같지만, 한 번 로드한 파일을 다시 require하면 무시한다. 파일을 못 찾으면 에러.4

bareword를 쓸경우는 ".pm"파일을 찾는다. "::"는 디렉토리 구분자로 변환5

require Monty::Python;
# @INC 패쓰에서 MOnty/Python.pm을 찾는다

1.3. use

require와 같지만, 프로그램이 시작되면 제일 먼저 실행한다. (컴파일 타임에)
# 아래와 같이 적어도, 두개의 모듈이 다 include된다
if ($graphical) {
   use MyProgram::Graphical;
} else {
   use MyProgram::Text;
}

2. perldoc use 번역

Perldoc:use 번역 (5.14.1 기준)

use Module VERSION LIST
use Module VERSION
use Module LIST
use Module
use VERSION

지정한 모듈로부터 일부 시맨틱을 가져와 현재 패키지에 임포트한다. 일반적으로 서브루틴이나 변수들의 이름을 현재 패키지에 alias하는 형태로 이루어진다.

    BEGIN { require Module; Module->import( LIST ); }

조건부로 임포트를 할 수 있다; Perldoc:if 참조

use VERSION 형태의 경우, VERSION은 5.006 같은 십진수 양의 소수일 수 있고 이것은 $]와 비교되게 된다. 또는 v5.6.1과 같은 v-string일 수도 있고, 이것은 $^V($PERL_VERSION)과 비교되게 된다. 만일 VERSION의 값이 현재 사용중인 Perl 인터프리터의 버전보다 크다면 익셉션이 발생한다; Perl은 스크립트 파일의 나머지를 해석하지 않으려 할 것이다. Perldoc:require는 비슷한 검사를 런타임에 하는 것과 비교된다. 반대로, no VERSION은 명시된 버전보다 이전 버전의 Perl을 쓰기를 요구한다.

VERSION을 v5.6.1 형태로 표시하는 건 이 형태를 지원하지 않는 오래된 버전(정확히는 5.6.0이전)의 Perl에서는 잘못 해석된 에러 메시지를 내므로 피하는 게 좋다. 동일한 의미의 소수 형태를 써야 한다.

    use v5.6.1;    # 컴파일타임에 버전 체크
    use 5.6.1;     # 마찬가지
    use 5.006_001; # 마찬가지; 하위호완성 유지를 위해 권장됨

이것은 오래된 버전의 펄에서 동작하지 않는 라이브러리 모듈을 use하기 전에 현재 Perl의 버전을 체크하고자 할 때 유용하다.

또한, 명시된 펄 버전이 5.9.5 또는 그 이후 버전일 경우, use VERSIONfeature 프라그마도 같이 로드하고 요청된 버전에서 제공하는 모든 기능을 가능하게 한다. Perldoc:feature 참조. 유사하게, 만일 명시된 펄 버전이 5.11.0 또는 그 이후 버전이라면, use strict를 한 것처럼 strict 프라그마도 작동하게 된다 (strict.pm 파일이 실제로 로드되지는 않는다는 것이 다르다)

BEGIN 블록은 requireimport가 컴파일타임에 실행되도록 한다. require는 모듈이 아직 메모리에 로드되지 않았다면 로드한다. import는 내장함수가 아니라, 단지 평범하게 Module 패키지에 정적으로 메쏘드를 호출하여 그 모듈로 하여금 여러 기능을 현재 패키지에 가져오도록 하는 것이다. 모듈은 자신의 import를 자신이 원하는 어떤 식으로든 구현할 수 있으나, 대부분의 모듈은 Cpan:Exporter 모듈에 정의되어 있는 Exporter 클래스에서 상속받아 제공한다. 만일 import 메쏘드가 없을 경우 이 호출은 생략되며, 설령 AUTOLOAD 메쏘드가 있는 상태라도 마찬가지이다.

만일 모듈 패키지의 import를 호출하고 싶지 않다면 (예를 들어 현재 패키지의 네임스페이스에 변화가 생기는 걸 막기 위해서), 명시적으로 빈 리스트를 넘겨주라:

    use Module ();
이것은 정확히 다음과 동일하다:
    BEGIN { require Module }

Module과 LIST 사이에 VERSION 인자가 존재한다면, use는 클래스 모듈에 있는 VERSION 메쏘드를 호출하며, 주어진 버전값을 인자로 넘겨준다. UNIVERSAL 클래스에서 상속되는 디폴트 VERSION 메쏘드는 $Module::VERSION 변수의 값이 인자로 받은 버전보다 낮으면 경고(croak)한다.

다시 한 번, LIST를 생략하는 것(이 경우 import가 인자 없이 호출된다)과 명시적으로 빈 리스트 ()를 넘겨주는 것(이 경우 import가 호출되지 않는다)을 구분하라. VERSION 다음에 쉼표가 없다는 것에 유의하라.

프라그마(컴파일러 지시자)들도 이 형태로 구현되어 있다. 현재 구현된 프라그마들은 다음과 같다:

    use constant;
    use diagnostics;
    use integer;
    use sigtrap  qw(SEGV BUS);
    use strict   qw(subs vars refs);
    use subs     qw(afunc blurfl);
    use warnings qw(all);
    use sort     qw(stable _quicksort _mergesort);

이런 pseudo-module들 중 일부는 시맨틱을 현재 블록 스코프에 임포트한다 (strictinteger처럼). 보통의 모듈들이 시맨틱을 현재 패키지(파일의 끝까지 적용된다)에 임포트하는 것과 대조적이다.

use는 컴파일타임에 적용되므로, 컴파일되는 코드의 실행흐름에 영향을 받지 않는다. 특히, use를 조건문에서 실행되지 않을 분기(false branch)에 둔다 해도 그 use는 처리된다. 모듈이나 프라그마가 특정 조건에서만 로드되어야 한다면, Perldoc:if 프라그마를 사용한다:

    use if $] < 5.008, "utf8";
    use if WANT_WARNINGS, warnings => qw(all);

no 선언은 use에 의해 임포트될 내용들은 unimport한다. 즉 unimport Module LIST를 호출한다. 이 호출은 import가 VERSION 인자를 받았을 때, LIST를 생략했을 때, 빈 LIST를 인자로 받았을 때, 메쏘드가 아예 없을 때 동작했던 방식과 동일하게 동작한다.

    no integer;
    no strict 'refs';
    no warnings;

no VERSION 형태를 사용할 때 주의하라. 이것은 단지 현재 실행되는 버전이 인자로 준 버전보다 낮다는 걸 확인하는 용도일 뿐, use VERSION에 의해 발생하는, 여러 feature가 사용가능하게 되는 효과를 취소하는 용도가 아니다.

Perldoc:perlmodlib에서 표준 모듈과 프라그마 목록을 볼 수 있다. Perldoc:perlrun에서, 커맨드라인에서 Perl을 실행할 때 -M-m 옵션을 주어 use 기능을 사용하는 방법에 대해 알 수 있다.

2.1. 참고: 'use VERSION'의 사이드 이펙트

원문: [Watch out for side effects with `use VERSION` | The Effective Perler]

Perl 5.9.5 이전 버전까지는 use VERSION은 단지 Perl 인터프리터의 버전을 체크하는 용도였다.

그러나 5.9.5와 그 이후 버전에서는 그 버전에 추가된 새로운 기능들을 추가하는 동작도 한다.

use 5.010

use 5.010을 하면, 이 버전에 추가된 세 가지 기능인 say, state, given-which가 임포트된다. 표면상으로는 새 버전의 perl에 새로운 키워드들이 추가됨에 따라 이전 버전에 맞춰 작성된 프로그램이 실행되지 못하게 하려는 거고, 또한 좋은 프로그래밍 철학을 받아들이도록 강요하기 위해서이기도 하다.

use 5.010;
say 'I can use Switch!';  # imported say()

given ($ARGV[0]) {        # imported given()
    when( defined ) { some_sub() }
};

sub some_sub {
    state $n = 0;         # imported state()
    say "$n: got a defined argument";
}

Perl 5.010을 쓰길 강요하되 새 기능들을 사용하지 않게 하려면, feature 프라그마를 사용하여 언임포트할 수 있다:

use 5.010;     # 묵시적인 임포트
no feature;    # 곧바로 되돌림

# 당신이 따로 작성한 say()
sub say {
    # something that you want to do
}

새 기능들 중 일부만 원한다면, 원하지 않는 기능들만 언임포트할 수 있다:

use 5.010;
no feature qw(say);   # state()와 given()은 남겨둠

sub say {
    # something that you want to do
}

use 5.012

Perl 5.12는 두 개의 기능이 더 추가된다. unicode_stringsbyteslocale 스코프 바깥쪽에 있는 모든 스트링을 유니코드 스트링으로 간주한다. 추가로, 자동으로 strict를 켠다:
use 5.012;
# now strictures are on

$foo = 1;   # compile-time error!

require를 쓰더라도 새 기능들과 strict는 켜진다:

BEGIN { require 5.012 }

$foo = 1;  # still a compile-time error

어떤 이상하고도 위험한 이유가 있어서 strict를 끄고 싶다면 직접 끌 수는 있다. 그러나 그럴 경우 당신이 포장도로를 벗어났고, 렌트카 계약 사항을 위반했으며, 전기톱 살인마가 당신을 기다리고 있다는 경고를 받지 못 할 것이다6

use 5.012;
no feature;
no strict;

my $foo = 1;

$fo0++;  # 확실히 된다, 계속 진행해서 에러를 만들라

회피 방법

오직 버전을 제한하는 것만 하고 싶다면, use를 쓰지 않고 $] 변수의 값을 직접 체크하면 된다.

BEGIN {
    die "Unsupported version"
        unless $] >= 5.010 and $] < 5.011
}
이 경우는, 허용할 perl 버전의 상한값도 제한할 수 있다는 추가 장점이 있다.

요점

3. @INC 변경하기

use 가 먼저 실행되어 버리기 때문에, @INC값을 바꾼 후에 use를 하려고 하는 것은 불가능. 이 때는 BEGIN 서브루틴을 사용한다. BEGIN은 컴파일타임에 실행된다.7
BEGIN {
   push @INC, "my/module/directory";
}
use Wibble;

# lib 프라그마를 사용하면 더 쉽다
use lib "my/module/directory";
use Wibble;

lib 프라그마를 사용하면 코드도 더 직관적이고, 자동으로 site-dependent path들을 추가하기 때문에 권장8

경로명에 변수를 사용할 수는 없다. (변수 할당은 런타임에 이뤄지므로) 이 경우는 use constant 프라그마 사용9

# 이렇게는 안 된다
my $LIB_DIR = '/home/gilligan/lib';
...
use lib $LIB_DIR;     # BROKEN
use Navigation::SeatOfPants;

# 아래와 같이
use constant LIB_DIR => '/home/gilligan/lib';
...
use lib LIB_DIR;
use Navigation::SeatOfPants;

펄 스크립트가 있는 경로를 기준으로 지정하고 싶다면, PerlDoc:FindBin 모듈을 사용하여 경로를 얻어낼 수 있다.10

use FindBin qw($Bin);
use lib $Bin;         # 스크립트가 있는 디렉토리
use lib "$Bin/lib";   # 서브디렉토리
use lib "$Bin/../lib";

3.1. 환경변수로 모듈 디렉토리 추가

PERL5LIB 환경변수에 추가11
export PERL5LIB=/Users/home/Ginger

3.2. 명령행 인자 -I

-I 옵션으로 추가 가능12
perl -I/home/skipper/perl-lib /home/skipper/bin/get_us_home

4. import, Exporter

모듈에 정의된 서브루틴을 호출자의 패키지로 가져오기13

use Wibble ("wobble", "bounce", "boing");
# 위는 Wibble 모듈을 로드한 후 다음을 실행한다
Wibble::import("wobble", "bounce", "boing");

import를 따로 정의해 줄 수도 있지만, 주로 PerlDoc:Exporter 모듈을 사용한다.

모듈의 @EXPORT_OK 패키지 변수에 지정된 것들만 import가능하고, use 에 파라메터가 없을 경우는 @EXPORT에 지정된 것이 디폴트로 import된다.14

# Wibble 모듈 샘플
package Wibble;
use warnings;
use strict;
use Exporter;                             # Exporter 를 사용
our @ISA = qw(Exporter);                  # Exporter 상속
our @EXPORT    = qw(bounce);              # 기본으로 export될 서브루틴
our @EXPORT_OK = qw(wobble bounce boing); # export가능한 서브루틴들

sub wobble { print "wobble\n"; mine(); }
sub bounce { warn  "bounce\n"; }
sub boing  { die   "boing!\n"; }
sub mine   { print "not be exported\n"; }

1;

4.1. %EXPORT_TAGS

여러 서브루틴이나 변수를 그룹지어서 태그로 묶음. 원하는 그룹을 한번에 import할 수 있게 함. 태그 이름 앞에는 콜론을 붙임15
use Fcntl qw( :flock );    # import all flock constants

자동적으로 사용가능한 태그들:16

태그 정의는 %EXPORT_TAGS 해쉬 변수에 한다.17

package Navigate::SeatOfPants;
use base qw(Exporter);

our @EXPORT    = qw(guess_direction_toward);
our @EXPORT_OK = qw(
                get_north_from_professor
                according_to_GPS
                ask_the_skipper_about
                );

our %EXPORT_TAGS = (
        all       => [ @EXPORT, @EXPORT_OK ],   # export할 수 있는 전부
        gps       => [ qw( according_to_GPS ) ],
        direction => [ qw(
                get_north_from_professor
                according_to_GPS
                guess_direction_toward
                ask_the_skipper_about
                ) ],
        );

4.2. 객체 지향 모듈의 경우

일반적으로 OO모듈은 아무것도 export하지 않는다.18
package My::OOModule::Base;
our @EXPORT = (  ); # you may even omit this line
use base qw(Exporter);

다음 메쏘드들은 Exporter에서 특별한 용도로 사용되므로, OO모듈에서 사용할 수 없거나, 오버라이드하지 않는 게 좋다.19

4.3. import 직접 구현하기

import도 서브루틴이므로, 이걸 구현하여 임포트 리스트에 옵션을 받는다거나 하는 용도로 쓸 수 있다. (PerlDoc:CGI, PerlDoc:Test::More 등이 예)20
sub import {
  no strict 'refs';
  my $debug = grep { $_ eq 'debug' } @_;       # 임포트 리스트에 'debug'가 있으면 디버깅 옵션 활성화
  my( $package, $file, $line ) = caller;       # caller는 자신을 부른 곳의 정보를 반환
  warn "I was called by $package in $file\n" if $debug;
  for (qw(filename basename fileparse)) {
    *{$package . "::$_"} = \&$_;               # 세 개의 심볼을 호출한 쪽의 패키지에 export 함
  }
}

5. 패키지

5.1. package 의 스코프

package directive의 스코프는21
package Navigation;

{  # start scope block
  package main;  # now in package main

  sub turn_toward_heading {  # main::turn_toward_heading
    .. code here ..
  }

}  # end scope block

# back to package Navigation

sub turn_toward_port { # Navigation::turn_toward_port
  .. code here ..
}

다음 이름들은 현재 패키지에 관계없이 main 패키지에 속한 것으로 간주된다:22

5.2. __PACKAGE__ 상수

__PACKAGE__ 상수는 현재 패키지 이름이 담겨 있다. 패키지 안에서 그 패키지 이름을 반복해서 사용해야 되는 경우에 사용한다. 나중에 패키지 이름을 변경하거나, 중간의 코드만 복사해서 다른 데서 사용할 때 에러를 예방할 수 있다.

        package Music::Artist;        # Inherit from the Music::DBI class (defined elsewhere)
        use base 'Music::DBI';        # These records are pulled from this database table

        Music::Artist->table('artist');    # 이렇게 패키지명을 직접 적는 대신
        __PACKAGE__->table('artist');      # __PACKAGE__ 사용

현재 패키지 이름을 /해쉬의 키로 사용할 경우 주의해야 한다. 해쉬키 자리에 bareword가 사용될 경우 자동으로 스트링으로 취급하기 때문이다.

        $hash{__PACKAGE__} = 1;      # 이렇게 쓰면
        $hash{"__PACKAGE__"} = 1;    # 이것과 동일한 결과. 즉 "__PACKAGE__"라는 키가 된다.

        # 패키지 명으로 치환하기 위해서 상수값을 먼저 계산하게 해야 한다.
        $hash{__PACKAGE__ . ""} = 1; # 빈 스트링을 붙여주거나

        my $package = __PACKAGE__;   # 변수에 먼저 넣은 후 사용
        $hash{$package} = 1;

__PACKAGE__ 는 컴파일타임에 계산되며, __FILE__이나 __LINE__과 마찬가지로 스트링 안에서 interpolate되지 않는다.[1]

6. 기타

7. Comments

[Perlmania Study 발표자료 - aero's Blog] - 타입글로브 얘기인데, 뒤쪽에 모듈의 import 원리가 나옴

-- Raymundo 2008-9-22 12:07 am

[question about "package" and variable scope... - comp.lang.perl.misc | Google 그룹스] - 패키지와 관련해서, 도저히 이해할 수 없는 결과가 나와서 뉴스그룹에 질문 올림.

-- Raymundo 2008-9-22 10:52 pm

아 놔 our도 렉시컬 스코프였다니;;;;
-- Raymundo 2008-9-22 11:24 pm
이름:  
Homepage:
내용:
 


컴퓨터분류
각주:
1. 4. 5. 7. 13. Beginning Perl, Chapter 10
2. 3. perldoc -f do
6. 원문이 이렇습니다 -_-;
8. 9. 11. Intermediate Perl, Chapter 03
10. Intermediate Perl, Chpater 10
12. 21. 22. Intermediate Perl, Chapter 10
14. 주인장 테스트로는, 반대로 use에 파라메터가 있을 경우는 @EXPORT에 있는 것이라고 해서 자동으로 import되지는 않는다
15. 16. 17. 18. 19. 20. Intermediate Perl, Chapter 15

마지막 편집일: 2013-8-3 11:20 am (변경사항 [d])
5826 hits | Permalink | 변경내역 보기 [h] | 페이지 소스 보기