Thread Modul für Typenspezifikation über attributes
(0 answers)
Opened by topeg at 2011-07-26 15:20
Ich habe hier ein Modul das ich nachträglich mit Typenspezifikationen ausstatten möchte um ein Interfache besser zu spezifizieren.
Ich habe mir gedacht dass ich Attribute dafür verwenden kann. Das Umzusetzen war nicht sonderlich schwer. Jedoch würde es mich interessieren, ob es so was nicht schon gibt, bevor ich das weiter ausbaue. mein Ziel ist es ohne Sourcefilter aus zu kommen und die Variablentypen genau testen zu können. So habe ich es jetzt gemacht: Code (perl): (dl
)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 #!/usr/bin/perl use strict; use warnings; ######################################################################## ######################################################################## ######################################################################## package param_test; use Carp; use attributes; use Scalar::Util; use 5.10.0; BEGIN { my %found; my %allowed=( _ => ['TRUE', sub{ 1 }], def => ['Defined', sub{ defined($_[0]) }], int => ['an Integer', sub{ defined($_[0]) && $_[0]!~/[^+\-\d]/ }], uint => ['an Unsigned Integer', sub{ defined($_[0]) && $_[0]!~/\D/ }], number => ['a Number', sub{ defined($_[0]) && Scalar::Util::looks_like_number($_[0]) }], string => ['a String', sub{ defined($_[0]) && !Scalar::Util::reftype($_[0]) }], ref => ['a Reference', sub{ Scalar::Util::reftype($_[0]) }], array => ['an Anonyme Array', sub{ Scalar::Util::reftype($_[0]) && Scalar::Util::reftype($_[0]) eq 'ARRAY' }], hash => ['an Anonyme Hash', sub{ Scalar::Util::reftype($_[0]) && Scalar::Util::reftype($_[0]) eq 'HASH' }], handle => ['a Reference to an Handle', sub{ Scalar::Util::reftype($_[0]) && Scalar::Util::reftype($_[0]) eq 'GLOB' }], code => ['an Anonyme Function', sub{ Scalar::Util::reftype($_[0]) && Scalar::Util::reftype($_[0]) eq 'CODE' }], object => ['an Object (blessed Reference)', sub{ defined($_[0]) && Scalar::Util::blessed($_[0]) }], self => ['an Object (blessed Reference of "%1")',sub{ defined($_[0]) && Scalar::Util::blessed($_[0]) && $_[0]->DOES($_[1]); }], ); my $my_sprintf = sub { my $string=shift; while(1) { #$string=~s/%%/-!\0!-/gs; last unless($string=~s/((?:[^%]|^)(?:%%)*)%(\d+)/ $1.$_[$2-1] /egs); } #$string=~s/-!\0!-/%/gs; $string=~s/%%/%/gs; return $string; }; sub MODIFY_CODE_ATTRIBUTES { my $pkg = shift; my $ref = shift; my ($param)=grep{ /^PARAM\s*\([^)]*\)\s*$/ }@_; next unless($param); my @opts; if($param=~/PARAM\s*\(\s*([^\)]+)\s*\)/s) { @opts=split(/\s*?(?:,|;|\s+)\s*?/s,$1); } $found{$pkg}{$ref}=\@opts; return; } sub __INIT__ { for my $pkg (keys(%found)) { no strict 'refs'; while(my ( $name , $symbol ) = each %{ $pkg . '::' }) { no warnings 'once'; my $ref = *{ $symbol }{ CODE } or next; next unless(exists($found{$pkg}{$ref})); for(@{$found{$pkg}{$ref}}) { croak($my_sprintf->(q(for %1 Unknown PARAM "%2"),$symbol,$_)) unless(exists($allowed{$_})); } no warnings 'redefine'; *{ $pkg . '::' . $name } = sub { croak($my_sprintf->(q(for %1::%2 @_ is to big),$pkg,$name)) if($#{$found{$pkg}{$ref}} < $#_); croak($my_sprintf->(q(for %1::%2 @_ is to smal),$pkg,$name)) if($#{$found{$pkg}{$ref}} > $#_); for(0..$#{$found{$pkg}{$ref}}) { my $p=$found{$pkg}{$ref}->[$_]; next if($allowed{$p}->[1]->($_[$_], $pkg, $name)); croak($my_sprintf->(q(for %1::%2 $_[%3]="%4" is not %5!),$pkg,$name,$_,$_[$_],$allowed{$p}->[0])); } goto $ref; } # sub end } } } } INIT{ __PACKAGE__->__INIT__(); } ######################################################################## ######################################################################## ######################################################################## package ttt; use base 'param_test'; sub new : PARAM(string) { my $class=shift; bless({},$class); } sub test1 : PARAM(self string array hash) { my ($self,$txt,$aref,$href)=@_; for(0..$#$aref) { my $s=$aref->[$_]; print "$txt: $href->{$s}\n" if(exists($href->{$s})); } } sub test2 : PARAM(self string) { my ($self,$txt)=@_; print "OUTPUT: $txt"; } sub test3 : PARAM(self uint) { my ($self,$int)=@_; print "TEXT($_)\n" for(1..$int); } #----------------------------------------------------------------------- package main; my $t=ttt->new(); $t->test1('TEST',[qw(a b c)],{a=>'TESTA', b=>'TetstB', d=>'TetstD'}); $t->test3(5); #$t->new(); # stirbt mit Fehler: ttt->test1('TEST',[qw(a b c)],{a=>'TESTA', b=>'TetstB', d=>'TetstD'}); Das ist noch etwas gebastelt. Wenn die Attribute geparst werden dann nehme ich alle die nach "PARAM(...)" aussehen. Hole die Einzelwerte heraus und ersetze die Funktion durch eine die einen Filter für die Variablen enthält. Last edited: 2011-07-26 15:22:46 +0200 (CEST) |