comparison Lib/IMPL/declare.pm @ 197:6b1dda998839

Added IMPL::declare, IMPL::require, to simplify module definitions IMPL::Transform now admires object inheritance while searching for the transformation Added HTTP some exceptions IMPL::Web::Application::RestResource almost implemented
author sergey
date Thu, 19 Apr 2012 02:10:02 +0400
parents
children 2ffe6f661605
comparison
equal deleted inserted replaced
196:a705e848dcc7 197:6b1dda998839
1 package IMPL::declare;
2 use strict;
3
4 use Scalar::Util qw(set_prototype);
5
6 sub import {
7 my ($self,$args) = @_;
8
9 return unless $args;
10
11 die "A hash reference is required" unless ref $args eq 'HASH';
12
13 no strict 'refs';
14
15 my $caller = caller;
16
17 my $aliases = $args->{require} || {};
18
19 while( my ($alias, $class) = each %$aliases ) {
20 _require($class);
21
22 *{"${caller}::$alias"} = set_prototype(sub {
23 $class
24 }, '');
25 }
26
27 my $base = $args->{base} || {};
28
29 my %ctor;
30 my @isa;
31
32 if (ref $base eq 'ARRAY') {
33 @isa = map _require($_), @$base if @$base;
34 } elsif (ref $base eq 'HASH' ) {
35 while ( my ($class,$mapper) = each %$base ) {
36 $class = $aliases->{$class} || _require($class);
37
38 push @isa,$class;
39 $ctor{$class} = $mapper;
40 }
41 }
42
43 *{"${caller}::CTOR"} = \%ctor;
44 *{"${caller}::ISA"} = \@isa;
45 }
46
47 sub _require {
48 my ($class) = @_;
49
50 if (not $class =~ s/^-//) {
51 (my $file = $class) =~ s/::|'/\//g;
52 require "$file.pm";
53 }
54 $class;
55 }
56
57
58 1;
59
60 __END__
61
62 =pod
63
64 =head1 NAME
65
66 C<IMPL::declare> - описывает класс
67
68 =head1 SYNOPSIS
69
70 =begin code
71
72 package My::Bar;
73
74 use IMPL::declare {
75 require => {
76 TFoo => 'My::Foo',
77 TBox => 'My::Box'
78 },
79 base => {
80 TFoo => '@_',
81 'IMPL::Object' => undef,
82 }
83 }
84
85 sub CreateBox {
86 my ($this) = @_;
87 return TBox->new($this);
88 }
89
90 =end code
91
92 Специальная ситрока C<@_> означает передачу параметров конструктора текущего класса конструктору
93 базового класса без изменений.
94
95 =head1 DESCRIPTION
96
97 Описывает текущий пакет(модуль) как класс. В качестве параметра получает ссылку на хеш,
98 в которой храняться метаданные для объявления класса.
99
100 =head1 METADATA
101
102 =head2 C<require>
103
104 Содержит ссылку на хеш с синонимами модулей, которые будут доступны в текушем модуле,
105 аналогично использованию C<IMPL::require>. Однако, если модуль не требует загрузки при
106 помощи C<require> нужно использовать префикс C<'-'> в его имени
107
108 =begin code
109
110 {
111 require => {
112 TObject => 'IMPL::Object', # will be loaded with require
113 TFoo => '-My:App::Data::Foo' # will not use 'require' to load module
114 }
115 }
116
117 =end code
118
119 =head2 C<base>
120
121 Обисывает базове классы для текущего класса. Если данный параметр - ссылка массив, то
122 этот массив будет превращен в массив C<@ISA>. Если данный параметр - ссылка на хеш, то
123 его ключи опичавют список базовых классов, а значения - преобразование параметров для
124 вызова базовых конструкторов.
125
126 В качестве имен базовых классов могут быть как полные имена модулей, так и назначенные
127 ранее псевдонимы. Использование префикса C<'-'> перед B<полным именем модуля> означает,
128 что модуль не требуется загружать, в случае с псевдонимами, префикс C<'-'> уже был указан
129 при их объявлении.
130
131 =begin code
132
133 {
134 require => {
135 TFoo => '-My:App::Data::Foo' # will not use 'require' to load module
136 },
137 base => {
138 TFoo => '@_', # pass parameters unchanged
139 'My::Base::Class' => sub { name => $_[0], data => $_[1] }, # remap parameters
140 '-My::Extentions' => undef, # do not pass any parameters
141 }
142 }
143
144 =end code
145
146 =cut