File Coverage

blib/lib/Regexp/Box.pm
Criterion Covered Total %
statement 10 12 83.3
branch n/a
condition n/a
subroutine 4 4 100.0
pod n/a
total 14 16 87.5


line stmt bran cond sub pod time code
1             package Regexp::Box;
2            
3             our $VERSION = '0.02';
4            
5             our $DEBUG = 0;
6            
7 4     4   115680 use Data::Dumper;
  4         48281  
  4         312  
8            
9 4     4   40 use Carp;
  4         7  
  4         260  
10            
11 4     4   4307 use Regexp::Common;
  4         10782  
  4         20  
12            
13 4     4   282858 use Class::Maker qw(:all);
  0            
  0            
14            
15             class
16             {
17             # isa => [qw()],
18            
19             public =>
20             {
21             string => [qw( name )],
22             },
23            
24             private =>
25             {
26             array => [qw( sets )],
27            
28             hash => [qw( registry )],
29             },
30            
31             default =>
32             {
33             _sets => [qw(std net bio db_mysql)],
34             },
35             };
36            
37             sub _preinit : method
38             {
39             my $this = shift;
40            
41             foreach ( $this->_sets )
42             {
43             my $fu = "_add_".$_;
44            
45             die __PACKAGE__.": Set $_ is not known yet. You already added it?" unless $this->can( $fu );
46            
47             $this->$fu;
48             }
49             }
50             # USAGE for field values are qr// or sub ( ID, FIELD, @_ ) { }
51             #
52             # where $_registry->{ID}->{FIELD}
53            
54             sub exact : method
55             {
56             my $this = shift;
57            
58             return '^'.$_[0].'$';
59             }
60            
61             sub register : method
62             {
63             my $this = shift;
64            
65             if( $DEBUG )
66             {
67             print "register: arguments\n";
68            
69             print Dumper \@_;
70             }
71            
72             my $id = shift;
73            
74             my $exact = shift;
75            
76             my $regexp = shift;
77            
78             my $desc = shift;
79            
80             $id and $regexp and $desc and defined $exact or Carp::croak "usage error: register( ID, EXACT, REGEXP, DESC )";
81            
82             $this->_registry->{$id}->{exact} = $exact;
83            
84             $this->_registry->{$id}->{regexp} = $regexp;
85            
86             $this->_registry->{$id}->{desc} = $desc;
87            
88             $this->_registry->{$id}->{created} = [ caller ];
89             }
90            
91             # request( 'domain', 'desc' ) - returns ->{domain}->{desc}
92             # request( 'domain', 'regexp' ) - returns ->{domain}->{regexp}
93             #
94             # alternativly a coderef will lead to execution and return result
95            
96             sub request
97             {
98             my $this = shift;
99            
100             if( $DEBUG )
101             {
102             print "request: arguments\n";
103            
104             print Dumper \@_;
105             }
106            
107             my $id = shift;
108            
109             my $field = shift;
110            
111             if( exists $this->_registry->{$id} )
112             {
113             if( exists $this->_registry->{$id}->{$field} )
114             {
115             my $x = $this->_registry->{$id}->{$field};
116            
117             my $result = ref($x) eq 'CODE' ? $x->( @_ ) : $x;
118            
119             Carp::croak sprintf "$id returned undef or empty for $field" unless $result;
120            
121             if( $field eq 'regexp' && exists $this->_registry->{$id}->{exact} )
122             {
123             return $this->exact( $result ) if $this->_registry->{$id}->{exact};
124             }
125            
126             return $result;
127             }
128            
129             Carp::croak sprintf "$id is not registered in Regexp::Box '%s'", $this->name;
130             }
131            
132             Carp::croak sprintf "$id is not registered in Regexp::Box '%s'", $this->name;
133             }
134            
135             sub requestable : method
136             {
137             my $this = shift;
138            
139            
140             return sort keys %{ $this->_registry };
141             }
142            
143             ###############################################################
144            
145             sub _add_std
146             {
147             my $this = shift;
148            
149             $this->register( 'std/word', 0, qr/[^\s]+/, 'set of non-spaces' );
150            
151             $this->register( 'std/binary', 1, qr/[01]+/, 'arbitrary combination of 0 and 1' );
152            
153             $this->register( 'std/hex', 1, qr/[0-9a-fA-F]+/, 'hexadecimal string' );
154            
155             $this->register( 'std/int', 1, $Regexp::Box::RE{num}{int}, 'integer' );
156            
157             $this->register( 'std/real', 1, $Regexp::Box::RE{num}{real}, 'real' );
158            
159             $this->register( 'std/quoted', 1, $Regexp::Box::RE{quoted}, 'string enclosed by matching quoting characters' );
160            
161             $this->register( 'std/uri', 1, sub { $Regexp::Box::RE{URI}{HTTP}{ -scheme => $_[1] || 'HTTP' } }, sub { sprintf "an uri (default: %s)", $_[1] || 'HTTP' } );
162            
163             $this->register( 'std/net', 1, sub { $Regexp::Box::RE{'net'}{ $_[1] || 'IPv4' } }, 'IP (V4, V6, MAC) network address' );
164            
165             $this->register( 'std/zip', 1, sub { $Regexp::Box::RE{zip}{ $_[1] || 'Germany' } }, sub { sprintf 'a zip %s code (default: german)', $_[1] || 'german' } );
166            
167             $this->register( 'std/domain', 0, $Regexp::Common::URI::RFC1035::domain, 'RFC1035 domain name' );
168             }
169            
170             sub _add_net
171             {
172             my $this = shift;
173            
174             $this->register( 'net/simple_email', 0, qr/(?:[^\@]*)\@(?:\w+)(?:\.\w+)+/, 'primitiv regexp for email' );
175             }
176            
177             sub _add_bio
178             {
179             my $this = shift;
180            
181             $this->register( 'bio/dna', 1, qr/[ATGC]+/, q{arbitrary set of A, T, G or C} );
182            
183             $this->register( 'bio/rna', 1, qr/[AUGC]+/, q{arbitrary set of A, U, G or C} );
184            
185             $this->register(
186            
187             'bio/triplet',
188            
189             1,
190            
191             sub
192             {
193             my $this = shift;
194            
195             my $type = lc( shift || 'dna' );
196            
197             Carp::croak __PACKAGE__." required parameter missing dna (default) or rna" unless defined $type;
198            
199             Carp::croak sprintf "%s triplet usage failure (dna or rna) only and not $_[1]", __PACKAGE__, $type unless $type =~ /^[rd]na$/;
200            
201             return $type eq 'dna' ? qr/[ATGC]{3,3}/ : qr/[AUGC]{3,3}/;
202             },
203            
204             sub { sprintf "a triplet string of %s", $_[1] || 'dna (default) or rna' }
205             );
206             }
207            
208             sub _add_db_mysql
209             {
210             my $this = shift;
211            
212             $this->register( 'db/mysql/date', 1, qr/\d{4}-[01]\d-[0-3]\d/, 'a date as described in the mysql doc' );
213            
214             $this->register( 'db/mysql/datetime', 1, qr/\d{4}-[01]\d-[0-3]\d [0-2]\d:[0-6]\d:[0-6]\d/, 'a datetime as described in the mysql doc' );
215            
216             $this->register( 'db/mysql/timestamp', 1, qr/[1-2][9|0][7-9,0-3][0-7]-[01]\d-[0-3]\d [0-2]\d:[0-6]\d:[0-6]\d/, 'a timestamp as described in the mysql doc' );
217            
218             $this->register( 'db/mysql/time', 1, qr/-?\d{3,3}:[0-6]\d:[0-6]\d/, 'a time as described in the mysql doc' );
219            
220             $this->register( 'db/mysql/year4', 1, qr/[0-2][9,0,1]\d\d/, 'as described in the mysql doc' );
221            
222             $this->register( 'db/mysql/year2', 1, qr/\d{2,2}/, 'as described in the mysql doc' );
223            
224             }
225            
226             1;
227            
228             =pod
229            
230             =head1 NAME
231            
232             Regexp::Box - store and retrieve regexp via names
233            
234             =head1 SYNOPSIS
235            
236             $rebox = Regexp::Box->new( name => 'name of the box' );
237            
238             $rebox->register( 'category/id', 0, qr/\w/, 'description' );
239            
240             $rebox->register( 'category/id2', 0,
241            
242             sub { '\w' x 3 },
243            
244             sub { sprintf 'description of %s', $_[0] }
245            
246             );
247            
248             unless( $_ =~ $rebox->request( 'category/id', 'regexp' ) )
249             {
250             warn "Expected ", $rebox->request( 'category/id', 'desc' );
251             }
252            
253             =head1 DESCRIPTION
254            
255             Store and retrieve regexp via names and serve them application wide. My favorite
256             L was somehow to complicated with that particular issue.
257            
258             =head1 METHODS
259            
260             =head3 $rebox = Regexp::Box->new( name => 'name of the box' )
261            
262             Just give the box a name. Helps when multiple box's have to be handled.
263            
264             =head3 $rebox->register( $id, $exact, $regexp, $desc )
265            
266             Register a regexp. All arguments are required. The C<$id> should contain
267             a category path ( i.e. 'net/uri' ). It is used when later retrieved with
268             C<$rebox-Erequest>. The C<$exact> is a boolean field that defines if the
269             regexp gets wrapped with '^$' (see C<$rebox-Eexact> below). One could
270             use closure/function-pointers as C<$regexp> or C<$desc> if some run-time
271             construction would be required (Some flexible L regexp's require
272             that for argument passing. Here some examples:
273            
274             $rebox->register( 'category/id', 0, qr//, 'description' );
275            
276             $rebox->register( 'category/id', 0, sub { }, sub { 'description' } );
277            
278             $rebox->register(
279            
280             'std/uri',
281            
282             1,
283            
284             sub { $Regexp::Box::RE{URI}{HTTP}{ -scheme => $_[1] || 'HTTP' } },
285            
286             sub { sprintf "an uri (default: %s)", $_[1] || 'HTTP' }
287             );
288            
289             =head3 $field = $rebox->request( $id, $field_name )
290            
291             Currently 'regexp', 'desc' and 'created', 'exact' as $field_name.
292            
293             $rebox->request( 'net/email', 'desc' );
294            
295             Returns the C field of the 'net/email' regexp.
296            
297             =head3 @ids = $rebox->request();
298            
299             Returns array of C<$id> of all registered regexps.
300            
301             =head3 $rebox->exact
302            
303             Wraps a regex internally into '^$'. May be overloaded if its too stupid.
304            
305             =head1 $Regexp::Box::RE
306            
307             L is heavily used and one could access it via C<$Regexp::Box::RE> without loading it redundantly.
308            
309             =back
310            
311             <& /maslib/delayed.mas, comp => '/maslib/signatures.mas:author_as_pod' &>
312            
313             =cut