Mercurial > pub > Impl
changeset 209:a8db61d0ed33
IMPL::Class::Meta refactoring
author | cin |
---|---|
date | Mon, 28 May 2012 19:58:56 +0400 |
parents | 3d433a977e3b |
children | 6adaeb86945d |
files | Lib/IMPL/Class/Meta.pm Lib/IMPL/Class/PropertyInfo.pm Lib/IMPL/Code/Loader.pm Lib/IMPL/DOM/Node.pm Lib/IMPL/declare.pm _test/Test/Class/Meta.pm _test/temp.pl |
diffstat | 7 files changed, 91 insertions(+), 222 deletions(-) [+] |
line wrap: on
line diff
--- a/Lib/IMPL/Class/Meta.pm Fri May 18 18:43:00 2012 +0400 +++ b/Lib/IMPL/Class/Meta.pm Mon May 28 19:58:56 2012 +0400 @@ -1,12 +1,13 @@ package IMPL::Class::Meta; use strict; +use Carp qw(carp); use IMPL::clone qw(clone); my %class_meta; my %class_data; -sub set_meta { +sub SetMeta { my ($class,$meta_data) = @_; $class = ref $class if ref $class; @@ -17,7 +18,11 @@ push @{$class_meta{$class}{ref $meta_data}},$meta_data; } -sub get_meta { +sub set_meta { + goto &SetMeta; +} + +sub GetMeta { my ($class,$meta_class,$predicate,$deep) = @_; $class = ref $class if ref $class; no strict 'refs'; @@ -35,10 +40,16 @@ wantarray ? @result : \@result; } +sub get_meta { + goto &GetMeta; +} + sub class_data { my $class = shift; $class = ref $class || $class; + carp 'The method is obsolete, use static_accessor($name,$value,\'clone\') instead'; + if (@_ > 1) { my ($name,$value) = @_; return $class_data{$class}{$name} = $value; @@ -58,23 +69,26 @@ } sub static_accessor { - my ($class,$name,$value) = @_; + my ($class,$name,$value,$clone) = @_; $class = ref $class || $class; no strict 'refs'; *{"${class}::${name}"} = sub { - if (@_ > 1) { - my $self = shift; - $self = ref $self || $self; + my $self = shift; + + if (@_ > 0) { + $self = ref $self || $self; if ($class ne $self) { - $self->static_accessor( $name => $_[0]); # define own class data + $self->static_accessor( $name => $_[0] ); # define own class data } else { $value = $_[0]; } } else { - $value; + ($clone and $class ne $self) + ? $self->static_accessor($name => clone($value),$clone) + : $value and $value ; } }; $value @@ -152,13 +166,11 @@ =head1 MEMBERS -=over - -=item C<set_meta($meta_data)> +=head2 C<set_meta($meta_data)> Добавляет метаданные C<$meta_data> к классу. -=item C<get_meta($meta_class,$predicate,$deep)> +=head2 C<get_meta($meta_class,$predicate,$deep)> Выбирает метаданные типа C<$meta_class> и его наследников, с возможностью фильтрации и получения метаданных базовых классов. @@ -201,50 +213,13 @@ =back -=item C<class_data($name,$new_value)> - -В отличии от метаданных, C<class_data> не накапливает информацию, -а хранит только один экземпляр для одного ключа C<$name>. - -Если новое значение не задано, то осуществляется выборка сохраненного, -если текущий класс не имеет сохраненного значения, то оно ищется в базовых -классах, затем копия найденного значения сохраняется в текущем классе и -возвращается наружу. Это позволяет базовым классам задавать значение по-умолчанию, -которые могут быть изменены или заменены субклассами. - -=begin code - -package Foo; -use parent qw(IMPL::Class::Meta); - -__PACKAGE__->class_data( info => { version => 1 } ); # will be default for all subclasses - -sub say_version { - my ($self) = @_; - - print $self->class_data('info')->{version}; -} - -package Bar; -use parent qw(Foo); - -__PACKAGE__->class_data('info')->{ language } = 'English'; - -package main; - -Foo->class_data('info')->{version} = 2; -Bar->say_version; # will print '1'; -Foo->say_version; # will print '2'; - -=end code - -=item C<static_accessor($name[,$value])> +=head2 C<static_accessor($name[,$value[,$clone]])> Создает статическое свойство с именем C<$name> и начальным значением C<$value>. -Использование данного свойство аналогично использованию C<class_data>, за исключением -того, что C<class_data> гарантирует, что наследник обладает собственной копией данных, -изменение которых не коснется ни базового класса, ни соседей. +Параметр C<$clone> контролирует то, как наследуются значения, если требуется каждому классу обеспечить +свое уникальное значение, то при первом обращении оно будет клонировано, по умолчанию клонирование не +происходит. =begin code @@ -260,8 +235,5 @@ __PACKAGE__->info({language => 'English'}); # will define own 'info' but will loose original data. =end code - - -=back =cut
--- a/Lib/IMPL/Class/PropertyInfo.pm Fri May 18 18:43:00 2012 +0400 +++ b/Lib/IMPL/Class/PropertyInfo.pm Mon May 28 19:58:56 2012 +0400 @@ -2,10 +2,13 @@ use strict; use IMPL::_core::version; -use parent qw(IMPL::Class::MemberInfo); +use IMPL::declare { + base =>{ + 'IMPL::Class::MemberInfo' => '@_' + } +}; __PACKAGE__->mk_accessors(qw(Type Mutators canGet canSet ownerSet)); -__PACKAGE__->PassThroughArgs; my %LoadedModules; @@ -49,4 +52,15 @@ =pod +=head1 NAME + +C<IMPL::Class::PropertyInfo> - метаданные о свойствах объектов. Используются для отражения и +проверки данных объектов. + +=head1 DESCRIPTION + +В зависимости от типа каждый объект предоставляет способ хранения данных, например хеши позволяют +хранить состояние в виде ассоциативного массива и т.д. Информация о свойстве предоставляет определенный +уровень абстракции. + =cut
--- a/Lib/IMPL/Code/Loader.pm Fri May 18 18:43:00 2012 +0400 +++ b/Lib/IMPL/Code/Loader.pm Mon May 28 19:58:56 2012 +0400 @@ -2,32 +2,47 @@ use strict; use warnings; -my %packages; +use IMPL::lang qw(:declare :constants); + +use IMPL::declare { + require => { + Exception => 'IMPL::Exception', + ArgumentException => '-IMPL::InvalidArgumentException' + }, + base => { + 'IMPL::Object' => undef, + 'IMPL::Object::Autofill' => '@_' + } +}; -sub Provide { - my ($self,$package) = @_; - - my ($declaringPackage,$file) = caller(); - $packages{$package} = { declaringPackage => $declaringPackage, file => $file, evidence => 'provide' }; +my $default; +sub default { + $default ||= new IMPL::Code::Loader; } +my $safe; +sub safe { + $safe ||= new IMPL::Code::Loader(verifyNames => 1); +} + +BEGIN { + public property verifyNames => PROP_GET | PROP_OWNERSET; + public property prefix => PROP_GET | PROP_OWNERSET; +} + + sub Require { - my ($self,$package) = @_; + my ($this,$package) = @_; - return 1 if $packages{$package}; + if ($this->verifyNames) { + $package =~ m/^([a-zA-Z_0-9]+(?:::[a-zA-Z_0-9]+)*)$/ or die ArgumentException->new("package") ; + } - if (my $file = $INC{$package}) { - $packages{$package} = { file => $file, evidence => 'inc' }; - return 1; - } + $package = $this->prefix . $package if $this->prefix; - undef $@; + my $file = join('/', split(/::/,$package)) . ".pm"; - if ( eval "require $package; 1;" and not $packages{$package}) { - $packages{$package} = { file => $INC{$package}, evidence => 'inc' }; - }; - - die $@ if $@ and not $!; + require $file; } 1;
--- a/Lib/IMPL/DOM/Node.pm Fri May 18 18:43:00 2012 +0400 +++ b/Lib/IMPL/DOM/Node.pm Mon May 28 19:58:56 2012 +0400 @@ -22,7 +22,6 @@ public _direct property schemaSource => prop_get | owner_set; private _direct property _propertyMap => prop_all ; - __PACKAGE__->class_data(property_bind => {}); } our %Axes = (
--- a/Lib/IMPL/declare.pm Fri May 18 18:43:00 2012 +0400 +++ b/Lib/IMPL/declare.pm Mon May 28 19:58:56 2012 +0400 @@ -2,6 +2,7 @@ use strict; use Scalar::Util qw(set_prototype); +use Carp qw(carp); sub import { my ($self,$args) = @_; @@ -30,6 +31,7 @@ my @isa; if (ref $base eq 'ARRAY') { + carp("will be changed in next version"); @isa = map _require($_), @$base if @$base; } elsif (ref $base eq 'HASH' ) { while ( my ($class,$mapper) = each %$base ) {
--- a/_test/Test/Class/Meta.pm Fri May 18 18:43:00 2012 +0400 +++ b/_test/Test/Class/Meta.pm Mon May 28 19:58:56 2012 +0400 @@ -5,42 +5,43 @@ __PACKAGE__->PassThroughArgs; -use IMPL::Test qw(test failed); +use IMPL::Test qw(test failed assert); test defineFooClassData => sub { - Foo->class_data(info => {}); + Foo->static_accessor(info => {},'clone'); }; test updateFooClassData => sub { - Foo->class_data('info')->{data} = 'Foo' ; + Foo->info->{data} = 'Foo' ; }; test getFooClassData => sub { - failed "Wrong class data", "Expected: Foo", "Got: ".Foo->class_data('info')->{data} unless Foo->class_data('info')->{data} eq 'Foo'; + assert( Foo->info->{data} eq 'Foo' ); }; test getBazClassData => sub { - failed "Wrong class data", "Expected: Foo", "Got: ".Baz->class_data('info')->{data} unless Baz->class_data('info')->{data} eq 'Foo'; + assert( Baz->info->{data} eq 'Foo' ); + assert( Bar->info->{data} eq 'Foo' ); }; test updateBarClassData => sub { - Bar->class_data('info')->{data} = 'Bar'; + Bar->info->{data} = 'Bar'; }; test getBarClassData => sub { - failed "Wrong class data", "Expected: Bar", "Got: ".Bar->class_data('info')->{data} unless Bar->class_data('info')->{data} eq 'Bar'; + assert( Bar->info->{data} eq 'Bar'); }; test validatetFooClassData => sub { - failed "Wrong class data", "Expected: Foo", "Got: ".Foo->class_data('info')->{data} unless Foo->class_data('info')->{data} eq 'Foo'; + assert( Foo->info->{data} eq 'Foo'); }; test validateBazClassData => sub { - failed "Wrong class data", "Expected: Foo", "Got: ".Baz->class_data('info')->{data} unless Baz->class_data('info')->{data} eq 'Foo'; + assert( Baz->info->{data} eq 'Foo'); }; test getwrongBazClassData => sub { - failed "Wrong class data", "Expected: undef", "Got: ".Foo->class_data( 'info2' ) if Foo->class_data( 'info2' ); + assert( not eval { Foo->info2; 1; } ); };
--- a/_test/temp.pl Fri May 18 18:43:00 2012 +0400 +++ b/_test/temp.pl Mon May 28 19:58:56 2012 +0400 @@ -1,135 +1,1 @@ -#!/usr/bin/perl -use strict; - -use Data::Dumper(); - -=pod - -{ - bar => { - next => { - foo => { - data => 'teo' - }, - baz => { - data => 'ioh' - } - }, - data => 'duo' - }, - wee => { - data => 'iwy' - } -} - -=cut - -my $tree = {}; - -foreach my $selector( - { path => [qw( foo bar )], data => 'teo' }, - { path => [qw( {x:.*} zoo bar )], data => 'view/{x}'}, - { path => [qw( foo >zoo >bar )], data => 'ilo' }, - { path => [qw( bar )], data => 'duo' }, - { path => [qw( wee )], data => 'iwy'}, - { path => [qw( foo wee )], data => 'fwy'}, - { path => [qw( {x:\w+} )], data => 'x:{x}'}, - { path => [qw( boo {x:\w+} )], data => 'boo/{x}'}, -) { - my $t = $tree; - my @path = reverse @{$selector->{path}}; - my $last = pop @path; - my $level = 1; - foreach my $prim (@path ) { - $t = ($t->{$prim}->{next} ||= {}); - $level ++; - } - $t->{$last}->{level} = $level; - $t->{$last}->{data} = $selector->{data}; -} - -my @target = qw( foo zoo bar ); -my @results; -my $alternatives = [ { selector => $tree, immediate => 1 } ]; - -$alternatives = MatchAlternatives($_,$alternatives,\@results) foreach reverse @target; - - -sub MatchAlternatives { - my ($segment,$alternatives,$results) = @_; - - warn "alternatives: ", scalar @$alternatives,", segment: $segment"; - - my @next; - - foreach my $alt (@$alternatives) { - while (my ($selector,$match) = each %{$alt->{selector}} ) { - warn $selector; - - warn "\timmediate" if $alt->{immediate}; - warn "\thas children" if $match->{next}; - - my $context = { - vars => \%{ $alt->{vars} || {} }, - selector => $match->{next} - }; - - if ($selector =~ s/^>//) { - $context->{immediate} = 1; - } - - if (my ($name,$rx) = ($selector =~ m/^\{(?:(\w+)\:)?(.*)\}$/) ) { - #this is a regexp - warn "\tregexp: [$name] $rx"; - - if ( my @captures = ($segment =~ m/($rx)/) ) { - $context->{success} = 1; - - warn "\t",join(',',@captures); - - if ($name) { - $context->{vars}->{$name} = \@captures; - } - } - } else { - #this is a segment name - if ($segment eq $selector) { - $context->{success} = 1; - } - } - - # test if there were a match - if (delete $context->{success}) { - warn "\tmatch"; - if (my $data = $match->{data}) { - # interpolate data - $data =~ s/{(\w+)(?:\:(\d+))?}/ - my ($name,$index) = ($1,$2 || 0); - - if ($context->{vars}{$name}) { - $context->{vars}{$name}[$index]; - } else { - ""; - } - /gex; - - push @$results, { level => $match->{level}, result => $data }; - } - warn "\tnext" if $context->{selector}; - push @next, $context if $context->{selector}; - } else { - #repeat current alternative if it's not required to be immediate - push @next, { - selector => { $selector, $match }, - vars => $alt->{vars} - } unless $alt->{immediate}; - } - } - } - - warn "end, next trip: ",scalar @next, " alternatives"; - - return \@next; -} - -print Data::Dumper->Dump([$tree,\@results],[qw(tree results)]); \ No newline at end of file +print "asd::asd" =~ /^[a-zA-Z]+(?:::[a-zA-Z]+)*$/; \ No newline at end of file