Mercurial > pub > Impl
comparison lib/IMPL/declare.pm @ 407:c6e90e02dd17 ref20150831
renamed Lib->lib
| author | cin |
|---|---|
| date | Fri, 04 Sep 2015 19:40:23 +0300 |
| parents | |
| children | ee36115f6a34 |
comparison
equal
deleted
inserted
replaced
| 406:f23fcb19d3c1 | 407:c6e90e02dd17 |
|---|---|
| 1 package IMPL::declare; | |
| 2 use strict; | |
| 3 | |
| 4 use Carp qw(carp); | |
| 5 use IMPL::Class::PropertyInfo(); | |
| 6 use IMPL::Const qw(:access); | |
| 7 use IMPL::require(); | |
| 8 | |
| 9 BEGIN { | |
| 10 *_require = *IMPL::require::_require; | |
| 11 *_trace = *IMPL::require::_trace; | |
| 12 } | |
| 13 | |
| 14 sub import { | |
| 15 my ( $self, $args ) = @_; | |
| 16 | |
| 17 return unless $args; | |
| 18 | |
| 19 die "A hash reference is required" unless ref $args eq 'HASH'; | |
| 20 | |
| 21 no strict 'refs'; | |
| 22 no warnings 'once'; | |
| 23 | |
| 24 my $caller = caller; | |
| 25 | |
| 26 my $aliases = $args->{require} || {}; | |
| 27 | |
| 28 $IMPL::require::PENDING{$caller} = 1; | |
| 29 _trace("declare $caller"); | |
| 30 $IMPL::require::level++; | |
| 31 | |
| 32 *{"${caller}::SELF"} = sub () { | |
| 33 $caller; | |
| 34 }; | |
| 35 | |
| 36 while ( my ( $alias, $class ) = each %$aliases ) { | |
| 37 _trace("$alias => $class"); | |
| 38 $IMPL::require::level++; | |
| 39 my $c = _require($class); | |
| 40 | |
| 41 *{"${caller}::$alias"} = sub() { | |
| 42 $c; | |
| 43 }; | |
| 44 $IMPL::require::level--; | |
| 45 } | |
| 46 | |
| 47 my $base = $args->{base} || {}; | |
| 48 | |
| 49 my %ctor; | |
| 50 my @isa; | |
| 51 | |
| 52 if ( ref $base eq 'ARRAY' ) { | |
| 53 carp "Odd elements number in require" | |
| 54 unless scalar(@$base) % 2 == 0; | |
| 55 while ( my ( $class, $mapper ) = splice @$base, 0, 2 ) { | |
| 56 _trace("parent $class"); | |
| 57 $IMPL::require::level++; | |
| 58 $class = $aliases->{$class} || _require($class); | |
| 59 $IMPL::require::level--; | |
| 60 | |
| 61 push @isa, $class; | |
| 62 $ctor{$class} = $mapper; | |
| 63 } | |
| 64 } | |
| 65 elsif ( ref $base eq 'HASH' ) { | |
| 66 while ( my ( $class, $mapper ) = each %$base ) { | |
| 67 _trace("parent $class"); | |
| 68 $IMPL::require::level++; | |
| 69 $class = $aliases->{$class} || _require($class); | |
| 70 $IMPL::require::level--; | |
| 71 | |
| 72 push @isa, $class; | |
| 73 $ctor{$class} = $mapper; | |
| 74 } | |
| 75 } | |
| 76 | |
| 77 %{"${caller}::CTOR"} = %ctor; | |
| 78 push @{"${caller}::ISA"}, @isa; | |
| 79 | |
| 80 if ( ref( $args->{meta} ) eq 'ARRAY' ) { | |
| 81 $caller->SetMeta($_) foreach @{ $args->{meta} }; | |
| 82 } | |
| 83 | |
| 84 my $props = $args->{props} || []; | |
| 85 | |
| 86 if ( $props eq 'HASH' ) { | |
| 87 $props = [%$props]; | |
| 88 } | |
| 89 | |
| 90 die "A hash or an array reference is required in the properties list" | |
| 91 unless ref $props eq 'ARRAY'; | |
| 92 | |
| 93 carp "Odd elements number in properties declaration of $caller" | |
| 94 unless scalar(@$props) % 2 == 0; | |
| 95 | |
| 96 if (@$props) { | |
| 97 $self->_implementProps( $props, $caller ); | |
| 98 } | |
| 99 | |
| 100 if ( $args->{_implement} ) { | |
| 101 $self->_implementProps( $caller->abstractProps, $caller ); | |
| 102 $caller->abstractProps( [] ); | |
| 103 } | |
| 104 | |
| 105 $IMPL::require::level--; | |
| 106 delete $IMPL::require::PENDING{$caller}; | |
| 107 } | |
| 108 | |
| 109 sub _implementProps { | |
| 110 my ( $self, $props, $caller ) = @_; | |
| 111 | |
| 112 for ( my $i = 0 ; $i < @$props - 1 ; $i = $i + 2 ) { | |
| 113 my ( $prop, $spec ) = @{$props}[ $i, $i + 1 ]; | |
| 114 | |
| 115 $caller->ClassPropertyImplementor->Implement( | |
| 116 $spec, | |
| 117 { | |
| 118 name => $prop, | |
| 119 class => $caller, | |
| 120 access => $prop =~ /^_/ | |
| 121 ? ACCESS_PRIVATE | |
| 122 : ACCESS_PUBLIC | |
| 123 } | |
| 124 ); | |
| 125 } | |
| 126 } | |
| 127 | |
| 128 1; | |
| 129 | |
| 130 __END__ | |
| 131 | |
| 132 =pod | |
| 133 | |
| 134 =head1 NAME | |
| 135 | |
| 136 C<IMPL::declare> - описывает класс | |
| 137 | |
| 138 =head1 SYNOPSIS | |
| 139 | |
| 140 =begin code | |
| 141 | |
| 142 package My::Bar; | |
| 143 | |
| 144 use IMPL::declare { | |
| 145 require => { | |
| 146 TFoo => 'My::Foo', | |
| 147 TBox => 'My::Box' | |
| 148 }, | |
| 149 base => { | |
| 150 TFoo => '@_', | |
| 151 'IMPL::Object' => undef, | |
| 152 } | |
| 153 } | |
| 154 | |
| 155 sub CreateBox { | |
| 156 my ($this) = @_; | |
| 157 return TBox->new($this); | |
| 158 } | |
| 159 | |
| 160 =end code | |
| 161 | |
| 162 Специальная ситрока C<@_> означает передачу параметров конструктора текущего класса конструктору | |
| 163 базового класса без изменений. | |
| 164 | |
| 165 =head1 DESCRIPTION | |
| 166 | |
| 167 Описывает текущий пакет(модуль) как класс. В качестве параметра получает ссылку на хеш, | |
| 168 в которой храняться метаданные для объявления класса. | |
| 169 | |
| 170 =head1 METADATA | |
| 171 | |
| 172 =head2 C<require> | |
| 173 | |
| 174 Содержит ссылку на хеш с синонимами модулей, которые будут доступны в текушем модуле, | |
| 175 аналогично использованию C<IMPL::require>. Однако, если модуль не требует загрузки при | |
| 176 помощи C<require> нужно использовать префикс C<'-'> в его имени | |
| 177 | |
| 178 =begin code | |
| 179 | |
| 180 { | |
| 181 require => { | |
| 182 TObject => 'IMPL::Object', # will be loaded with require | |
| 183 TFoo => '-My:App::Data::Foo' # will not use 'require' to load module | |
| 184 } | |
| 185 } | |
| 186 | |
| 187 =end code | |
| 188 | |
| 189 =head2 C<base> | |
| 190 | |
| 191 Обисывает базове классы для текущего класса. Если данный параметр - ссылка массив, то | |
| 192 этот массив будет превращен в массив C<@ISA>. Если данный параметр - ссылка на хеш, то | |
| 193 его ключи опичавют список базовых классов, а значения - преобразование параметров для | |
| 194 вызова базовых конструкторов. | |
| 195 | |
| 196 В качестве имен базовых классов могут быть как полные имена модулей, так и назначенные | |
| 197 ранее псевдонимы. Использование префикса C<'-'> перед B<полным именем модуля> означает, | |
| 198 что модуль не требуется загружать, в случае с псевдонимами, префикс C<'-'> уже был указан | |
| 199 при их объявлении. | |
| 200 | |
| 201 =begin code | |
| 202 | |
| 203 { | |
| 204 require => { | |
| 205 TFoo => '-My:App::Data::Foo' # will not use 'require' to load module | |
| 206 }, | |
| 207 base => { | |
| 208 TFoo => '@_', # pass parameters unchanged | |
| 209 'My::Base::Class' => sub { name => $_[0], data => $_[1] }, # remap parameters | |
| 210 '-My::Extentions' => undef, # do not pass any parameters | |
| 211 } | |
| 212 } | |
| 213 | |
| 214 =end code | |
| 215 | |
| 216 =cut |
