File Coverage

blib/lib/Sub/Mage.pm
Criterion Covered Total %
statement 42 205 20.4
branch 11 80 13.7
condition 0 3 0.0
subroutine 9 33 27.2
pod 19 20 95.0
total 81 341 23.7


line stmt bran cond sub pod time code
1             package Sub::Mage;
2              
3             =head1 NAME
4              
5             Sub::Mage - Multi-Use utility for manipulating subroutines, classes and more.
6              
7             =head1 DESCRIPTION
8              
9             What this module attempts to do is make a developers life easier by allowing them to manage and manipulate subroutines and modules. You can override a subroutine, then
10             restore it as it was originally, create after, before and around hook modifiers, delete subroutines, or even tag every subroutine in a class to let you know when each one
11             is being run, which is great for debugging.
12             Unfortunately, thanks to late-night RPGs, a lot of coffee, and an over-active imagination, the namespace Sub::Mage was chosen. Sorry.
13              
14             =head1 SYNOPSIS
15              
16             # Simple usage
17              
18             use Sub::Mage;
19              
20             sub greet { print "Hello, World!"; }
21             greet(); # prints Hello, World!
22              
23             override 'greet' => sub {
24             print "Goodbye, World!";
25             };
26              
27             greet(); # now prints Goodbye, World!
28             restore 'greet'; # restores it back to its original state
29              
30             Changing a class method (Remote control), by example
31              
32             # Foo.pm
33              
34             use Sub::Mage;
35              
36             sub hello {
37             my $self = shift;
38              
39             $self->{name} = "World";
40             }
41              
42             # test.pl
43              
44             use Foo;
45              
46             my $foo = Foo->new;
47              
48             Foo->override( 'hello' => sub {
49             my $self = shift;
50              
51             $self->{name} = "Town";
52             });
53              
54             print "Hello, " . $foo->hello . "!\n"; # prints Hello, Town!
55              
56             Foo->restore('hello');
57              
58             print "Hello, " . $foo->hello . "!\n"; # prints Hello, World!
59              
60             =cut
61              
62 4     4   130564 use Class::LOP;
  4         13  
  4         13067  
63              
64             our $VERSION = '0.032';
65             $Sub::Mage::Subs = {};
66             $Sub::Mage::Imports = [];
67             $Sub::Mage::Classes = [];
68             $Sub::Mage::Debug = 0;
69              
70             sub import {
71 4     4   56 my ($class, @args) = @_;
72 4         16 my $pkg = caller;
73            
74 4 100       25 if (@args > 0) {
75 3         9 for (@args) {
76 3 100       14 _debug_on()
77             if $_ eq ':Debug';
78            
79 3 100       22 _setup_moosed()
80             if $_ eq ':Class';
81             }
82             }
83              
84 4         26 Class::LOP->init(__PACKAGE__)
85             ->warnings_strict
86             ->import_methods($pkg, qw/
87             override
88             restore
89             after
90             before
91             create
92             sub_alert
93             clone
94             exports
95             have
96             around
97             withdraw
98             sub_run
99             tag
100             constructor
101             destructor
102             sublist
103             /,
104             );
105             }
106              
107             sub withdraw {
108 0     0 1 0 my ($class, $sub);
109 0 0       0 if (@_ < 2) {
110 0         0 $sub = shift;
111 0         0 $class = getscope();
112             }
113             else {
114 0         0 ($class, $sub) = @_;
115             }
116 0         0 $class = \%{"$class\::"};
  0         0  
117 0         0 delete $class->{$sub};
118             }
119              
120             sub extends {
121 0     0 1 0 Class::LOP->init(getscope())
122             ->extend_class(@_);
123             }
124              
125             sub _setup_moosed {
126 1     1   3 my $class = caller(1);
127              
128 1         5 Class::LOP->init(__PACKAGE__)
129             ->import_methods($class, qw/
130             extends
131             chainable
132             accessor
133             /);
134              
135 1         26 Class::LOP->init($class)
136             ->create_constructor
137             ->have_accessors('has');
138             }
139              
140             sub override {
141 1     1 1 2297 my ($pkg, $name, $sub) = @_;
142              
143 1 50       7 if (scalar @_ > 2) {
144 1         3 ($pkg, $name, $sub) = @_;
145             }
146             else {
147 0         0 ($name, $sub) = ($pkg, $name);
148 0         0 $pkg = caller;
149             }
150 1         3 my $full = "${pkg}::${name}";
151 1         5 _add_to_subs($full);
152 1         7 Class::LOP->init($pkg)->override_method($name, $sub);
153             }
154              
155             sub _add_to_subs {
156 1     1   3 my $sub = shift;
157              
158 1 50       5 if (! exists $Sub::Mage::Subs->{$sub}) {
159 1         5 $Sub::Mage::Subs->{$sub} = {};
160 1         3 $Sub::Mage::Subs->{$sub} = \&{$sub};
  1         5  
161 1         5 _debug("$sub does not exist. Adding to Subs list\n");
162             }
163             }
164              
165             sub constructor(&) {
166 0     0 1 0 my $sub = shift;
167 0         0 my $pkg = getscope();
168 0         0 *{"$pkg\::import"} = $sub;
  0         0  
169             }
170              
171             sub destructor(&) {
172 0     0 1 0 my $sub = shift;
173 0         0 my $pkg = getscope();
174 0         0 *{"$pkg\::DESTROY"} = $sub;
  0         0  
175             }
176              
177             sub restore {
178 1     1 1 2033 my ($pkg, $sub) = @_;
179              
180 1 50       5 if (scalar @_ > 1) {
181 1         3 my ($pkg, $sub) = @_;
182             }
183             else {
184 0         0 $sub = $pkg;
185 0         0 $pkg = caller;
186             }
187              
188 1         3 $sub = "$pkg\:\:$sub";
189              
190 1 50       6 if (! exists $Sub::Mage::Subs->{$sub}) {
191 0         0 _debug("Failed to restore '$sub' because it's not in the Subs list. Was it overriden or modified by a hook?");
192 0         0 warn "I have no recollection of '$sub'";
193 0         0 return 0;
194             }
195              
196 1         3 *{$sub} = $Sub::Mage::Subs->{$sub};
  1         10  
197 1         6 _debug("Restores sub $sub");
198             }
199              
200             sub after {
201 0     0 1 0 my ($pkg, $name, $sub) = @_;
202              
203 0 0       0 if (scalar @_ > 2) {
204 0         0 ($pkg, $name, $sub) = @_;
205             }
206             else {
207 0         0 ($name, $sub) = ($pkg, $name);
208 0         0 $pkg = caller;
209             }
210              
211 0         0 my $full = "${pkg}::${name}";
212 0         0 _add_to_subs($full);
213 0         0 Class::LOP->init($pkg)->add_hook(
214             type => 'after',
215             name => $name,
216             method => $sub,
217             );
218              
219 0         0 _debug("Added after hook modified to '$name'");
220             }
221              
222             sub before {
223 0     0 1 0 my ($pkg, $name, $sub) = @_;
224              
225 0 0       0 if (scalar @_ > 2) {
226 0         0 ($pkg, $name, $sub) = @_;
227             }
228             else {
229 0         0 ($name, $sub) = ($pkg, $name);
230 0         0 $pkg = caller;
231             }
232              
233 0         0 my $full = "${pkg}::${name}";
234 0         0 _add_to_subs($full);
235 0         0 Class::LOP->init($pkg)->add_hook(
236             type => 'before',
237             name => $name,
238             method => $sub,
239             );
240              
241 0         0 _debug("Added before hook modifier to $name");
242             }
243              
244             sub around {
245 0     0 1 0 my ($pkg, $name, $sub) = @_;
246              
247 0 0       0 if (scalar @_ > 2) {
248 0         0 ($pkg, $name, $sub) = @_;
249             }
250             else {
251 0         0 ($name, $sub) = ($pkg, $name);
252 0         0 $pkg = caller;
253             }
254              
255 0         0 my $full = "${pkg}::${name}";
256 0         0 _add_to_subs($full);
257 0         0 Class::LOP->init($pkg)->add_hook(
258             type => 'around',
259             name => $name,
260             method => $sub,
261             );
262             }
263              
264             sub getscope {
265 0     0 0 0 my ($self) = @_;
266              
267 0 0       0 if (defined $self) { return ref($self); }
  0         0  
268 0         0 else { return scalar caller(1); }
269             }
270              
271             sub create {
272 0     0 1 0 my ($pkg, $name, $sub) = @_;
273              
274 0 0       0 if (scalar @_ > 2) {
275 0         0 ($pkg, $name, $sub) = @_;
276             }
277             else {
278 0         0 ($name, $sub) = ($pkg, $name);
279 0         0 $pkg = caller;
280             }
281              
282 0 0       0 if (Class::LOP->init($pkg)->create_method($name, $sub)) {
283 0         0 _debug("Created new subroutine '$name' in '$pkg'");
284             }
285             }
286              
287             sub sub_alert {
288 0     0 1 0 my $pkg = shift;
289 0         0 my $module = __PACKAGE__;
290              
291 0         0 for (keys %{$pkg . "::"}) {
  0         0  
292 0         0 my $sub = $_;
293              
294 0 0       0 unless ($sub eq uc $sub) {
295 0     0   0 $pkg->before($sub => sub { print "[$module/Sub Alert] '$sub' called from $pkg\n"; })
296 0 0       0 unless grep { $_ eq $sub } @{$Sub::Mage::Imports};
  0         0  
  0         0  
297             }
298             }
299             }
300              
301             sub clone {
302 0     0 1 0 my ($name, %opts) = @_;
303              
304 0         0 my $from;
305             my $to;
306 0         0 foreach my $opt (keys %opts) {
307 0 0       0 $from = $opts{$opt}
308             if $opt eq 'from';
309 0 0       0 $to = $opts{$opt}
310             if $opt eq 'to';
311             }
312              
313 0 0 0     0 if ((! $from || ! $to )) {
314 0         0 warn "clone(): 'from' and 'to' needed to clone a subroutine";
315 0         0 return ;
316             }
317              
318 0 0       0 if (! $from->can($name)) {
319 0         0 warn "clone(): $from does not have the method '$name'";
320 0         0 return ;
321             }
322              
323 0         0 Class::LOP->init($from)
324             ->import_methods($to, $name);
325             }
326            
327             sub exports {
328 0     0 1 0 my ($name, %args) = @_;
329              
330 0         0 my $class = caller;
331 0         0 my $into = [];
332 0         0 foreach my $opt (keys %args) {
333 0 0       0 if ($opt eq 'into') {
334 0 0       0 if (ref($args{into}) eq 'ARRAY') {
335 0         0 for my $gc (@{$args{into}}) {
  0         0  
336 0         0 push @$into, $gc;
337             }
338             }
339 0         0 else { push @$into, $args{into}; }
340             }
341             }
342            
343 0     0   0 my $code = sub { $class->$name(@_); };
  0         0  
344 0 0       0 if (scalar @$into > 0) {
345 0         0 for my $c (@$into) {
346 0 0       0 if (! _class_exists($c)) {
347 0         0 warn "Can't export $name into $c\:: because class $c does not exist";
348 0         0 next;
349             }
350 0         0 *{"$c\::$name"} = \*{"$class\::$name"};
  0         0  
  0         0  
351             }
352             }
353 0         0 return;
354             }
355              
356             sub have {
357 0     0 1 0 my ($class, $method, %args) = @_;
358              
359 0 0       0 my $can = $class->can($method) ? 1 : 0;
360 0         0 my $then;
361 0         0 for $opt (keys %args) {
362 0 0       0 if ($opt eq 'then') {
363 0 0       0 if ($can) { $args{$opt}->($class, $method); }
  0         0  
364             }
365 0 0       0 if ($opt eq 'or') {
366 0 0       0 if (! $can) {
367 0 0       0 if (ref $args{$opt} eq 'CODE') {
368 0         0 $args{$opt}->(@_);
369 0         0 return 0;
370             }
371 0         0 else { warn $args{$opt}; }
372             }
373             }
374             }
375             }
376              
377             sub accessor {
378 0     0 1 0 my ($name, $value) = @_;
379 0         0 my $pkg = caller;
380              
381 0         0 *{$pkg . "::$name"} = sub {
382 0     0   0 my ($class, $val) = @_;
383 0 0       0 if ($val) { *{$pkg . "::$name"} = sub { return $val; }; return $val; }
  0         0  
  0         0  
  0         0  
  0         0  
384 0         0 else { return $value; }
385 0         0 };
386             }
387              
388             sub tag {
389 0     0 1 0 my ($pkg, $name, $message) = @_;
390              
391 0 0       0 if (scalar @_ > 2) {
392 0         0 ($pkg, $name, $message) = @_;
393             }
394             else {
395 0         0 ($name, $message) = ($pkg, $name);
396 0         0 $pkg = getscope();
397             }
398              
399 0 0       0 if (ref($name) eq 'ARRAY') {
400 0         0 for my $sub (@$name) {
401            
402 0 0       0 if (! $pkg->can($sub)) {
403 0         0 warn "Cannot tag a subroutine that doesn't exist";
404             }
405             else {
406             $pkg->before($sub => sub {
407 0     0   0 print $message . " ($sub)\n";
408             }
409 0         0 );
410             }
411             }
412             }
413             else {
414 0 0       0 if (! $pkg->can($name)) {
415 0         0 warn "Cannot tag a subroutine that doesn't exist";
416             }
417             else {
418             $pkg->before($name => sub {
419 0     0   0 print $message . "\n";
420 0         0 });
421             }
422             }
423             }
424              
425             sub chainable {
426 0     0 1 0 my ($method, %args) = @_;
427 0         0 my $pkg = getscope();
428 0         0 my $bless;
429             my $class;
430 0 0       0 if (! $pkg->can($method)) {
431 0         0 warn "Cannot chain subroutine that doesn't exist";
432 0         0 return ;
433             }
434            
435 0         0 foreach my $var (keys %args) {
436 0 0       0 if ($var eq 'class') {
437 0         0 $class = $args{$var};
438             }
439 0 0       0 if ($var eq 'bless') {
440 0         0 $bless = $args{$var};
441             }
442             }
443              
444             $pkg->after( $method => sub {
445 0     0   0 my $self = shift;
446 0 0       0 if (! $bless) { return bless $self, $class; }
  0         0  
447 0         0 else { return bless $self->{$bless}, $class; }
448 0         0 });
449             }
450              
451             sub sub_run {
452 1     1 1 18 my ($class,$subs, $methods) = @_;
453            
454 1         3 my $name;
455             my $orig;
456 1         3 for my $sub (@$subs) {
457 1         3 *{"$class\::$sub"}->($class, @$methods);
  1         7  
458             }
459             }
460              
461             sub _debug_on {
462 1     1   2 $Sub::Mage::Debug = 1;
463 1         3 _debug("Sub::Mage debugging ON");
464             }
465              
466             sub _debug {
467 3     3   6 my $msg = shift;
468 3 50       713 print "[debug] $msg\n"
469             if $Sub::Mage::Debug == 1;
470             }
471              
472             sub _class_exists {
473 0     0     my $class = shift;
474            
475 0           return Class::LOP->init($class)->class_exists();
476             }
477              
478             sub sublist {
479 0     0 1   my $pkg = caller(0);
480 0           return Class::LOP->init($pkg)->list_methods();
481             }
482              
483             =head1 IMPORT ATTRIBUTES
484              
485             =head2 :Debug
486              
487             If for some reason you want some kind of debugging going on when you override, restore, create
488             or create hook modifiers, then this will enable it for you. It can get verbose, so use it only when you need to.
489              
490             use Sub::Mage ':Debug';
491              
492             create 'this_sub' => sub { }; # notifies you with [debug] that a subroutine was createed
493              
494             =head2 :Class
495              
496             Turns Sub::Mage into a minimal class builder, giving you access to special class-only methods. They are explained in the methods section.
497              
498             use Sub::Mage ':Class';
499              
500             has 'x' => ();
501             chainable 'this' => ( class => 'ThisClass' );
502              
503             =head1 METHODS
504              
505             =head2 override
506              
507             Overrides a subroutine with the one specified. On its own will override the one in the current script, but if you call it from
508             a class, and that class is visible, then it will alter the subroutine in that class instead.
509             Overriding a subroutine inherits everything the old one had, including C<$self> in class methods.
510              
511              
512             override 'subname' => sub {
513             # do stuff here
514             };
515              
516             # class method
517             FooClass->override( 'subname' => sub {
518             my $self = shift;
519              
520             # do stuff
521             });
522              
523             =head2 withdraw
524              
525             Deletes an entire subroutine from the current package, or a remote one. Please be aware this is non-reversable. There is no recycle bin for subroutines unfortunately. Not yet, anyway.
526              
527             package MyBin;
528              
529             sub test { print "Huzzah!" }
530            
531             __PACKAGE__->test; # prints Huzzah!
532            
533             withdraw 'test'
534              
535             __PACKAGE__->test; # fails, because there's no subroutine named 'test'
536              
537             use AnotherPackage;
538             AnotherPackage->withdraw('test'); # removes the 'test' method from 'AnotherPackage'
539              
540             =head2 restore
541              
542             Restores a subroutine to its original state.
543              
544             override 'foo' => sub { };
545              
546             restore 'foo'; # and we're back in the room
547              
548             =head2 after
549              
550             Adds an after hook modifier to the subroutine. Anything in the after subroutine is called directly after the original sub.
551             Hook modifiers can also be restored.
552              
553             sub greet { print "Hello, "; }
554            
555             after 'greet' => sub { print "World!"; };
556              
557             greet(); # prints Hello, World!
558              
559             =head2 before
560              
561             Very similar to C, but calls the before subroutine, yes that's right, before the original one.
562              
563             sub bye { print "Bye!"; }
564              
565             before 'bye' => sub { print "Good "; };
566              
567             bye(); # prints Good Bye!
568              
569             Fancy calling C on multiple subroutines? Sure. Just add them to an array.
570              
571             sub like {
572             my ($self, $what) = @_;
573            
574             print "I like $what\n";
575             }
576            
577             sub dislike {
578             my ($self, $what) = @_;
579            
580             print "I dislike $what\n";
581             }
582              
583             before [qw( like dislike )] => sub {
584             my ($self, $name) = @_;
585              
586             print "I'm going to like or dislike $name\n";
587             };
588              
589             =head2 around
590              
591             Around gives the user a bit more control over the subroutine. When you create an around method the first argument will be the old method, the second is C<$self> and the third is any arguments passed to the original subroutine. In a away this allows you to control the flow of the entire subroutine.
592              
593             sub greet {
594             my ($self, $name) = @_;
595              
596             print "Hello, $name!\n";
597             }
598              
599             # only call greet if any arguments were passed to Class->greet()
600             around 'greet' => sub {
601             my $method = shift;
602             my $self = shift;
603              
604             $self->$method(@_)
605             if @_;
606             };
607              
608             =head2 create
609              
610             Creates a new subroutine into the current script or a class. It will not allow you to override a subroutine.
611              
612             create 'test' => sub { print "In test\n"; }
613             test;
614              
615             Foo->create( hello => sub {
616             my ($self, $name) = @_;
617              
618             print "Hello, $name!\n";
619             });
620              
621             =head2 sub_alert
622              
623             B: Adds a before hook modifier to every subroutine in the package to let you know when a sub is being called. Great for debugging if you're not sure a method is being ran.
624              
625             __PACKAGE__->sub_alert;
626              
627             # define a normal sub
628             sub test { return "World"; }
629              
630             say "Hello, " . test(); # prints Hello, World but also lets you know 'test' in 'package' was called.
631              
632             =head2 clone
633              
634             Clones a subroutine from one class to another. Probably rarely used, but the feature is there if you need it.
635              
636             use ThisPackage;
637             use ThatPackage;
638              
639             clone 'subname' => ( from => 'ThisPackage', to => 'ThatPackage' );
640              
641             ThatPackage->subname; # duplicate of ThisPackage->subname
642              
643             =head2 extends
644              
645             To use C you need to have C<:Class> imported. This will extend the given class thereby inheriting it into
646             the current class.
647              
648             package Foo;
649              
650             sub baz { }
651              
652             1;
653              
654             package Fooness;
655              
656             use Sub::Mage ':Class';
657             extends 'Foo';
658              
659             override 'baz' => sub { say "Hello!" };
660             Foo->baz;
661              
662             1;
663              
664             The above would not have worked if we had not have extended 'Foo'. This is because when we
665             inheritted it, we also got access to its C method.
666              
667             =head2 exports
668              
669             Exporting subroutines is not generally needed or a good idea, so Sub::Mage will only allow you to export one subroutine at a time.
670             Once you export the subroutine you can call it into the given package without referencing the class of the subroutines package.
671              
672             package Foo;
673            
674             use Sub::Mage;
675            
676             exports 'boo' => ( into => [qw/ThisClass ThatClass/] );
677             exports 'spoons' => ( into => 'MyClass' );
678              
679             sub spoons { print "Spoons!\n"; }
680             sub boo { print "boo!!!\n"; }
681             sub test { print "A test\n"; }
682              
683             package ThisClass;
684              
685             use Foo;
686              
687             boo(); # instead of Foo->boo;
688             test(); # this will fail because it was not exported
689              
690             =head2 have
691              
692             A pretty useless function, but it may be used to silently error, or create custom errors for failed subroutines. Similar to $class->can($method), but with some extra sugar.
693              
694             package Foo;
695              
696             use Sub::Mage;
697              
698             sub test { }
699            
700             package MyApp;
701              
702             use Sub::Mage qw/:5.010/;
703            
704             use Foo;
705            
706             my $success = sub {
707             my ($class, $name) = @_;
708            
709             say "$class\::$name checked out OK";
710             after $class => sub {
711             say "Successfully ran $name in $class";
712             };
713             };
714              
715             Foo->have( 'test' => ( then => $success ) );
716              
717             On success the above will run whatever is in C. But what about errors? If this fails it will not do anything - sometimes you just want silent deaths, right? You can create custom
718             error handlers by using C. This parameter may take a coderef or a string.
719              
720             package Foo;
721            
722             use Sub::Mage;
723              
724             sub knife { }
725            
726             package MyApp;
727              
728             use Sub::Mage qw/:5.010/;
729              
730             use Foo;
731              
732             my $error = sub {
733             my ($class, $name) = @_;
734              
735             say "Oh dear! $class failed because no method $name exists";
736             # do some other funky stuff if you wish
737             };
738              
739             Foo->have( 'spoon' => ( then => $success, or => $error ) );
740              
741             Or you may wish for something really simply.
742              
743             Foo->have( 'spoon' => ( then => $success, or => 'There is no spoon') );
744              
745             This one will simply throw a warning with C so to still execute any following code you may have.
746              
747             =head2 accessor
748              
749             Simply creates an accessor for the current class. You will need to first import C<:Class> when using Sub::Mage before you can use C. When you create an
750             accessor it adds the subroutine for you with the specified default value. The parameter in the subroutine will cause its default value to change to whatever that is.
751              
752             package FooClass;
753              
754             use Sub::Mage qw/:Class/;
755              
756             accessor 'name' => 'World'; # creates the subroutine 'name'
757              
758             1;
759              
760             package main;
761              
762             use FooClass;
763              
764             my $foo = FooClass->new;
765             print "Hello, " . $foo->name; # prints Hello, World
766              
767             $foo->name('Foo');
768            
769             print "Seeya, " . $foo->name; # prints Seeya, Foo
770              
771             =head2 chainable
772              
773             Another C<:Class> only method is C. It doesn't really do anything you can't do yourself, but I find it helps to keep a visual of your chains at the top of your code so you can see in plain sight
774             where they are leading you. Let's look at an example.
775             As of 0.015 you can now bless a different reference other than C<$self>. Whatever you bless will be C<$self->{option}>.
776              
777             # test.pl
778              
779             use Greeter;
780            
781             my $foo = Greeter->new;
782             print "Hello, " . $foo->greet('World')->hello;
783              
784             # Greeter.pm
785             package Greeter;
786              
787             use Greet::Class;
788             use Sub::Mage qw/:Class/;
789              
790             chainable 'greet' => ( class => 'Greet::Class' );
791              
792             sub greet {
793             my ($self, $name) = @_;
794             $self->{_name} = $name;
795             }
796              
797             # Greet/Class.pm
798             package Greet;
799            
800             sub hello {
801             my $self = shift;
802              
803             return $self->{_name};
804             }
805              
806             If you don't want to bless the entire C<$self>, use C.
807              
808             chainable 'greet' => ( bless => '_source', class => 'Greet::Class' );
809              
810             sub greet {
811             my $self = shift;
812              
813             $self->{_source} = {
814             _name => $self->{_name},
815             };
816             }
817              
818             =head2 has
819              
820             Create a more advanced accessor similar to Moose (but not as cool). It currently supports C and C. Don't forget to import C<:Class>
821              
822             package Foo;
823              
824             use Sub::Mage ':Class';
825              
826             has name => ( is => 'rw' );
827             has x => ( is => 'ro', default => 7 );
828             print __PACKAGE__->x; # 7
829             __PACKAGE__->x(5); # BAD! It's Read-Only!!
830             __PACKAGE__->name('World'); # set and return 'World'
831            
832             =head2 sub_run
833              
834             Runs multiple subroutines in a class, with arguments if necessary. This function takes two arrayrefs, the first being the subroutines you want to run, and the last is
835             the arguments to pass to each subroutine.
836              
837             # MyApp.pm
838             package MyApp;
839             use Sub::Mage;
840              
841             sub greet {
842             my ($self, $name) = @_;
843             print "Hello, $name!\n";
844             }
845              
846             sub bye {
847             my ($self, $name, $where) = @_;
848             print "Bye, $name. I'm going $where\n";
849             }
850              
851             # run.pl
852             use MyApp;
853             MyApp->sub_run(
854             [qw/greet bye/],
855             [qw/World home/]
856             );
857              
858             # Hello, World!
859             # Bye, World. I'm going home
860              
861             =head2 tag
862              
863             Same sort of principle as C but a little more flexible. You can "tag" a subroutine, or multiple subroutines using an arrayref and give them a custom message when ran.
864             If you group multiple subs they will have the same message.
865             Great for debugging.
866              
867             use Sub::Mage;
868            
869             tag 'test' => 'Test was run!'
870              
871             sub test { print "World"; }
872             test; # outputs 'Test was run!' then 'World'
873              
874             You can call it from a remote package, too.
875              
876             # Foo.pm
877             package Foo;
878            
879             use Sub::Mage;
880            
881             sub hello { print "hi"; }
882             sub bye { print "goodbye"; }
883              
884             # goose.pl
885            
886             use Foo;
887              
888             Foo->tag( [qw(hello goodbye)], 'Tagged subroutines called' );
889              
890             Foo->hello;
891             Foo->goodbye;
892              
893             If you tag multiple subroutines, to avoid confusion Sub::Mage will output the name of the subroutine in brackets at the end of the message.
894              
895             =head2 constructor
896              
897             Basically just C. I wanted to keep the initialisation of a module and the destruction of it same-ish.
898              
899             constructor sub {
900             my ($class, $args) = @_;
901             print "$class has loaded\n";
902             };
903            
904             =head2 destructor
905              
906             Same as constructor, but is run when the module has finished.
907              
908             destructor sub {
909             my $self = shift;
910             print "Module finished: $self->{some_var}\n";
911             };
912              
913             =head2 sublist
914              
915             Fetches an array of available subroutines in the current package.
916              
917             foreach my $sub (sublist) {
918             print "Running $sub\n";
919             eval $sub;
920             }
921              
922             my @subs = sublist;
923             print "Found " . scalar(@subs) . " subroutines\n";
924              
925             =head1 AUTHOR
926              
927             Brad Haywood
928              
929             =head1 LICENSE
930              
931             You may distribute this code under the same terms as Perl itself.
932              
933             =cut
934              
935             1;