블로그 이미지
JEEN

서울에 사는 꽃청년의 IT찌질모험기

Rss feed Tistory
IT/Perl 2008.06.07 14:27

[ Perl ] Perl 로 OOP 하지 않겠나(요)? - Moose #3 - 형태에 관한 이야기

사용자 삽입 이미지

 지난번에는 Moose 의 상속에 대한 이야기를 해봤습니다. 사실 이것저것 빼먹고 가는 것이 많기 때문에, 개인적으로 좀 더 알아봐주셨으면 하는 심정이 있고, 좀 더 알아보자 라고 했을 때 좀 지루할 것 같아서... 일단 원리를 알고 쓰기보다는 쓰면서 원리를 알아가는 게 더 쉬운 방법인 것 같기도 합니다.

2008/06/02 - [IT/Perl] - [ Perl ] Perl 로 OOP 하지 않겠나(요)? - Moose #1-2

여기에서 isa 에 들어가는 형태에 대한 언급이 있었고, Int 에서 문자열 쓰면 에러난다는 등의 해서는 안될 짓에 대한 이야기를 한 적이 있습니다. 이번에는 형태에 대한 좀 더 자세한 이야기입니다.
 
package Me2day::Request;
use Moose;
use Moose::Util::TypeConstraints;

subtype 'URI' # 자기가 정의하고픈 형태의 이름
  => as 'Object'  # 계승한 형태
  => where { $_->isa('URI') }; # 형태의 Validation 체크 

has 'uri' => (is => 'rw', isa => 'URI');

1;

  일단 가장 간단한 예제를 주워와봤습니다. 이런 'URI' 같은 자신이 직접 형태를 정해줄 경우에는
use Moose::Util::TypeConstraints;
이 필수입니다.

 그런 다음에는 자기 나름대로 URI 이라는 형태를 지정해 줍니다.
subtype 'URI'
  => as 'Object'
  => where { $_->isa('URI') };
 이제 uri 접근자는 URI가 아니면 받아들일 수 없게 되어버립니다. 이 말인 즉슨...

 my $blah = Me2day::Request->new( 'uri' => 'http://jeen.tistory.com' );

 일 때, uri 의 값을 문자열인 http://jeen.tistory.com 으로 지정했습니다. 이러면 자신이 정의한 URI 의 타입에 맞지 않게 됩니다. URI 는 Object 이기를 기대하며, URI 모듈을 사용하기를 원하고 있죠. 그럼 이 입맛에 맞춰주면 됩니다.
 my $blah = Me2day::Request->new( 'uri' => URI->new('http://jeen.tistory.com') );

 그러면 이제 화를 내지 않는 우리의 Moooooose ~
 Moose 특유의 뿔 처럼 엄격함만을 강조하는 것이냐면, 그럴 수도 있습니다만, 여기서 더욱 유연하게 처리해줄 수 도 있습니다.
 coerce 'URI'
   => from 'Str'
   => via { URI->new($_) }
   => from 'Int'
   => via { blahblah... }
 coerce 를 사용하는 것입니다. 이러면 URI 속성을 사용하는 접근자에 문자열('Str') 이 올때에는 URI 모듈을 사용해서 부르게 됩니다. 이때는 여러 상속형태에 대해서 강제변경을 지정할 수 있습니다.

 여기서 중요한 것은 coerce 를 사용해서 강제로 형태변경할 경우에는 접근자에 옵션을 하나 더 추가해줘야 합니다.
has 'uri' => (is => 'rw', isa => 'URI', coerce => 1);
 이렇게 말이죠.

 전체코드입니다.

package Me2day::Request;
use Moose;
use Moose::Util::TypeConstraints; # 아래와 같은 일을 하려면 반드시!
use URI;

subtype 'URI' # 자기가 정의하고픈 형태의 이름
  => as 'Object'  # 계승한 형태
    => where { $_->isa('URI') }; # 형태의 Validation 체크

coerce 'URI' # 강제 형태변경
  => from 'Str' # 이런 타입이 오면
  => via { URI->new($_) };  # 이렇게 해줘야지.

has 'uri' => (is => 'rw', isa => 'URI', coerce => 1);

1;

my $blah = Me2day::Request->new ( uri => 'http://jeen.tistory.com' );
print $blah->uri."\n";  # http://jeen.tistory.com
print $blah->uri->scheme;  # http
 
  물론 uri 의 값은 URI->new('http://jeen.tistory.com') 를 써도 됩니다. 이건  subtype 에서 기본적으로 바라고 있는 값의 형태이기 때문입니다.

 이쯤에서 다른 예제를 불러오도록 하죠.
package Me2day::Request;
use Moose;
use Moose::Util::TypeConstraints;
use Digest::MD5;

subtype 'Encrypt'
    => as 'Str';

coerce 'Encrypt'
    => from 'Str'
    => via {
        my $nonce = sprintf "%08x", rand(16 ** 8);
        $nonce.Digest::MD5->new->add($nonce.$_)->hexdigest;
    };

has 'username' => (is => 'ro', isa => 'Str', required => 1);
has 'password' => (is => 'ro', isa => 'Encrypt', required => 1, coerce => 1);

1;

my $blah = Me2day->new ( username => 'jeen', password => '22830' );
print $blah->password; # 65dfb0a73f23368b4701a2435d8a64cabd26762b

 어떤 별 다른 차이점도 없습니다. Me2day의  인증키 생성을 위한 처리를 coerce 'Encrypt' 에 담아서,
password 값이 들어오면 자동으로 인증키를 만들고 그 값이 password 의 값으로 강제변경되는 것입니다. 위에서 언급을 빼먹었는데. coerce 를 사용하기 위해서는 subtype 이 지정되어 있어야 합니다.

 이상으로 Moose 의 형태변경에 대한 이야기를 마치겠습니다.
  • suns1997 2009.12.20 20:32 ADDR 수정/삭제 답글

    안녕하세요~ Moose 글 잘보고 있습니다 ^^

    위에 예제를 따라하고 있는데요.

    coerce 'URI' # 강제 형태변경
    => as 'Str' # 이런 타입이 오면
    => via { URI->new($_) }; # 이렇게 해줘야지.

    이 코드가 있는 예제를 실행하면 아래 처럼 에러가 발생합니다.

    Can't call method "_compiled_type_constraint" on unblessed reference at /Users/suns1997/perl5/lib/perl5/Moose/Meta/TypeCoercion.pm line 52.

    Str타입에 대해 URI 객체가 생성이 안되는 것 같은데
    어떻게 해야할지..;;;

    • BlogIcon JEEN 2009.12.20 23:29 신고 수정/삭제

      Oops, 죄송합니다.

      Coerce 에서는 as 가 아니라, from 을 사용합니다.

      ;ㅁ; 죄송 또 죄송합니다. 고쳐놓겠습니다.

  • suns1997 2009.12.21 01:25 ADDR 수정/삭제 답글

    감사합니다; from으로 하니 잘 되네요~

    또 질문이 있는데...

    맨 아래 코드에 실행하면 22820이 나옵니다.
    Encrypt type이 'Str'이라 coerce로 넘어가지 않는것 같습니다.

    혹시 cocero이 아니라 password을 Dafault로 MD5로 만들어줄수 있을까요?

    만약 기존 Object라면 생성자에서 바로 MD5로 바꿔주고 bless하면 되는데 ^^;

    • BlogIcon JEEN 2009.12.21 10:37 신고 수정/삭제

      아, 그러고보니 MD5 HASH 값 자체가 Str 이니까 뭐 무리해서 Coerce 할 필요는 없지 않을까 하는 생각을 했습니다. 그냥,

      default => sub { CODE }

      로 기본 설정해주실 수 있고, (via 코드를 아마 그대로 넣으면 될겁니다.)

      접근자 지정시에,

      lazy_build => 1,

      옵션을 설정해서

      sub _build_password { CODE }

      를 통해서 lazy building 도 가능합니다.

TOTAL 530,006 TODAY 2