File Coverage

blib/lib/Devel/GlobalSub.pm
Criterion Covered Total %
statement 48 48 100.0
branch 11 12 91.6
condition 10 12 83.3
subroutine 8 8 100.0
pod n/a
total 77 80 96.2


line stmt bran cond sub pod time code
1             package Devel::GlobalSub;
2 2     2   56096 use 5.006;
  2         7  
3 2     2   9 use strict;
  2         4  
  2         48  
4 2     2   10 use warnings;
  2         3  
  2         377  
5            
6             our $VERSION = '0.03';
7            
8             unshift @INC, \&_inject;
9             my $seen;
10             my @EXPORT;
11            
12             sub import {
13 2     2   11 my $self = shift;
14 2         7 my ($package, $file, $line) = caller;
15 2         12 for my $name (@_) {
16 2         3 my $full_name = $name;
17 2 50       7 unless ($name =~ /::/) {
18 2         5 $full_name = "${package}::$name";
19             }
20 2         59 push @EXPORT, $full_name;
21             }
22             }
23            
24             sub _inject {
25 2     2   15 no strict 'refs';
  2         3  
  2         427  
26 44     44   216884 my @known_packages = keys %{_get_known_packages()};
  44         129  
27 44         625 my $caller = caller;
28 44         4713 for my $sub (@EXPORT) {
29 76         760 my ($sub_pack, $sub_name) = split /::([^:]+)$/, $sub;
30 76         6152 for my $package (sort @known_packages) {
31 15452 100       17895 if (not defined &{"${package}::$sub_name"}) {
  15452         70370  
32 460         686 *{"${package}::$sub_name"} = \&{$sub};
  460         2493  
  460         895  
33             }
34             }
35             }
36             }
37            
38             sub _get_known_packages {
39 264 100   264   2348 my @packs = @_ ? @_ : 'main';
40 264         854 my $result = {main => 1};
41 264         485 my @todo;
42 264         489 for my $pack (@packs) {
43 2     2   22 no strict 'refs';
  2         3  
  2         452  
44 9072         12465 while (my ($key, $val) = each %{*{"$pack\::"}}) {
  186065         224946  
  186065         675594  
45 176993         267882 local(*ENTRY) = $val;
46 176993 100 66     625560 if (
      100        
      100        
      66        
47             defined $val &&
48             defined *ENTRY{HASH} &&
49             $key =~ /::$/ &&
50             $key ne 'main::' &&
51             $key ne '::'
52             ) {
53 9028 100       18743 my $p = $pack ne 'main' ? "$pack\::" : '';
54 9028         26661 ($p .= $key) =~ s/::$//;
55 9028         19503 $result->{$p}++;
56 9028         21117 push @todo, $p;
57             }
58             }
59             }
60 264 100       3015 $result = {%$result, %{_get_known_packages(@todo)}} if @todo;
  220         1369  
61 264         11431 $result;
62             }
63            
64             1;
65            
66            
67             =head1 NAME
68            
69             Devel::GlobalSub - Automagically import a subroutine into all namespaces
70            
71             =head1 VERSION
72            
73             Version 0.03
74            
75             =head1 SYNOPSIS
76            
77             *** WARNING ***
78            
79             This module will allow you to import one or more subroutines into all namespaces automatically.
80            
81             Please note: This is generally A REALLY BAD IDEA. You should never use this module in production environments. If you need your project to import subroutines into some namespaces, do it the normal way: using Exporter or some other controlled method.
82            
83             This module should be useful only for development purposes. For example, when you temporarily want a certain subroutine to be available anywhere in a project for debugging purposes.
84            
85             Using this module for purposes other than development/debugging is a terrible idea. You've been warned.
86            
87             You can use this module
88            
89             To ensure this module to properly work, loading it should be the very first thing your code does. Ideally, you shouldn't even use the module in your code, but in your call to Perl (see bellow). If this module is called late, it might not be able to discover all known namespaces and consequently not be able to import your desired subroutines.
90            
91             First, you want to write a module of your own, where you can define which subroutines will be globally available. Example:
92            
93             # File: MyGlobalSubs.pm
94            
95             # Very first thing in your code:
96             use Devel::GlobalSub qw(global_sub_1 global_sub_2);
97            
98             sub global_sub_1 {
99             print "I'm global_sub_1 being called!\n";
100             }
101            
102             sub global_sub_2 {
103             print "I'm global_sub_2 being called!\n";
104             }
105            
106             1;
107            
108             Later, the ideal point in time to inject your global functions, is in the call to Perl. Example:
109            
110             joe@devbox:~$ perl -MMyGlobalSubs some_script.pl
111            
112             If you need to tell perl where your module is, you can also do this, assuming you have your module at /home/joe/my_perl_libs/MyGlobalSubs.pm:
113            
114             joe@devbox:~$ perl -I/home/joe/my_perl_libs -MMyGlobalSubs some_script.pl
115            
116             If that's is not possible for you for any reason, then you can simply call your module in your script. But, it should be the first thing that gets loaded in your code, so it should be also be called in the main script being executed. Example:
117            
118             #!/usr/bin/perl
119             # File: some_script.pl
120            
121             use MyGlobalSubs qw(exported_1 exported_2); # <- Very first thing in your code
122             use strict;
123             use warnings;
124            
125             # ... the rest of your code
126            
127            
128            
129             =head1 EXPORT
130            
131             None.
132            
133             =head1 SUBROUTINES/METHODS
134            
135             =head2 Devel::GlobalSub->import(@list_of_sub_names)
136            
137             You shouldn't ever need to call import. This module works only if it is called at compile time. By simply Cing it, the import method is automatically invoked, like with any other module. That is:
138            
139             use Devel::GlobalSub qw(your_global_sub1 your_global_sub_2 your_global_sub_3 etc);
140            
141             It needs to receive the names of the subroutines you want to export everywhere. For exmaple:
142            
143             # File: MyGlobalSubs.pm
144            
145             use Devel::GlobalSub qw(global_sub_1 global_sub_2); # Just the names, not references
146             use strict;
147             use warnings;
148            
149             # Define the subs you are exporting:
150            
151             sub global_sub_1 {
152             print "I'm global_sub_1 being called!\n";
153             }
154            
155             sub global_sub_2 {
156             print "I'm global_sub_2 being called!\n";
157             }
158            
159             1;
160            
161             If you call this module after having called other modules, you might not see your functions exported everywhere, or at all.
162            
163             =head1 AUTHOR
164            
165             Francisco Zarabozo, C<< >>
166            
167             =head1 BACKGROUND/WHY
168            
169             As noted at the beginning: This is generally a really bad idea and it shouldn't be ever used as a permanent solution. So, why did I write it?
170            
171             I work on big projects at my everyday job. Many under platforms like Catalyst or Mojolicious. Some times, I need to do some custom debugging in them and I use some personal debugging modules/functions for that. For example, to send deugging information/messages to a custom file I'm following through `tail -f` in a separate console, away from the rest of the system logging, making it really easy to read for me.
172            
173             I found myself constantly wanting to use my custom tools, and having to edit each file in the project where I wanted to run them, having to C my custom module on each one, or having to call my subs with fully qualified names.
174            
175             I wanted something cleaner, quick to type, that didn't need me to add unnecessary, some times dangerous lines to the files. I resolved it with this module. I include it in my call to Perl as:
176            
177             perl -I/home/me/perllibs -MMyDebuggingModule some_project_startup_script.pl -D
178            
179             And with that, I can suddenly put a line in the middle of any file in the project like this:
180            
181             # Some code...
182             my_debug('Hi there, here are some objects:', $request, $stash, $schema);
183             # Some more code
184            
185             After my work is complete, it's a lot easier to search for the lines I need to delete this way. Also, there's no possible way this will run in another machine, as it is not defined anywhere for real.
186            
187             =head1 BUGS
188            
189             Please report any bugs or feature requests to C, or through
190             the web interface at L. I will be notified, and then you'll
191             automatically be notified of progress on your bug as I make changes.
192            
193            
194             =head1 SUPPORT
195            
196             You can find documentation for this module with the perldoc command.
197            
198             perldoc Devel::GlobalSub
199            
200            
201             You can also look for information at:
202            
203             =over 4
204            
205             =item * RT: CPAN's request tracker (report bugs here)
206            
207             L
208            
209             =item * AnnoCPAN: Annotated CPAN documentation
210            
211             L
212            
213             =item * CPAN Ratings
214            
215             L
216            
217             =item * Search CPAN
218            
219             L
220            
221             =back
222            
223            
224             =head1 ACKNOWLEDGEMENTS
225            
226            
227             =head1 LICENSE AND COPYRIGHT
228            
229             This software is copyright (c) 2021 by Francisco Zarabozo.
230            
231             This is free software; you can redistribute it and/or modify it under
232             the same terms as the Perl 5 programming language system itself.
233            
234            
235             =cut