File Coverage

lib/self/init.pm
Criterion Covered Total %
statement 37 37 100.0
branch 15 16 93.7
condition 7 9 77.7
subroutine 6 6 100.0
pod n/a
total 65 68 95.5


line stmt bran cond sub pod time code
1             # Copyright (c) 2009 Mons Anderson . All rights reserved
2             # This program is free software; you can redistribute it and/or
3             # modify it under the same terms as Perl itself.
4             package self::init;
5              
6             =head1 NAME
7              
8             self::init - Invoke package init methods at compile time
9              
10             =cut
11              
12             $self::init::VERSION = '0.01';
13              
14             =head1 VERSION
15              
16             Version 0.01
17              
18             =head1 SYNOPSIS
19              
20             # At compile time
21             use self::init
22             \-x => qw( y z ), # same as BEGIN { CLASS->x('y','z'); }
23             ;
24            
25             # At runtime
26             self::init
27             \-a => qw(a b),
28             \-b => (),
29             \-c => qw( c c ),
30             ;
31            
32             # Same as
33             CLASS->a('a','v');
34             CLASS->b();
35             CLASS->c('c','c');
36            
37             # With bad arguments (scalarrefs, containing string, beginning from -)
38             self::init
39             [ a => \'-arg1', \'-arg2' ],
40             [ b => 'arg3', 'arg4' ],
41             ;
42            
43             # ! Warning!
44             # Mixed syntax is not allowed
45             self::init
46             \-a => qw(arg1 arg2),
47             [ b => \'-arg1', \'-arg2' ],
48             ;
49              
50             # will be invoked as
51              
52             CLASS->a('arg1','arg2', [ 'b', \'-arg1', \'-arg2' ] );
53              
54             # So be aware
55              
56             =head1 DESCRIPTION
57              
58             This module is just a helper to avoid repetiotion of ugly __PACKAGE__->method();
59              
60             =head1 INTERFACE
61              
62             =over 4
63              
64             =item self::init pragma
65              
66             use self::init ARGS;
67              
68             =item self::init statement
69              
70             self::init ARGS;
71              
72             =item ARGS
73              
74             Synopsis 1:
75              
76             Method name is constructed as a reference to string, containing method name, prefixed with '-'.
77             Rest in list is threated as arguments to that method, until next method name or end of whole statement.
78             So, if your arguments not written by hand or in some way could receive value of SCALARREF, containing string, beginning from -, invocation will be wrong (see Synopsis 2)
79              
80             When writing method names not quoted (hash key bareword), the whole statement looks like an ASCII tree, where methods are descendants of self::init ;)
81              
82             self::init
83             \-method1 => (1,2,3),
84             \-method_another => ('some', 'args'),
85             \-_private_method => (), # no args,
86             # so on
87             ;
88              
89             Synopsis 2:
90              
91             Single method invocation is constructed as ARRAYREF, containing first element as method name and rest as arguments.
92             It is reliable to any arguments, but don't mix both synopsises in a single call
93              
94             self::init
95             [ method1 => 1,2,3 ],
96             [ method_another => 'some', 'args' ],
97             [ _private_method => (), ], # no args
98             # so on
99             ;
100              
101             =back
102              
103             =cut
104              
105 2     2   64920 use strict;
  2         4  
  2         73  
106 2     2   11 use warnings;
  2         4  
  2         63  
107 2     2   10 use Carp;
  2         9  
  2         946  
108              
109             sub _declare($@) {
110 10     10   19 my ($class,$method,@args) = @_;
111             #if ($class->can($method)) {
112             #warn "$class $method (@args)";
113 10 100       14 eval{ $class->$method(@args); 1 } or do {
  10         61  
  8         18106  
114 2         5 local $_ = $@;
115 2         5 my $f = __FILE__;
116 2         34 s{ at \Q$f\E line \d+.\s*$}{};
117 2         358 croak $_;
118             }
119             #} else {
120             # push @DELAYED , [ $class, $method, @args ];
121             #}
122             }
123              
124             sub self::init (%) {
125 8 100   8   1213 @_ or return 'self::init';
126 6         12 my $class = caller;
127 6         14 my @opts = @_; # copy
128 6         5 my ($key, @args);
129 6         17 while (@opts) {
130 16         23 my $v = shift @opts;
131 16 100 100     102 if (ref $v and ref $v eq 'ARRAY' and !defined $key) {
    100 66        
      66        
132 5         12 _declare $class, @$v;
133             }
134 5 50       7 elsif (ref $v eq 'SCALAR' and do { local $_ = $$v; s/^-// and $v = $_ }) {
  5         40  
135 5 100       15 _declare $class, $key, @args if defined $key;
136 5         8 @args = ();
137 5         14 $key = $v;
138             } else {
139 6         24 push @args, $v;
140             }
141             }
142 5 100       20 _declare $class, $key, @args if defined $key;
143 4         268 return 'self::init';
144             }
145              
146             sub import {
147 5     5   29 shift;
148 5         8 my $class = caller;
149 5 100       25 @_ or return;
150 4         12 goto &self::init;
151             }
152              
153             1;
154             __END__